@flowuent-org/diagramming-core 1.1.8 ā 1.1.9
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
CHANGED
|
@@ -1,204 +1,245 @@
|
|
|
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 (
|
|
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
|
+
}
|
|
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 (edges.length > 0) {
|
|
70
|
+
// Get only nodes that are connected by edges (exclude orphan nodes)
|
|
71
|
+
const nodeOrder = orderNodesByEdges(nodes, edges, { includeOrphanNodes: false });
|
|
72
|
+
|
|
73
|
+
// Get only connected nodes (nodes that appear in edges)
|
|
74
|
+
const connectedNodeIds = new Set<string>();
|
|
75
|
+
edges.forEach((edge) => {
|
|
76
|
+
connectedNodeIds.add(edge.source);
|
|
77
|
+
connectedNodeIds.add(edge.target);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Filter ordered nodes to only include connected ones
|
|
81
|
+
const connectedOrderedNodes = nodeOrder.orderedNodes.filter(
|
|
82
|
+
(node) => connectedNodeIds.has(node.id)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Print node structure to console
|
|
86
|
+
console.log('\n========== NODE ORDER BY EDGES ==========');
|
|
87
|
+
console.log('\nš CONNECTED NODES ORDER (following arrows):');
|
|
88
|
+
connectedOrderedNodes.forEach((node, index) => {
|
|
89
|
+
console.log(` ${index + 1}. [${node.type || 'unknown'}] ${node.id}`);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
console.log('\nš¢ START NODE:', nodeOrder.startNodes[0]?.id || '(none)');
|
|
93
|
+
console.log('š“ END NODE:', nodeOrder.endNodes[0]?.id || '(none)');
|
|
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 CONNECTED NODES:', connectedOrderedNodes.length);
|
|
101
|
+
console.log('==========================================\n');
|
|
102
|
+
|
|
103
|
+
// Create updated result with only connected nodes
|
|
104
|
+
const connectedNodeOrder: NodeOrderResult = {
|
|
105
|
+
...nodeOrder,
|
|
106
|
+
orderedNodes: connectedOrderedNodes,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// Send to parent project if callback provided
|
|
110
|
+
if (onNodeOrderChange) {
|
|
111
|
+
onNodeOrderChange(connectedNodeOrder);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}, [nodes, edges, onNodeOrderChange]);
|
|
115
|
+
|
|
116
|
+
useImperativeHandle(ref, () => ({
|
|
117
|
+
undo,
|
|
118
|
+
redo,
|
|
119
|
+
canUndo: () => historyIndex > 0,
|
|
120
|
+
canRedo: () => historyIndex < history.length - 1,
|
|
121
|
+
reset,
|
|
122
|
+
getHistoryLength: () => history.length,
|
|
123
|
+
getHistoryIndex: () => historyIndex,
|
|
124
|
+
// Node data management methods
|
|
125
|
+
getNodeData: (nodeId: string) => {
|
|
126
|
+
const node = nodes.find(n => n.id === nodeId);
|
|
127
|
+
return node ? node.data : null;
|
|
128
|
+
},
|
|
129
|
+
updateNodeData: (nodeId: string, newData: any) => {
|
|
130
|
+
const nodeIndex = nodes.findIndex(n => n.id === nodeId);
|
|
131
|
+
if (nodeIndex === -1) return false;
|
|
132
|
+
|
|
133
|
+
const updatedNodes = [...nodes];
|
|
134
|
+
updatedNodes[nodeIndex] = {
|
|
135
|
+
...updatedNodes[nodeIndex],
|
|
136
|
+
data: { ...updatedNodes[nodeIndex].data, ...newData }
|
|
137
|
+
};
|
|
138
|
+
setNodes(updatedNodes);
|
|
139
|
+
return true;
|
|
140
|
+
},
|
|
141
|
+
getSelectedNode: () => selectedNode,
|
|
142
|
+
getNodes: () => nodes,
|
|
143
|
+
getEdges: () => edges,
|
|
144
|
+
// Get ordered nodes based on edge connections
|
|
145
|
+
getNodeOrder: () => orderNodesByEdges(nodes, edges),
|
|
146
|
+
}));
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
<DiagramContainer
|
|
150
|
+
defaultEdgeOptions={defaultEdgeOptions}
|
|
151
|
+
edgeTypes={edgeTypes}
|
|
152
|
+
nodeTypes={nodeTypes as any}
|
|
153
|
+
connectionLineComponent={FloatingConnectionLine}
|
|
154
|
+
style={{ backgroundColor: '#141519' }}
|
|
155
|
+
className={className}
|
|
156
|
+
showAutomationExecutionPanel={showAutomationExecutionPanel}
|
|
157
|
+
>
|
|
158
|
+
<Background
|
|
159
|
+
color="#ffffff"
|
|
160
|
+
variant={BackgroundVariant.Dots}
|
|
161
|
+
gap={20}
|
|
162
|
+
size={1}
|
|
163
|
+
/>
|
|
164
|
+
{children}
|
|
165
|
+
</DiagramContainer>
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
export interface DiagrammingPageProps {
|
|
170
|
+
diagramType: DiagramTypes;
|
|
171
|
+
onChange?: OnChangeEventHandler;
|
|
172
|
+
defaultNodes: ICardNode[];
|
|
173
|
+
defaultEdges: Edge[];
|
|
174
|
+
children?: React.ReactNode;
|
|
175
|
+
workflowNodeContent?: WorkflowNodeContentType;
|
|
176
|
+
renderAddNodeView?: RenderAddNodeViewType;
|
|
177
|
+
getDefaultNodeData?: GetDefaultNodeDataType;
|
|
178
|
+
availableFunctions: FunctionSignature[];
|
|
179
|
+
availableVariables?: AvailableVariable[];
|
|
180
|
+
id: number;
|
|
181
|
+
className?: string;
|
|
182
|
+
conditionBuilderStates?: ConditionBuilderState;
|
|
183
|
+
// New: emit node selection to host app
|
|
184
|
+
onNodeSelect?: (payload: { nodeId: string; type?: string; data?: any }) => void;
|
|
185
|
+
// New: allow host to disable library JSON popovers/drawers
|
|
186
|
+
enableNodeJsonPopover?: boolean;
|
|
187
|
+
// New: control visibility of automation execution panel
|
|
188
|
+
showAutomationExecutionPanel?: boolean;
|
|
189
|
+
// New: callback to receive node order based on arrow/edge connections
|
|
190
|
+
onNodeOrderChange?: (nodeOrder: NodeOrderResult) => void;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export const DiagrammingPage = forwardRef<DiagrammingPageRef, DiagrammingPageProps>(({
|
|
194
|
+
diagramType,
|
|
195
|
+
defaultNodes,
|
|
196
|
+
defaultEdges,
|
|
197
|
+
onChange,
|
|
198
|
+
children,
|
|
199
|
+
workflowNodeContent,
|
|
200
|
+
renderAddNodeView,
|
|
201
|
+
getDefaultNodeData,
|
|
202
|
+
availableFunctions,
|
|
203
|
+
availableVariables,
|
|
204
|
+
id,
|
|
205
|
+
className,
|
|
206
|
+
conditionBuilderStates,
|
|
207
|
+
onNodeSelect: onNodeSelectProp,
|
|
208
|
+
enableNodeJsonPopover: enableNodeJsonPopoverProp,
|
|
209
|
+
showAutomationExecutionPanel,
|
|
210
|
+
onNodeOrderChange
|
|
211
|
+
}, ref) => {
|
|
212
|
+
return (
|
|
213
|
+
<ThemeProvider theme={theme}>
|
|
214
|
+
<CssBaseline />
|
|
215
|
+
|
|
216
|
+
<DiagramStoreProvider
|
|
217
|
+
id={id}
|
|
218
|
+
availableFunctions={availableFunctions}
|
|
219
|
+
availableVariables={availableVariables}
|
|
220
|
+
defaultNodes={defaultNodes} // Pass defaultNodes to the context
|
|
221
|
+
defaultEdges={defaultEdges} // Pass defaultEdges to the context
|
|
222
|
+
diagramType={diagramType} // Pass diagramType to the context
|
|
223
|
+
onChange={onChange} // Pass onChange to the context
|
|
224
|
+
workflowNodeContent={workflowNodeContent} // Pass workflowNodeContent to the context
|
|
225
|
+
renderAddNodeView={renderAddNodeView} // Pass workflowNodeContent to the context
|
|
226
|
+
getDefaultNodeData={getDefaultNodeData}
|
|
227
|
+
conditionBuilderStates={conditionBuilderStates}
|
|
228
|
+
onNodeSelect={onNodeSelectProp}
|
|
229
|
+
enableNodeJsonPopover={enableNodeJsonPopoverProp}
|
|
230
|
+
>
|
|
231
|
+
{/* Variable registration handler */}
|
|
232
|
+
<VariableRegistrationHandler />
|
|
233
|
+
|
|
234
|
+
<DiagrammingPageInternal
|
|
235
|
+
ref={ref}
|
|
236
|
+
className={className}
|
|
237
|
+
showAutomationExecutionPanel={showAutomationExecutionPanel}
|
|
238
|
+
onNodeOrderChange={onNodeOrderChange}
|
|
239
|
+
>
|
|
240
|
+
{children}
|
|
241
|
+
</DiagrammingPageInternal>
|
|
242
|
+
</DiagramStoreProvider>
|
|
243
|
+
</ThemeProvider>
|
|
244
|
+
);
|
|
245
|
+
});
|