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/MapNode.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

48 lines
1.4 KiB
TypeScript

import { memo } from "react";
import { Handle, Position, type NodeProps } from "reactflow";
import type { RFData } from "../layout";
// One pipeline stage on the map. Color encodes live state; a badge shows the
// live task count; gated (P3/inert) nodes render dimmed with a tag. ARIA role +
// label keep the map reachable for screen readers / keyboard users.
function MapNodeImpl({ data }: NodeProps<RFData>) {
const { meta, state, count, dimmed, onPath } = data;
const cls = [
"node",
`state-${state}`,
meta.gated ? "gated" : "",
dimmed ? "dimmed" : "",
onPath ? "on-path" : "",
]
.filter(Boolean)
.join(" ");
return (
<div
className={cls}
role="group"
aria-label={`${meta.label} stage, ${state}, ${count} task${count === 1 ? "" : "s"}`}
tabIndex={0}
>
<Handle type="target" position={Position.Left} />
<div className="node-label">
{meta.label}
{meta.kind === "gate" && (
<span className="gate-pip" title="human gate" aria-hidden>
⛋
</span>
)}
</div>
<div className="node-agent">{meta.agent}</div>
{count > 0 && (
<span className="node-count" aria-hidden>
{count}
</span>
)}
{meta.gated && <span className="node-gated-tag">inert</span>}
<Handle type="source" position={Position.Right} />
</div>
);
}
export const MapNode = memo(MapNodeImpl);