diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts index 616bb5a6..1bd3ed45 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/useFileBrowserApp.ts @@ -82,14 +82,41 @@ export const useFileBrowserApp = ( // visit still opens at home, because a URL with no `path` means the base. Either way the main // (unscoped) browser mirrors its folder into files/currentPath so the Create Dashboard flow can // default a new dashboard's cwd to it. - const currentPath = urlPath ? folderFromPathname(location.pathname) : localPath; + /* + Three sources, mutually exclusive by construction: the pathname for /files, a named query param for + an embedded browser, and component state for an ordinary panel. + + A param naming a folder OUTSIDE the jail is ignored rather than obeyed — it arrives from a URL + somebody may have edited, and `basePath` is the whole promise of an embedded browser. + */ + const paramPath = pathParam ? searchParams.get(pathParam) : null; + const currentPath = urlPath + ? folderFromPathname(location.pathname) + : pathParam + ? paramPath && paramPath.startsWith(basePath) + ? paramPath + : basePath + : localPath; const setCurrentPath = (path: string) => { // Leaving a folder closes what was open in it. A pane shows a file from the folder you were in, so // carrying it into the next one leaves the two disagreeing — the listing says one place, the pane // another. Only the OVERLAY params go; anything else in the query (global UI state) is left alone, // which is the distinction a wholesale reset kept getting wrong. if (urlPath) navigate({ pathname: folderHref(path), search: withoutViewerParams(location.search) }); - else { + else if (pathParam) { + setSearchParams( + (prev) => { + const next = new URLSearchParams(withoutViewerParams(prev.toString())); + // The base folder is the ABSENCE of the param, so a link to the top of an embedded browser is + // the plain screen URL and nothing accumulates for having gone nowhere. + if (path === basePath) next.delete(pathParam); + else next.set(pathParam, path); + return next; + }, + // Browsing folders is not navigation anybody wants twenty back-button presses of. + { replace: true }, + ); + } else { setLocalPath(path); // Written here rather than in an effect on `currentPath`, so it records a NAVIGATION and not the // initial render. An effect would fire once on mount with the restored value and persist it back,