a Media section, browsing the site's originals in place
a new section above Administration. it embeds THE PLATFORM'S OWN file browser rather than drawing a file list — upload, delete, rename, move, thumbnails, the context menu and every task hanging off it already exist and are maintained in one place. a plugin's own would be a second to keep in step, arriving without any of that. `basePath` IS A JAIL, not a starting folder: `useFileBrowserApp` resets currentPath whenever it leaves, so pointing it at `<root>/media/originals` means the breadcrumb stops there and `derived/` is not reachable by navigating. that is what was asked for — people work in originals, derived is made for them. IT IS A GUARDRAIL AND NOT A PERMISSION BOUNDARY, and the panel says so in its own docstring because the difference will matter to whoever reads this next. the file-browser API is unchanged and still addresses the whole home: anyone with file access reaches derived/ through the Files screen. this prevents an accident, not a determined person. confining it properly means scoping that API per user, which is a platform change and a much larger one. the panel also says, once, that derived/ exists and is made from these — otherwise somebody who knows about it would think it had been lost. `rootRelative` is new on the settings API because only the SERVER knows what home is. the file browser addresses everything relative to a root, and a browser deriving that prefix from the absolute path would be guessing. null when the root sits outside home — a legitimate setting the browser cannot address, which the panel explains rather than rendering an empty folder. NOTHING HERE IS FOFOS-SPECIFIC, which matters now that this plugin is the template for other site admins: the root is a setting, media/originals is the layout this plugin creates, and both are read from the API. another site's plugin changes the label. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+23
-1
@@ -29,6 +29,18 @@ import { fofosAdminSettings } from '../db/schema';
|
||||
export type SettingsView = {
|
||||
/** Absolute. Never null — an unset root reports its default rather than nothing. */
|
||||
rootPath: string;
|
||||
/**
|
||||
* The same place, relative to the owner's home, with a leading slash.
|
||||
*
|
||||
* The file browser addresses everything relative to a root — `home` — so a panel embedding it needs
|
||||
* this form and cannot work it out: only the server knows what home is, and a browser computing it
|
||||
* from the absolute path would be guessing at a prefix.
|
||||
*
|
||||
* Null when the root is outside home. That is a legitimate configuration — the root may be anywhere
|
||||
* absolute — and it means the embedded browser cannot show it, which the panel says rather than
|
||||
* rendering an empty folder.
|
||||
*/
|
||||
rootRelative: string | null;
|
||||
/** False while the default is standing in, so a form can show it as a suggestion, not a choice. */
|
||||
isSet: boolean;
|
||||
};
|
||||
@@ -44,7 +56,17 @@ export const defaultRootPath = (email: string): string => join(getOwnerHomeDir(e
|
||||
export async function readSettings(email: string): Promise<SettingsView> {
|
||||
const found = await row();
|
||||
const stored = found?.rootPath ?? null;
|
||||
return { rootPath: stored ?? defaultRootPath(email), isSet: stored !== null };
|
||||
const rootPath = stored ?? defaultRootPath(email);
|
||||
|
||||
// `home` or a path beneath it — anything else is outside what the file browser can address.
|
||||
const home = getOwnerHomeDir(email);
|
||||
const inside = rootPath === home || rootPath.startsWith(`${home}/`);
|
||||
|
||||
return {
|
||||
rootPath,
|
||||
rootRelative: inside ? `/${rootPath.slice(home.length).replace(/^\/+/, '')}`.replace(/\/$/, '') || '/' : null,
|
||||
isSet: stored !== null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user