frontend_nyla/src/components/FlowEditor/nodes/shared/graphUtils.ts
2026-04-13 09:54:11 +02:00

96 lines
3.1 KiB
TypeScript

/**
* Automation2 Flow Editor - Graph conversion utilities
* Converts between API graph format and canvas internal format.
*/
import type {
NodeType,
Automation2Graph,
Automation2GraphNode,
Automation2Connection,
} from '../../../../api/workflowApi';
import type { CanvasNode, CanvasConnection } from '../../editor/FlowCanvas';
export function fromApiGraph(
graph: Automation2Graph,
nodeTypes: NodeType[]
): { nodes: CanvasNode[]; connections: CanvasConnection[] } {
const nodeMap = new Map<string, { inputs: number; outputs: number }>();
nodeTypes.forEach((nt) => {
nodeMap.set(nt.id, { inputs: nt.inputs ?? 1, outputs: nt.outputs ?? 1 });
});
const nodes: CanvasNode[] = (graph.nodes || []).map((n: Automation2GraphNode) => {
const io = nodeMap.get(n.type) ?? { inputs: 1, outputs: 1 };
let outputs = io.outputs;
if (n.type === 'flow.switch') {
const cases = (n.parameters?.cases as unknown[]) ?? [];
outputs = Math.max(1, cases.length);
}
const nt = nodeTypes.find((t) => t.id === n.type);
return {
id: n.id,
type: n.type,
x: (n as { x?: number }).x ?? 0,
y: (n as { y?: number }).y ?? 0,
title: (n as { title?: string }).title ?? (typeof n.type === 'string' ? n.type : ''),
comment: (n as { comment?: string }).comment,
inputs: io.inputs,
outputs,
parameters: n.parameters ?? {},
inputPorts: nt?.inputPorts
? Object.entries(nt.inputPorts).map(([, v]) => ({ name: '', schema: '', accepts: (v as { accepts?: string[] }).accepts }))
: undefined,
outputPorts: nt?.outputPorts
? Object.entries(nt.outputPorts).map(([, v]) => ({ name: '', schema: (v as { schema?: string }).schema ?? '' }))
: undefined,
};
});
const connId = (s: string, t: string, so: number, ti: number) => `c_${s}_${so}_${t}_${ti}`;
const connections: CanvasConnection[] = (graph.connections || []).map((c: Automation2Connection) => {
const srcNode = nodes.find((n) => n.id === c.source);
const sourceOutput = c.sourceOutput ?? 0;
const sourceHandle = srcNode ? srcNode.inputs + sourceOutput : 0;
return {
id: connId(c.source, c.target, sourceOutput, c.targetInput ?? 0),
sourceId: c.source,
sourceHandle,
targetId: c.target,
targetHandle: c.targetInput ?? 0,
};
});
return { nodes, connections };
}
export function toApiGraph(
nodes: CanvasNode[],
connections: CanvasConnection[]
): Automation2Graph {
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
return {
nodes: nodes.map((n) => ({
id: n.id,
type: n.type,
x: n.x,
y: n.y,
title: n.title,
comment: n.comment,
parameters: n.parameters ?? {},
inputPorts: n.inputPorts,
outputPorts: n.outputPorts,
})),
connections: connections.map((c) => {
const srcNode = nodeMap.get(c.sourceId);
const sourceOutput =
srcNode && c.sourceHandle >= srcNode.inputs ? c.sourceHandle - srcNode.inputs : 0;
return {
source: c.sourceId,
target: c.targetId,
sourceOutput,
targetInput: c.targetHandle,
};
}),
};
}