a plugin can put an action in the file browser's context menu
Tasks already reach that menu and are right for "do this to these files" — a script, run as the owner, reported through the job system, needing no frontend. They are the wrong shape for anything that continues in the interface. "Create Gallery" from a folder is not a job to watch; it is a name to type and a screen to land on, and expressing that as a script would mean a job whose only output is somewhere to go next. So a plugin exports `fileActions` from `web/file-actions.ts` and the generated module collects them. Presence on disk is the declaration, exactly as panels.ts and layout.ts already are — the manifest says nothing, because an action carries its own label and decides for itself whether it applies. They are registered by injection rather than imported by the browser. Plugins.gen.tsx is generated INTO the app, and the file browser lives in a workspace package that app depends on; importing it there would point the dependency backwards and make the package unusable outside Officer's frontend. The selection is resolved by FileGrid, which has it, and FileItem is handed ready-made items. An action receives the whole selection when the right-clicked item is part of one and just that item otherwise — what every file manager does; acting on a selection the click was not part of is the surprising alternative. An action whose `appliesTo` throws hides itself rather than breaking the menu for everything else on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,8 @@ function findWeb(
|
||||
screens: [
|
||||
{ segment: null, label: manifest?.label ?? appName, icon: manifest?.icon, art: null, panels, layout },
|
||||
],
|
||||
// Optional and unannounced — presence is the declaration, as it is for panels and layout.
|
||||
fileActions: fileOrNull(join(webDir, 'file-actions.ts')),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -157,7 +159,7 @@ function findWeb(
|
||||
}
|
||||
|
||||
if (problems.length) return { web: null, error: `${appName}: ${problems.join('; ')}.` };
|
||||
return { web: { screens } };
|
||||
return { web: { screens, fileActions: fileOrNull(join(webDir, 'file-actions.ts')) } };
|
||||
}
|
||||
|
||||
const fileOrNull = (path: string): string | null => (existsSync(path) ? path : null);
|
||||
|
||||
Reference in New Issue
Block a user