the file browser can be a file picker
A prop, not a second component. `onPickFile` turns opening a file into handing it back rather than opening a viewer; folders still navigate, because choosing a file means getting to it. Building a picker separately would mean reimplementing a listing, a breadcrumb, sorting, thumbnails, upload and keyboard handling — all of it free to drift from the real browser, and none of it better. fofos-admin needs one to choose media and it is the first of several, so this belongs here rather than in the plugin. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ import { TaskRunnerDialog } from './components/TaskRunnerDialog';
|
||||
import { AgentRunnerDialog } from './components/AgentRunnerDialog';
|
||||
import { VideoDownloadDialog } from './components/VideoDownloadDialog';
|
||||
import { DictateDialog } from './components/DictateDialog';
|
||||
import { useFileBrowserApp } from './useFileBrowserApp';
|
||||
import { useFileBrowserApp, type PickedFile } from './useFileBrowserApp';
|
||||
|
||||
type FileBrowserAppProps = {
|
||||
basePath?: string;
|
||||
@@ -27,6 +27,14 @@ type FileBrowserAppProps = {
|
||||
* where the folder is the URL and already does.
|
||||
*/
|
||||
panelId?: string;
|
||||
/**
|
||||
* Turn this into a CHOOSER: opening a file hands it back instead of opening a viewer.
|
||||
*
|
||||
* Folders still navigate, because choosing a file means getting to it. A prop rather than a second
|
||||
* component — a picker built separately is a listing, a breadcrumb, a sort, thumbnails and keyboard
|
||||
* handling reimplemented, all of it free to drift from the real browser.
|
||||
*/
|
||||
onPickFile?: (file: PickedFile) => void;
|
||||
};
|
||||
|
||||
export const FileBrowserApp = ({
|
||||
@@ -36,8 +44,9 @@ export const FileBrowserApp = ({
|
||||
urlPath,
|
||||
panelId,
|
||||
pathParam,
|
||||
onPickFile,
|
||||
}: FileBrowserAppProps) => {
|
||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId, pathParam);
|
||||
const fileBrowserManager = useFileBrowserApp(basePath, rootOverride, urlPath, panelId, pathParam, onPickFile);
|
||||
const { handleNavigate } = fileBrowserManager;
|
||||
|
||||
return (
|
||||
|
||||
@@ -36,12 +36,17 @@ export const FILES_PATH_PARAM = 'path';
|
||||
* 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.
|
||||
*/
|
||||
/** What a picker is handed when somebody opens a file in pick mode. */
|
||||
export type PickedFile = { name: string; path: string; type: string };
|
||||
|
||||
export const useFileBrowserApp = (
|
||||
basePath: string,
|
||||
rootOverride?: string,
|
||||
urlPath = false,
|
||||
panelId?: string,
|
||||
pathParam?: string,
|
||||
/** Set to turn this into a chooser: opening a file calls this instead of a viewer. */
|
||||
onPickFile?: (file: PickedFile) => void,
|
||||
) => {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useAuth();
|
||||
@@ -475,6 +480,21 @@ export const useFileBrowserApp = (
|
||||
setCurrentPath(next);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
PICK MODE.
|
||||
|
||||
When a caller is using this browser to CHOOSE a file rather than to work in a folder, opening a
|
||||
file means handing it back — not opening a viewer the caller would then have to close. Folders
|
||||
still navigate above, because choosing a file requires getting to it.
|
||||
|
||||
A prop rather than a second browser: a picker built separately would be a listing, a breadcrumb,
|
||||
a sort, thumbnails and keyboard handling reimplemented, all of it drifting from the real one.
|
||||
This is the same component with one branch.
|
||||
*/
|
||||
if (onPickFile) {
|
||||
onPickFile({ name: entry.name, path: entryPath(entry.name), type: entry.type });
|
||||
return;
|
||||
}
|
||||
// An archive extracts rather than opening a pane. The viewer has nothing to show for one — it renders
|
||||
// a placeholder reading "Archive file" and the name you can already see in the listing — so a pane
|
||||
// was a step on the way to the only thing anyone opens a zip for. Extract resolves collisions, so a
|
||||
|
||||
@@ -9,6 +9,7 @@ export { useTasks, type TaskSummary } from './useTasks';
|
||||
export { useRecentFiles } from './useRecentFiles';
|
||||
export { usePinnedFiles } from './usePinnedFiles';
|
||||
export { FileBrowserApp, FileBrowserPanelWrapper } from './FileBrowserApp';
|
||||
export type { PickedFile } from './FileBrowserApp/useFileBrowserApp';
|
||||
export { FileBrowserWidget } from './FileBrowserWidget';
|
||||
export { TaskRunnerModal } from './FileBrowserApp/components/TaskRunnerModal';
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ export {
|
||||
useRecentFiles,
|
||||
usePinnedFiles,
|
||||
FileBrowserApp,
|
||||
type PickedFile,
|
||||
FileBrowserPanelWrapper,
|
||||
FileBrowserWidget,
|
||||
TaskRunnerModal,
|
||||
|
||||
Reference in New Issue
Block a user