From 10d5bda2adaf10b845c73e156112ef318a300ff4 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Sun, 29 Mar 2026 12:02:09 +0200 Subject: [PATCH] fix: select kind for synthetic folders --- .../components/__test__/restore-form.test.tsx | 1 + .../__tests__/snapshot-tree-browser.test.tsx | 25 +++++++++++++++++++ .../file-browsers/snapshot-tree-browser.tsx | 17 ++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/client/components/__test__/restore-form.test.tsx b/app/client/components/__test__/restore-form.test.tsx index 97dcfbf3..3638f1a5 100644 --- a/app/client/components/__test__/restore-form.test.tsx +++ b/app/client/components/__test__/restore-form.test.tsx @@ -70,6 +70,7 @@ describe("RestoreForm", () => { expect(restoreRequestBody).toEqual({ snapshotId: "snap-1", include: ["/mnt/project"], + selectedItemKind: "dir", overwrite: "always", }); }); diff --git a/app/client/components/file-browsers/__tests__/snapshot-tree-browser.test.tsx b/app/client/components/file-browsers/__tests__/snapshot-tree-browser.test.tsx index 463f6bc0..3e8fc202 100644 --- a/app/client/components/file-browsers/__tests__/snapshot-tree-browser.test.tsx +++ b/app/client/components/file-browsers/__tests__/snapshot-tree-browser.test.tsx @@ -82,6 +82,26 @@ describe("SnapshotTreeBrowser", () => { expect(await screen.findByRole("button", { name: "project" })).toBeTruthy(); }); + test("renders a single file when no display base path is available", async () => { + const requests = mockListSnapshotFiles({ + files: [{ name: "report.txt", path: "/mnt/project/report.txt", type: "file" }], + }); + + renderSnapshotTreeBrowser({ + queryBasePath: "/mnt/project/report.txt", + displayBasePath: undefined, + }); + + expect(await screen.findByRole("button", { name: "report.txt" })).toBeTruthy(); + expect(requests[0]).toEqual({ + shortId: "repo-1", + snapshotId: "snap-1", + path: "/mnt/project/report.txt", + offset: null, + limit: null, + }); + }); + test("returns the ancestor folder path when selecting above the query root", async () => { mockListSnapshotFiles({ files: [ @@ -91,6 +111,7 @@ describe("SnapshotTreeBrowser", () => { }); let selectedPaths: Set | undefined; + let selectedKind: "file" | "dir" | null = null; renderSnapshotTreeBrowser({ queryBasePath: "/mnt/project/subdir", @@ -99,6 +120,9 @@ describe("SnapshotTreeBrowser", () => { onSelectionChange: (paths) => { selectedPaths = paths; }, + onSingleSelectionKindChange: (kind) => { + selectedKind = kind; + }, }); const row = await screen.findByRole("button", { name: "project" }); @@ -107,6 +131,7 @@ describe("SnapshotTreeBrowser", () => { await userEvent.click(checkbox); expect(selectedPaths ? Array.from(selectedPaths) : []).toEqual(["/mnt/project"]); + expect(selectedKind === "dir").toBe(true); }); test("shows selected folder state when full paths are provided from the parent", async () => { diff --git a/app/client/components/file-browsers/snapshot-tree-browser.tsx b/app/client/components/file-browsers/snapshot-tree-browser.tsx index f6879888..8a764415 100644 --- a/app/client/components/file-browsers/snapshot-tree-browser.tsx +++ b/app/client/components/file-browsers/snapshot-tree-browser.tsx @@ -47,7 +47,7 @@ export const SnapshotTreeBrowser = (props: SnapshotTreeBrowserProps) => { const { selectedPaths, onSelectionChange, onSingleSelectionKindChange, ...fileBrowserUiProps } = uiProps; const queryClient = useQueryClient(); const normalizedQueryBasePath = normalizeAbsolutePath(queryBasePath); - const normalizedDisplayBasePath = normalizeAbsolutePath(displayBasePath ?? normalizedQueryBasePath); + const normalizedDisplayBasePath = normalizeAbsolutePath(displayBasePath ?? "/"); const { data, isLoading, error } = useQuery({ ...listSnapshotFilesOptions({ @@ -98,6 +98,21 @@ export const SnapshotTreeBrowser = (props: SnapshotTreeBrowserProps) => { const kinds = new Map(); for (const entry of fileBrowser.fileArray) { kinds.set(entry.path, entry.type === "file" ? "file" : "dir"); + + let parentPath = entry.path; + while (true) { + const lastSlashIndex = parentPath.lastIndexOf("/"); + if (lastSlashIndex <= 0) { + break; + } + + parentPath = parentPath.slice(0, lastSlashIndex); + if (kinds.has(parentPath)) { + continue; + } + + kinds.set(parentPath, "dir"); + } } return kinds; }, [fileBrowser.fileArray]);