@flowuent-org/diagramming-core 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. package/package.json +116 -116
  2. package/packages/diagrams/src/index.ts +1 -0
  3. package/packages/diagrams/src/lib/atoms/ConnectionPoints.tsx +149 -0
  4. package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +794 -650
  5. package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +606 -449
  6. package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +831 -687
  7. package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +420 -275
  8. package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +1118 -974
  9. package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +509 -344
  10. package/packages/diagrams/src/lib/components/automation/NodeAIAssistantPopup.tsx +504 -0
  11. package/packages/diagrams/src/lib/components/automation/NodeActionButtons.tsx +146 -0
  12. package/packages/diagrams/src/lib/components/automation/index.ts +20 -11
  13. package/packages/diagrams/src/lib/molecules/SideHandles.tsx +177 -12
  14. package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge-generator.tsx +10 -5
  15. package/packages/diagrams/src/lib/styles.css +53 -0
  16. package/packages/diagrams/src/lib/templates/DiagramContainer.tsx +59 -0
  17. package/packages/diagrams/src/lib/templates/Diagramming.tsx +246 -204
  18. package/packages/diagrams/src/lib/types/edge-types.ts +17 -0
  19. package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -0
  20. package/packages/diagrams/src/lib/utils/nodeAIAssistantConfig.ts +54 -0
@@ -1,204 +1,246 @@
1
- import { CssBaseline, ThemeProvider } from '@mui/material';
2
- import React, { forwardRef, useImperativeHandle, useEffect } from 'react';
3
- import { Edge, Background, BackgroundVariant, Node } from '@xyflow/react';
4
- import FloatingConnectionLine from '../atoms/FloatingConnectionLine';
5
- import { DiagramStoreProvider, useDiagram } from '../contexts/DiagramProvider';
6
- import { theme } from '../theme';
7
- import { ICardNode } from '../types/card-node';
8
- import DiagramTypes from '../types/diagram-types';
9
- import edgeTypes, { defaultEdgeOptions } from '../types/edge-types';
10
- import nodeTypes from '../types/node-types';
11
- import { useAutoRegisterVariables } from '../hooks/useAutoRegisterVariables';
12
- import { orderNodesByEdges, NodeOrderResult } from '../utils/nodeOrderByEdges';
13
-
14
- import {
15
- ConditionBuilderState,
16
- GetDefaultNodeDataType,
17
- OnChangeEventHandler,
18
- RenderAddNodeViewType,
19
- WorkflowNodeContentType,
20
- } from '../contexts/diagramStoreTypes';
21
- import { DiagramContainer } from './DiagramContainer';
22
- import { FunctionSignature } from '../types/FunctionSignature';
23
- import { AvailableVariable } from '../types/available-variables';
24
-
25
- // Component that handles variable registration
26
- const VariableRegistrationHandler: React.FC = () => {
27
- useAutoRegisterVariables();
28
- return null;
29
- };
30
-
31
- // Interface for the ref methods
32
- export interface DiagrammingPageRef {
33
- undo: () => void;
34
- redo: () => void;
35
- canUndo: () => boolean;
36
- canRedo: () => boolean;
37
- reset: () => void;
38
- getHistoryLength: () => number;
39
- getHistoryIndex: () => number;
40
- // Node data management methods
41
- getNodeData: (nodeId: string) => any | null;
42
- updateNodeData: (nodeId: string, data: any) => boolean;
43
- getSelectedNode: () => string | null;
44
- getNodes: () => any[];
45
- getEdges: () => any[];
46
- // Get ordered nodes based on edge connections (arrow direction)
47
- getNodeOrder: () => NodeOrderResult;
48
- }
49
-
50
- // Internal component that exposes undo/redo functionality
51
- const DiagrammingPageInternal = forwardRef<DiagrammingPageRef, {
52
- children?: React.ReactNode;
53
- className?: string;
54
- showAutomationExecutionPanel?: boolean;
55
- onNodeOrderChange?: (nodeOrder: NodeOrderResult) => void;
56
- }>(({ children, className, showAutomationExecutionPanel, onNodeOrderChange }, ref) => {
57
- const undo = useDiagram((state) => state.undo);
58
- const redo = useDiagram((state) => state.redo);
59
- const reset = useDiagram((state) => state.reset);
60
- const history = useDiagram((state) => state.history);
61
- const historyIndex = useDiagram((state) => state.historyIndex);
62
- const nodes = useDiagram((state) => state.nodes);
63
- const edges = useDiagram((state) => state.edges);
64
- const selectedNode = useDiagram((state) => state.selectedNode);
65
- const setNodes = useDiagram((state) => state.setNodes);
66
-
67
- // Send node order to parent project whenever nodes/edges change
68
- useEffect(() => {
69
- if (nodes.length > 0 && edges.length > 0 && onNodeOrderChange) {
70
- const nodeOrder = orderNodesByEdges(nodes, edges);
71
- onNodeOrderChange(nodeOrder);
72
- }
73
- }, [nodes, edges, onNodeOrderChange]);
74
-
75
- useImperativeHandle(ref, () => ({
76
- undo,
77
- redo,
78
- canUndo: () => historyIndex > 0,
79
- canRedo: () => historyIndex < history.length - 1,
80
- reset,
81
- getHistoryLength: () => history.length,
82
- getHistoryIndex: () => historyIndex,
83
- // Node data management methods
84
- getNodeData: (nodeId: string) => {
85
- const node = nodes.find(n => n.id === nodeId);
86
- return node ? node.data : null;
87
- },
88
- updateNodeData: (nodeId: string, newData: any) => {
89
- const nodeIndex = nodes.findIndex(n => n.id === nodeId);
90
- if (nodeIndex === -1) return false;
91
-
92
- const updatedNodes = [...nodes];
93
- updatedNodes[nodeIndex] = {
94
- ...updatedNodes[nodeIndex],
95
- data: { ...updatedNodes[nodeIndex].data, ...newData }
96
- };
97
- setNodes(updatedNodes);
98
- return true;
99
- },
100
- getSelectedNode: () => selectedNode,
101
- getNodes: () => nodes,
102
- getEdges: () => edges,
103
- // Get ordered nodes based on edge connections
104
- getNodeOrder: () => orderNodesByEdges(nodes, edges),
105
- }));
106
-
107
- return (
108
- <DiagramContainer
109
- defaultEdgeOptions={defaultEdgeOptions}
110
- edgeTypes={edgeTypes}
111
- nodeTypes={nodeTypes as any}
112
- connectionLineComponent={FloatingConnectionLine}
113
- style={{ backgroundColor: '#141519' }}
114
- className={className}
115
- showAutomationExecutionPanel={showAutomationExecutionPanel}
116
- >
117
- <Background
118
- color="#ffffff"
119
- variant={BackgroundVariant.Dots}
120
- gap={20}
121
- size={1}
122
- />
123
- {children}
124
- </DiagramContainer>
125
- );
126
- });
127
-
128
- export interface DiagrammingPageProps {
129
- diagramType: DiagramTypes;
130
- onChange?: OnChangeEventHandler;
131
- defaultNodes: ICardNode[];
132
- defaultEdges: Edge[];
133
- children?: React.ReactNode;
134
- workflowNodeContent?: WorkflowNodeContentType;
135
- renderAddNodeView?: RenderAddNodeViewType;
136
- getDefaultNodeData?: GetDefaultNodeDataType;
137
- availableFunctions: FunctionSignature[];
138
- availableVariables?: AvailableVariable[];
139
- id: number;
140
- className?: string;
141
- conditionBuilderStates?: ConditionBuilderState;
142
- // New: emit node selection to host app
143
- onNodeSelect?: (payload: { nodeId: string; type?: string; data?: any }) => void;
144
- // New: allow host to disable library JSON popovers/drawers
145
- enableNodeJsonPopover?: boolean;
146
- // New: control visibility of automation execution panel
147
- showAutomationExecutionPanel?: boolean;
148
- // New: callback to receive node order based on arrow/edge connections
149
- onNodeOrderChange?: (nodeOrder: NodeOrderResult) => void;
150
- }
151
-
152
- export const DiagrammingPage = forwardRef<DiagrammingPageRef, DiagrammingPageProps>(({
153
- diagramType,
154
- defaultNodes,
155
- defaultEdges,
156
- onChange,
157
- children,
158
- workflowNodeContent,
159
- renderAddNodeView,
160
- getDefaultNodeData,
161
- availableFunctions,
162
- availableVariables,
163
- id,
164
- className,
165
- conditionBuilderStates,
166
- onNodeSelect: onNodeSelectProp,
167
- enableNodeJsonPopover: enableNodeJsonPopoverProp,
168
- showAutomationExecutionPanel,
169
- onNodeOrderChange
170
- }, ref) => {
171
- return (
172
- <ThemeProvider theme={theme}>
173
- <CssBaseline />
174
-
175
- <DiagramStoreProvider
176
- id={id}
177
- availableFunctions={availableFunctions}
178
- availableVariables={availableVariables}
179
- defaultNodes={defaultNodes} // Pass defaultNodes to the context
180
- defaultEdges={defaultEdges} // Pass defaultEdges to the context
181
- diagramType={diagramType} // Pass diagramType to the context
182
- onChange={onChange} // Pass onChange to the context
183
- workflowNodeContent={workflowNodeContent} // Pass workflowNodeContent to the context
184
- renderAddNodeView={renderAddNodeView} // Pass workflowNodeContent to the context
185
- getDefaultNodeData={getDefaultNodeData}
186
- conditionBuilderStates={conditionBuilderStates}
187
- onNodeSelect={onNodeSelectProp}
188
- enableNodeJsonPopover={enableNodeJsonPopoverProp}
189
- >
190
- {/* Variable registration handler */}
191
- <VariableRegistrationHandler />
192
-
193
- <DiagrammingPageInternal
194
- ref={ref}
195
- className={className}
196
- showAutomationExecutionPanel={showAutomationExecutionPanel}
197
- onNodeOrderChange={onNodeOrderChange}
198
- >
199
- {children}
200
- </DiagrammingPageInternal>
201
- </DiagramStoreProvider>
202
- </ThemeProvider>
203
- );
204
- });
1
+ import { CssBaseline, ThemeProvider } from '@mui/material';
2
+ import React, { forwardRef, useImperativeHandle, useEffect } from 'react';
3
+ import { Edge, Background, BackgroundVariant, Node } from '@xyflow/react';
4
+ import FloatingConnectionLine from '../atoms/FloatingConnectionLine';
5
+ import { DiagramStoreProvider, useDiagram } from '../contexts/DiagramProvider';
6
+ import { theme } from '../theme';
7
+ import { ICardNode } from '../types/card-node';
8
+ import DiagramTypes from '../types/diagram-types';
9
+ import edgeTypes, { defaultEdgeOptions } from '../types/edge-types';
10
+ import nodeTypes from '../types/node-types';
11
+ import { useAutoRegisterVariables } from '../hooks/useAutoRegisterVariables';
12
+ import { orderNodesByEdges, NodeOrderResult } from '../utils/nodeOrderByEdges';
13
+
14
+ import {
15
+ ConditionBuilderState,
16
+ GetDefaultNodeDataType,
17
+ OnChangeEventHandler,
18
+ RenderAddNodeViewType,
19
+ WorkflowNodeContentType,
20
+ } from '../contexts/diagramStoreTypes';
21
+ import { DiagramContainer } from './DiagramContainer';
22
+ import { FunctionSignature } from '../types/FunctionSignature';
23
+ import { AvailableVariable } from '../types/available-variables';
24
+
25
+ // Component that handles variable registration
26
+ const VariableRegistrationHandler: React.FC = () => {
27
+ useAutoRegisterVariables();
28
+ return null;
29
+ };
30
+
31
+ // Interface for the ref methods
32
+ export interface DiagrammingPageRef {
33
+ undo: () => void;
34
+ redo: () => void;
35
+ canUndo: () => boolean;
36
+ canRedo: () => boolean;
37
+ reset: () => void;
38
+ getHistoryLength: () => number;
39
+ getHistoryIndex: () => number;
40
+ // Node data management methods
41
+ getNodeData: (nodeId: string) => any | null;
42
+ updateNodeData: (nodeId: string, data: any) => boolean;
43
+ getSelectedNode: () => string | null;
44
+ getNodes: () => any[];
45
+ getEdges: () => any[];
46
+ // Get ordered nodes based on edge connections (arrow direction)
47
+ getNodeOrder: () => NodeOrderResult;
48
+ // Get current state for saving
49
+ getCurrentState: () => { nodes: any[]; edges: any[] };
50
+ // Set nodes and edges (for restoring saved state)
51
+ setNodesAndEdges: (nodes: any[], edges: any[]) => void;
52
+ }
53
+
54
+ // Internal component that exposes undo/redo functionality
55
+ const DiagrammingPageInternal = forwardRef<DiagrammingPageRef, {
56
+ children?: React.ReactNode;
57
+ className?: string;
58
+ showAutomationExecutionPanel?: boolean;
59
+ onNodeOrderChange?: (nodeOrder: NodeOrderResult) => void;
60
+ }>(({ children, className, showAutomationExecutionPanel, onNodeOrderChange }, ref) => {
61
+ const undo = useDiagram((state) => state.undo);
62
+ const redo = useDiagram((state) => state.redo);
63
+ const reset = useDiagram((state) => state.reset);
64
+ const history = useDiagram((state) => state.history);
65
+ const historyIndex = useDiagram((state) => state.historyIndex);
66
+ const nodes = useDiagram((state) => state.nodes);
67
+ const edges = useDiagram((state) => state.edges);
68
+ const selectedNode = useDiagram((state) => state.selectedNode);
69
+ const setNodes = useDiagram((state) => state.setNodes);
70
+ const setEdges = useDiagram((state) => state.setEdges);
71
+
72
+ // Send node order to parent project whenever nodes/edges change
73
+ useEffect(() => {
74
+ if (edges.length > 0) {
75
+ // Get only nodes that are connected by edges
76
+ const connectedNodeIds = new Set<string>();
77
+ edges.forEach((edge) => {
78
+ connectedNodeIds.add(edge.source);
79
+ connectedNodeIds.add(edge.target);
80
+ });
81
+
82
+ // Filter nodes to only include connected ones
83
+ const connectedNodes = nodes.filter((node) => connectedNodeIds.has(node.id));
84
+
85
+ // Get node order for connected nodes only
86
+ const nodeOrder = orderNodesByEdges(connectedNodes, edges, { includeOrphanNodes: false });
87
+
88
+ // Print only connected nodes to console
89
+ console.log('\n========== NODE ORDER (Connected Only) ==========');
90
+ console.log('\n📋 EXECUTION ORDER:');
91
+ nodeOrder.orderedNodes.forEach((node, index) => {
92
+ console.log(` ${index + 1}. [${node.type || 'unknown'}] ${node.id}`);
93
+ });
94
+
95
+ console.log('\n🔗 EDGE ORDER:');
96
+ edges.forEach((edge, index) => {
97
+ console.log(` ${index + 1}. ${edge.source} ──→ ${edge.target}`);
98
+ });
99
+
100
+ console.log('\n📊 TOTAL:', nodeOrder.orderedNodes.length, 'nodes,', edges.length, 'edges');
101
+ console.log('=================================================\n');
102
+
103
+ // Send to parent project if callback provided
104
+ if (onNodeOrderChange) {
105
+ onNodeOrderChange(nodeOrder);
106
+ }
107
+ }
108
+ }, [nodes, edges, onNodeOrderChange]);
109
+
110
+ useImperativeHandle(ref, () => ({
111
+ undo,
112
+ redo,
113
+ canUndo: () => historyIndex > 0,
114
+ canRedo: () => historyIndex < history.length - 1,
115
+ reset,
116
+ getHistoryLength: () => history.length,
117
+ getHistoryIndex: () => historyIndex,
118
+ // Node data management methods
119
+ getNodeData: (nodeId: string) => {
120
+ const node = nodes.find(n => n.id === nodeId);
121
+ return node ? node.data : null;
122
+ },
123
+ updateNodeData: (nodeId: string, newData: any) => {
124
+ const nodeIndex = nodes.findIndex(n => n.id === nodeId);
125
+ if (nodeIndex === -1) return false;
126
+
127
+ const updatedNodes = [...nodes];
128
+ updatedNodes[nodeIndex] = {
129
+ ...updatedNodes[nodeIndex],
130
+ data: { ...updatedNodes[nodeIndex].data, ...newData }
131
+ };
132
+ setNodes(updatedNodes);
133
+ return true;
134
+ },
135
+ getSelectedNode: () => selectedNode,
136
+ getNodes: () => nodes,
137
+ getEdges: () => edges,
138
+ // Get ordered nodes based on edge connections
139
+ getNodeOrder: () => orderNodesByEdges(nodes, edges),
140
+ // Get current state for saving
141
+ getCurrentState: () => ({ nodes: [...nodes], edges: [...edges] }),
142
+ // Set nodes and edges (for restoring saved state)
143
+ setNodesAndEdges: (newNodes: any[], newEdges: any[]) => {
144
+ setNodes(newNodes);
145
+ setEdges(newEdges);
146
+ },
147
+ }));
148
+
149
+ return (
150
+ <DiagramContainer
151
+ defaultEdgeOptions={defaultEdgeOptions}
152
+ edgeTypes={edgeTypes}
153
+ nodeTypes={nodeTypes as any}
154
+ connectionLineComponent={FloatingConnectionLine}
155
+ style={{ backgroundColor: '#141519' }}
156
+ className={className}
157
+ showAutomationExecutionPanel={showAutomationExecutionPanel}
158
+ >
159
+ <Background
160
+ color="#ffffff"
161
+ variant={BackgroundVariant.Dots}
162
+ gap={20}
163
+ size={1}
164
+ />
165
+ {children}
166
+ </DiagramContainer>
167
+ );
168
+ });
169
+
170
+ export interface DiagrammingPageProps {
171
+ diagramType: DiagramTypes;
172
+ onChange?: OnChangeEventHandler;
173
+ defaultNodes: ICardNode[];
174
+ defaultEdges: Edge[];
175
+ children?: React.ReactNode;
176
+ workflowNodeContent?: WorkflowNodeContentType;
177
+ renderAddNodeView?: RenderAddNodeViewType;
178
+ getDefaultNodeData?: GetDefaultNodeDataType;
179
+ availableFunctions: FunctionSignature[];
180
+ availableVariables?: AvailableVariable[];
181
+ id: number;
182
+ className?: string;
183
+ conditionBuilderStates?: ConditionBuilderState;
184
+ // New: emit node selection to host app
185
+ onNodeSelect?: (payload: { nodeId: string; type?: string; data?: any }) => void;
186
+ // New: allow host to disable library JSON popovers/drawers
187
+ enableNodeJsonPopover?: boolean;
188
+ // New: control visibility of automation execution panel
189
+ showAutomationExecutionPanel?: boolean;
190
+ // New: callback to receive node order based on arrow/edge connections
191
+ onNodeOrderChange?: (nodeOrder: NodeOrderResult) => void;
192
+ }
193
+
194
+ export const DiagrammingPage = forwardRef<DiagrammingPageRef, DiagrammingPageProps>(({
195
+ diagramType,
196
+ defaultNodes,
197
+ defaultEdges,
198
+ onChange,
199
+ children,
200
+ workflowNodeContent,
201
+ renderAddNodeView,
202
+ getDefaultNodeData,
203
+ availableFunctions,
204
+ availableVariables,
205
+ id,
206
+ className,
207
+ conditionBuilderStates,
208
+ onNodeSelect: onNodeSelectProp,
209
+ enableNodeJsonPopover: enableNodeJsonPopoverProp,
210
+ showAutomationExecutionPanel,
211
+ onNodeOrderChange
212
+ }, ref) => {
213
+ return (
214
+ <ThemeProvider theme={theme}>
215
+ <CssBaseline />
216
+
217
+ <DiagramStoreProvider
218
+ id={id}
219
+ availableFunctions={availableFunctions}
220
+ availableVariables={availableVariables}
221
+ defaultNodes={defaultNodes} // Pass defaultNodes to the context
222
+ defaultEdges={defaultEdges} // Pass defaultEdges to the context
223
+ diagramType={diagramType} // Pass diagramType to the context
224
+ onChange={onChange} // Pass onChange to the context
225
+ workflowNodeContent={workflowNodeContent} // Pass workflowNodeContent to the context
226
+ renderAddNodeView={renderAddNodeView} // Pass workflowNodeContent to the context
227
+ getDefaultNodeData={getDefaultNodeData}
228
+ conditionBuilderStates={conditionBuilderStates}
229
+ onNodeSelect={onNodeSelectProp}
230
+ enableNodeJsonPopover={enableNodeJsonPopoverProp}
231
+ >
232
+ {/* Variable registration handler */}
233
+ <VariableRegistrationHandler />
234
+
235
+ <DiagrammingPageInternal
236
+ ref={ref}
237
+ className={className}
238
+ showAutomationExecutionPanel={showAutomationExecutionPanel}
239
+ onNodeOrderChange={onNodeOrderChange}
240
+ >
241
+ {children}
242
+ </DiagrammingPageInternal>
243
+ </DiagramStoreProvider>
244
+ </ThemeProvider>
245
+ );
246
+ });
@@ -1,3 +1,4 @@
1
+ import { MarkerType } from '@xyflow/react';
1
2
  import { Markers } from '../assets/markers/markers.type';
2
3
  import { CustomEdgeGenerator } from '../organisms/CustomEdge/custom-edge-generator';
3
4
  import { EdgeTypes } from '../organisms/CustomEdge/custom-edge.type';
@@ -13,6 +14,22 @@ export default {
13
14
  };
14
15
 
15
16
  export const defaultEdgeOptions = {
17
+ style: {
18
+ strokeWidth: 2,
19
+ stroke: '#10B981', // Green color for better visibility
20
+ },
21
+ // Arrow marker at the end of the edge
22
+ markerEnd: {
23
+ type: MarkerType.ArrowClosed,
24
+ width: 20,
25
+ height: 20,
26
+ color: '#10B981',
27
+ },
28
+ animated: false,
29
+ };
30
+
31
+ // ER Diagram edge options (for entity relationship diagrams)
32
+ export const erDiagramEdgeOptions = {
16
33
  style: {
17
34
  strokeWidth: 2,
18
35
  stroke: '#4858E9',
@@ -0,0 +1,113 @@
1
+ import { Edge, MarkerType } from '@xyflow/react';
2
+ import { ICardNode } from '../types/card-node';
3
+
4
+ /**
5
+ * Generates edges based on the order of nodes in the array.
6
+ * Creates a linear connection from first node to last node.
7
+ *
8
+ * @param nodes - Array of nodes in the desired order
9
+ * @param options - Configuration options for edge generation
10
+ * @returns Array of edges connecting nodes in sequence
11
+ */
12
+ export interface GenerateEdgesOptions {
13
+ /** Edge style stroke color */
14
+ strokeColor?: string;
15
+ /** Edge stroke width */
16
+ strokeWidth?: number;
17
+ /** Whether to add arrow marker at the end */
18
+ markerEnd?: boolean;
19
+ /** Whether edges should be animated */
20
+ animated?: boolean;
21
+ /** Source handle ID pattern (e.g., 'right-source', 'bottom-source') */
22
+ sourceHandleId?: string;
23
+ /** Target handle ID pattern (e.g., 'left-target', 'top-target') */
24
+ targetHandleId?: string;
25
+ }
26
+
27
+ const defaultOptions: GenerateEdgesOptions = {
28
+ strokeColor: '#10B981',
29
+ strokeWidth: 2,
30
+ markerEnd: true,
31
+ animated: false,
32
+ sourceHandleId: 'right-source',
33
+ targetHandleId: 'left-target',
34
+ };
35
+
36
+ export function generateEdgesFromNodeOrder(
37
+ nodes: ICardNode[],
38
+ options: GenerateEdgesOptions = {}
39
+ ): Edge[] {
40
+ const opts = { ...defaultOptions, ...options };
41
+ const edges: Edge[] = [];
42
+
43
+ // Need at least 2 nodes to create edges
44
+ if (nodes.length < 2) {
45
+ return edges;
46
+ }
47
+
48
+ // Create edges between consecutive nodes
49
+ for (let i = 0; i < nodes.length - 1; i++) {
50
+ const sourceNode = nodes[i];
51
+ const targetNode = nodes[i + 1];
52
+
53
+ const edge: Edge = {
54
+ id: `edge-${sourceNode.id}-${targetNode.id}`,
55
+ source: sourceNode.id,
56
+ target: targetNode.id,
57
+ sourceHandle: opts.sourceHandleId,
58
+ targetHandle: opts.targetHandleId,
59
+ type: 'default',
60
+ animated: opts.animated,
61
+ style: {
62
+ stroke: opts.strokeColor,
63
+ strokeWidth: opts.strokeWidth,
64
+ },
65
+ };
66
+
67
+ // Add arrow marker if enabled
68
+ if (opts.markerEnd) {
69
+ edge.markerEnd = {
70
+ type: MarkerType.ArrowClosed,
71
+ width: 20,
72
+ height: 20,
73
+ color: opts.strokeColor,
74
+ };
75
+ }
76
+
77
+ edges.push(edge);
78
+ }
79
+
80
+ return edges;
81
+ }
82
+
83
+ /**
84
+ * Generates edges based on node order for automation diagrams (horizontal layout)
85
+ */
86
+ export function generateAutomationEdges(nodes: ICardNode[]): Edge[] {
87
+ return generateEdgesFromNodeOrder(nodes, {
88
+ strokeColor: '#10B981',
89
+ strokeWidth: 2,
90
+ markerEnd: true,
91
+ animated: false,
92
+ sourceHandleId: 'right-source',
93
+ targetHandleId: 'left-target',
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Generates edges based on node order for vertical layout diagrams
99
+ */
100
+ export function generateVerticalEdges(nodes: ICardNode[]): Edge[] {
101
+ return generateEdgesFromNodeOrder(nodes, {
102
+ strokeColor: '#10B981',
103
+ strokeWidth: 2,
104
+ markerEnd: true,
105
+ animated: false,
106
+ sourceHandleId: 'bottom-source',
107
+ targetHandleId: 'top-target',
108
+ });
109
+ }
110
+
111
+ export default generateEdgesFromNodeOrder;
112
+
113
+
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Configuration utility for Node AI Assistant
3
+ * This allows setting a global API endpoint and headers for all node AI assistants
4
+ */
5
+
6
+ let globalApiEndpoint: string | undefined = undefined;
7
+ let globalApiHeaders: Record<string, string> = {};
8
+
9
+ /**
10
+ * Set the global API endpoint for Node AI Assistant
11
+ * @param endpoint - The API endpoint URL (e.g., 'https://api.example.com/chat')
12
+ */
13
+ export const setNodeAIAssistantEndpoint = (endpoint: string | undefined) => {
14
+ globalApiEndpoint = endpoint;
15
+ };
16
+
17
+ /**
18
+ * Set global API headers for Node AI Assistant requests
19
+ * @param headers - Headers object (e.g., { 'Authorization': 'Bearer token' })
20
+ */
21
+ export const setNodeAIAssistantHeaders = (headers: Record<string, string>) => {
22
+ globalApiHeaders = headers;
23
+ };
24
+
25
+ /**
26
+ * Get the global API endpoint
27
+ */
28
+ export const getNodeAIAssistantEndpoint = (): string | undefined => {
29
+ return globalApiEndpoint;
30
+ };
31
+
32
+ /**
33
+ * Get the global API headers
34
+ */
35
+ export const getNodeAIAssistantHeaders = (): Record<string, string> => {
36
+ return globalApiHeaders;
37
+ };
38
+
39
+ /**
40
+ * Configure Node AI Assistant with endpoint and headers
41
+ * @param config - Configuration object
42
+ */
43
+ export const configureNodeAIAssistant = (config: {
44
+ endpoint?: string;
45
+ headers?: Record<string, string>;
46
+ }) => {
47
+ if (config.endpoint !== undefined) {
48
+ globalApiEndpoint = config.endpoint;
49
+ }
50
+ if (config.headers) {
51
+ globalApiHeaders = { ...globalApiHeaders, ...config.headers };
52
+ }
53
+ };
54
+