@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.
- package/apps/diagramming/src/AutomationDiagramData.ts +22 -0
- package/apps/diagramming/src/components/AddNodeView.tsx +252 -252
- package/apps/diagramming/src/main.tsx +463 -463
- package/apps/diagramming/src/node-data.ts +664 -664
- package/apps/diagramming/src/stencil-items.ts +31 -31
- package/apps/diagramming/src/vite-env.d.ts +1 -1
- package/package.json +1 -1
- package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
- package/packages/diagrams/README.md +7 -463
- package/packages/diagrams/UNDO_REDO_API.md +306 -306
- package/packages/diagrams/package.json +27 -27
- package/packages/diagrams/project.json +42 -42
- package/packages/diagrams/rollup.config.js +26 -26
- package/packages/diagrams/src/DiagramFlow.tsx +7 -7
- package/packages/diagrams/src/index.ts +116 -116
- package/packages/diagrams/src/index.ts.bak +99 -99
- package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
- package/packages/diagrams/src/lib/atoms/ExpressionInput.tsx +437 -437
- package/packages/diagrams/src/lib/components/DiagramPanel.tsx +331 -331
- package/packages/diagrams/src/lib/components/automation/AISuggestionsModal.tsx +269 -0
- package/packages/diagrams/src/lib/components/automation/AISuggestionsPanel.tsx +227 -0
- package/packages/diagrams/src/lib/components/automation/AutomationAISuggestionNode.tsx +178 -115
- package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +133 -27
- package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +134 -28
- package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +132 -27
- package/packages/diagrams/src/lib/components/automation/AutomationNoteNode.tsx +124 -17
- package/packages/diagrams/src/lib/components/automation/AutomationSheetsNode.tsx +122 -15
- package/packages/diagrams/src/lib/components/automation/index.ts +3 -0
- package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +65 -65
- package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -121
- package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +45 -45
- package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
- package/packages/diagrams/src/lib/templates/systemFlow/components/FloatingEdge.tsx +219 -219
- package/packages/diagrams/src/lib/types/card-node.ts +68 -68
- package/packages/diagrams/src/lib/types/node-types.ts +29 -29
- package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +1179 -1179
- package/packages/diagrams/tsconfig.lib.json +25 -25
- package/tsconfig.base.json +29 -30
- package/TRANSLATION_FIX_SUMMARY.md +0 -118
- package/packages/diagrams/I18N_SETUP.md +0 -126
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { Handle, Position } from '@xyflow/react';
|
|
2
|
+
import { Handle, Position, useReactFlow, useNodeId } from '@xyflow/react';
|
|
3
3
|
import { Box, Typography, Chip, Button } from '@mui/material';
|
|
4
|
+
import { AccessTime as AccessTimeIcon, CheckCircle as CheckCircleIcon, Link as LinkIcon } from '@mui/icons-material';
|
|
4
5
|
import { getIconByName } from '../../utils/iconMapper';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
|
|
@@ -14,11 +15,19 @@ interface AutomationAISuggestionNodeProps {
|
|
|
14
15
|
iconName?: string;
|
|
15
16
|
formData?: {
|
|
16
17
|
pointers?: string[];
|
|
18
|
+
mappings?: Array<{
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
}>;
|
|
17
22
|
mapping?: {
|
|
18
23
|
from: string;
|
|
19
24
|
to: string;
|
|
20
25
|
};
|
|
21
26
|
badgeText?: string;
|
|
27
|
+
benefits?: string[];
|
|
28
|
+
lastRun?: string;
|
|
29
|
+
edgeId?: string; // ID of the edge connecting this node
|
|
30
|
+
isConfirmed?: boolean; // Whether "Add this" button has been clicked
|
|
22
31
|
};
|
|
23
32
|
};
|
|
24
33
|
selected?: boolean;
|
|
@@ -27,9 +36,59 @@ interface AutomationAISuggestionNodeProps {
|
|
|
27
36
|
export const AutomationAISuggestionNode: React.FC<AutomationAISuggestionNodeProps> = ({ data, selected }) => {
|
|
28
37
|
const { t } = useTranslation();
|
|
29
38
|
const nodeRef = useRef<HTMLDivElement | null>(null);
|
|
39
|
+
const { setEdges, getEdges, setNodes } = useReactFlow();
|
|
40
|
+
const nodeId = useNodeId();
|
|
30
41
|
|
|
31
42
|
const IconComponent = getIconByName(data.iconName || 'Lightbulb');
|
|
32
43
|
|
|
44
|
+
// Handle "Add this" button click - convert dotted edge to solid
|
|
45
|
+
const handleAddThis = () => {
|
|
46
|
+
if (!data.formData?.edgeId || data.formData?.isConfirmed || !nodeId) return;
|
|
47
|
+
|
|
48
|
+
const edges = getEdges();
|
|
49
|
+
const edge = edges.find(e => e.id === data.formData?.edgeId);
|
|
50
|
+
|
|
51
|
+
if (edge) {
|
|
52
|
+
// Update edge to solid line (remove strokeDasharray)
|
|
53
|
+
setEdges((prevEdges) =>
|
|
54
|
+
prevEdges.map((e) =>
|
|
55
|
+
e.id === edge.id
|
|
56
|
+
? {
|
|
57
|
+
...e,
|
|
58
|
+
style: {
|
|
59
|
+
...e.style,
|
|
60
|
+
strokeDasharray: undefined, // Remove dotted line
|
|
61
|
+
},
|
|
62
|
+
data: {
|
|
63
|
+
...e.data,
|
|
64
|
+
isSuggested: false, // Mark as confirmed
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
: e
|
|
68
|
+
)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Update node to mark as confirmed and change background from transparent to opaque
|
|
72
|
+
setNodes((prevNodes) =>
|
|
73
|
+
prevNodes.map((n) =>
|
|
74
|
+
n.id === nodeId
|
|
75
|
+
? {
|
|
76
|
+
...n,
|
|
77
|
+
data: {
|
|
78
|
+
...n.data,
|
|
79
|
+
backgroundColor: 'rgba(24, 28, 37, 0.99)', // Change from 0.65 to 0.99 opacity
|
|
80
|
+
formData: {
|
|
81
|
+
...(n.data.formData || {}),
|
|
82
|
+
isConfirmed: true,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
: n
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
33
92
|
// Debug logging for node dimensions
|
|
34
93
|
useEffect(() => {
|
|
35
94
|
if (nodeRef.current) {
|
|
@@ -65,7 +124,7 @@ export const AutomationAISuggestionNode: React.FC<AutomationAISuggestionNodeProp
|
|
|
65
124
|
sx={{
|
|
66
125
|
width: '336px',
|
|
67
126
|
minHeight: '150px',
|
|
68
|
-
backgroundColor: '
|
|
127
|
+
backgroundColor: data.backgroundColor || 'rgba(24, 28, 37, 0.65)',
|
|
69
128
|
border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
|
|
70
129
|
borderRadius: '12px',
|
|
71
130
|
color: '#ffffff',
|
|
@@ -76,133 +135,137 @@ export const AutomationAISuggestionNode: React.FC<AutomationAISuggestionNodeProp
|
|
|
76
135
|
overflow: 'hidden',
|
|
77
136
|
}}
|
|
78
137
|
>
|
|
79
|
-
{/* Suggested badge / label strip */}
|
|
80
|
-
<Box sx={{
|
|
81
|
-
backgroundColor: 'rgba(30, 58, 138, 0.8)', // #1E3A8A with 0.8 opacity
|
|
82
|
-
padding: '8px 16px',
|
|
83
|
-
borderRadius: '12px 12px 0 0',
|
|
84
|
-
display: 'flex',
|
|
85
|
-
alignItems: 'center',
|
|
86
|
-
justifyContent: 'space-between'
|
|
87
|
-
}}>
|
|
88
|
-
<Typography variant="body2" sx={{ color: '#ffffff', fontSize: '12px', fontWeight: 500 }}>
|
|
89
|
-
{data.formData?.badgeText || t('automation.aiSuggestionNode.badgeSuggested')}
|
|
90
|
-
</Typography>
|
|
91
|
-
<Chip
|
|
92
|
-
label={t('automation.aiSuggestionNode.badgeAI')}
|
|
93
|
-
size="small"
|
|
94
|
-
sx={{
|
|
95
|
-
bgcolor: 'rgba(147, 197, 253, 0.15)',
|
|
96
|
-
color: '#93C5FD',
|
|
97
|
-
height: '20px',
|
|
98
|
-
fontSize: '11px',
|
|
99
|
-
borderRadius: '10px'
|
|
100
|
-
}}
|
|
101
|
-
/>
|
|
102
|
-
</Box>
|
|
103
|
-
|
|
104
138
|
{/* Main content */}
|
|
105
139
|
<Box sx={{ padding: '16px' }}>
|
|
106
|
-
{/* Title */}
|
|
107
|
-
<Box sx={{ display: 'flex', alignItems: 'center',
|
|
108
|
-
<Box
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
<IconComponent sx={{ color: 'white', fontSize: '18px' }} />
|
|
121
|
-
</Box>
|
|
122
|
-
<Typography variant="h6" sx={{ fontWeight: 600, fontSize: '16px' }}>
|
|
123
|
-
{data.label}
|
|
124
|
-
</Typography>
|
|
140
|
+
{/* Title with Icon */}
|
|
141
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5, mb: 1.5 }}>
|
|
142
|
+
<Box
|
|
143
|
+
sx={{
|
|
144
|
+
width: '32px',
|
|
145
|
+
height: '32px',
|
|
146
|
+
backgroundColor: '#0ea5e9',
|
|
147
|
+
borderRadius: '50%',
|
|
148
|
+
display: 'flex',
|
|
149
|
+
alignItems: 'center',
|
|
150
|
+
justifyContent: 'center',
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<IconComponent sx={{ color: 'white', fontSize: '18px' }} />
|
|
125
154
|
</Box>
|
|
155
|
+
<Typography variant="h6" sx={{ fontWeight: 600, fontSize: '16px', color: '#ffffff' }}>
|
|
156
|
+
{data.label}
|
|
157
|
+
</Typography>
|
|
126
158
|
</Box>
|
|
127
159
|
|
|
128
|
-
{/*
|
|
129
|
-
<Box sx={{
|
|
130
|
-
backgroundColor: '#1F2937',
|
|
131
|
-
borderRadius: '8px',
|
|
132
|
-
padding: '12px',
|
|
133
|
-
mb: 2,
|
|
134
|
-
border: '1px solid #374151'
|
|
135
|
-
}}>
|
|
136
|
-
<Box sx={{
|
|
137
|
-
backgroundColor: 'transparent',
|
|
138
|
-
borderRadius: '4px',
|
|
139
|
-
padding: '8px',
|
|
140
|
-
border: '1px solid #4B5563',
|
|
141
|
-
minHeight: '40px',
|
|
142
|
-
display: 'flex',
|
|
143
|
-
alignItems: 'center'
|
|
144
|
-
}}>
|
|
145
|
-
<Typography variant="body2" sx={{
|
|
146
|
-
color: '#9CA3AF',
|
|
147
|
-
fontSize: '12px',
|
|
148
|
-
lineHeight: 1.4,
|
|
149
|
-
m: 0
|
|
150
|
-
}}>
|
|
151
|
-
{data.description}
|
|
152
|
-
</Typography>
|
|
153
|
-
</Box>
|
|
154
|
-
</Box>
|
|
155
|
-
|
|
156
|
-
{/* Mapping / pointers section */}
|
|
157
|
-
<Box sx={{
|
|
158
|
-
backgroundColor: '#1F2937',
|
|
159
|
-
borderRadius: '8px',
|
|
160
|
-
padding: '12px',
|
|
161
|
-
mb: 2,
|
|
162
|
-
border: '1px solid #374151'
|
|
163
|
-
}}>
|
|
164
|
-
{/* Simple 2-column mapping like Data Mapping */}
|
|
165
|
-
{data.formData?.mapping ? (
|
|
166
|
-
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }}>
|
|
167
|
-
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px' }}>
|
|
168
|
-
{data.formData.mapping.from}
|
|
169
|
-
</Typography>
|
|
170
|
-
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px' }}>
|
|
171
|
-
→ {data.formData.mapping.to}
|
|
172
|
-
</Typography>
|
|
173
|
-
</Box>
|
|
174
|
-
) : null}
|
|
175
|
-
|
|
176
|
-
{(data.formData?.pointers || []).map((p, i) => (
|
|
177
|
-
<Box key={i} sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
|
|
178
|
-
<Box sx={{ color: '#93C5FD', fontSize: '14px' }}>•</Box>
|
|
179
|
-
<Typography variant="body2" sx={{ color: '#E5E7EB', fontSize: '11px' }}>{p}</Typography>
|
|
180
|
-
</Box>
|
|
181
|
-
))}
|
|
182
|
-
</Box>
|
|
183
|
-
|
|
184
|
-
{/* Add this button */}
|
|
160
|
+
{/* Suggested Node Button */}
|
|
185
161
|
<Button
|
|
186
|
-
variant="
|
|
187
|
-
fullWidth
|
|
162
|
+
variant="contained"
|
|
188
163
|
sx={{
|
|
189
|
-
backgroundColor: '
|
|
190
|
-
|
|
191
|
-
|
|
164
|
+
backgroundColor: '#4B5563', // Dark grey background
|
|
165
|
+
color: '#ffffff',
|
|
166
|
+
borderRadius: '20px', // Pill-shaped
|
|
192
167
|
textTransform: 'none',
|
|
193
|
-
fontSize: '
|
|
194
|
-
fontWeight:
|
|
168
|
+
fontSize: '11px',
|
|
169
|
+
fontWeight: 400,
|
|
170
|
+
padding: '6px 14px',
|
|
171
|
+
mb: 1.5,
|
|
172
|
+
minWidth: 'auto',
|
|
195
173
|
'&:hover': {
|
|
196
|
-
backgroundColor: '
|
|
197
|
-
borderColor: '#2563EB'
|
|
174
|
+
backgroundColor: '#6B7280',
|
|
198
175
|
}
|
|
199
176
|
}}
|
|
200
177
|
>
|
|
201
|
-
{
|
|
178
|
+
{data.formData?.badgeText || 'Suggested Node'}
|
|
202
179
|
</Button>
|
|
203
180
|
|
|
204
|
-
{/*
|
|
205
|
-
<
|
|
181
|
+
{/* Description */}
|
|
182
|
+
<Typography variant="body2" sx={{
|
|
183
|
+
color: '#9CA3AF',
|
|
184
|
+
fontSize: '12px',
|
|
185
|
+
lineHeight: 1.4,
|
|
186
|
+
mb: 2
|
|
187
|
+
}}>
|
|
188
|
+
{data.description}
|
|
189
|
+
</Typography>
|
|
190
|
+
|
|
191
|
+
{/* Data Mapping Section */}
|
|
192
|
+
{(data.formData?.mappings && data.formData.mappings.length > 0) || data.formData?.mapping ? (
|
|
193
|
+
<Box sx={{ mb: 2 }}>
|
|
194
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mb: 1 }}>
|
|
195
|
+
<LinkIcon sx={{ fontSize: '14px', color: '#93C5FD' }} />
|
|
196
|
+
<Typography variant="body2" sx={{ color: '#93C5FD', fontSize: '12px', fontWeight: 500 }}>
|
|
197
|
+
Data Mapping
|
|
198
|
+
</Typography>
|
|
199
|
+
</Box>
|
|
200
|
+
{(data.formData?.mappings || (data.formData?.mapping ? [data.formData.mapping] : [])).map((mapping, index) => (
|
|
201
|
+
<Box key={index} sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
|
|
202
|
+
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px' }}>
|
|
203
|
+
{mapping.from}
|
|
204
|
+
</Typography>
|
|
205
|
+
<Typography variant="body2" sx={{ color: '#93C5FD', fontSize: '11px' }}>
|
|
206
|
+
→
|
|
207
|
+
</Typography>
|
|
208
|
+
<Typography variant="body2" sx={{ color: '#93C5FD', fontSize: '11px' }}>
|
|
209
|
+
{mapping.to}
|
|
210
|
+
</Typography>
|
|
211
|
+
</Box>
|
|
212
|
+
))}
|
|
213
|
+
</Box>
|
|
214
|
+
) : null}
|
|
215
|
+
|
|
216
|
+
{/* Benefits Section */}
|
|
217
|
+
{(data.formData?.benefits && data.formData.benefits.length > 0) || (data.formData?.pointers && data.formData.pointers.length > 0) ? (
|
|
218
|
+
<Box sx={{ mb: 2 }}>
|
|
219
|
+
<Typography variant="body2" sx={{ color: '#93C5FD', fontSize: '12px', fontWeight: 500, mb: 1 }}>
|
|
220
|
+
Benefits
|
|
221
|
+
</Typography>
|
|
222
|
+
{(data.formData?.benefits || data.formData?.pointers || []).map((benefit, index) => (
|
|
223
|
+
<Box key={index} sx={{ display: 'flex', alignItems: 'flex-start', gap: 1, mb: 0.5 }}>
|
|
224
|
+
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px', mt: 0.25 }}>•</Typography>
|
|
225
|
+
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px', lineHeight: 1.4 }}>
|
|
226
|
+
{benefit}
|
|
227
|
+
</Typography>
|
|
228
|
+
</Box>
|
|
229
|
+
))}
|
|
230
|
+
</Box>
|
|
231
|
+
) : null}
|
|
232
|
+
|
|
233
|
+
{/* Last Ran and Add This Button Row */}
|
|
234
|
+
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mt: 2 }}>
|
|
235
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
|
|
236
|
+
<AccessTimeIcon sx={{ fontSize: '14px', color: '#9CA3AF' }} />
|
|
237
|
+
<Typography variant="body2" sx={{ color: '#9CA3AF', fontSize: '11px' }}>
|
|
238
|
+
Last ran: {data.formData?.lastRun || 'Never'}
|
|
239
|
+
</Typography>
|
|
240
|
+
</Box>
|
|
241
|
+
<Button
|
|
242
|
+
variant="outlined"
|
|
243
|
+
startIcon={<CheckCircleIcon sx={{ fontSize: '16px' }} />}
|
|
244
|
+
onClick={handleAddThis}
|
|
245
|
+
disabled={data.formData?.isConfirmed}
|
|
246
|
+
sx={{
|
|
247
|
+
backgroundColor: 'transparent',
|
|
248
|
+
borderColor: '#2563EB',
|
|
249
|
+
color: '#93C5FD',
|
|
250
|
+
textTransform: 'none',
|
|
251
|
+
fontSize: '12px',
|
|
252
|
+
fontWeight: 500,
|
|
253
|
+
borderRadius: '20px',
|
|
254
|
+
padding: '6px 16px',
|
|
255
|
+
'&:hover': {
|
|
256
|
+
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
|
257
|
+
borderColor: '#2563EB'
|
|
258
|
+
},
|
|
259
|
+
'&:disabled': {
|
|
260
|
+
borderColor: '#10b981',
|
|
261
|
+
color: '#10b981',
|
|
262
|
+
opacity: 0.7
|
|
263
|
+
}
|
|
264
|
+
}}
|
|
265
|
+
>
|
|
266
|
+
{data.formData?.isConfirmed ? 'Added' : 'Add this'}
|
|
267
|
+
</Button>
|
|
268
|
+
</Box>
|
|
206
269
|
</Box>
|
|
207
270
|
|
|
208
271
|
{/* Handles - Hidden but functional */}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useState, useRef } from 'react';
|
|
2
2
|
import { createRoot } from 'react-dom/client';
|
|
3
3
|
import { Handle, Position, useNodeId } from '@xyflow/react';
|
|
4
|
-
import { Box, Typography, Chip, IconButton, Card, CardContent } from '@mui/material';
|
|
4
|
+
import { Box, Typography, Chip, IconButton, Card, CardContent, Button } from '@mui/material';
|
|
5
5
|
import {
|
|
6
6
|
AccessTime as AccessTimeIcon,
|
|
7
7
|
Visibility as VisibilityIcon,
|
|
@@ -9,13 +9,16 @@ import {
|
|
|
9
9
|
Psychology as PsychologyIcon,
|
|
10
10
|
Send as SendIcon,
|
|
11
11
|
Settings as SettingsIcon,
|
|
12
|
-
Storage as StorageIcon
|
|
12
|
+
Storage as StorageIcon,
|
|
13
|
+
Lightbulb as LightbulbIcon
|
|
13
14
|
} from '@mui/icons-material';
|
|
14
15
|
import { RiCloseLine, RiUser2Line } from 'react-icons/ri';
|
|
15
16
|
import ReactJson from 'react-json-view';
|
|
16
17
|
import { getIconByName } from '../../utils/iconMapper';
|
|
17
18
|
import { useTranslation } from 'react-i18next';
|
|
18
19
|
import { useDiagram } from '../../contexts/DiagramProvider';
|
|
20
|
+
import { AISuggestion } from './AISuggestionsModal';
|
|
21
|
+
import { AISuggestionsPanel } from './AISuggestionsPanel';
|
|
19
22
|
|
|
20
23
|
interface AutomationApiNodeProps {
|
|
21
24
|
data: {
|
|
@@ -45,6 +48,8 @@ interface AutomationApiNodeProps {
|
|
|
45
48
|
label: string;
|
|
46
49
|
iconColor: string;
|
|
47
50
|
}>;
|
|
51
|
+
aiSuggestionsCount?: number; // Number of AI suggestions available
|
|
52
|
+
aiSuggestions?: AISuggestion[]; // AI suggestions data
|
|
48
53
|
[key: string]: any;
|
|
49
54
|
}; // Include formData for configuration
|
|
50
55
|
};
|
|
@@ -54,6 +59,7 @@ interface AutomationApiNodeProps {
|
|
|
54
59
|
export const AutomationApiNode: React.FC<AutomationApiNodeProps> = ({ data, selected }) => {
|
|
55
60
|
const { t } = useTranslation();
|
|
56
61
|
const [isJsonOpen, setIsJsonOpen] = useState(false);
|
|
62
|
+
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
57
63
|
const rootRef = useRef<any>(null);
|
|
58
64
|
const portalRef = useRef<HTMLDivElement | null>(null);
|
|
59
65
|
const nodeRef = useRef<HTMLDivElement | null>(null);
|
|
@@ -265,35 +271,42 @@ export const AutomationApiNode: React.FC<AutomationApiNodeProps> = ({ data, sele
|
|
|
265
271
|
|
|
266
272
|
return (
|
|
267
273
|
<Box
|
|
268
|
-
ref={nodeRef}
|
|
269
274
|
sx={{
|
|
270
|
-
width: '336px',
|
|
271
|
-
minHeight: '150px',
|
|
272
|
-
backgroundColor: '#181C25', // New background color from image
|
|
273
|
-
border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
|
|
274
|
-
borderRadius: '12px',
|
|
275
|
-
color: '#ffffff',
|
|
276
275
|
position: 'relative',
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
cursor: 'pointer',
|
|
280
|
-
overflow: 'hidden',
|
|
281
|
-
...(data.status === 'Running' && {
|
|
282
|
-
animation: 'pulse-glow 2s ease-in-out infinite',
|
|
283
|
-
'@keyframes pulse-glow': {
|
|
284
|
-
'0%, 100%': {
|
|
285
|
-
boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
|
|
286
|
-
borderColor: 'rgba(251, 191, 36, 0.6)',
|
|
287
|
-
},
|
|
288
|
-
'50%': {
|
|
289
|
-
boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
|
|
290
|
-
borderColor: 'rgba(251, 191, 36, 0.9)',
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
}),
|
|
276
|
+
width: '336px',
|
|
277
|
+
overflow: 'visible',
|
|
294
278
|
}}
|
|
295
|
-
onClick={handleJsonClick}
|
|
296
279
|
>
|
|
280
|
+
<Box
|
|
281
|
+
ref={nodeRef}
|
|
282
|
+
sx={{
|
|
283
|
+
width: '336px',
|
|
284
|
+
minHeight: '150px',
|
|
285
|
+
backgroundColor: '#181C25', // New background color from image
|
|
286
|
+
border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
|
|
287
|
+
borderRadius: '12px',
|
|
288
|
+
color: '#ffffff',
|
|
289
|
+
position: 'relative',
|
|
290
|
+
boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
|
|
291
|
+
transition: 'all 0.2s ease',
|
|
292
|
+
cursor: 'pointer',
|
|
293
|
+
overflow: 'hidden',
|
|
294
|
+
...(data.status === 'Running' && {
|
|
295
|
+
animation: 'pulse-glow 2s ease-in-out infinite',
|
|
296
|
+
'@keyframes pulse-glow': {
|
|
297
|
+
'0%, 100%': {
|
|
298
|
+
boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
|
|
299
|
+
borderColor: 'rgba(251, 191, 36, 0.6)',
|
|
300
|
+
},
|
|
301
|
+
'50%': {
|
|
302
|
+
boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
|
|
303
|
+
borderColor: 'rgba(251, 191, 36, 0.9)',
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
}),
|
|
307
|
+
}}
|
|
308
|
+
onClick={handleJsonClick}
|
|
309
|
+
>
|
|
297
310
|
{/* Top Header Section */}
|
|
298
311
|
<Box sx={{
|
|
299
312
|
backgroundColor: "rgba(67, 93, 132, 0.1)",
|
|
@@ -535,6 +548,99 @@ export const AutomationApiNode: React.FC<AutomationApiNodeProps> = ({ data, sele
|
|
|
535
548
|
opacity: 0, // Hidden but functional
|
|
536
549
|
}}
|
|
537
550
|
/>
|
|
551
|
+
</Box>
|
|
552
|
+
|
|
553
|
+
{/* AI Suggestions Button - Positioned below the node box */}
|
|
554
|
+
{data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
|
|
555
|
+
<Box
|
|
556
|
+
sx={{
|
|
557
|
+
position: 'absolute',
|
|
558
|
+
top: '100%',
|
|
559
|
+
left: '50%',
|
|
560
|
+
transform: 'translateX(-50%)',
|
|
561
|
+
marginTop: '12px',
|
|
562
|
+
zIndex: 10,
|
|
563
|
+
whiteSpace: 'nowrap',
|
|
564
|
+
}}
|
|
565
|
+
onClick={(e) => {
|
|
566
|
+
e.stopPropagation();
|
|
567
|
+
// Toggle AI Suggestions panel
|
|
568
|
+
setShowSuggestions(!showSuggestions);
|
|
569
|
+
}}
|
|
570
|
+
>
|
|
571
|
+
<Button
|
|
572
|
+
variant="contained"
|
|
573
|
+
startIcon={<LightbulbIcon sx={{ fontSize: '12px' }} />}
|
|
574
|
+
sx={{
|
|
575
|
+
backgroundColor: '#2563EB',
|
|
576
|
+
color: '#ffffff',
|
|
577
|
+
borderRadius: '20px',
|
|
578
|
+
textTransform: 'none',
|
|
579
|
+
fontSize: '10px',
|
|
580
|
+
fontWeight: 400,
|
|
581
|
+
padding: '8px 16px',
|
|
582
|
+
whiteSpace: 'nowrap',
|
|
583
|
+
display: 'inline-flex',
|
|
584
|
+
alignItems: 'center',
|
|
585
|
+
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
|
|
586
|
+
'&:hover': {
|
|
587
|
+
backgroundColor: '#2563eb',
|
|
588
|
+
},
|
|
589
|
+
'& .MuiButton-startIcon': {
|
|
590
|
+
marginRight: '8px',
|
|
591
|
+
}
|
|
592
|
+
}}
|
|
593
|
+
>
|
|
594
|
+
AI Suggestions
|
|
595
|
+
<Box
|
|
596
|
+
component="span"
|
|
597
|
+
sx={{
|
|
598
|
+
marginLeft: '8px',
|
|
599
|
+
backgroundColor: '#FFFFFF26',
|
|
600
|
+
color: '#ffffff',
|
|
601
|
+
fontSize: '10px',
|
|
602
|
+
fontWeight: 400,
|
|
603
|
+
minWidth: '18px',
|
|
604
|
+
height: '18px',
|
|
605
|
+
borderRadius: '9px',
|
|
606
|
+
display: 'inline-flex',
|
|
607
|
+
alignItems: 'center',
|
|
608
|
+
justifyContent: 'center',
|
|
609
|
+
padding: '0 6px',
|
|
610
|
+
border: '1px solid rgba(255, 255, 255, 0.2)',
|
|
611
|
+
}}
|
|
612
|
+
>
|
|
613
|
+
{data.formData.aiSuggestionsCount}
|
|
614
|
+
</Box>
|
|
615
|
+
</Button>
|
|
616
|
+
</Box>
|
|
617
|
+
)}
|
|
618
|
+
|
|
619
|
+
{/* AI Suggestions Panel - Rendered on canvas below the button */}
|
|
620
|
+
{showSuggestions && data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && nodeId && (
|
|
621
|
+
<AISuggestionsPanel
|
|
622
|
+
suggestions={data.formData?.aiSuggestions || [
|
|
623
|
+
{
|
|
624
|
+
id: '1',
|
|
625
|
+
title: 'Add Citation Extraction',
|
|
626
|
+
description: 'Automatically extract and format citations from article content.',
|
|
627
|
+
tags: ['classification', 'enhancement'],
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
id: '2',
|
|
631
|
+
title: 'Generate Bullet Summary',
|
|
632
|
+
description: 'Create a concise bullet-point summary of the article\'s main points.',
|
|
633
|
+
tags: ['classification', 'enhancement'],
|
|
634
|
+
},
|
|
635
|
+
]}
|
|
636
|
+
parentNodeId={nodeId}
|
|
637
|
+
onSuggestionClick={(suggestion) => {
|
|
638
|
+
console.log('Suggestion clicked:', suggestion);
|
|
639
|
+
// Handle suggestion selection here
|
|
640
|
+
}}
|
|
641
|
+
onClose={() => setShowSuggestions(false)}
|
|
642
|
+
/>
|
|
643
|
+
)}
|
|
538
644
|
</Box>
|
|
539
645
|
);
|
|
540
646
|
};
|