@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.
- package/package.json +116 -116
- package/packages/diagrams/src/index.ts +1 -0
- package/packages/diagrams/src/lib/atoms/ConnectionPoints.tsx +149 -0
- package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +794 -650
- package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +606 -449
- package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +831 -687
- package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +420 -275
- package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +1118 -974
- package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +509 -344
- package/packages/diagrams/src/lib/components/automation/NodeAIAssistantPopup.tsx +504 -0
- package/packages/diagrams/src/lib/components/automation/NodeActionButtons.tsx +146 -0
- package/packages/diagrams/src/lib/components/automation/index.ts +20 -11
- package/packages/diagrams/src/lib/molecules/SideHandles.tsx +177 -12
- package/packages/diagrams/src/lib/organisms/CustomEdge/custom-edge-generator.tsx +10 -5
- package/packages/diagrams/src/lib/styles.css +53 -0
- package/packages/diagrams/src/lib/templates/DiagramContainer.tsx +59 -0
- package/packages/diagrams/src/lib/templates/Diagramming.tsx +246 -204
- package/packages/diagrams/src/lib/types/edge-types.ts +17 -0
- package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -0
- 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
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
+
|