"use client";
import { Handle, Position, type NodeProps } from "@xyflow/react";
import {
AlertTriangle,
CheckCircle2,
Loader2,
PauseCircle,
XCircle,
} from "lucide-react";
import { lookup } from "@/lib/node-catalog";
import { cn } from "@/lib/utils";
import type { FlowNodeData } from "@/lib/pipeline-graph";
export type NodeRunStatus =
| "pending"
| "running"
| "success"
| "failed"
| "paused";
export function FlowNode({ data, selected }: NodeProps) {
const fd = data as FlowNodeData & { runStatus?: NodeRunStatus };
const pn = fd.pipelineNode;
const status = fd.runStatus;
const entry = lookup(pn.type);
const Icon = entry?.icon ?? AlertTriangle;
const outputs = entry?.outputs ?? 1;
const isTrigger = pn.type === "flow-nodes-base.trigger";
// Per-type accent colour for the TYPE label. Keeps the existing
// catalog `color` (full bg) but extracts the hue for header text.
const typeAccent = typeAccentClass(entry?.color);
return (
{(entry?.label ?? "Unsupported")}
{pn.name}
{/* Input handle: triggers have no inputs */}
{!isTrigger && (
)}
{/* Output handle(s) */}
{Array.from({ length: outputs }).map((_, i) => {
const top = outputs === 1 ? "50%" : `${((i + 1) / (outputs + 1)) * 100}%`;
return (
);
})}
);
}
function StatusPill({ status }: { status?: NodeRunStatus }) {
if (!status || status === "pending") {
return (
pending
);
}
if (status === "running") {
return (
running
);
}
if (status === "success") {
return (
succeeded
);
}
if (status === "failed") {
return (
failed
);
}
if (status === "paused") {
return (
paused
);
}
return null;
}
// typeAccentClass picks a tailwind text-color class that pairs with the
// node's catalog `color` (bg-X-500) so the TYPE row reads as a distinct
// accent against the card background.
function typeAccentClass(bg?: string): string {
switch (bg) {
case "bg-emerald-500":
return "text-emerald-500";
case "bg-amber-500":
return "text-amber-500";
case "bg-sky-500":
return "text-sky-500";
case "bg-violet-500":
return "text-violet-500";
case "bg-indigo-500":
return "text-indigo-500";
case "bg-fuchsia-500":
return "text-fuchsia-500";
case "bg-rose-500":
case "bg-red-600":
return "text-rose-500";
case "bg-orange-500":
return "text-orange-500";
case "bg-slate-500":
case "bg-slate-400":
return "text-slate-500";
default:
return "text-primary";
}
}