1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
import { Handle, Position } from "@xyflow/react";
import type { StepStatus, ConfidenceLevel, DirectiveGraphNode } from "../../lib/api";
// Step status colors for both list and DAG views
export const stepStatusStyles: Record<StepStatus, { border: string; bg: string; text: string }> = {
pending: { border: "#556677", bg: "#556677", text: "#556677" },
ready: { border: "#3b82f6", bg: "#3b82f6", text: "#3b82f6" },
running: { border: "#22c55e", bg: "#22c55e", text: "#22c55e" },
evaluating: { border: "#eab308", bg: "#eab308", text: "#eab308" },
passed: { border: "#75aafc", bg: "#75aafc", text: "#75aafc" },
failed: { border: "#ef4444", bg: "#ef4444", text: "#ef4444" },
rework: { border: "#f97316", bg: "#f97316", text: "#f97316" },
skipped: { border: "#556677", bg: "#556677", text: "#556677" },
blocked: { border: "#ef4444", bg: "#ef4444", text: "#ef4444" },
};
// Confidence level colors
export const confidenceColors: Record<ConfidenceLevel, string> = {
green: "#22c55e",
yellow: "#eab308",
red: "#ef4444",
};
// Node dimensions
export const NODE_WIDTH = 180;
export const NODE_HEIGHT = 70;
// Custom node component for steps
export function StepNodeComponent({ data }: { data: DirectiveGraphNode & { selected?: boolean } }) {
const styles = stepStatusStyles[data.status] || stepStatusStyles.pending;
const isRunning = data.status === "running" || data.status === "evaluating";
return (
<div
className={`rounded-lg border-2 bg-[#0a1628] overflow-hidden ${
isRunning ? "animate-pulse" : ""
}`}
style={{
width: NODE_WIDTH,
height: NODE_HEIGHT,
borderColor: styles.border,
borderStyle: data.status === "pending" ? "dashed" : "solid",
}}
>
<Handle
type="target"
position={Position.Top}
className="!bg-[#75aafc] !w-3 !h-3 !border-2 !border-[#0a1628]"
/>
{/* Status indicator bar */}
<div className="h-1.5" style={{ backgroundColor: styles.bg }} />
{/* Content */}
<div className="p-2">
<div className="flex items-center justify-between mb-1">
<span className="font-mono text-xs text-[#dbe7ff] truncate flex-1">{data.name}</span>
{data.confidenceScore !== null && data.confidenceLevel && (
<div
className="w-2 h-2 rounded-full flex-shrink-0 ml-1"
style={{ backgroundColor: confidenceColors[data.confidenceLevel] }}
title={`Confidence: ${Math.round(data.confidenceScore * 100)}%`}
/>
)}
</div>
<div className="flex items-center justify-between">
<span
className="font-mono text-[10px] uppercase px-1.5 py-0.5 rounded"
style={{
color: styles.text,
backgroundColor: `${styles.bg}20`,
}}
>
{data.status}
</span>
<span className="font-mono text-[10px] text-[#8b949e]">{data.stepType}</span>
</div>
</div>
<Handle
type="source"
position={Position.Bottom}
className="!bg-[#f59e0b] !w-3 !h-3 !border-2 !border-[#0a1628]"
/>
</div>
);
}
|