fix(FN-3161): migrate roadmap dashboard surface to bundled plugin
- Move RoadmapsView UI, hooks, and tests from dashboard app into fusion-plugin-roadmap - Replace the built-in roadmaps route/nav wiring with plugin view registration and host rendering - Add bundled plugin view registration bootstrap in dashboard startup - Update roadmap plugin build/test config and add FN-3161 removal changeset Fusion-Task-Id: FN-3161
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { PluginDashboardViewHost as RegistryPluginDashboardViewHost } from "./pluginViewRegistry";
|
||||
import type { PluginDashboardViewContext, PluginTaskView } from "./pluginViewRegistry";
|
||||
import type { PluginTaskView } from "./pluginViewRegistry";
|
||||
import type { PluginDashboardViewContext } from "./types";
|
||||
|
||||
export function PluginDashboardViewHost({ taskView, context }: { taskView: PluginTaskView; context?: PluginDashboardViewContext }) {
|
||||
return <RegistryPluginDashboardViewHost viewId={taskView} context={context} />;
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
import type { Task, TaskDetail, WorkflowStep } from "@fusion/core";
|
||||
import type { PluginDashboardViewContext } from "./types";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { lazy, Suspense, type LazyExoticComponent, type ReactElement, type ReactNode } from "react";
|
||||
import { ErrorBoundary } from "../components/ErrorBoundary";
|
||||
import type { DetailTaskTab } from "../hooks/useModalManager";
|
||||
import "./pluginViewRegistry.css";
|
||||
|
||||
export type PluginTaskView = `plugin:${string}:${string}`;
|
||||
|
||||
export interface PluginDashboardViewContext {
|
||||
projectId?: string;
|
||||
tasks: Task[];
|
||||
workflowSteps: WorkflowStep[];
|
||||
openTaskDetail: (task: Task | TaskDetail, initialTab?: DetailTaskTab) => void;
|
||||
renderTaskCard?: (task: Task | TaskDetail) => ReactNode;
|
||||
}
|
||||
|
||||
type PluginViewComponent = LazyExoticComponent<({ context }: { context?: PluginDashboardViewContext }) => ReactElement>;
|
||||
|
||||
const registry = new Map<string, PluginViewComponent>();
|
||||
@@ -46,25 +37,15 @@ export function getPluginViewComponent(pluginId: string, viewId: string): Plugin
|
||||
return registry.get(getPluginViewId(pluginId, viewId)) ?? null;
|
||||
}
|
||||
|
||||
export function isPluginViewRegistered(pluginId: string, viewId: string): boolean {
|
||||
return registry.has(getPluginViewId(pluginId, viewId));
|
||||
}
|
||||
|
||||
/** Test helper for clearing global registry state. */
|
||||
export function __test_clearPluginViewRegistry(): void {
|
||||
registry.clear();
|
||||
registerBundledPluginViews();
|
||||
}
|
||||
|
||||
function registerBundledPluginViews(): void {
|
||||
registerPluginView(
|
||||
"fusion-plugin-dependency-graph",
|
||||
"graph",
|
||||
lazy(async () => {
|
||||
const mod = await import("@fusion-plugin-examples/dependency-graph/dashboard-view");
|
||||
return { default: mod.DependencyGraphDashboardView };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
registerBundledPluginViews();
|
||||
|
||||
function PluginViewUnavailable({ viewId }: { viewId: string }): ReactNode {
|
||||
return (
|
||||
<section className="card plugin-dashboard-view-missing" data-testid="plugin-view-unavailable">
|
||||
|
||||
27
packages/dashboard/app/plugins/registerBundledPluginViews.ts
Normal file
27
packages/dashboard/app/plugins/registerBundledPluginViews.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { lazy } from "react";
|
||||
import { registerPluginView } from "./pluginViewRegistry";
|
||||
|
||||
let registered = false;
|
||||
|
||||
export function registerBundledPluginViews(): void {
|
||||
if (registered) return;
|
||||
registered = true;
|
||||
|
||||
registerPluginView(
|
||||
"fusion-plugin-dependency-graph",
|
||||
"graph",
|
||||
lazy(async () => {
|
||||
const mod = await import("@fusion-plugin-examples/dependency-graph/dashboard-view");
|
||||
return { default: mod.DependencyGraphDashboardView };
|
||||
}),
|
||||
);
|
||||
|
||||
registerPluginView(
|
||||
"roadmap-planner",
|
||||
"roadmaps",
|
||||
lazy(async () => {
|
||||
const mod = await import("@fusion-plugin-examples/roadmap/dashboard-view");
|
||||
return { default: mod.RoadmapDashboardView };
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import type { Task, TaskDetail, WorkflowStep } from "@fusion/core";
|
||||
/** Tab identifiers for the task detail modal. Mirrors the dashboard's local enum. */
|
||||
export type DetailTaskTab = "definition" | "logs" | "changes" | "comments" | "model" | "workflow";
|
||||
|
||||
export type PluginToastType = "success" | "error" | "warning" | "info";
|
||||
|
||||
/** Runtime context passed to a plugin dashboard view component. */
|
||||
export interface PluginDashboardViewContext {
|
||||
projectId?: string;
|
||||
@@ -21,6 +23,7 @@ export interface PluginDashboardViewContext {
|
||||
workflowSteps: WorkflowStep[];
|
||||
openTaskDetail: (task: Task | TaskDetail, initialTab?: DetailTaskTab) => void;
|
||||
renderTaskCard?: (task: Task | TaskDetail) => ReactNode;
|
||||
addToast?: (message: string, type?: PluginToastType) => void;
|
||||
}
|
||||
|
||||
/** Composite view ID format: `plugin:{pluginId}:{viewId}`. */
|
||||
|
||||
Reference in New Issue
Block a user