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;
|
rootOverride?: string;
|
||||||
/** What the root crumb is called. Defaults to the base folder's own name. */
|
/** What the root crumb is called. Defaults to the base folder's own name. */
|
||||||
rootLabel?: string;
|
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. */
|
/** Put the current folder in `?path=`. Opt-in — only the /files screen is guaranteed one browser. */
|
||||||
urlPath?: boolean;
|
urlPath?: boolean;
|
||||||
/**
|
/**
|
||||||
@@ -22,8 +29,15 @@ type FileBrowserAppProps = {
|
|||||||
panelId?: string;
|
panelId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FileBrowserApp = ({ basePath = '/', rootOverride, rootLabel, urlPath, panelId }: FileBrowserAppProps) => {
|
export const FileBrowserApp = ({
|
||||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId);
|
basePath = '/',
|
||||||
|
rootOverride,
|
||||||
|
rootLabel,
|
||||||
|
urlPath,
|
||||||
|
panelId,
|
||||||
|
pathParam,
|
||||||
|
}: FileBrowserAppProps) => {
|
||||||
|
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId, pathParam);
|
||||||
const { handleNavigate } = fileBrowserManager;
|
const { handleNavigate } = fileBrowserManager;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -24,7 +24,25 @@ import { useTranslation } from '../../../locales';
|
|||||||
*/
|
*/
|
||||||
export const FILES_PATH_PARAM = 'path';
|
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 { t } = useTranslation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|||||||
Reference in New Issue
Block a user