From cad0ea3c9cfcf7c3653c6361255258244c009f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 29 Aug 2026 08:50:30 +0100 Subject: [PATCH] the embedded file browser can name its own root crumb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `rootLabel` on FileBrowserApp, through to the breadcrumb. it defaults to the base folder's own name, which is right for /files and wrong for an embedder: a panel scoped to `/media/originals` is called Media, and "originals" is an implementation detail of how that plugin lays out a directory. the person looking at it never chose that word and has no reason to recognise it. one prop rather than the plugin drawing its own breadcrumb — which is the same trade as embedding the browser at all: upload, delete, thumbnails and the context menu come from one maintained place, and this is the small thing that was missing to make that honest. Co-Authored-By: Claude Opus 5 Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043 --- .../FileBrowser/FileBrowserApp/FileBrowserApp.tsx | 5 ++++- .../FileBrowserApp/components/Breadcrumb.tsx | 12 ++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx index 645e9e04..d84356c7 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/FileBrowserApp.tsx @@ -11,6 +11,8 @@ import { useFileBrowserApp } from './useFileBrowserApp'; type FileBrowserAppProps = { basePath?: string; rootOverride?: string; + /** What the root crumb is called. Defaults to the base folder's own name. */ + rootLabel?: string; /** Put the current folder in `?path=`. Opt-in — only the /files screen is guaranteed one browser. */ urlPath?: boolean; /** @@ -20,7 +22,7 @@ type FileBrowserAppProps = { panelId?: string; }; -export const FileBrowserApp = ({ basePath = '/', rootOverride, urlPath, panelId }: FileBrowserAppProps) => { +export const FileBrowserApp = ({ basePath = '/', rootOverride, rootLabel, urlPath, panelId }: FileBrowserAppProps) => { const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId); const { handleNavigate } = fileBrowserManager; @@ -31,6 +33,7 @@ export const FileBrowserApp = ({ basePath = '/', rootOverride, urlPath, panelId path={fileBrowserManager.currentPath} onNavigate={handleNavigate} basePath={basePath} + rootLabel={rootLabel} hrefForPath={fileBrowserManager.hrefForPath} /> diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx index 2741a200..e3993bb5 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/Breadcrumb.tsx @@ -5,6 +5,14 @@ type BreadcrumbProps = { path: string; onNavigate: (path: string) => void; basePath?: string; + /** + * What to call the root crumb. + * + * Defaults to the base folder's own name, which is right for `/files` and wrong for an embedder: a + * panel scoped to `/media/originals` is called Media, and "originals" is an implementation + * detail of how that plugin lays out a directory. The person looking at it never chose that word. + */ + rootLabel?: string; /** * Where a folder lives, when this browser owns the address bar. Given, the crumbs are real links and * cmd-click opens the folder in a new tab; absent (a dashboard panel, the widget) they stay buttons, @@ -15,7 +23,7 @@ type BreadcrumbProps = { hrefForPath?: ((path: string) => { pathname: string; search: string }) | null; }; -export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath }: BreadcrumbProps) => { +export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath, rootLabel }: BreadcrumbProps) => { const relativePath = basePath !== '/' && path.startsWith(basePath) ? path.slice(basePath.length) : path; const segments = relativePath.split('/').filter(Boolean); @@ -35,7 +43,7 @@ export const Breadcrumb = ({ path, onNavigate, basePath = '/', hrefForPath }: Br