chore: pr feedbacks

This commit is contained in:
Nicolas Meienberger 2026-02-18 19:58:20 +01:00
parent bb102b0619
commit 221fd18820
6 changed files with 42 additions and 59 deletions

View file

@ -1,4 +1,4 @@
import { useCallback } from "react"; import { useCallback, useMemo } from "react";
import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useQuery, useQueryClient } from "@tanstack/react-query";
import { listSnapshotFilesOptions } from "~/client/api-client/@tanstack/react-query.gen"; import { listSnapshotFilesOptions } from "~/client/api-client/@tanstack/react-query.gen";
import { FileBrowser, type FileBrowserUiProps } from "~/client/components/file-browsers/file-browser"; import { FileBrowser, type FileBrowserUiProps } from "~/client/components/file-browsers/file-browser";
@ -28,6 +28,7 @@ export const SnapshotTreeBrowser = ({
enabled = true, enabled = true,
...uiProps ...uiProps
}: SnapshotTreeBrowserProps) => { }: SnapshotTreeBrowserProps) => {
const { selectedPaths, onSelectionChange, ...fileBrowserUiProps } = uiProps;
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const normalizedBasePath = normalizeAbsolutePath(basePath); const normalizedBasePath = normalizeAbsolutePath(basePath);
@ -60,6 +61,31 @@ export const SnapshotTreeBrowser = ({
[normalizedBasePath], [normalizedBasePath],
); );
const displaySelectedPaths = useMemo(() => {
if (!selectedPaths) return undefined;
const displayPaths = new Set<string>();
for (const fullPath of selectedPaths) {
displayPaths.add(stripBasePath(fullPath));
}
return displayPaths;
}, [selectedPaths, stripBasePath]);
const handleSelectionChange = useCallback(
(nextDisplayPaths: Set<string>) => {
if (!onSelectionChange) return;
const nextFullPaths = new Set<string>();
for (const displayPath of nextDisplayPaths) {
nextFullPaths.add(addBasePath(displayPath));
}
onSelectionChange(nextFullPaths);
},
[onSelectionChange, addBasePath],
);
const fileBrowser = useFileBrowser({ const fileBrowser = useFileBrowser({
initialData: data, initialData: data,
isLoading, isLoading,
@ -102,7 +128,7 @@ export const SnapshotTreeBrowser = ({
return ( return (
<FileBrowser <FileBrowser
{...uiProps} {...fileBrowserUiProps}
fileArray={fileBrowser.fileArray} fileArray={fileBrowser.fileArray}
expandedFolders={fileBrowser.expandedFolders} expandedFolders={fileBrowser.expandedFolders}
loadingFolders={fileBrowser.loadingFolders} loadingFolders={fileBrowser.loadingFolders}
@ -113,7 +139,9 @@ export const SnapshotTreeBrowser = ({
isLoading={fileBrowser.isLoading} isLoading={fileBrowser.isLoading}
isEmpty={fileBrowser.isEmpty} isEmpty={fileBrowser.isEmpty}
errorMessage={errorMessage} errorMessage={errorMessage}
loadingMessage={uiProps.loadingMessage ?? "Loading files..."} loadingMessage={fileBrowserUiProps.loadingMessage ?? "Loading files..."}
selectedPaths={displaySelectedPaths}
onSelectionChange={onSelectionChange ? handleSelectionChange : undefined}
/> />
); );
}; };

View file

@ -1,5 +1,5 @@
import { useState } from "react"; import { useState } from "react";
import { LocalFileBrowser } from "./file-browsers/local-file-browser"; import { DirectoryBrowser } from "./file-browsers/directory-browser";
import { Button } from "./ui/button"; import { Button } from "./ui/button";
type Props = { type Props = {
@ -14,21 +14,12 @@ export const PathSelector = ({ value, onChange }: Props) => {
if (showBrowser) { if (showBrowser) {
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<LocalFileBrowser <DirectoryBrowser
className="border rounded-lg overflow-hidden" selectedPath={value}
useScrollArea onSelectPath={(path) => {
scrollAreaClassName="h-64"
foldersOnly
selectableFolders
selectedFolder={value}
onFolderSelect={(path) => {
onChange(path); onChange(path);
setShowBrowser(false); setShowBrowser(false);
}} }}
showSelectedPathFooter
selectedPath={value}
loadingMessage="Loading directories..."
emptyMessage="No subdirectories found"
/> />
<Button type="button" variant="ghost" size="sm" onClick={() => setShowBrowser(false)}> <Button type="button" variant="ghost" size="sm" onClick={() => setShowBrowser(false)}>
Cancel Cancel

View file

@ -88,17 +88,6 @@ export function RestoreForm({ snapshot, repository, snapshotId, returnPath }: Re
}; };
}, [addEventListener, repository.id, snapshotId]); }, [addEventListener, repository.id, snapshotId]);
const addBasePath = useCallback(
(displayPath: string): string => {
const vbp = volumeBasePath === "/" ? "" : volumeBasePath;
if (!vbp) return displayPath;
if (displayPath === "/") return vbp;
return `${vbp}${displayPath}`;
},
[volumeBasePath],
);
const { mutate: restoreSnapshot, isPending: isRestoring } = useMutation({ const { mutate: restoreSnapshot, isPending: isRestoring } = useMutation({
...restoreSnapshotMutation(), ...restoreSnapshotMutation(),
onError: (error) => { onError: (error) => {
@ -117,8 +106,7 @@ export function RestoreForm({ snapshot, repository, snapshotId, returnPath }: Re
const isCustomLocation = restoreLocation === "custom"; const isCustomLocation = restoreLocation === "custom";
const targetPath = isCustomLocation && customTargetPath.trim() ? customTargetPath.trim() : undefined; const targetPath = isCustomLocation && customTargetPath.trim() ? customTargetPath.trim() : undefined;
const pathsArray = Array.from(selectedPaths); const includePaths = Array.from(selectedPaths);
const includePaths = pathsArray.map((path) => addBasePath(path));
restoreCompletedRef.current = false; restoreCompletedRef.current = false;
setIsRestoreActive(true); setIsRestoreActive(true);
@ -142,7 +130,6 @@ export function RestoreForm({ snapshot, repository, snapshotId, returnPath }: Re
restoreLocation, restoreLocation,
customTargetPath, customTargetPath,
selectedPaths, selectedPaths,
addBasePath,
overwriteMode, overwriteMode,
restoreSnapshot, restoreSnapshot,
]); ]);

View file

@ -3,7 +3,7 @@ import type { UseFormReturn } from "react-hook-form";
import { Check, Pencil, X, AlertTriangle } from "lucide-react"; import { Check, Pencil, X, AlertTriangle } from "lucide-react";
import { Button } from "../../../../components/ui/button"; import { Button } from "../../../../components/ui/button";
import { FormItem, FormLabel, FormDescription, FormField, FormControl } from "../../../../components/ui/form"; import { FormItem, FormLabel, FormDescription, FormField, FormControl } from "../../../../components/ui/form";
import { LocalFileBrowser } from "../../../../components/file-browsers/local-file-browser"; import { DirectoryBrowser } from "../../../../components/file-browsers/directory-browser";
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
@ -96,20 +96,9 @@ export const LocalRepositoryForm = ({ form }: Props) => {
</AlertDialogDescription> </AlertDialogDescription>
</AlertDialogHeader> </AlertDialogHeader>
<div className="py-4"> <div className="py-4">
<LocalFileBrowser <DirectoryBrowser
className="border rounded-lg overflow-hidden" onSelectPath={field.onChange}
useScrollArea
scrollAreaClassName="h-64"
foldersOnly
selectableFolders
onFolderSelect={(path) => {
field.onChange(path);
}}
selectedFolder={field.value || constants.REPOSITORY_BASE}
showSelectedPathFooter
selectedPath={field.value || constants.REPOSITORY_BASE} selectedPath={field.value || constants.REPOSITORY_BASE}
loadingMessage="Loading directories..."
emptyMessage="No subdirectories found"
/> />
</div> </div>
<AlertDialogFooter> <AlertDialogFooter>

View file

@ -1,7 +1,7 @@
import { Pencil } from "lucide-react"; import { Pencil } from "lucide-react";
import type { UseFormReturn } from "react-hook-form"; import type { UseFormReturn } from "react-hook-form";
import type { FormValues } from "../create-volume-form"; import type { FormValues } from "../create-volume-form";
import { LocalFileBrowser } from "../../../../components/file-browsers/local-file-browser"; import { DirectoryBrowser } from "../../../../components/file-browsers/directory-browser";
import { Button } from "../../../../components/ui/button"; import { Button } from "../../../../components/ui/button";
import { import {
FormControl, FormControl,
@ -38,19 +38,7 @@ export const DirectoryForm = ({ form }: Props) => {
</Button> </Button>
</div> </div>
) : ( ) : (
<LocalFileBrowser <DirectoryBrowser onSelectPath={field.onChange} selectedPath={field.value} />
className="border rounded-lg overflow-hidden"
useScrollArea
scrollAreaClassName="h-64"
foldersOnly
selectableFolders
onFolderSelect={(path) => field.onChange(path)}
selectedFolder={field.value}
showSelectedPathFooter
selectedPath={field.value}
loadingMessage="Loading directories..."
emptyMessage="No subdirectories found"
/>
)} )}
</FormControl> </FormControl>
<FormDescription>Browse and select a directory on the host filesystem to track.</FormDescription> <FormDescription>Browse and select a directory on the host filesystem to track.</FormDescription>

View file

@ -5,7 +5,7 @@ export const findCommonAncestor = (paths: string[]): string => {
const splitPaths = paths.map((path) => path.split("/").filter(Boolean)); const splitPaths = paths.map((path) => path.split("/").filter(Boolean));
const minLength = Math.min(...splitPaths.map((parts) => parts.length)); const minLength = Math.min(...splitPaths.map((parts) => parts.length));
let commonParts: string[] = []; const commonParts: string[] = [];
for (let i = 0; i < minLength; i++) { for (let i = 0; i < minLength; i++) {
const partSet = new Set(splitPaths.map((parts) => parts[i])); const partSet = new Set(splitPaths.map((parts) => parts[i]));
if (partSet.size === 1) { if (partSet.size === 1) {