@flowuent-org/diagramming-core 1.0.8 → 1.1.1

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 (40) hide show
  1. package/apps/diagramming/src/AutomationDiagramData.ts +22 -0
  2. package/apps/diagramming/src/components/AddNodeView.tsx +252 -252
  3. package/apps/diagramming/src/main.tsx +463 -463
  4. package/apps/diagramming/src/node-data.ts +664 -664
  5. package/apps/diagramming/src/stencil-items.ts +31 -31
  6. package/apps/diagramming/src/vite-env.d.ts +1 -1
  7. package/package.json +1 -1
  8. package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
  9. package/packages/diagrams/README.md +7 -463
  10. package/packages/diagrams/UNDO_REDO_API.md +306 -306
  11. package/packages/diagrams/package.json +27 -27
  12. package/packages/diagrams/project.json +42 -42
  13. package/packages/diagrams/rollup.config.js +26 -26
  14. package/packages/diagrams/src/DiagramFlow.tsx +7 -7
  15. package/packages/diagrams/src/index.ts +116 -116
  16. package/packages/diagrams/src/index.ts.bak +99 -99
  17. package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
  18. package/packages/diagrams/src/lib/atoms/ExpressionInput.tsx +437 -437
  19. package/packages/diagrams/src/lib/components/DiagramPanel.tsx +331 -331
  20. package/packages/diagrams/src/lib/components/automation/AISuggestionsModal.tsx +269 -0
  21. package/packages/diagrams/src/lib/components/automation/AISuggestionsPanel.tsx +227 -0
  22. package/packages/diagrams/src/lib/components/automation/AutomationAISuggestionNode.tsx +178 -115
  23. package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +133 -27
  24. package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +134 -28
  25. package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +132 -27
  26. package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +124 -17
  27. package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +122 -15
  28. package/packages/diagrams/src/lib/components/automation/index.ts +3 -0
  29. package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +65 -65
  30. package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -121
  31. package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +45 -45
  32. package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
  33. package/packages/diagrams/src/lib/templates/systemFlow/components/FloatingEdge.tsx +219 -219
  34. package/packages/diagrams/src/lib/types/card-node.ts +68 -68
  35. package/packages/diagrams/src/lib/types/node-types.ts +29 -29
  36. package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +1179 -1179
  37. package/packages/diagrams/tsconfig.lib.json +25 -25
  38. package/tsconfig.base.json +29 -30
  39. package/TRANSLATION_FIX_SUMMARY.md +0 -118
  40. package/packages/diagrams/I18N_SETUP.md +0 -126
@@ -18,13 +18,16 @@ import {
18
18
  Error as ErrorIcon,
19
19
  ArrowForwardIos as ArrowForwardIcon,
20
20
  WhatsApp as WhatsAppIcon,
21
- Phone as PhoneIcon
21
+ Phone as PhoneIcon,
22
+ Lightbulb as LightbulbIcon
22
23
  } from '@mui/icons-material';
23
24
  import { RiCloseLine } from 'react-icons/ri';
24
25
  import ReactJson from 'react-json-view';
25
26
  import { getIconByName } from '../../utils/iconMapper';
26
27
  import { useTranslation } from 'react-i18next';
27
28
  import { useDiagram } from '../../contexts/DiagramProvider';
29
+ import { AISuggestion } from './AISuggestionsModal';
30
+ import { AISuggestionsPanel } from './AISuggestionsPanel';
28
31
 
29
32
  interface AutomationSheetsNodeProps {
30
33
  data: {
@@ -83,7 +86,10 @@ interface AutomationSheetsNodeProps {
83
86
  };
84
87
  };
85
88
  };
86
- formData?: any;
89
+ formData?: {
90
+ aiSuggestionsCount?: number; // Number of AI suggestions available
91
+ [key: string]: any;
92
+ };
87
93
  // Optional per-output-method statuses supplied by engine
88
94
  outputStatuses?: {
89
95
  googleSheets?: 'not-set' | 'configured' | 'running' | 'connected' | 'failed';
@@ -97,6 +103,7 @@ interface AutomationSheetsNodeProps {
97
103
  export const AutomationSheetsNode: React.FC<AutomationSheetsNodeProps> = ({ data, selected }) => {
98
104
  const { t } = useTranslation();
99
105
  const [isJsonOpen, setIsJsonOpen] = useState(false);
106
+ const [showSuggestions, setShowSuggestions] = useState(false);
100
107
  const rootRef = useRef<any>(null);
101
108
  const portalRef = useRef<HTMLDivElement | null>(null);
102
109
  const nodeRef = useRef<HTMLDivElement | null>(null);
@@ -694,23 +701,30 @@ Data: ${JSON.stringify(data, null, 2)}
694
701
 
695
702
  return (
696
703
  <Box
697
- ref={nodeRef}
698
704
  sx={{
699
- width: '380px',
700
- minHeight: '280px',
701
- backgroundColor: '#181C25', // Darker background like in image
702
- border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
703
- borderRadius: '12px',
704
- padding: '0',
705
- color: '#ffffff',
706
705
  position: 'relative',
707
- boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
708
- transition: 'all 0.2s ease',
709
- cursor: 'pointer',
710
- overflow: 'hidden',
706
+ width: '380px',
707
+ overflow: 'visible',
711
708
  }}
712
- onClick={handleJsonClick}
713
709
  >
710
+ <Box
711
+ ref={nodeRef}
712
+ sx={{
713
+ width: '380px',
714
+ minHeight: '280px',
715
+ backgroundColor: '#181C25', // Darker background like in image
716
+ border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
717
+ borderRadius: '12px',
718
+ padding: '0',
719
+ color: '#ffffff',
720
+ position: 'relative',
721
+ boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
722
+ transition: 'all 0.2s ease',
723
+ cursor: 'pointer',
724
+ overflow: 'hidden',
725
+ }}
726
+ onClick={handleJsonClick}
727
+ >
714
728
  {/* Header */}
715
729
  <Box sx={{
716
730
  display: 'flex',
@@ -825,6 +839,99 @@ Data: ${JSON.stringify(data, null, 2)}
825
839
  opacity: 0, // Hidden but functional
826
840
  }}
827
841
  />
842
+ </Box>
843
+
844
+ {/* AI Suggestions Button - Positioned below the node box */}
845
+ {data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
846
+ <Box
847
+ sx={{
848
+ position: 'absolute',
849
+ top: '100%',
850
+ left: '50%',
851
+ transform: 'translateX(-50%)',
852
+ marginTop: '12px',
853
+ zIndex: 10,
854
+ whiteSpace: 'nowrap',
855
+ }}
856
+ onClick={(e) => {
857
+ e.stopPropagation();
858
+ // Toggle AI Suggestions panel
859
+ setShowSuggestions(!showSuggestions);
860
+ }}
861
+ >
862
+ <Button
863
+ variant="contained"
864
+ startIcon={<LightbulbIcon sx={{ fontSize: '12px' }} />}
865
+ sx={{
866
+ backgroundColor: '#2563EB',
867
+ color: '#ffffff',
868
+ borderRadius: '20px',
869
+ textTransform: 'none',
870
+ fontSize: '10px',
871
+ fontWeight: 400,
872
+ padding: '8px 16px',
873
+ whiteSpace: 'nowrap',
874
+ display: 'inline-flex',
875
+ alignItems: 'center',
876
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
877
+ '&:hover': {
878
+ backgroundColor: '#2563eb',
879
+ },
880
+ '& .MuiButton-startIcon': {
881
+ marginRight: '8px',
882
+ }
883
+ }}
884
+ >
885
+ AI Suggestions
886
+ <Box
887
+ component="span"
888
+ sx={{
889
+ marginLeft: '8px',
890
+ backgroundColor: '#FFFFFF26',
891
+ color: '#ffffff',
892
+ fontSize: '10px',
893
+ fontWeight: 400,
894
+ minWidth: '18px',
895
+ height: '18px',
896
+ borderRadius: '9px',
897
+ display: 'inline-flex',
898
+ alignItems: 'center',
899
+ justifyContent: 'center',
900
+ padding: '0 6px',
901
+ border: '1px solid rgba(255, 255, 255, 0.2)',
902
+ }}
903
+ >
904
+ {data.formData.aiSuggestionsCount}
905
+ </Box>
906
+ </Button>
907
+ </Box>
908
+ )}
909
+
910
+ {/* AI Suggestions Panel - Rendered on canvas below the button */}
911
+ {showSuggestions && data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && nodeId && (
912
+ <AISuggestionsPanel
913
+ suggestions={data.formData?.aiSuggestions || [
914
+ {
915
+ id: '1',
916
+ title: 'Add Citation Extraction',
917
+ description: 'Automatically extract and format citations from article content.',
918
+ tags: ['classification', 'enhancement'],
919
+ },
920
+ {
921
+ id: '2',
922
+ title: 'Generate Bullet Summary',
923
+ description: 'Create a concise bullet-point summary of the article\'s main points.',
924
+ tags: ['classification', 'enhancement'],
925
+ },
926
+ ]}
927
+ parentNodeId={nodeId}
928
+ onSuggestionClick={(suggestion) => {
929
+ console.log('Suggestion clicked:', suggestion);
930
+ // Handle suggestion selection here
931
+ }}
932
+ onClose={() => setShowSuggestions(false)}
933
+ />
934
+ )}
828
935
  </Box>
829
936
  );
830
937
  };
@@ -6,3 +6,6 @@ export { AutomationEndNode } from './AutomationEndNode';
6
6
  export { AutomationNoteNode } from './AutomationNoteNode';
7
7
  export { AutomationExecutionPanel } from './AutomationExecutionPanel';
8
8
  export { AutomationAISuggestionNode } from './AutomationAISuggestionNode';
9
+ export { AISuggestionsModal, showAISuggestionsModal } from './AISuggestionsModal';
10
+ export { AISuggestionsPanel } from './AISuggestionsPanel';
11
+ export type { AISuggestion } from './AISuggestionsModal';
@@ -1,65 +1,65 @@
1
- import { DiagramState } from './diagramStoreTypes';
2
- import { ICardNode } from '@flowuent-labs/diagrams';
3
-
4
- // Helper function to handle node deletion and edge updates
5
- export const onWorkflowNodeDelete = (
6
- node: ICardNode, // The node to be deleted
7
- draft: DiagramState, // The current diagram state (edges and nodes)
8
- ) => {
9
- const { edges, nodes: allNodes } = draft;
10
-
11
- if (node.data.branchRoot) {
12
- // Find all nodes with the same branchRoot value
13
- const nodesToDelete = allNodes.filter(
14
- (n) => n.data.branchRoot === node.data.branchRoot,
15
- );
16
-
17
- // Remove the edges connected to these nodes
18
- const nodeIdsToDelete = new Set(nodesToDelete.map((n) => n.id));
19
- console.log('nodeIdsToDelete', nodeIdsToDelete);
20
- // Get the previous node of the root and the next node of the final node
21
- const branchRootNode = allNodes.find((n) => n.id === node.data.branchRoot);
22
- const finalNode = allNodes.find((n) => n.id === node.data.finalNodeId);
23
-
24
- if (branchRootNode && finalNode) {
25
- const previousEdge = edges.find(
26
- (edge) => edge.target === branchRootNode.id,
27
- );
28
- const nextEdge = edges.find((edge) => edge.source === finalNode.id);
29
-
30
- // Find the next node (if exists)
31
- const nextNode =
32
- nextEdge && allNodes.find((n) => n.id === nextEdge.target);
33
- // If there's a previous edge and a next node, update the previous edge's target to the next node's id
34
- if (previousEdge && nextNode) {
35
- previousEdge.target = nextNode.id;
36
- }
37
- }
38
-
39
- // Remove the nodes that are part of the branch
40
- draft.nodes = allNodes.filter((n) => !nodeIdsToDelete.has(n.id));
41
- } else {
42
- // Find the previous edge and next edge
43
- const previousEdge = edges.find((edge) => edge.target === node.id);
44
- const nextEdge = edges.find((edge) => edge.source === node.id);
45
-
46
- // Find the next node (if exists)
47
- const nextNode = nextEdge && allNodes.find((n) => n.id === nextEdge.target);
48
-
49
- // If there's a previous edge and a next node, update the previous edge's target to the next node's id
50
- if (previousEdge && nextNode) {
51
- previousEdge.target = nextNode.id;
52
- }
53
-
54
- // If there's a next edge, remove it
55
- if (nextEdge) {
56
- const nextEdgeIndex = edges.findIndex((edge) => edge.id === nextEdge.id);
57
- if (nextEdgeIndex !== -1) {
58
- edges.splice(nextEdgeIndex, 1); // Remove the next edge from the edges array
59
- }
60
- }
61
-
62
- // Remove the node from the nodes array
63
- draft.nodes = allNodes.filter((n) => n.id !== node.id);
64
- }
65
- };
1
+ import { DiagramState } from './diagramStoreTypes';
2
+ import { ICardNode } from '@flowuent-labs/diagrams';
3
+
4
+ // Helper function to handle node deletion and edge updates
5
+ export const onWorkflowNodeDelete = (
6
+ node: ICardNode, // The node to be deleted
7
+ draft: DiagramState, // The current diagram state (edges and nodes)
8
+ ) => {
9
+ const { edges, nodes: allNodes } = draft;
10
+
11
+ if (node.data.branchRoot) {
12
+ // Find all nodes with the same branchRoot value
13
+ const nodesToDelete = allNodes.filter(
14
+ (n) => n.data.branchRoot === node.data.branchRoot,
15
+ );
16
+
17
+ // Remove the edges connected to these nodes
18
+ const nodeIdsToDelete = new Set(nodesToDelete.map((n) => n.id));
19
+ console.log('nodeIdsToDelete', nodeIdsToDelete);
20
+ // Get the previous node of the root and the next node of the final node
21
+ const branchRootNode = allNodes.find((n) => n.id === node.data.branchRoot);
22
+ const finalNode = allNodes.find((n) => n.id === node.data.finalNodeId);
23
+
24
+ if (branchRootNode && finalNode) {
25
+ const previousEdge = edges.find(
26
+ (edge) => edge.target === branchRootNode.id,
27
+ );
28
+ const nextEdge = edges.find((edge) => edge.source === finalNode.id);
29
+
30
+ // Find the next node (if exists)
31
+ const nextNode =
32
+ nextEdge && allNodes.find((n) => n.id === nextEdge.target);
33
+ // If there's a previous edge and a next node, update the previous edge's target to the next node's id
34
+ if (previousEdge && nextNode) {
35
+ previousEdge.target = nextNode.id;
36
+ }
37
+ }
38
+
39
+ // Remove the nodes that are part of the branch
40
+ draft.nodes = allNodes.filter((n) => !nodeIdsToDelete.has(n.id));
41
+ } else {
42
+ // Find the previous edge and next edge
43
+ const previousEdge = edges.find((edge) => edge.target === node.id);
44
+ const nextEdge = edges.find((edge) => edge.source === node.id);
45
+
46
+ // Find the next node (if exists)
47
+ const nextNode = nextEdge && allNodes.find((n) => n.id === nextEdge.target);
48
+
49
+ // If there's a previous edge and a next node, update the previous edge's target to the next node's id
50
+ if (previousEdge && nextNode) {
51
+ previousEdge.target = nextNode.id;
52
+ }
53
+
54
+ // If there's a next edge, remove it
55
+ if (nextEdge) {
56
+ const nextEdgeIndex = edges.findIndex((edge) => edge.id === nextEdge.id);
57
+ if (nextEdgeIndex !== -1) {
58
+ edges.splice(nextEdgeIndex, 1); // Remove the next edge from the edges array
59
+ }
60
+ }
61
+
62
+ // Remove the node from the nodes array
63
+ draft.nodes = allNodes.filter((n) => n.id !== node.id);
64
+ }
65
+ };
@@ -1,121 +1,121 @@
1
- import { Edge } from '@xyflow/react';
2
- import {
3
- closestPoint,
4
- DiagramStore,
5
- EdgeTypes,
6
- HistoryEvent,
7
- ICardNode,
8
- useCustomReactFlow,
9
- useDiagram,
10
- } from '@flowuent-labs/diagrams';
11
- import React, { useCallback } from 'react';
12
- import { v4 as uuidv4 } from 'uuid';
13
- import addToHistory from '../../utils/addToHistory';
14
-
15
- export const useCreateBendPoint = (
16
- currentEdge: Edge,
17
- sourceNode: ICardNode,
18
- targetNode: ICardNode,
19
- pathRef: React.RefObject<SVGPathElement>,
20
- ) => {
21
- const { setEdges, getEdge, screenToFlowPosition, addNodes } =
22
- useCustomReactFlow();
23
- const store = useDiagram<DiagramStore>();
24
- const { diagramType, nodes, edges, setStore } = store;
25
-
26
- return useCallback(
27
- (evt: React.MouseEvent<SVGPathElement, MouseEvent>) => {
28
- if (diagramType === 'workflow') {
29
- return;
30
- }
31
- evt.preventDefault();
32
- evt.stopPropagation();
33
- if (!pathRef.current) return;
34
-
35
- const position = screenToFlowPosition({
36
- x: evt.clientX,
37
- y: evt.clientY,
38
- });
39
- const cpoint = closestPoint(pathRef.current, [position.x, position.y]);
40
- if (!currentEdge || !sourceNode || !targetNode)
41
- throw new Error(
42
- 'Invalid Edge found with source, target or curr edge missing',
43
- );
44
-
45
- const nodesAndEdgesBefore = {
46
- nodes: [...nodes],
47
- edges: [...edges],
48
- };
49
- const nodeId = uuidv4();
50
- const newBendPoint: ICardNode = {
51
- id: nodeId,
52
- position: { x: cpoint[0], y: cpoint[1] },
53
- data: { nodeId: nodeId },
54
- type: 'bendPoint',
55
- };
56
- const newEdge: Edge = {
57
- id: uuidv4(),
58
- source: newBendPoint.id,
59
- target: currentEdge.target,
60
- type:
61
- currentEdge.type === EdgeTypes.Default ||
62
- currentEdge.type === EdgeTypes.Bend2Target
63
- ? EdgeTypes.Bend2Target
64
- : EdgeTypes.Bend2Bend,
65
- };
66
- newEdge.markerEnd =
67
- newEdge.type === EdgeTypes.Bend2Target
68
- ? currentEdge.markerEnd
69
- : undefined;
70
- currentEdge.target = newBendPoint.id;
71
- currentEdge.type =
72
- currentEdge.type === EdgeTypes.Default ||
73
- currentEdge.type === EdgeTypes.Source2Bend
74
- ? EdgeTypes.Source2Bend
75
- : EdgeTypes.Bend2Bend;
76
- delete currentEdge.markerEnd;
77
- currentEdge.markerStart =
78
- currentEdge.type === EdgeTypes.Source2Bend
79
- ? currentEdge.markerStart
80
- : undefined;
81
-
82
- const newEdges = [
83
- ...edges.filter((e) => e.id !== currentEdge.id),
84
- currentEdge,
85
- newEdge,
86
- ];
87
- const newNodes = [...nodes, newBendPoint];
88
- const nodesAndEdgesAfter = {
89
- nodes: newNodes,
90
- edges: newEdges,
91
- };
92
-
93
- const event: HistoryEvent = {
94
- forward: {
95
- t: 'complex-change',
96
- type: 'complex',
97
- nodesAndEdges: nodesAndEdgesAfter,
98
- },
99
- backward: {
100
- t: 'complex-change',
101
- type: 'complex',
102
- nodesAndEdges: nodesAndEdgesBefore,
103
- },
104
- title: 'Bend point created in the middle of ' + currentEdge.id,
105
- };
106
- setStore({
107
- ...addToHistory(store, [event]),
108
- ...nodesAndEdgesAfter,
109
- });
110
- },
111
- [
112
- pathRef.current,
113
- currentEdge.id,
114
- getEdge,
115
- setEdges,
116
- addNodes,
117
- sourceNode,
118
- targetNode,
119
- ],
120
- );
121
- };
1
+ import { Edge } from '@xyflow/react';
2
+ import {
3
+ closestPoint,
4
+ DiagramStore,
5
+ EdgeTypes,
6
+ HistoryEvent,
7
+ ICardNode,
8
+ useCustomReactFlow,
9
+ useDiagram,
10
+ } from '@flowuent-labs/diagrams';
11
+ import React, { useCallback } from 'react';
12
+ import { v4 as uuidv4 } from 'uuid';
13
+ import addToHistory from '../../utils/addToHistory';
14
+
15
+ export const useCreateBendPoint = (
16
+ currentEdge: Edge,
17
+ sourceNode: ICardNode,
18
+ targetNode: ICardNode,
19
+ pathRef: React.RefObject<SVGPathElement>,
20
+ ) => {
21
+ const { setEdges, getEdge, screenToFlowPosition, addNodes } =
22
+ useCustomReactFlow();
23
+ const store = useDiagram<DiagramStore>();
24
+ const { diagramType, nodes, edges, setStore } = store;
25
+
26
+ return useCallback(
27
+ (evt: React.MouseEvent<SVGPathElement, MouseEvent>) => {
28
+ if (diagramType === 'workflow') {
29
+ return;
30
+ }
31
+ evt.preventDefault();
32
+ evt.stopPropagation();
33
+ if (!pathRef.current) return;
34
+
35
+ const position = screenToFlowPosition({
36
+ x: evt.clientX,
37
+ y: evt.clientY,
38
+ });
39
+ const cpoint = closestPoint(pathRef.current, [position.x, position.y]);
40
+ if (!currentEdge || !sourceNode || !targetNode)
41
+ throw new Error(
42
+ 'Invalid Edge found with source, target or curr edge missing',
43
+ );
44
+
45
+ const nodesAndEdgesBefore = {
46
+ nodes: [...nodes],
47
+ edges: [...edges],
48
+ };
49
+ const nodeId = uuidv4();
50
+ const newBendPoint: ICardNode = {
51
+ id: nodeId,
52
+ position: { x: cpoint[0], y: cpoint[1] },
53
+ data: { nodeId: nodeId },
54
+ type: 'bendPoint',
55
+ };
56
+ const newEdge: Edge = {
57
+ id: uuidv4(),
58
+ source: newBendPoint.id,
59
+ target: currentEdge.target,
60
+ type:
61
+ currentEdge.type === EdgeTypes.Default ||
62
+ currentEdge.type === EdgeTypes.Bend2Target
63
+ ? EdgeTypes.Bend2Target
64
+ : EdgeTypes.Bend2Bend,
65
+ };
66
+ newEdge.markerEnd =
67
+ newEdge.type === EdgeTypes.Bend2Target
68
+ ? currentEdge.markerEnd
69
+ : undefined;
70
+ currentEdge.target = newBendPoint.id;
71
+ currentEdge.type =
72
+ currentEdge.type === EdgeTypes.Default ||
73
+ currentEdge.type === EdgeTypes.Source2Bend
74
+ ? EdgeTypes.Source2Bend
75
+ : EdgeTypes.Bend2Bend;
76
+ delete currentEdge.markerEnd;
77
+ currentEdge.markerStart =
78
+ currentEdge.type === EdgeTypes.Source2Bend
79
+ ? currentEdge.markerStart
80
+ : undefined;
81
+
82
+ const newEdges = [
83
+ ...edges.filter((e) => e.id !== currentEdge.id),
84
+ currentEdge,
85
+ newEdge,
86
+ ];
87
+ const newNodes = [...nodes, newBendPoint];
88
+ const nodesAndEdgesAfter = {
89
+ nodes: newNodes,
90
+ edges: newEdges,
91
+ };
92
+
93
+ const event: HistoryEvent = {
94
+ forward: {
95
+ t: 'complex-change',
96
+ type: 'complex',
97
+ nodesAndEdges: nodesAndEdgesAfter,
98
+ },
99
+ backward: {
100
+ t: 'complex-change',
101
+ type: 'complex',
102
+ nodesAndEdges: nodesAndEdgesBefore,
103
+ },
104
+ title: 'Bend point created in the middle of ' + currentEdge.id,
105
+ };
106
+ setStore({
107
+ ...addToHistory(store, [event]),
108
+ ...nodesAndEdgesAfter,
109
+ });
110
+ },
111
+ [
112
+ pathRef.current,
113
+ currentEdge.id,
114
+ getEdge,
115
+ setEdges,
116
+ addNodes,
117
+ sourceNode,
118
+ targetNode,
119
+ ],
120
+ );
121
+ };
@@ -1,45 +1,45 @@
1
- import React from 'react';
2
- import { Button } from '@mui/material';
3
- import { WorkflowNodeActionButtons } from '../../molecules/WorkflowNodeActionButtons';
4
- import { ICardNode } from '../../types/card-node';
5
- import { useNodeType } from '@flowuent-labs/diagrams';
6
-
7
- interface NodeActionButtonsProps {
8
- addButtonVisible: boolean;
9
- addNewCaseNode: () => void;
10
- nextNodes: ICardNode[];
11
- }
12
-
13
- const NodeActionButtons = React.memo(
14
- ({ addButtonVisible, addNewCaseNode, nextNodes }: NodeActionButtonsProps) => {
15
- const type = useNodeType();
16
-
17
- return (
18
- <>
19
- {addButtonVisible && (
20
- <WorkflowNodeActionButtons
21
- direction={'bottom'}
22
- variant={'addParallelCol'}
23
- />
24
- )}
25
-
26
- {type === 'switch' && (
27
- <Button onClick={addNewCaseNode}>
28
- Add new case
29
- </Button>
30
- )}
31
-
32
- {nextNodes &&
33
- (nextNodes.length < 2 || type === 'emptyNode' ? (
34
- <WorkflowNodeActionButtons
35
- addInMiddle={nextNodes.length === 1}
36
- direction={'bottom'}
37
- isReplacing={type === 'emptyNode'}
38
- />
39
- ) : null)}
40
- </>
41
- );
42
- },
43
- );
44
-
45
- export default NodeActionButtons;
1
+ import React from 'react';
2
+ import { Button } from '@mui/material';
3
+ import { WorkflowNodeActionButtons } from '../../molecules/WorkflowNodeActionButtons';
4
+ import { ICardNode } from '../../types/card-node';
5
+ import { useNodeType } from '@flowuent-labs/diagrams';
6
+
7
+ interface NodeActionButtonsProps {
8
+ addButtonVisible: boolean;
9
+ addNewCaseNode: () => void;
10
+ nextNodes: ICardNode[];
11
+ }
12
+
13
+ const NodeActionButtons = React.memo(
14
+ ({ addButtonVisible, addNewCaseNode, nextNodes }: NodeActionButtonsProps) => {
15
+ const type = useNodeType();
16
+
17
+ return (
18
+ <>
19
+ {addButtonVisible && (
20
+ <WorkflowNodeActionButtons
21
+ direction={'bottom'}
22
+ variant={'addParallelCol'}
23
+ />
24
+ )}
25
+
26
+ {type === 'switch' && (
27
+ <Button onClick={addNewCaseNode}>
28
+ Add new case
29
+ </Button>
30
+ )}
31
+
32
+ {nextNodes &&
33
+ (nextNodes.length < 2 || type === 'emptyNode' ? (
34
+ <WorkflowNodeActionButtons
35
+ addInMiddle={nextNodes.length === 1}
36
+ direction={'bottom'}
37
+ isReplacing={type === 'emptyNode'}
38
+ />
39
+ ) : null)}
40
+ </>
41
+ );
42
+ },
43
+ );
44
+
45
+ export default NodeActionButtons;