diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx index 3ff50552..57a145f1 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx +++ b/src/workspaces/officerdev/src/apps/FileBrowser/FileBrowserApp/components/FileGrid.tsx @@ -4,6 +4,7 @@ import { ChevronUp, ChevronDown } from 'lucide-react'; import type { DirEntry } from '../../../../hooks/useFilesAPI'; import { getFileType } from '../../../FileViewer'; import type { UseFileBrowserAppType } from '../useFileBrowserApp'; +import { useClient } from 'hooks/useClient'; import { fileActionsFor } from '../../file-actions'; import { FileItem } from './FileItem'; import { useTranslation } from '../../../../locales'; @@ -62,6 +63,8 @@ const useColumnCount = (scrollRef: React.RefObject) => { export const FileGrid = ({ fileBrowserManager }: FileGridProps) => { const { t } = useTranslation(); + // For plugin actions: `run` is outside React and cannot call the hook itself. + const client = useClient(); const { visibleEntries: entries, viewMode, @@ -182,7 +185,7 @@ export const FileGrid = ({ fileBrowserManager }: FileGridProps) => { key: action.key, label: action.label, Icon: action.icon, - onClick: () => action.run(payload, { currentPath, refresh }), + onClick: () => action.run(payload, { currentPath, refresh, client }), })); }; diff --git a/src/workspaces/officerdev/src/apps/FileBrowser/file-actions.ts b/src/workspaces/officerdev/src/apps/FileBrowser/file-actions.ts index 392360bd..85849035 100644 --- a/src/workspaces/officerdev/src/apps/FileBrowser/file-actions.ts +++ b/src/workspaces/officerdev/src/apps/FileBrowser/file-actions.ts @@ -34,6 +34,19 @@ export type FileActionContext = { currentPath: string; /** Re-read the listing. For an action that creates or removes something on disk. */ refresh: () => void; + /** + * An authenticated client for Officer's API, rooted at `/api`. + * + * Handed over rather than left to the action, because there is no way for it to build one: `run` is + * called from an event handler outside React, so it cannot use `useClient`, and a bare `fetch` gets a + * 401 — this API authenticates with a bearer token, not a cookie, and only the hook holds it. + */ + client: { + get: (url: string) => Promise; + post: (url: string, payload?: unknown) => Promise; + put: (url: string, payload?: unknown) => Promise; + delete: (url: string, payload?: unknown) => Promise; + }; }; export type FileAction = {