@flowuent-org/diagramming-core 1.1.9 → 1.2.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.
- 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 +151 -13
- package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +158 -7
- package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +151 -13
- package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +152 -13
- package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +151 -13
- package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +166 -7
- package/packages/diagrams/src/lib/components/automation/NodeActionButtons.tsx +145 -0
- package/packages/diagrams/src/lib/components/automation/index.ts +1 -0
- 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 +25 -24
- package/packages/diagrams/src/lib/types/edge-types.ts +17 -0
- package/packages/diagrams/src/lib/utils/generateEdgesFromNodeOrder.ts +113 -0
|
@@ -28,6 +28,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
28
28
|
import { useDiagram } from '../../contexts/DiagramProvider';
|
|
29
29
|
import { AISuggestion } from './AISuggestionsModal';
|
|
30
30
|
import { AISuggestionsPanel } from './AISuggestionsPanel';
|
|
31
|
+
import { NodeActionButtons } from './NodeActionButtons';
|
|
31
32
|
|
|
32
33
|
interface AutomationSheetsNodeProps {
|
|
33
34
|
data: {
|
|
@@ -110,6 +111,9 @@ export const AutomationSheetsNode: React.FC<AutomationSheetsNodeProps> = ({ data
|
|
|
110
111
|
const nodeId = useNodeId();
|
|
111
112
|
const setSelectedNode = useDiagram((state) => state.setSelectedNode);
|
|
112
113
|
const enableJson = useDiagram((state) => state.enableNodeJsonPopover ?? true);
|
|
114
|
+
const onNodesChange = useDiagram((state) => state.onNodesChange);
|
|
115
|
+
const nodes = useDiagram((state) => state.nodes);
|
|
116
|
+
const setNodes = useDiagram((state) => state.setNodes);
|
|
113
117
|
|
|
114
118
|
// Get the icon component based on the iconName
|
|
115
119
|
const IconComponent = getIconByName(data.iconName || 'TableChart');
|
|
@@ -848,35 +852,169 @@ Data: ${JSON.stringify(data, null, 2)}
|
|
|
848
852
|
</Button>
|
|
849
853
|
</Box>
|
|
850
854
|
|
|
851
|
-
{/* Handles -
|
|
855
|
+
{/* Connection Handles - Bidirectional (source + target at each position) */}
|
|
856
|
+
{/* Top - Source */}
|
|
857
|
+
<Handle
|
|
858
|
+
type="source"
|
|
859
|
+
position={Position.Top}
|
|
860
|
+
id="top-source"
|
|
861
|
+
className="connection-handle"
|
|
862
|
+
style={{
|
|
863
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
864
|
+
width: '14px',
|
|
865
|
+
height: '14px',
|
|
866
|
+
border: '3px solid #10B981',
|
|
867
|
+
top: '-8px',
|
|
868
|
+
opacity: selected ? 1 : 0,
|
|
869
|
+
transition: 'all 0.2s ease-in-out',
|
|
870
|
+
cursor: 'crosshair',
|
|
871
|
+
zIndex: 10,
|
|
872
|
+
}}
|
|
873
|
+
/>
|
|
874
|
+
{/* Top - Target (hidden but functional) */}
|
|
875
|
+
<Handle
|
|
876
|
+
type="target"
|
|
877
|
+
position={Position.Top}
|
|
878
|
+
id="top-target"
|
|
879
|
+
style={{
|
|
880
|
+
background: 'transparent',
|
|
881
|
+
width: '14px',
|
|
882
|
+
height: '14px',
|
|
883
|
+
border: 'none',
|
|
884
|
+
top: '-8px',
|
|
885
|
+
opacity: 0,
|
|
886
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
887
|
+
}}
|
|
888
|
+
/>
|
|
889
|
+
{/* Bottom - Source */}
|
|
890
|
+
<Handle
|
|
891
|
+
type="source"
|
|
892
|
+
position={Position.Bottom}
|
|
893
|
+
id="bottom-source"
|
|
894
|
+
className="connection-handle"
|
|
895
|
+
style={{
|
|
896
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
897
|
+
width: '14px',
|
|
898
|
+
height: '14px',
|
|
899
|
+
border: '3px solid #10B981',
|
|
900
|
+
bottom: '-8px',
|
|
901
|
+
opacity: selected ? 1 : 0,
|
|
902
|
+
transition: 'all 0.2s ease-in-out',
|
|
903
|
+
cursor: 'crosshair',
|
|
904
|
+
zIndex: 10,
|
|
905
|
+
}}
|
|
906
|
+
/>
|
|
907
|
+
{/* Bottom - Target (hidden but functional) */}
|
|
908
|
+
<Handle
|
|
909
|
+
type="target"
|
|
910
|
+
position={Position.Bottom}
|
|
911
|
+
id="bottom-target"
|
|
912
|
+
style={{
|
|
913
|
+
background: 'transparent',
|
|
914
|
+
width: '14px',
|
|
915
|
+
height: '14px',
|
|
916
|
+
border: 'none',
|
|
917
|
+
bottom: '-8px',
|
|
918
|
+
opacity: 0,
|
|
919
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
920
|
+
}}
|
|
921
|
+
/>
|
|
922
|
+
{/* Left - Source */}
|
|
923
|
+
<Handle
|
|
924
|
+
type="source"
|
|
925
|
+
position={Position.Left}
|
|
926
|
+
id="left-source"
|
|
927
|
+
className="connection-handle"
|
|
928
|
+
style={{
|
|
929
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
930
|
+
width: '14px',
|
|
931
|
+
height: '14px',
|
|
932
|
+
border: '3px solid #10B981',
|
|
933
|
+
left: '-8px',
|
|
934
|
+
opacity: selected ? 1 : 0,
|
|
935
|
+
transition: 'all 0.2s ease-in-out',
|
|
936
|
+
cursor: 'crosshair',
|
|
937
|
+
zIndex: 10,
|
|
938
|
+
}}
|
|
939
|
+
/>
|
|
940
|
+
{/* Left - Target (hidden but functional) */}
|
|
852
941
|
<Handle
|
|
853
942
|
type="target"
|
|
854
943
|
position={Position.Left}
|
|
855
|
-
id="left"
|
|
944
|
+
id="left-target"
|
|
856
945
|
style={{
|
|
857
|
-
background: '
|
|
858
|
-
width: '
|
|
859
|
-
height: '
|
|
860
|
-
border: '
|
|
946
|
+
background: 'transparent',
|
|
947
|
+
width: '14px',
|
|
948
|
+
height: '14px',
|
|
949
|
+
border: 'none',
|
|
861
950
|
left: '-8px',
|
|
862
|
-
opacity: 0,
|
|
951
|
+
opacity: 0,
|
|
952
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
863
953
|
}}
|
|
864
954
|
/>
|
|
955
|
+
{/* Right - Source */}
|
|
865
956
|
<Handle
|
|
866
957
|
type="source"
|
|
867
958
|
position={Position.Right}
|
|
868
|
-
id="right"
|
|
959
|
+
id="right-source"
|
|
960
|
+
className="connection-handle"
|
|
869
961
|
style={{
|
|
870
|
-
background: '#
|
|
871
|
-
width: '
|
|
872
|
-
height: '
|
|
873
|
-
border: '
|
|
962
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
963
|
+
width: '14px',
|
|
964
|
+
height: '14px',
|
|
965
|
+
border: '3px solid #10B981',
|
|
874
966
|
right: '-8px',
|
|
875
|
-
opacity:
|
|
967
|
+
opacity: selected ? 1 : 0,
|
|
968
|
+
transition: 'all 0.2s ease-in-out',
|
|
969
|
+
cursor: 'crosshair',
|
|
970
|
+
zIndex: 10,
|
|
876
971
|
}}
|
|
877
972
|
/>
|
|
973
|
+
{/* Right - Target (hidden but functional) */}
|
|
974
|
+
<Handle
|
|
975
|
+
type="target"
|
|
976
|
+
position={Position.Right}
|
|
977
|
+
id="right-target"
|
|
978
|
+
style={{
|
|
979
|
+
background: 'transparent',
|
|
980
|
+
width: '14px',
|
|
981
|
+
height: '14px',
|
|
982
|
+
border: 'none',
|
|
983
|
+
right: '-8px',
|
|
984
|
+
opacity: 0,
|
|
985
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
986
|
+
}}
|
|
987
|
+
/>
|
|
988
|
+
|
|
878
989
|
</Box>
|
|
879
990
|
|
|
991
|
+
{/* Node Action Buttons - Shows when selected */}
|
|
992
|
+
<NodeActionButtons
|
|
993
|
+
selected={selected}
|
|
994
|
+
onDelete={() => {
|
|
995
|
+
if (nodeId && onNodesChange) {
|
|
996
|
+
onNodesChange([{ id: nodeId, type: 'remove' }]);
|
|
997
|
+
}
|
|
998
|
+
}}
|
|
999
|
+
onDuplicate={() => {
|
|
1000
|
+
if (nodeId) {
|
|
1001
|
+
const currentNode = nodes.find(n => n.id === nodeId);
|
|
1002
|
+
if (currentNode) {
|
|
1003
|
+
const newNode = {
|
|
1004
|
+
...currentNode,
|
|
1005
|
+
id: `${currentNode.id}-copy-${Date.now()}`,
|
|
1006
|
+
position: {
|
|
1007
|
+
x: currentNode.position.x + 50,
|
|
1008
|
+
y: currentNode.position.y + 50,
|
|
1009
|
+
},
|
|
1010
|
+
selected: false,
|
|
1011
|
+
};
|
|
1012
|
+
setNodes([...nodes, newNode]);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
}}
|
|
1016
|
+
/>
|
|
1017
|
+
|
|
880
1018
|
{/* AI Suggestions Button - Positioned below the node box */}
|
|
881
1019
|
{data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
|
|
882
1020
|
<Box
|
|
@@ -8,6 +8,7 @@ import ReactJson from 'react-json-view';
|
|
|
8
8
|
import { getIconByName } from '../../utils/iconMapper';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
|
10
10
|
import { useDiagram } from '../../contexts/DiagramProvider';
|
|
11
|
+
import { NodeActionButtons } from './NodeActionButtons';
|
|
11
12
|
|
|
12
13
|
interface AutomationStartNodeProps {
|
|
13
14
|
data: {
|
|
@@ -39,6 +40,9 @@ export const AutomationStartNode: React.FC<AutomationStartNodeProps> = ({ data,
|
|
|
39
40
|
const nodeId = useNodeId();
|
|
40
41
|
const setSelectedNode = useDiagram((state) => state.setSelectedNode);
|
|
41
42
|
const enableJson = useDiagram((state) => state.enableNodeJsonPopover ?? true);
|
|
43
|
+
const onNodesChange = useDiagram((state) => state.onNodesChange);
|
|
44
|
+
const nodes = useDiagram((state) => state.nodes);
|
|
45
|
+
const setNodes = useDiagram((state) => state.setNodes);
|
|
42
46
|
|
|
43
47
|
// Get the icon component based on the iconName
|
|
44
48
|
const IconComponent = getIconByName(data.iconName);
|
|
@@ -195,6 +199,13 @@ export const AutomationStartNode: React.FC<AutomationStartNodeProps> = ({ data,
|
|
|
195
199
|
|
|
196
200
|
return (
|
|
197
201
|
<Box
|
|
202
|
+
sx={{
|
|
203
|
+
position: 'relative',
|
|
204
|
+
width: '336px',
|
|
205
|
+
overflow: 'visible',
|
|
206
|
+
}}
|
|
207
|
+
>
|
|
208
|
+
<Box
|
|
198
209
|
ref={nodeRef}
|
|
199
210
|
sx={{
|
|
200
211
|
width: '336px',
|
|
@@ -325,18 +336,166 @@ export const AutomationStartNode: React.FC<AutomationStartNodeProps> = ({ data,
|
|
|
325
336
|
</Box>
|
|
326
337
|
</Box>
|
|
327
338
|
|
|
328
|
-
{/*
|
|
339
|
+
{/* Connection Handles - Bidirectional (source + target at each position) */}
|
|
340
|
+
{/* Top - Source */}
|
|
341
|
+
<Handle
|
|
342
|
+
type="source"
|
|
343
|
+
position={Position.Top}
|
|
344
|
+
id="top-source"
|
|
345
|
+
className="connection-handle"
|
|
346
|
+
style={{
|
|
347
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
348
|
+
width: '14px',
|
|
349
|
+
height: '14px',
|
|
350
|
+
border: '3px solid #10B981',
|
|
351
|
+
top: '-8px',
|
|
352
|
+
opacity: selected ? 1 : 0,
|
|
353
|
+
transition: 'all 0.2s ease-in-out',
|
|
354
|
+
cursor: 'crosshair',
|
|
355
|
+
zIndex: 10,
|
|
356
|
+
}}
|
|
357
|
+
/>
|
|
358
|
+
{/* Top - Target (hidden but functional) */}
|
|
359
|
+
<Handle
|
|
360
|
+
type="target"
|
|
361
|
+
position={Position.Top}
|
|
362
|
+
id="top-target"
|
|
363
|
+
style={{
|
|
364
|
+
background: 'transparent',
|
|
365
|
+
width: '14px',
|
|
366
|
+
height: '14px',
|
|
367
|
+
border: 'none',
|
|
368
|
+
top: '-8px',
|
|
369
|
+
opacity: 0,
|
|
370
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
371
|
+
}}
|
|
372
|
+
/>
|
|
373
|
+
{/* Bottom - Source */}
|
|
374
|
+
<Handle
|
|
375
|
+
type="source"
|
|
376
|
+
position={Position.Bottom}
|
|
377
|
+
id="bottom-source"
|
|
378
|
+
className="connection-handle"
|
|
379
|
+
style={{
|
|
380
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
381
|
+
width: '14px',
|
|
382
|
+
height: '14px',
|
|
383
|
+
border: '3px solid #10B981',
|
|
384
|
+
bottom: '-8px',
|
|
385
|
+
opacity: selected ? 1 : 0,
|
|
386
|
+
transition: 'all 0.2s ease-in-out',
|
|
387
|
+
cursor: 'crosshair',
|
|
388
|
+
zIndex: 10,
|
|
389
|
+
}}
|
|
390
|
+
/>
|
|
391
|
+
{/* Bottom - Target (hidden but functional) */}
|
|
392
|
+
<Handle
|
|
393
|
+
type="target"
|
|
394
|
+
position={Position.Bottom}
|
|
395
|
+
id="bottom-target"
|
|
396
|
+
style={{
|
|
397
|
+
background: 'transparent',
|
|
398
|
+
width: '14px',
|
|
399
|
+
height: '14px',
|
|
400
|
+
border: 'none',
|
|
401
|
+
bottom: '-8px',
|
|
402
|
+
opacity: 0,
|
|
403
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
404
|
+
}}
|
|
405
|
+
/>
|
|
406
|
+
{/* Left - Source */}
|
|
329
407
|
<Handle
|
|
330
408
|
type="source"
|
|
409
|
+
position={Position.Left}
|
|
410
|
+
id="left-source"
|
|
411
|
+
className="connection-handle"
|
|
412
|
+
style={{
|
|
413
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
414
|
+
width: '14px',
|
|
415
|
+
height: '14px',
|
|
416
|
+
border: '3px solid #10B981',
|
|
417
|
+
left: '-8px',
|
|
418
|
+
opacity: selected ? 1 : 0,
|
|
419
|
+
transition: 'all 0.2s ease-in-out',
|
|
420
|
+
cursor: 'crosshair',
|
|
421
|
+
zIndex: 10,
|
|
422
|
+
}}
|
|
423
|
+
/>
|
|
424
|
+
{/* Left - Target (hidden but functional) */}
|
|
425
|
+
<Handle
|
|
426
|
+
type="target"
|
|
427
|
+
position={Position.Left}
|
|
428
|
+
id="left-target"
|
|
429
|
+
style={{
|
|
430
|
+
background: 'transparent',
|
|
431
|
+
width: '14px',
|
|
432
|
+
height: '14px',
|
|
433
|
+
border: 'none',
|
|
434
|
+
left: '-8px',
|
|
435
|
+
opacity: 0,
|
|
436
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
437
|
+
}}
|
|
438
|
+
/>
|
|
439
|
+
{/* Right - Source */}
|
|
440
|
+
<Handle
|
|
441
|
+
type="source"
|
|
442
|
+
position={Position.Right}
|
|
443
|
+
id="right-source"
|
|
444
|
+
className="connection-handle"
|
|
445
|
+
style={{
|
|
446
|
+
background: selected ? '#10B981' : '#1a1a2e',
|
|
447
|
+
width: '14px',
|
|
448
|
+
height: '14px',
|
|
449
|
+
border: '3px solid #10B981',
|
|
450
|
+
right: '-8px',
|
|
451
|
+
opacity: selected ? 1 : 0,
|
|
452
|
+
transition: 'all 0.2s ease-in-out',
|
|
453
|
+
cursor: 'crosshair',
|
|
454
|
+
zIndex: 10,
|
|
455
|
+
}}
|
|
456
|
+
/>
|
|
457
|
+
{/* Right - Target (hidden but functional) */}
|
|
458
|
+
<Handle
|
|
459
|
+
type="target"
|
|
331
460
|
position={Position.Right}
|
|
332
|
-
id="right"
|
|
461
|
+
id="right-target"
|
|
333
462
|
style={{
|
|
334
|
-
background: '
|
|
335
|
-
width: '
|
|
336
|
-
height: '
|
|
337
|
-
border: '
|
|
463
|
+
background: 'transparent',
|
|
464
|
+
width: '14px',
|
|
465
|
+
height: '14px',
|
|
466
|
+
border: 'none',
|
|
338
467
|
right: '-8px',
|
|
339
|
-
opacity: 0,
|
|
468
|
+
opacity: 0,
|
|
469
|
+
pointerEvents: selected ? 'all' : 'none',
|
|
470
|
+
}}
|
|
471
|
+
/>
|
|
472
|
+
|
|
473
|
+
</Box>
|
|
474
|
+
|
|
475
|
+
{/* Node Action Buttons - Shows when selected */}
|
|
476
|
+
<NodeActionButtons
|
|
477
|
+
selected={selected}
|
|
478
|
+
onDelete={() => {
|
|
479
|
+
if (nodeId && onNodesChange) {
|
|
480
|
+
onNodesChange([{ id: nodeId, type: 'remove' }]);
|
|
481
|
+
}
|
|
482
|
+
}}
|
|
483
|
+
onDuplicate={() => {
|
|
484
|
+
if (nodeId) {
|
|
485
|
+
const currentNode = nodes.find(n => n.id === nodeId);
|
|
486
|
+
if (currentNode) {
|
|
487
|
+
const newNode = {
|
|
488
|
+
...currentNode,
|
|
489
|
+
id: `${currentNode.id}-copy-${Date.now()}`,
|
|
490
|
+
position: {
|
|
491
|
+
x: currentNode.position.x + 50,
|
|
492
|
+
y: currentNode.position.y + 50,
|
|
493
|
+
},
|
|
494
|
+
selected: false,
|
|
495
|
+
};
|
|
496
|
+
setNodes([...nodes, newNode]);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
340
499
|
}}
|
|
341
500
|
/>
|
|
342
501
|
</Box>
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, IconButton, Tooltip } from '@mui/material';
|
|
3
|
+
import {
|
|
4
|
+
IconLayoutGrid,
|
|
5
|
+
IconMessage,
|
|
6
|
+
IconPlus,
|
|
7
|
+
IconCopy,
|
|
8
|
+
IconTrash,
|
|
9
|
+
} from '@tabler/icons-react';
|
|
10
|
+
|
|
11
|
+
interface NodeActionButtonsProps {
|
|
12
|
+
selected?: boolean;
|
|
13
|
+
onLayout?: () => void;
|
|
14
|
+
onAddNote?: () => void;
|
|
15
|
+
onAddToGroup?: () => void;
|
|
16
|
+
onDuplicate?: () => void;
|
|
17
|
+
onDelete?: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const NodeActionButtons: React.FC<NodeActionButtonsProps> = ({
|
|
21
|
+
selected,
|
|
22
|
+
onLayout,
|
|
23
|
+
onAddNote,
|
|
24
|
+
onAddToGroup,
|
|
25
|
+
onDuplicate,
|
|
26
|
+
onDelete,
|
|
27
|
+
}) => {
|
|
28
|
+
if (!selected) return null;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Box
|
|
32
|
+
sx={{
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
left: '100%',
|
|
35
|
+
top: '50%',
|
|
36
|
+
transform: 'translateY(-50%)',
|
|
37
|
+
marginLeft: '12px',
|
|
38
|
+
display: 'flex',
|
|
39
|
+
flexDirection: 'column',
|
|
40
|
+
gap: 0.5,
|
|
41
|
+
backgroundColor: 'rgba(15, 15, 35, 0.95)',
|
|
42
|
+
borderRadius: '12px',
|
|
43
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
44
|
+
p: 0.5,
|
|
45
|
+
zIndex: 1000,
|
|
46
|
+
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
|
|
47
|
+
}}
|
|
48
|
+
onClick={(e) => e.stopPropagation()}
|
|
49
|
+
>
|
|
50
|
+
<Tooltip title="Layout" placement="right">
|
|
51
|
+
<IconButton
|
|
52
|
+
size="small"
|
|
53
|
+
onClick={(e) => {
|
|
54
|
+
e.stopPropagation();
|
|
55
|
+
onLayout?.();
|
|
56
|
+
}}
|
|
57
|
+
sx={{
|
|
58
|
+
color: 'rgba(255, 255, 255, 0.6)',
|
|
59
|
+
'&:hover': {
|
|
60
|
+
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
61
|
+
color: '#fff',
|
|
62
|
+
},
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<IconLayoutGrid size={18} />
|
|
66
|
+
</IconButton>
|
|
67
|
+
</Tooltip>
|
|
68
|
+
<Tooltip title="Add Note" placement="right">
|
|
69
|
+
<IconButton
|
|
70
|
+
size="small"
|
|
71
|
+
onClick={(e) => {
|
|
72
|
+
e.stopPropagation();
|
|
73
|
+
onAddNote?.();
|
|
74
|
+
}}
|
|
75
|
+
sx={{
|
|
76
|
+
color: 'rgba(255, 255, 255, 0.6)',
|
|
77
|
+
'&:hover': {
|
|
78
|
+
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
79
|
+
color: '#fff',
|
|
80
|
+
},
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<IconMessage size={18} />
|
|
84
|
+
</IconButton>
|
|
85
|
+
</Tooltip>
|
|
86
|
+
<Tooltip title="Add to Group" placement="right">
|
|
87
|
+
<IconButton
|
|
88
|
+
size="small"
|
|
89
|
+
onClick={(e) => {
|
|
90
|
+
e.stopPropagation();
|
|
91
|
+
onAddToGroup?.();
|
|
92
|
+
}}
|
|
93
|
+
sx={{
|
|
94
|
+
color: 'rgba(255, 255, 255, 0.6)',
|
|
95
|
+
'&:hover': {
|
|
96
|
+
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
97
|
+
color: '#fff',
|
|
98
|
+
},
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<IconPlus size={18} />
|
|
102
|
+
</IconButton>
|
|
103
|
+
</Tooltip>
|
|
104
|
+
<Tooltip title="Duplicate" placement="right">
|
|
105
|
+
<IconButton
|
|
106
|
+
size="small"
|
|
107
|
+
onClick={(e) => {
|
|
108
|
+
e.stopPropagation();
|
|
109
|
+
onDuplicate?.();
|
|
110
|
+
}}
|
|
111
|
+
sx={{
|
|
112
|
+
color: 'rgba(255, 255, 255, 0.6)',
|
|
113
|
+
'&:hover': {
|
|
114
|
+
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
|
115
|
+
color: '#fff',
|
|
116
|
+
},
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
<IconCopy size={18} />
|
|
120
|
+
</IconButton>
|
|
121
|
+
</Tooltip>
|
|
122
|
+
<Tooltip title="Delete" placement="right">
|
|
123
|
+
<IconButton
|
|
124
|
+
size="small"
|
|
125
|
+
onClick={(e) => {
|
|
126
|
+
e.stopPropagation();
|
|
127
|
+
onDelete?.();
|
|
128
|
+
}}
|
|
129
|
+
sx={{
|
|
130
|
+
color: 'rgba(255, 255, 255, 0.6)',
|
|
131
|
+
'&:hover': {
|
|
132
|
+
backgroundColor: 'rgba(239, 68, 68, 0.2)',
|
|
133
|
+
color: '#EF4444',
|
|
134
|
+
},
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
<IconTrash size={18} />
|
|
138
|
+
</IconButton>
|
|
139
|
+
</Tooltip>
|
|
140
|
+
</Box>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default NodeActionButtons;
|
|
145
|
+
|
|
@@ -8,4 +8,5 @@ export { AutomationExecutionPanel } from './AutomationExecutionPanel';
|
|
|
8
8
|
export { AutomationAISuggestionNode } from './AutomationAISuggestionNode';
|
|
9
9
|
export { AISuggestionsModal, showAISuggestionsModal } from './AISuggestionsModal';
|
|
10
10
|
export { AISuggestionsPanel } from './AISuggestionsPanel';
|
|
11
|
+
export { NodeActionButtons } from './NodeActionButtons';
|
|
11
12
|
export type { AISuggestion } from './AISuggestionsModal';
|