plugins contribute dock tiles, and the doc says what is actually built
offscale had no dock tile: that field comes from the app store's catalogue, so a plugin installed through the plugin system was reachable only by typing its url or following the link on /plugins. built at runtime rather than baked into the generated bundle, deliberately — WHO sees a tile is a permission question, and a grant takes effect on the next request rather than the next build. presentation comes from the manifest and the route from mountPrefix, so there is one source for both, and is the plugin's first permission so the endpoint can filter a tile out for an account that cannot reach the screen. two sources for tiles today, because the app store still has its own catalogue. one when it is rebuilt on this. the doc now records the system as complete rather than half-stubbed, including the three bugs the extraction found — the sidecar-before-mount ordering, the missing tailwind, and the build that could delete its own shell — and what is genuinely still open. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -162,3 +162,43 @@ export async function refreshPluginMounts(options: { skipFrontend?: boolean } =
|
||||
...(frontend ? { frontend } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dock tiles for installed, enabled plugins, in the shape the shell already renders
|
||||
* (`dockItemsFromPlugins`).
|
||||
*
|
||||
* Presentation comes from the manifest and the route from `mountPrefix`, so there is one source for both
|
||||
* and nothing to keep in step. `capability` is the plugin's first permission when it has one, which is
|
||||
* what lets `/api/user/capabilities` filter the tile out for an account that cannot reach the screen —
|
||||
* a member must not be handed the manifest of a feature they may not use, even to hide it.
|
||||
*
|
||||
* Built here rather than baked into the generated frontend module on purpose: WHO sees a tile is a
|
||||
* runtime question, because a grant takes effect on the next request rather than the next build.
|
||||
*/
|
||||
export async function pluginDockManifests(): Promise<
|
||||
Array<{
|
||||
sidecarId: string;
|
||||
capability: string | null;
|
||||
name: string;
|
||||
icon?: string;
|
||||
color: string;
|
||||
rootRoute: string;
|
||||
routes: string[];
|
||||
}>
|
||||
> {
|
||||
const { states } = await snapshotPlugins();
|
||||
return states
|
||||
.filter((s) => s.install?.enabled && s.plugin.web)
|
||||
.map(({ plugin }) => {
|
||||
const prefix = mountPrefix(plugin);
|
||||
return {
|
||||
sidecarId: plugin.appName,
|
||||
capability: plugin.manifest.permissions[0]?.key ?? null,
|
||||
name: plugin.manifest.label,
|
||||
icon: plugin.manifest.icon,
|
||||
color: plugin.manifest.color,
|
||||
rootRoute: prefix,
|
||||
routes: [prefix],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user