feat: persist and edit versioned workflow definitions
This commit is contained in:
99
webui/src/features/workflow/WorkflowNode.tsx
Normal file
99
webui/src/features/workflow/WorkflowNode.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
CalendarClock,
|
||||
CheckCircle2,
|
||||
CirclePlay,
|
||||
CircleX,
|
||||
ClipboardCheck,
|
||||
GitFork,
|
||||
PlugZap,
|
||||
Radio,
|
||||
Split,
|
||||
SquareCheckBig,
|
||||
Timer,
|
||||
Waypoints,
|
||||
type LucideIcon
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Handle,
|
||||
Position,
|
||||
type Node,
|
||||
type NodeProps
|
||||
} from "@xyflow/react";
|
||||
import type { WorkflowNodeType } from "../../api/workflow";
|
||||
|
||||
export type WorkflowFlowNodeData = {
|
||||
label: string;
|
||||
workflowType: string;
|
||||
definition: WorkflowNodeType;
|
||||
hasError: boolean;
|
||||
};
|
||||
|
||||
export type WorkflowFlowNode = Node<WorkflowFlowNodeData, "workflow">;
|
||||
|
||||
const iconByName: Record<string, LucideIcon> = {
|
||||
"calendar-clock": CalendarClock,
|
||||
"circle-check-big": CheckCircle2,
|
||||
"circle-play": CirclePlay,
|
||||
"circle-x": CircleX,
|
||||
"clipboard-check": ClipboardCheck,
|
||||
"plug-zap": PlugZap,
|
||||
radio: Radio,
|
||||
split: Split,
|
||||
"square-check-big": SquareCheckBig,
|
||||
timer: Timer,
|
||||
waypoints: Waypoints
|
||||
};
|
||||
|
||||
export default function WorkflowNode({
|
||||
data,
|
||||
selected,
|
||||
isConnectable
|
||||
}: NodeProps<WorkflowFlowNode>) {
|
||||
const Icon = iconByName[data.definition.icon] ?? GitFork;
|
||||
const inputPorts = data.definition.input_ports;
|
||||
const outputPorts = data.definition.output_ports;
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
"workflow-node",
|
||||
`workflow-node-${data.definition.category}`,
|
||||
selected ? "is-selected" : "",
|
||||
data.hasError ? "has-error" : ""
|
||||
].filter(Boolean).join(" ")}
|
||||
>
|
||||
{inputPorts.map((port, index) => (
|
||||
<Handle
|
||||
key={port.id}
|
||||
id={port.id}
|
||||
type="target"
|
||||
position={Position.Left}
|
||||
className="workflow-node-handle"
|
||||
style={{ top: portPosition(index, inputPorts.length) }}
|
||||
isConnectable={isConnectable}
|
||||
title={port.label}
|
||||
/>
|
||||
))}
|
||||
<span className="workflow-node-icon"><Icon size={17} /></span>
|
||||
<span className="workflow-node-copy">
|
||||
<strong>{data.label}</strong>
|
||||
<small>{data.definition.label}</small>
|
||||
</span>
|
||||
{outputPorts.map((port, index) => (
|
||||
<Handle
|
||||
key={port.id}
|
||||
id={port.id}
|
||||
type="source"
|
||||
position={Position.Right}
|
||||
className="workflow-node-handle"
|
||||
style={{ top: portPosition(index, outputPorts.length) }}
|
||||
isConnectable={isConnectable}
|
||||
title={port.label}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function portPosition(index: number, count: number): string {
|
||||
return `${((index + 1) / (count + 1)) * 100}%`;
|
||||
}
|
||||
Reference in New Issue
Block a user