an embedded browser can put its folder in a query param
`urlPath` was the wrong tool and I reached for it because it was there. it owns the URL's PATHNAME — reads the folder out of `location.pathname`, navigates to `/files/<folder>` — which is correct for the Files screen, because that screen IS that route, and catastrophic in a panel: opening a folder in the fofos Media section took the whole app to /files. so an embedder gets its own mechanism rather than a shared one bent to fit. `pathParam` names a SEARCH param and never touches the pathname. three sources of the current folder now, mutually exclusive by construction: the pathname for /files, a named query param for an embedder, component state for an ordinary panel. two details that are not obvious and would each be a bug: a param naming a folder OUTSIDE `basePath` is ignored rather than obeyed. it arrives from a URL somebody may have edited, and the jail is the whole promise of an embedded browser — a shared link must not be a way through it. the base folder is the ABSENCE of the param, not a value. so a link to the top of an embedded browser is the plain screen URL, and nothing accumulates in the query string for having done nothing. written with `replace`, because browsing folders is not navigation anybody wants twenty back-button presses of. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -13,6 +13,13 @@ type FileBrowserAppProps = {
|
||||
rootOverride?: string;
|
||||
/** What the root crumb is called. Defaults to the base folder's own name. */
|
||||
rootLabel?: string;
|
||||
/**
|
||||
* Keep the current folder in this query param, on the route you are already on.
|
||||
*
|
||||
* For an embedded browser that wants a reloadable, shareable location. NOT `urlPath`, which owns the
|
||||
* pathname and navigates to `/files` — passing that from a panel takes the whole app with it.
|
||||
*/
|
||||
pathParam?: string;
|
||||
/** Put the current folder in `?path=`. Opt-in — only the /files screen is guaranteed one browser. */
|
||||
urlPath?: boolean;
|
||||
/**
|
||||
@@ -22,8 +29,15 @@ type FileBrowserAppProps = {
|
||||
panelId?: string;
|
||||
};
|
||||
|
||||
export const FileBrowserApp = ({ basePath = '/', rootOverride, rootLabel, urlPath, panelId }: FileBrowserAppProps) => {
|
||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId);
|
||||
export const FileBrowserApp = ({
|
||||
basePath = '/',
|
||||
rootOverride,
|
||||
rootLabel,
|
||||
urlPath,
|
||||
panelId,
|
||||
pathParam,
|
||||
}: FileBrowserAppProps) => {
|
||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId, pathParam);
|
||||
const { handleNavigate } = fileBrowserManager;
|
||||
|
||||
return (
|
||||
|
||||
@@ -24,7 +24,25 @@ import { useTranslation } from '../../../locales';
|
||||
*/
|
||||
export const FILES_PATH_PARAM = 'path';
|
||||
|
||||
export const useFileBrowserApp = (basePath: string, rootOverride?: string, urlPath = false, panelId?: string) => {
|
||||
/**
|
||||
* `pathParam` — keep the current folder in a QUERY PARAM, on whatever route we are already on.
|
||||
*
|
||||
* This is not `urlPath` and must not be confused with it. `urlPath` owns the URL's PATHNAME: it reads
|
||||
* the folder out of `location.pathname` and navigates to `/files/<folder>`. That is correct for the
|
||||
* Files screen, which IS that route, and catastrophic inside a panel — a plugin passing `urlPath`
|
||||
* navigated the whole app to /files the moment anybody opened a folder.
|
||||
*
|
||||
* So an embedder gets its own mechanism: a named search param, written with `replace` so browsing does
|
||||
* not fill the back stack, and no pathname involved at all. A reload lands where you were and the link
|
||||
* can be sent to somebody, which is what was actually wanted.
|
||||
*/
|
||||
export const useFileBrowserApp = (
|
||||
basePath: string,
|
||||
rootOverride?: string,
|
||||
urlPath = false,
|
||||
panelId?: string,
|
||||
pathParam?: string,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
Reference in New Issue
Block a user