FN-6071: add plugin registry browsing and install actions
Add a curated plugin registry surface to the dashboard plugin manager. - expose GET /api/plugins/registry with search, category filtering, and installed-state annotations from the dashboard registry manifest - add registry fetch/install support to the dashboard plugin manager UI, including search, install/manage actions, and related tests - document plugin registry entries and registry installability in plugin authoring docs and shared concepts Files changed: CONCEPTS.md | 6 + docs/PLUGIN_AUTHORING.md | 23 ++ packages/dashboard/app/api/legacy.ts | 36 +++ .../dashboard/app/components/PluginManager.css | 185 ++++++++++++++- .../dashboard/app/components/PluginManager.tsx | 162 ++++++++++++- .../PluginManager.install-browse.test.tsx | 5 +- .../__tests__/PluginManager.registry.test.tsx | 260 +++++++++++++++++++++ .../components/__tests__/PluginManager.test.tsx | 3 +- .../__tests__/PluginManager.toggle.test.tsx | 5 +- .../src/__tests__/routes-plugin-registry.test.ts | 156 +++++++++++++ packages/dashboard/src/plugin-routes.ts | 115 +++++++++ packages/dashboard/src/registry-manifest.json | 143 ++++++++++++ 12 files changed, 1091 insertions(+), 8 deletions(-) Fusion-Task-Id: FN-6071 Fusion-Task-Lineage: 72c7bdfd-5832-4323-b675-63d0680167d8
This commit is contained in:
@@ -20,6 +20,7 @@ import type {
|
||||
WorkflowStepResult,
|
||||
PluginInstallation,
|
||||
PluginSetupCheckResult,
|
||||
PluginState,
|
||||
PluginUiSlotDefinition,
|
||||
PluginUiContributionDefinition,
|
||||
PluginDashboardViewDefinition,
|
||||
@@ -9073,11 +9074,46 @@ export function resetAgentBudget(agentId: string, projectId?: string): Promise<v
|
||||
|
||||
// ── Plugin Management ────────────────────────────────────────────────────────
|
||||
|
||||
export interface RegistryPluginEntry {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
author: string;
|
||||
category: "runtime" | "integration";
|
||||
npmPackage?: string;
|
||||
path?: string;
|
||||
homepage?: string;
|
||||
tags?: string[];
|
||||
installed: boolean;
|
||||
state?: PluginState;
|
||||
installedVersion?: string;
|
||||
canInstall: boolean;
|
||||
}
|
||||
|
||||
/** Fetch all installed plugins */
|
||||
export async function fetchPlugins(projectId?: string): Promise<PluginInstallation[]> {
|
||||
return api<PluginInstallation[]>(withProjectId("/plugins", projectId));
|
||||
}
|
||||
|
||||
/** Fetch curated registry plugins with installed-state metadata */
|
||||
export async function fetchPluginRegistry(
|
||||
query?: string,
|
||||
category?: string,
|
||||
projectId?: string,
|
||||
): Promise<RegistryPluginEntry[]> {
|
||||
const params = new URLSearchParams();
|
||||
if (query?.trim()) {
|
||||
params.set("q", query.trim());
|
||||
}
|
||||
if (category?.trim()) {
|
||||
params.set("category", category.trim());
|
||||
}
|
||||
const suffix = params.size > 0 ? `?${params.toString()}` : "";
|
||||
const response = await api<{ plugins: RegistryPluginEntry[] }>(withProjectId(`/plugins/registry${suffix}`, projectId));
|
||||
return response.plugins;
|
||||
}
|
||||
|
||||
/** Fetch a single plugin by ID */
|
||||
export async function fetchPluginDetail(id: string, projectId?: string): Promise<PluginInstallation> {
|
||||
return api<PluginInstallation>(withProjectId(`/plugins/${encodeURIComponent(id)}`, projectId));
|
||||
|
||||
Reference in New Issue
Block a user