feat: migrate folder browser to /api/file/search_subdirs (#100)

This commit is contained in:
Hiep Le
2026-05-06 21:40:45 +07:00
committed by GitHub
parent 179192ca01
commit 6a5d1b0049
4 changed files with 33 additions and 21 deletions
@@ -83,23 +83,23 @@ describe("WorkspaceSelectionForm", () => {
it("Add Workspaces opens Finder-like modal, navigates, and imports subfolders deduped on repeat", async () => {
vi.spyOn(FilesService, "getHome").mockResolvedValue({ home: "/Users/me" });
const listSpy = vi
.spyOn(FilesService, "listSubdirs")
const searchSpy = vi
.spyOn(FilesService, "searchSubdirs")
.mockImplementation(async (path: string) => {
if (path === "/Users/me") {
return {
path,
subdirs: [{ name: "dev", path: "/Users/me/dev" }],
items: [{ name: "dev", path: "/Users/me/dev" }],
next_page_id: null,
};
}
if (path === "/Users/me/dev") {
return {
path,
subdirs: [
items: [
{ name: "repo1", path: "/Users/me/dev/repo1" },
{ name: "repo2", path: "/Users/me/dev/repo2" },
{ name: "repo3", path: "/Users/me/dev/repo3" },
],
next_page_id: null,
};
}
throw new Error(`unexpected path ${path}`);
@@ -141,7 +141,7 @@ describe("WorkspaceSelectionForm", () => {
"/Users/me/dev/repo2",
"/Users/me/dev/repo3",
]);
expect(listSpy).toHaveBeenCalledWith("/Users/me/dev");
expect(searchSpy).toHaveBeenCalledWith("/Users/me/dev");
});
it("Launch creates a v1 conversation with the selected workspace path as working_dir", async () => {
+19 -7
View File
@@ -5,20 +5,32 @@ export interface SubdirectoryEntry {
path: string;
}
export interface ListSubdirsResponse {
path: string;
subdirs: SubdirectoryEntry[];
export interface SubdirectoryPage {
items: SubdirectoryEntry[];
next_page_id: string | null;
}
export interface HomeResponse {
home: string;
}
export interface SearchSubdirsOptions {
pageId?: string | null;
limit?: number;
}
const FilesService = {
async listSubdirs(path: string): Promise<ListSubdirsResponse> {
const response = await createHttpClient().get<ListSubdirsResponse>(
"/api/file/list_subdirs",
{ params: { path } },
async searchSubdirs(
path: string,
options: SearchSubdirsOptions = {},
): Promise<SubdirectoryPage> {
const params: Record<string, string | number> = { path };
if (options.pageId) params.page_id = options.pageId;
if (typeof options.limit === "number") params.limit = options.limit;
const response = await createHttpClient().get<SubdirectoryPage>(
"/api/file/search_subdirs",
{ params },
);
return response.data;
},
@@ -7,8 +7,8 @@ import { I18nKey } from "#/i18n/declaration";
import { LocalWorkspace } from "#/types/workspace";
import {
useHomeDirectory,
useListSubdirs,
} from "#/hooks/query/use-list-subdirs";
useSearchSubdirs,
} from "#/hooks/query/use-search-subdirs";
import { cn } from "#/utils/utils";
import FolderIcon from "#/icons/folder.svg?react";
import ChevronLeft from "#/icons/chevron-left-small.svg?react";
@@ -122,7 +122,7 @@ export function FolderBrowserModal({
isLoading,
isError,
error,
} = useListSubdirs(isOpen ? currentPath : null);
} = useSearchSubdirs(isOpen ? currentPath : null);
const sidebar = useMemo(
() => buildSidebar(homeData?.home ?? null),
@@ -131,7 +131,7 @@ export function FolderBrowserModal({
if (!isOpen) return null;
const subdirs = listing?.subdirs ?? [];
const subdirs = listing?.items ?? [];
const parent = currentPath ? getParentPath(currentPath) : null;
const handleUseThisFolder = () => {
@@ -1,10 +1,10 @@
import { useQuery } from "@tanstack/react-query";
import FilesService from "#/api/files-service/files-service.api";
export const useListSubdirs = (path: string | null) =>
export const useSearchSubdirs = (path: string | null) =>
useQuery({
queryKey: ["file", "list_subdirs", path],
queryFn: () => FilesService.listSubdirs(path as string),
queryKey: ["file", "search_subdirs", path],
queryFn: () => FilesService.searchSubdirs(path as string),
enabled: !!path,
retry: false,
meta: { disableToast: true },