@inspirer-dev/crm-dashboard 1.0.66 → 1.0.68
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/admin/src/components/StepFlowBuilder/flow-canvas/FlowCanvas.tsx +12 -5
- package/admin/src/components/StepFlowBuilder/nodes/EntryNode.tsx +1 -0
- package/admin/src/components/StepFlowBuilder/utils.ts +30 -8
- package/dist/_chunks/{index-PhHmqA3f.js → index-CzxnKN-q.js} +34 -11
- package/dist/_chunks/{index-paSmi6BE.mjs → index-D6i3MTUb.mjs} +35 -12
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import ReactFlow, {
|
|
|
6
6
|
useEdgesState,
|
|
7
7
|
useReactFlow,
|
|
8
8
|
useStoreApi,
|
|
9
|
+
useUpdateNodeInternals,
|
|
9
10
|
addEdge,
|
|
10
11
|
type Connection,
|
|
11
12
|
type OnNodesChange,
|
|
@@ -69,6 +70,7 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({
|
|
|
69
70
|
const history = useFlowHistory();
|
|
70
71
|
const { fitView, getViewport, setViewport, setCenter } = useReactFlow();
|
|
71
72
|
const store = useStoreApi();
|
|
73
|
+
const updateNodeInternals = useUpdateNodeInternals();
|
|
72
74
|
|
|
73
75
|
const validation = useMemo(() => {
|
|
74
76
|
return validateFlow(nodes as FlowNode[], edges as FlowEdge[]);
|
|
@@ -298,14 +300,19 @@ const FlowCanvas: React.FC<FlowCanvasProps> = ({
|
|
|
298
300
|
const hasPositions = steps.length > 0 && steps[0].positionX != null;
|
|
299
301
|
const finalNodes = hasPositions ? n : applyAutoLayout(n, e);
|
|
300
302
|
setNodes(finalNodes);
|
|
301
|
-
setEdges(e);
|
|
302
303
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
304
|
+
requestAnimationFrame(() => {
|
|
305
|
+
finalNodes.forEach((node) => updateNodeInternals(node.id));
|
|
306
|
+
requestAnimationFrame(() => {
|
|
307
|
+
setEdges(e);
|
|
308
|
+
setTimeout(() => {
|
|
309
|
+
fitViewWithOffset();
|
|
310
|
+
}, 50);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
306
313
|
}
|
|
307
314
|
isInitialMount.current = false;
|
|
308
|
-
}, [steps, setNodes, setEdges, fitViewWithOffset]);
|
|
315
|
+
}, [steps, setNodes, setEdges, fitViewWithOffset, updateNodeInternals]);
|
|
309
316
|
|
|
310
317
|
const syncToParent = useCallback(() => {
|
|
311
318
|
if (isInitialMount.current) return;
|
|
@@ -37,6 +37,7 @@ const EntryNode: React.FC<NodeProps<FlowNodeData>> = ({ selected }) => {
|
|
|
37
37
|
style={{
|
|
38
38
|
width: NODE_DIMENSIONS.width,
|
|
39
39
|
height: NODE_DIMENSIONS.height,
|
|
40
|
+
boxSizing: 'border-box',
|
|
40
41
|
background: colors.background,
|
|
41
42
|
borderRadius: 12,
|
|
42
43
|
border: getBorderStyle(),
|
|
@@ -26,15 +26,15 @@ export const stepsToFlow = (
|
|
|
26
26
|
const nodes: FlowNode[] = [];
|
|
27
27
|
const edges: FlowEdge[] = [];
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
:
|
|
32
|
-
|
|
29
|
+
const entryStep = steps.find((s) => s.stepKey === ENTRY_NODE_ID);
|
|
30
|
+
const entryPosition = entryStep?.positionX != null && entryStep?.positionY != null
|
|
31
|
+
? { x: entryStep.positionX, y: entryStep.positionY }
|
|
32
|
+
: { x: 250, y: 0 };
|
|
33
33
|
|
|
34
34
|
const entryNode: FlowNode = {
|
|
35
35
|
id: ENTRY_NODE_ID,
|
|
36
36
|
type: 'entry',
|
|
37
|
-
position:
|
|
37
|
+
position: entryPosition,
|
|
38
38
|
data: {
|
|
39
39
|
stepType: 'entry',
|
|
40
40
|
name: 'Entry',
|
|
@@ -44,7 +44,13 @@ export const stepsToFlow = (
|
|
|
44
44
|
};
|
|
45
45
|
nodes.push(entryNode);
|
|
46
46
|
|
|
47
|
-
const
|
|
47
|
+
const nonEntrySteps = steps.filter((s) => s.stepKey !== ENTRY_NODE_ID);
|
|
48
|
+
const firstStep = nonEntrySteps.length > 0
|
|
49
|
+
? [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))[0]
|
|
50
|
+
: null;
|
|
51
|
+
const hasPositions = firstStep != null && firstStep.positionX != null;
|
|
52
|
+
|
|
53
|
+
const sortedSteps = [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
48
54
|
|
|
49
55
|
sortedSteps.forEach((step, index) => {
|
|
50
56
|
const node: FlowNode = {
|
|
@@ -111,13 +117,27 @@ export const stepsToFlow = (
|
|
|
111
117
|
};
|
|
112
118
|
|
|
113
119
|
export const flowToSteps = (nodes: FlowNode[], edges: FlowEdge[]): FlowStep[] => {
|
|
120
|
+
const entryNode = nodes.find((n) => n.id === ENTRY_NODE_ID);
|
|
114
121
|
const stepNodes = nodes.filter((n) => n.data.stepType !== 'entry');
|
|
115
122
|
const nodePositions = new Map(nodes.map((n) => [n.id, n.position.y]));
|
|
116
123
|
const sorted = [...stepNodes].sort(
|
|
117
124
|
(a, b) => (nodePositions.get(a.id) ?? 0) - (nodePositions.get(b.id) ?? 0)
|
|
118
125
|
);
|
|
119
126
|
|
|
120
|
-
|
|
127
|
+
const steps: FlowStep[] = [];
|
|
128
|
+
|
|
129
|
+
if (entryNode) {
|
|
130
|
+
steps.push({
|
|
131
|
+
stepKey: ENTRY_NODE_ID,
|
|
132
|
+
name: 'Entry',
|
|
133
|
+
stepType: 'entry' as any,
|
|
134
|
+
order: -1,
|
|
135
|
+
positionX: Math.round(entryNode.position.x),
|
|
136
|
+
positionY: Math.round(entryNode.position.y),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
sorted.forEach((node, index) => {
|
|
121
141
|
const step: FlowStep = {
|
|
122
142
|
stepKey: node.id,
|
|
123
143
|
name: node.data.name,
|
|
@@ -139,8 +159,10 @@ export const flowToSteps = (nodes: FlowNode[], edges: FlowEdge[]): FlowStep[] =>
|
|
|
139
159
|
step.nextStep = outEdges[0]?.target;
|
|
140
160
|
}
|
|
141
161
|
|
|
142
|
-
|
|
162
|
+
steps.push(step);
|
|
143
163
|
});
|
|
164
|
+
|
|
165
|
+
return steps;
|
|
144
166
|
};
|
|
145
167
|
|
|
146
168
|
export const applyAutoLayout = (nodes: FlowNode[], edges: FlowEdge[]): FlowNode[] => {
|
|
@@ -151,12 +151,12 @@ const parseValue = (value) => {
|
|
|
151
151
|
const stepsToFlow = (steps) => {
|
|
152
152
|
const nodes = [];
|
|
153
153
|
const edges = [];
|
|
154
|
-
const
|
|
155
|
-
const
|
|
154
|
+
const entryStep = steps.find((s) => s.stepKey === ENTRY_NODE_ID);
|
|
155
|
+
const entryPosition = entryStep?.positionX != null && entryStep?.positionY != null ? { x: entryStep.positionX, y: entryStep.positionY } : { x: 250, y: 0 };
|
|
156
156
|
const entryNode = {
|
|
157
157
|
id: ENTRY_NODE_ID,
|
|
158
158
|
type: "entry",
|
|
159
|
-
position:
|
|
159
|
+
position: entryPosition,
|
|
160
160
|
data: {
|
|
161
161
|
stepType: "entry",
|
|
162
162
|
name: "Entry",
|
|
@@ -165,7 +165,10 @@ const stepsToFlow = (steps) => {
|
|
|
165
165
|
deletable: false
|
|
166
166
|
};
|
|
167
167
|
nodes.push(entryNode);
|
|
168
|
-
const
|
|
168
|
+
const nonEntrySteps = steps.filter((s) => s.stepKey !== ENTRY_NODE_ID);
|
|
169
|
+
const firstStep = nonEntrySteps.length > 0 ? [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))[0] : null;
|
|
170
|
+
const hasPositions = firstStep != null && firstStep.positionX != null;
|
|
171
|
+
const sortedSteps = [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
169
172
|
sortedSteps.forEach((step, index) => {
|
|
170
173
|
const node = {
|
|
171
174
|
id: step.stepKey,
|
|
@@ -225,12 +228,24 @@ const stepsToFlow = (steps) => {
|
|
|
225
228
|
return { nodes, edges };
|
|
226
229
|
};
|
|
227
230
|
const flowToSteps = (nodes, edges) => {
|
|
231
|
+
const entryNode = nodes.find((n) => n.id === ENTRY_NODE_ID);
|
|
228
232
|
const stepNodes = nodes.filter((n) => n.data.stepType !== "entry");
|
|
229
233
|
const nodePositions = new Map(nodes.map((n) => [n.id, n.position.y]));
|
|
230
234
|
const sorted = [...stepNodes].sort(
|
|
231
235
|
(a, b) => (nodePositions.get(a.id) ?? 0) - (nodePositions.get(b.id) ?? 0)
|
|
232
236
|
);
|
|
233
|
-
|
|
237
|
+
const steps = [];
|
|
238
|
+
if (entryNode) {
|
|
239
|
+
steps.push({
|
|
240
|
+
stepKey: ENTRY_NODE_ID,
|
|
241
|
+
name: "Entry",
|
|
242
|
+
stepType: "entry",
|
|
243
|
+
order: -1,
|
|
244
|
+
positionX: Math.round(entryNode.position.x),
|
|
245
|
+
positionY: Math.round(entryNode.position.y)
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
sorted.forEach((node, index) => {
|
|
234
249
|
const step = {
|
|
235
250
|
stepKey: node.id,
|
|
236
251
|
name: node.data.name,
|
|
@@ -249,8 +264,9 @@ const flowToSteps = (nodes, edges) => {
|
|
|
249
264
|
} else {
|
|
250
265
|
step.nextStep = outEdges[0]?.target;
|
|
251
266
|
}
|
|
252
|
-
|
|
267
|
+
steps.push(step);
|
|
253
268
|
});
|
|
269
|
+
return steps;
|
|
254
270
|
};
|
|
255
271
|
const applyAutoLayout = (nodes, edges) => {
|
|
256
272
|
const g = new dagre__default.default.graphlib.Graph();
|
|
@@ -364,6 +380,7 @@ const EntryNode = ({ selected }) => {
|
|
|
364
380
|
style: {
|
|
365
381
|
width: NODE_DIMENSIONS.width,
|
|
366
382
|
height: NODE_DIMENSIONS.height,
|
|
383
|
+
boxSizing: "border-box",
|
|
367
384
|
background: colors.background,
|
|
368
385
|
borderRadius: 12,
|
|
369
386
|
border: getBorderStyle(),
|
|
@@ -3456,6 +3473,7 @@ const FlowCanvas = ({
|
|
|
3456
3473
|
const history = useFlowHistory();
|
|
3457
3474
|
const { fitView, getViewport, setViewport, setCenter } = ReactFlow.useReactFlow();
|
|
3458
3475
|
const store = ReactFlow.useStoreApi();
|
|
3476
|
+
const updateNodeInternals = ReactFlow.useUpdateNodeInternals();
|
|
3459
3477
|
const validation = React.useMemo(() => {
|
|
3460
3478
|
return validateFlow(nodes, edges);
|
|
3461
3479
|
}, [nodes, edges]);
|
|
@@ -3625,13 +3643,18 @@ const FlowCanvas = ({
|
|
|
3625
3643
|
const hasPositions = steps.length > 0 && steps[0].positionX != null;
|
|
3626
3644
|
const finalNodes = hasPositions ? n : applyAutoLayout(n, e);
|
|
3627
3645
|
setNodes(finalNodes);
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3646
|
+
requestAnimationFrame(() => {
|
|
3647
|
+
finalNodes.forEach((node) => updateNodeInternals(node.id));
|
|
3648
|
+
requestAnimationFrame(() => {
|
|
3649
|
+
setEdges(e);
|
|
3650
|
+
setTimeout(() => {
|
|
3651
|
+
fitViewWithOffset();
|
|
3652
|
+
}, 50);
|
|
3653
|
+
});
|
|
3654
|
+
});
|
|
3632
3655
|
}
|
|
3633
3656
|
isInitialMount.current = false;
|
|
3634
|
-
}, [steps, setNodes, setEdges, fitViewWithOffset]);
|
|
3657
|
+
}, [steps, setNodes, setEdges, fitViewWithOffset, updateNodeInternals]);
|
|
3635
3658
|
const syncToParent = React.useCallback(() => {
|
|
3636
3659
|
if (isInitialMount.current) return;
|
|
3637
3660
|
if (syncTimeoutRef.current) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, memo, useState, useEffect, useCallback, useRef, useMemo, forwardRef } from "react";
|
|
3
|
-
import ReactFlow, { Handle, Position, useReactFlow, getSimpleBezierPath, BaseEdge, EdgeLabelRenderer, useNodesState, useEdgesState, useStoreApi, addEdge, Background, MiniMap, ReactFlowProvider } from "reactflow";
|
|
3
|
+
import ReactFlow, { Handle, Position, useReactFlow, getSimpleBezierPath, BaseEdge, EdgeLabelRenderer, useNodesState, useEdgesState, useStoreApi, useUpdateNodeInternals, addEdge, Background, MiniMap, ReactFlowProvider } from "reactflow";
|
|
4
4
|
import "reactflow/dist/style.css";
|
|
5
5
|
import { Flex, Box, Typography, SingleSelect, SingleSelectOption, TextInput, NumberInput, Loader, Tooltip, Field, Badge as Badge$1, Modal } from "@strapi/design-system";
|
|
6
6
|
import { Plus, Trash, Cross, Layout, Pencil } from "@strapi/icons";
|
|
@@ -146,12 +146,12 @@ const parseValue = (value) => {
|
|
|
146
146
|
const stepsToFlow = (steps) => {
|
|
147
147
|
const nodes = [];
|
|
148
148
|
const edges = [];
|
|
149
|
-
const
|
|
150
|
-
const
|
|
149
|
+
const entryStep = steps.find((s) => s.stepKey === ENTRY_NODE_ID);
|
|
150
|
+
const entryPosition = entryStep?.positionX != null && entryStep?.positionY != null ? { x: entryStep.positionX, y: entryStep.positionY } : { x: 250, y: 0 };
|
|
151
151
|
const entryNode = {
|
|
152
152
|
id: ENTRY_NODE_ID,
|
|
153
153
|
type: "entry",
|
|
154
|
-
position:
|
|
154
|
+
position: entryPosition,
|
|
155
155
|
data: {
|
|
156
156
|
stepType: "entry",
|
|
157
157
|
name: "Entry",
|
|
@@ -160,7 +160,10 @@ const stepsToFlow = (steps) => {
|
|
|
160
160
|
deletable: false
|
|
161
161
|
};
|
|
162
162
|
nodes.push(entryNode);
|
|
163
|
-
const
|
|
163
|
+
const nonEntrySteps = steps.filter((s) => s.stepKey !== ENTRY_NODE_ID);
|
|
164
|
+
const firstStep = nonEntrySteps.length > 0 ? [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))[0] : null;
|
|
165
|
+
const hasPositions = firstStep != null && firstStep.positionX != null;
|
|
166
|
+
const sortedSteps = [...nonEntrySteps].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
164
167
|
sortedSteps.forEach((step, index) => {
|
|
165
168
|
const node = {
|
|
166
169
|
id: step.stepKey,
|
|
@@ -220,12 +223,24 @@ const stepsToFlow = (steps) => {
|
|
|
220
223
|
return { nodes, edges };
|
|
221
224
|
};
|
|
222
225
|
const flowToSteps = (nodes, edges) => {
|
|
226
|
+
const entryNode = nodes.find((n) => n.id === ENTRY_NODE_ID);
|
|
223
227
|
const stepNodes = nodes.filter((n) => n.data.stepType !== "entry");
|
|
224
228
|
const nodePositions = new Map(nodes.map((n) => [n.id, n.position.y]));
|
|
225
229
|
const sorted = [...stepNodes].sort(
|
|
226
230
|
(a, b) => (nodePositions.get(a.id) ?? 0) - (nodePositions.get(b.id) ?? 0)
|
|
227
231
|
);
|
|
228
|
-
|
|
232
|
+
const steps = [];
|
|
233
|
+
if (entryNode) {
|
|
234
|
+
steps.push({
|
|
235
|
+
stepKey: ENTRY_NODE_ID,
|
|
236
|
+
name: "Entry",
|
|
237
|
+
stepType: "entry",
|
|
238
|
+
order: -1,
|
|
239
|
+
positionX: Math.round(entryNode.position.x),
|
|
240
|
+
positionY: Math.round(entryNode.position.y)
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
sorted.forEach((node, index) => {
|
|
229
244
|
const step = {
|
|
230
245
|
stepKey: node.id,
|
|
231
246
|
name: node.data.name,
|
|
@@ -244,8 +259,9 @@ const flowToSteps = (nodes, edges) => {
|
|
|
244
259
|
} else {
|
|
245
260
|
step.nextStep = outEdges[0]?.target;
|
|
246
261
|
}
|
|
247
|
-
|
|
262
|
+
steps.push(step);
|
|
248
263
|
});
|
|
264
|
+
return steps;
|
|
249
265
|
};
|
|
250
266
|
const applyAutoLayout = (nodes, edges) => {
|
|
251
267
|
const g = new dagre.graphlib.Graph();
|
|
@@ -359,6 +375,7 @@ const EntryNode = ({ selected }) => {
|
|
|
359
375
|
style: {
|
|
360
376
|
width: NODE_DIMENSIONS.width,
|
|
361
377
|
height: NODE_DIMENSIONS.height,
|
|
378
|
+
boxSizing: "border-box",
|
|
362
379
|
background: colors.background,
|
|
363
380
|
borderRadius: 12,
|
|
364
381
|
border: getBorderStyle(),
|
|
@@ -3451,6 +3468,7 @@ const FlowCanvas = ({
|
|
|
3451
3468
|
const history = useFlowHistory();
|
|
3452
3469
|
const { fitView, getViewport, setViewport, setCenter } = useReactFlow();
|
|
3453
3470
|
const store = useStoreApi();
|
|
3471
|
+
const updateNodeInternals = useUpdateNodeInternals();
|
|
3454
3472
|
const validation = useMemo(() => {
|
|
3455
3473
|
return validateFlow(nodes, edges);
|
|
3456
3474
|
}, [nodes, edges]);
|
|
@@ -3620,13 +3638,18 @@ const FlowCanvas = ({
|
|
|
3620
3638
|
const hasPositions = steps.length > 0 && steps[0].positionX != null;
|
|
3621
3639
|
const finalNodes = hasPositions ? n : applyAutoLayout(n, e);
|
|
3622
3640
|
setNodes(finalNodes);
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3641
|
+
requestAnimationFrame(() => {
|
|
3642
|
+
finalNodes.forEach((node) => updateNodeInternals(node.id));
|
|
3643
|
+
requestAnimationFrame(() => {
|
|
3644
|
+
setEdges(e);
|
|
3645
|
+
setTimeout(() => {
|
|
3646
|
+
fitViewWithOffset();
|
|
3647
|
+
}, 50);
|
|
3648
|
+
});
|
|
3649
|
+
});
|
|
3627
3650
|
}
|
|
3628
3651
|
isInitialMount.current = false;
|
|
3629
|
-
}, [steps, setNodes, setEdges, fitViewWithOffset]);
|
|
3652
|
+
}, [steps, setNodes, setEdges, fitViewWithOffset, updateNodeInternals]);
|
|
3630
3653
|
const syncToParent = useCallback(() => {
|
|
3631
3654
|
if (isInitialMount.current) return;
|
|
3632
3655
|
if (syncTimeoutRef.current) {
|
package/dist/admin/index.js
CHANGED
package/dist/admin/index.mjs
CHANGED