import { useMemo } from "react"; import type { DirectiveStep } from "../../lib/api"; import { StepNode } from "./StepNode"; interface DirectiveDAGProps { steps: DirectiveStep[]; onComplete?: (stepId: string) => void; onFail?: (stepId: string) => void; onSkip?: (stepId: string) => void; } interface Layer { steps: DirectiveStep[]; } function topoSort(steps: DirectiveStep[]): Layer[] { if (steps.length === 0) return []; // Group steps by orderIndex — each unique orderIndex is one execution phase const byOrder = new Map(); for (const step of steps) { const group = byOrder.get(step.orderIndex) ?? []; group.push(step); byOrder.set(step.orderIndex, group); } // Sort groups by ascending orderIndex const sortedKeys = [...byOrder.keys()].sort((a, b) => a - b); return sortedKeys.map((key) => ({ steps: byOrder.get(key)!.sort((a, b) => a.name.localeCompare(b.name)), })); } export function DirectiveDAG({ steps, onComplete, onFail, onSkip }: DirectiveDAGProps) { const layers = useMemo(() => topoSort(steps), [steps]); if (steps.length === 0) { return (
No steps yet. Add steps to build the DAG.
); } return (
{layers.map((layer, layerIdx) => (
{layerIdx > 0 && (
)}
{layer.steps.map((step) => ( onComplete(step.id) : undefined} onFail={onFail ? () => onFail(step.id) : undefined} onSkip={onSkip ? () => onSkip(step.id) : undefined} /> ))}
))}
); }