This repository has been archived on 2026-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
orchestrator/agent-team/web/src/components/PipelineMap.tsx
Adam Moussa 677f3d3c71 feat(agent-team): React/Vite status-dashboard SPA
New web/ SPA (React 18 + Vite 5 + TypeScript + React Flow + dagre, all pinned, no
CDN). Dark, three-pane layout: summary top bar, filterable task list, center
auto-laid pipeline map, and a right drawer showing a selected task's history
through each node (timeline with timestamps/duration/cost + Q&A/verdicts/plan).
Map nodes color by live state, loop-backs render dashed, clicking a node filters
the list, selecting a task highlights its path. Polls /api/state every 4s;
topology fetched once. dist/ is gitignored (built on the Mac, rsynced).
2026-06-23 17:15:23 -04:00

55 lines
1.6 KiB
TypeScript

import { useMemo } from "react";
import ReactFlow, {
Background,
Controls,
type NodeMouseHandler,
ReactFlowProvider,
} from "reactflow";
import "reactflow/dist/style.css";
import type { StateResponse, Topology } from "../api";
import { layout } from "../layout";
import { MapNode } from "./MapNode";
const nodeTypes = { pipeline: MapNode };
interface Props {
topology: Topology;
state: StateResponse | null;
pathNodeIds: Set<string> | null;
onNodeClick: (nodeId: string) => void;
}
// The center pipeline map. Nodes are dagre-laid from the topology; live state
// colors them; clicking a node filters the task list. Multiple trees (processes
// off intake) lay out as separate lanes automatically.
export function PipelineMap({ topology, state, pathNodeIds, onNodeClick }: Props) {
const { nodes, edges } = useMemo(
() => layout(topology, state?.nodes ?? {}, pathNodeIds),
[topology, state, pathNodeIds],
);
const handleNodeClick: NodeMouseHandler = (_evt, node) => onNodeClick(node.id);
return (
<div className="map-pane" aria-label="pipeline map">
<ReactFlowProvider>
<ReactFlow
nodes={nodes}
edges={edges}
nodeTypes={nodeTypes}
fitView
nodesDraggable={false}
nodesConnectable={false}
elementsSelectable
onNodeClick={handleNodeClick}
proOptions={{ hideAttribution: true }}
minZoom={0.3}
maxZoom={1.6}
>
<Background color="#222a36" gap={22} />
<Controls showInteractive={false} />
</ReactFlow>
</ReactFlowProvider>
</div>
);
}