a file action gets an authenticated client, because it cannot build one
`run` is an event handler outside React, so it cannot call `useClient` — and a bare fetch gets a 401, since this API authenticates with a bearer token rather than a cookie and only the hook holds it. So the browser hands one over in the context. Without it, the only way to call Officer's own API from an action was to reimplement the token handling, which is the kind of thing that works on one page and silently stops when the token rotates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+4
-1
@@ -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<HTMLDivElement | null>) => {
|
||||
|
||||
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 }),
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@@ -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: <T>(url: string) => Promise<T>;
|
||||
post: <T>(url: string, payload?: unknown) => Promise<T>;
|
||||
put: <T>(url: string, payload?: unknown) => Promise<T>;
|
||||
delete: <T>(url: string, payload?: unknown) => Promise<T>;
|
||||
};
|
||||
};
|
||||
|
||||
export type FileAction = {
|
||||
|
||||
Reference in New Issue
Block a user