diff options
Diffstat (limited to 'makima/frontend/src/components/directives/StepNode.tsx')
| -rw-r--r-- | makima/frontend/src/components/directives/StepNode.tsx | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/makima/frontend/src/components/directives/StepNode.tsx b/makima/frontend/src/components/directives/StepNode.tsx new file mode 100644 index 0000000..fa91956 --- /dev/null +++ b/makima/frontend/src/components/directives/StepNode.tsx @@ -0,0 +1,82 @@ +import type { DirectiveStep, StepStatus } from "../../lib/api"; + +const STATUS_COLORS: Record<StepStatus, { bg: string; border: string; text: string }> = { + pending: { bg: "bg-[#1a2540]", border: "border-[#2a3a5a]", text: "text-[#7788aa]" }, + ready: { bg: "bg-[#2a2a10]", border: "border-[#4a4a20]", text: "text-yellow-400" }, + running: { bg: "bg-[#0a2a1a]", border: "border-[#1a5a3a]", text: "text-green-400" }, + completed: { bg: "bg-[#0a2a2a]", border: "border-[#1a5a5a]", text: "text-emerald-400" }, + failed: { bg: "bg-[#2a1a1a]", border: "border-[#5a2a2a]", text: "text-red-400" }, + skipped: { bg: "bg-[#1a1a2a]", border: "border-[#2a2a4a]", text: "text-[#7788aa]" }, +}; + +const STATUS_LABELS: Record<StepStatus, string> = { + pending: "PENDING", + ready: "READY", + running: "RUNNING", + completed: "DONE", + failed: "FAILED", + skipped: "SKIP", +}; + +interface StepNodeProps { + step: DirectiveStep; + onComplete?: () => void; + onFail?: () => void; + onSkip?: () => void; +} + +export function StepNode({ step, onComplete, onFail, onSkip }: StepNodeProps) { + const colors = STATUS_COLORS[step.status] || STATUS_COLORS.pending; + const label = STATUS_LABELS[step.status] || step.status.toUpperCase(); + + return ( + <div + className={`${colors.bg} ${colors.border} border rounded px-3 py-2 min-w-[160px] max-w-[220px]`} + > + <div className="flex items-center justify-between gap-2 mb-1"> + <span className="text-[11px] font-mono text-white truncate font-medium"> + {step.name} + </span> + <span className={`text-[9px] font-mono ${colors.text} uppercase shrink-0`}> + {label} + </span> + </div> + {step.description && ( + <p className="text-[10px] text-[#7788aa] font-mono truncate mb-1"> + {step.description} + </p> + )} + {(step.status === "running" || step.status === "ready") && ( + <div className="flex gap-1 mt-1"> + {onComplete && ( + <button + type="button" + onClick={onComplete} + className="text-[9px] font-mono text-emerald-400 hover:text-emerald-300 bg-transparent border border-emerald-800 rounded px-1.5 py-0.5" + > + Done + </button> + )} + {onFail && ( + <button + type="button" + onClick={onFail} + className="text-[9px] font-mono text-red-400 hover:text-red-300 bg-transparent border border-red-800 rounded px-1.5 py-0.5" + > + Fail + </button> + )} + {onSkip && ( + <button + type="button" + onClick={onSkip} + className="text-[9px] font-mono text-[#7788aa] hover:text-white bg-transparent border border-[#2a3a5a] rounded px-1.5 py-0.5" + > + Skip + </button> + )} + </div> + )} + </div> + ); +} |
