From 2921553d40b61d2303459bf1a54039d4231166e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Salavisa?= Date: Tue, 21 Jul 2026 14:07:54 +0100 Subject: [PATCH] feat(plugins): render plugin-settings slot at top of settings page (#1838) Move the plugin-settings slot above the schema-driven settings card so a plugin's live status/health card is the first content under the header, instead of sitting between the settings and manifest cards. Docs updated to match. Co-authored-by: Kandev Agent Co-authored-by: Claude Opus 4.8 (1M context) --- apps/web/components/settings/plugins/plugin-detail.tsx | 4 ++-- apps/web/lib/plugins/types.ts | 4 ++-- docs/plans/plugins/PLUGIN-API.md | 4 ++-- docs/public/plugins-authoring.md | 10 +++++----- docs/public/plugins.md | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/web/components/settings/plugins/plugin-detail.tsx b/apps/web/components/settings/plugins/plugin-detail.tsx index 09cdd27853..324324bf25 100644 --- a/apps/web/components/settings/plugins/plugin-detail.tsx +++ b/apps/web/components/settings/plugins/plugin-detail.tsx @@ -54,13 +54,13 @@ export function PluginDetail({ pluginId }: { pluginId: string }) { - - {/* Owner-scoped inline slot for the plugin's own settings UI (see PLUGIN-API.md). */} + {/* Owner-scoped inline slot for the plugin's own settings UI, at the top (see PLUGIN-API.md). */} + diff --git a/apps/web/lib/plugins/types.ts b/apps/web/lib/plugins/types.ts index 875c8adfb9..02caf00ebc 100644 --- a/apps/web/lib/plugins/types.ts +++ b/apps/web/lib/plugins/types.ts @@ -77,8 +77,8 @@ export interface PluginRouteOptions { * `slotProps`), "chat-top-bar" (status in the session top bar, beside the * CPU/DB metrics — receives `{ taskId, taskTitle, workspaceId, activeSessionId, * sessionIds }`), and "plugin-settings" (inline UI on a plugin's own settings - * page, Settings > Plugins > , between the settings form and the - * manifest card — receives `{ pluginId: string; status: PluginStatus }` as + * page, Settings > Plugins > , at the top above the settings form — + * receives `{ pluginId: string; status: PluginStatus }` as * `slotProps`). "plugin-settings" is owner-scoped: the host renders only the * component registered by the plugin being viewed, so a plugin never appears on * another plugin's page and authors don't gate on the current id themselves. diff --git a/docs/plans/plugins/PLUGIN-API.md b/docs/plans/plugins/PLUGIN-API.md index 53c7998bc7..38c7b353e4 100644 --- a/docs/plans/plugins/PLUGIN-API.md +++ b/docs/plans/plugins/PLUGIN-API.md @@ -136,8 +136,8 @@ interface PluginRegistry { // tokscale cost data on a session) is the plugin's job, done server-side in // the plugin backend via the Host data API; the host only propagates ids. // "plugin-settings" renders inline on a plugin's own settings page - // (Settings > Plugins > , between the schema-driven settings form and - // the manifest card) and forwards `{ pluginId: string, status: PluginStatus }` + // (Settings > Plugins > , at the top above the schema-driven settings + // form) and forwards `{ pluginId: string, status: PluginStatus }` // as `slotProps`. It is owner-scoped: the host renders only the component // registered by the plugin currently being viewed, so your card appears on // your own settings page and never on another plugin's — no per-id gating diff --git a/docs/public/plugins-authoring.md b/docs/public/plugins-authoring.md index f8dde5e9d5..37341afb14 100644 --- a/docs/public/plugins-authoring.md +++ b/docs/public/plugins-authoring.md @@ -344,7 +344,7 @@ plugins at once. Available slots: | `main-nav-footer` | Footer of the main sidebar | — | | `chat-input-actions` | Chat composer toolbar, beside the model picker, mic, and send button | `{ taskId, taskTitle, activeSessionId, sessionIds }` | | `chat-top-bar` | Session top bar, beside the CPU/DB metrics and the document/editor/debug controls | `{ taskId, taskTitle, workspaceId, activeSessionId, sessionIds }` | -| `plugin-settings` | A plugin's own settings page (**Settings > Plugins > ``**), between the settings form and the manifest card | `{ pluginId, status }` | +| `plugin-settings` | A plugin's own settings page (**Settings > Plugins > ``**), at the top above the settings form | `{ pluginId, status }` | `plugin-settings` is the one exception to "every plugin's component renders": it is **owner-scoped**, so the host renders only the component registered by the @@ -444,10 +444,10 @@ registry.registerComponent("chat-top-bar", makeTopBarStatus(host)); ### Plugin settings page Register a `plugin-settings` component to render your own UI inline on your -plugin's settings page (**Settings > Plugins > ``**), between the -schema-driven settings form and the manifest card. Use it for live integration -health — e.g. "CLI installed ✅ v0.45.2" or "API token ✅ authenticated" — or any -custom controls next to the config form. The host passes: +plugin's settings page (**Settings > Plugins > ``**), at the top above +the schema-driven settings form. Use it for live integration health — e.g. "CLI +installed ✅ v0.45.2" or "API token ✅ authenticated" — or any custom controls +alongside the config form. The host passes: ```ts type PluginSettingsSlotProps = { diff --git a/docs/public/plugins.md b/docs/public/plugins.md index d20d6a9412..9357cdff26 100644 --- a/docs/public/plugins.md +++ b/docs/public/plugins.md @@ -143,8 +143,8 @@ references rather than cleartext for secret fields. ![A plugin's settings page: a schema-driven form with a masked API-token field, a toggle, and a text field, above a Manifest card showing the plugin's id, version, signing status, and capabilities.](../screenshots/plugin-settings-page.png) -A plugin can also render its own UI inline on this page — between the settings -form and the manifest card — via the `plugin-settings` slot, for example a live +A plugin can also render its own UI inline on this page — at the top, above the +settings form — via the `plugin-settings` slot, for example a live integration-health card ("CLI installed ✅ v0.45.2", "API token ✅ authenticated"). This is owner-scoped, so a plugin's card only ever appears on its own settings page. See [Named