diff --git a/web/src/lib/components/layout/LeftSidebar.svelte b/web/src/lib/components/layout/LeftSidebar.svelte index c53eae3..41801f1 100644 --- a/web/src/lib/components/layout/LeftSidebar.svelte +++ b/web/src/lib/components/layout/LeftSidebar.svelte @@ -43,7 +43,13 @@ type Section, type TagCategory } from '$lib/stores/filters.svelte'; - import { isAuthenticated, session, userBasePath } from '$lib/stores/session.svelte'; + import { + isAuthenticated, + session, + userBasePath, + toOriginalsPath, + toUserPath + } from '$lib/stores/session.svelte'; import { openMove } from '$lib/stores/moveDialog.svelte'; import { indexer } from '$lib/stores/indexer.svelte'; import FolderTree, { buildTree } from './FolderTree.svelte'; @@ -285,10 +291,15 @@ } const createFolderMut = createMutation(() => ({ - mutationFn: (relPath: string) => createFolder(relPath), + // The sidebar deals in user-relative paths (BasePath stripped); the + // sidecar operates on originals-relative paths. Translate on the way + // out (toOriginalsPath) and back for display (toUserPath), exactly like + // the move flow — otherwise a BasePath user's folder ops resolve to the + // wrong directory and the sidecar returns "invalid path". + mutationFn: (relPath: string) => createFolder(toOriginalsPath(relPath)), onSuccess: (r) => { qc.invalidateQueries({ queryKey: ['folders'] }); - toast.success(`Folder created: ${r.path}`); + toast.success(`Folder created: ${toUserPath(r.path)}`); }, onError: (err) => toast.error(err instanceof Error ? err.message : 'Could not create folder') @@ -296,31 +307,36 @@ const renameFolderMut = createMutation(() => ({ mutationFn: (args: { rel: string; newName: string }) => - renameFolder(args.rel, args.newName), + renameFolder(toOriginalsPath(args.rel), args.newName), onSuccess: (r) => { qc.invalidateQueries({ queryKey: ['folders'] }); qc.invalidateQueries({ queryKey: ['photos'] }); + // Handler returns originals-relative paths; map back to the UI's + // user-relative space before comparing/navigating. + const oldUi = toUserPath(r.oldPath); + const newUi = toUserPath(r.newPath); // If the active folder filter was on this folder, follow the rename. - if (filters.folderPath === r.oldPath) { - setFolderPath(r.newPath); - const params = new URLSearchParams({ folder: r.newPath }); + if (filters.folderPath === oldUi) { + setFolderPath(newUi); + const params = new URLSearchParams({ folder: newUi }); void goto(`/?${params.toString()}`, { keepFocus: true, noScroll: true }); } - toast.success(`Renamed: ${r.oldPath} → ${r.newPath}`); + toast.success(`Renamed: ${oldUi} → ${newUi}`); }, onError: (err) => toast.error(err instanceof Error ? err.message : 'Rename failed') })); const deleteFolderMut = createMutation(() => ({ - mutationFn: (rel: string) => deleteFolder(rel), + mutationFn: (rel: string) => deleteFolder(toOriginalsPath(rel)), onSuccess: (r) => { qc.invalidateQueries({ queryKey: ['folders'] }); - if (filters.folderPath && filters.folderPath.startsWith(r.path)) { + const ui = toUserPath(r.path); + if (filters.folderPath && filters.folderPath.startsWith(ui)) { setFolderPath(null); void goto('/', { keepFocus: true, noScroll: true }); } - toast.success(`Folder deleted: ${r.path}`); + toast.success(`Folder deleted: ${ui}`); }, onError: (err) => toast.error(err instanceof Error ? err.message : 'Delete failed')