diff --git a/packages/app/src/components/directory-picker-domain.test.ts b/packages/app/src/components/directory-picker-domain.test.ts index 1bc9af08334..c733a35e6b8 100644 --- a/packages/app/src/components/directory-picker-domain.test.ts +++ b/packages/app/src/components/directory-picker-domain.test.ts @@ -139,6 +139,7 @@ test("resolves directory autocomplete from the current browser root", async () = directories.push(input.location?.directory ?? "") return Promise.resolve({ data: [] }) }, + list: () => Promise.resolve({ data: [] }), }, }, } as unknown as Parameters[0]["sdk"] @@ -152,6 +153,70 @@ test("resolves directory autocomplete from the current browser root", async () = expect(directories).toEqual(["/repo", "/repo/src"]) }) +test("keeps indexed directory results for servers that support empty search", async () => { + const sdk = { + api: { + file: { + find: () => Promise.resolve({ data: [{ path: "projects/", type: "directory" }] }), + list: () => Promise.reject(new Error("listing should not run when search returns results")), + }, + }, + } as unknown as Parameters[0]["sdk"] + const search = createDirectorySearch({ sdk, home: () => "/home/luke", base: () => "/home/luke" }) + + expect(await search("")).toEqual(["/home/luke/projects"]) +}) + +test("lists the default directory when empty search is unsupported", async () => { + const calls: string[] = [] + const directories = Array.from({ length: 60 }, (_, index) => ({ + path: `project-${index}/`, + type: "directory" as const, + })) + const sdk = { + api: { + file: { + find: () => Promise.resolve({ data: [] }), + list: (input: { location?: { directory?: string } }) => { + calls.push(input.location?.directory ?? "") + return Promise.resolve({ + data: [ + ...directories, + { path: "README.md", type: "file" }, + ], + }) + }, + }, + }, + } as unknown as Parameters[0]["sdk"] + const search = createDirectorySearch({ sdk, home: () => "/home/luke", base: () => "/home/luke" }) + + const results = await search("") + expect(results).toHaveLength(60) + expect(results.at(-1)).toBe("/home/luke/project-59") + expect(calls).toEqual(["/home/luke"]) +}) + +test("matches the default directory listing when typed search is unsupported", async () => { + const sdk = { + api: { + file: { + find: () => Promise.resolve({ data: [] }), + list: () => + Promise.resolve({ + data: [ + { path: "Documents/", type: "directory" }, + { path: "Downloads/", type: "directory" }, + ], + }), + }, + }, + } as unknown as Parameters[0]["sdk"] + const search = createDirectorySearch({ sdk, home: () => "/home/luke", base: () => "/home/luke" }) + + expect(await search("documents")).toEqual(["/home/luke/Documents"]) +}) + test("searches from an absolute root without a default base", async () => { const directories: string[] = [] const sdk = { diff --git a/packages/app/src/components/directory-picker-domain.ts b/packages/app/src/components/directory-picker-domain.ts index 9539ae1d01d..dfd8ee74add 100644 --- a/packages/app/src/components/directory-picker-domain.ts +++ b/packages/app/src/components/directory-picker-domain.ts @@ -379,7 +379,14 @@ export function createDirectorySearch(args: { sdk: ServerSDK; base: () => string .then((result) => result.data.map((entry) => entry.path)) .catch(() => []) if (!active()) return [] - return results.map((path) => joinPickerPath(input.directory, path)).slice(0, 50) + if (results.length) { + return results.map((path) => joinPickerPath(input.directory, path)).slice(0, 50) + } + const fallback = query + ? await match(input.directory, query, 50) + : (await directories(input.directory)).map((item) => item.absolute) + if (!active()) return [] + return fallback } const segments = query.replace(/^\/+/, "").split("/") const head = segments.slice(0, -1).filter((part) => part && part !== ".")