@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
@@ -1,13 +1,15 @@
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';
5
- import { AccessTime as AccessTimeIcon, Visibility as VisibilityIcon, Save as SaveIcon, Send as SendIcon } from '@mui/icons-material';
4
+ import { Box, Typography, Chip, IconButton, Card, CardContent, Button } from '@mui/material';
5
+ import { AccessTime as AccessTimeIcon, Visibility as VisibilityIcon, Save as SaveIcon, Send as SendIcon, Lightbulb as LightbulbIcon } from '@mui/icons-material';
6
6
  import { RiCloseLine, RiUser2Line } from 'react-icons/ri';
7
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 { AISuggestion } from './AISuggestionsModal';
12
+ import { AISuggestionsPanel } from './AISuggestionsPanel';
11
13
 
12
14
  interface AutomationEndNodeProps {
13
15
  data: {
@@ -26,7 +28,10 @@ interface AutomationEndNodeProps {
26
28
  textColor: string;
27
29
  borderColor: string;
28
30
  iconName?: string; // Add iconName to the interface
29
- formData?: any; // Include formData for configuration
31
+ formData?: {
32
+ aiSuggestionsCount?: number; // Number of AI suggestions available
33
+ [key: string]: any;
34
+ }; // Include formData for configuration
30
35
  };
31
36
  selected?: boolean;
32
37
  }
@@ -34,6 +39,7 @@ interface AutomationEndNodeProps {
34
39
  export const AutomationEndNode: React.FC<AutomationEndNodeProps> = ({ data, selected }) => {
35
40
  const { t } = useTranslation();
36
41
  const [isJsonOpen, setIsJsonOpen] = useState(false);
42
+ const [showSuggestions, setShowSuggestions] = useState(false);
37
43
  const rootRef = useRef<any>(null);
38
44
  const portalRef = useRef<HTMLDivElement | null>(null);
39
45
  const nodeRef = useRef<HTMLDivElement | null>(null);
@@ -194,35 +200,42 @@ export const AutomationEndNode: React.FC<AutomationEndNodeProps> = ({ data, sele
194
200
 
195
201
  return (
196
202
  <Box
197
- ref={nodeRef}
198
203
  sx={{
199
- width: '336px',
200
- minHeight: '150px',
201
- backgroundColor: '#181C25', // New background color from image
202
- border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
203
- borderRadius: '12px',
204
- color: '#ffffff',
205
204
  position: 'relative',
206
- boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
207
- transition: 'all 0.2s ease',
208
- cursor: 'pointer',
209
- overflow: 'hidden',
210
- ...(data.status === 'Running' && {
211
- animation: 'pulse-glow 2s ease-in-out infinite',
212
- '@keyframes pulse-glow': {
213
- '0%, 100%': {
214
- boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
215
- borderColor: 'rgba(251, 191, 36, 0.6)',
216
- },
217
- '50%': {
218
- boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
219
- borderColor: 'rgba(251, 191, 36, 0.9)',
220
- },
221
- },
222
- }),
205
+ width: '336px',
206
+ overflow: 'visible',
223
207
  }}
224
- onClick={handleJsonClick}
225
208
  >
209
+ <Box
210
+ ref={nodeRef}
211
+ sx={{
212
+ width: '336px',
213
+ minHeight: '150px',
214
+ backgroundColor: '#181C25', // New background color from image
215
+ border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
216
+ borderRadius: '12px',
217
+ color: '#ffffff',
218
+ position: 'relative',
219
+ boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
220
+ transition: 'all 0.2s ease',
221
+ cursor: 'pointer',
222
+ overflow: 'hidden',
223
+ ...(data.status === 'Running' && {
224
+ animation: 'pulse-glow 2s ease-in-out infinite',
225
+ '@keyframes pulse-glow': {
226
+ '0%, 100%': {
227
+ boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
228
+ borderColor: 'rgba(251, 191, 36, 0.6)',
229
+ },
230
+ '50%': {
231
+ boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
232
+ borderColor: 'rgba(251, 191, 36, 0.9)',
233
+ },
234
+ },
235
+ }),
236
+ }}
237
+ onClick={handleJsonClick}
238
+ >
226
239
  {/* Top Header Section */}
227
240
  <Box sx={{
228
241
  backgroundColor: "rgba(67, 93, 132, 0.1)",
@@ -334,6 +347,99 @@ export const AutomationEndNode: React.FC<AutomationEndNodeProps> = ({ data, sele
334
347
  opacity: 0, // Hidden but functional
335
348
  }}
336
349
  />
350
+ </Box>
351
+
352
+ {/* AI Suggestions Button - Positioned below the node box */}
353
+ {data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
354
+ <Box
355
+ sx={{
356
+ position: 'absolute',
357
+ top: '100%',
358
+ left: '50%',
359
+ transform: 'translateX(-50%)',
360
+ marginTop: '12px',
361
+ zIndex: 10,
362
+ whiteSpace: 'nowrap',
363
+ }}
364
+ onClick={(e) => {
365
+ e.stopPropagation();
366
+ // Toggle AI Suggestions panel
367
+ setShowSuggestions(!showSuggestions);
368
+ }}
369
+ >
370
+ <Button
371
+ variant="contained"
372
+ startIcon={<LightbulbIcon sx={{ fontSize: '12px' }} />}
373
+ sx={{
374
+ backgroundColor: '#2563EB',
375
+ color: '#ffffff',
376
+ borderRadius: '20px',
377
+ textTransform: 'none',
378
+ fontSize: '10px',
379
+ fontWeight: 400,
380
+ padding: '8px 16px',
381
+ whiteSpace: 'nowrap',
382
+ display: 'inline-flex',
383
+ alignItems: 'center',
384
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
385
+ '&:hover': {
386
+ backgroundColor: '#2563eb',
387
+ },
388
+ '& .MuiButton-startIcon': {
389
+ marginRight: '8px',
390
+ }
391
+ }}
392
+ >
393
+ AI Suggestions
394
+ <Box
395
+ component="span"
396
+ sx={{
397
+ marginLeft: '8px',
398
+ backgroundColor: '#FFFFFF26',
399
+ color: '#ffffff',
400
+ fontSize: '10px',
401
+ fontWeight: 400,
402
+ minWidth: '18px',
403
+ height: '18px',
404
+ borderRadius: '9px',
405
+ display: 'inline-flex',
406
+ alignItems: 'center',
407
+ justifyContent: 'center',
408
+ padding: '0 6px',
409
+ border: '1px solid rgba(255, 255, 255, 0.2)',
410
+ }}
411
+ >
412
+ {data.formData.aiSuggestionsCount}
413
+ </Box>
414
+ </Button>
415
+ </Box>
416
+ )}
417
+
418
+ {/* AI Suggestions Panel - Rendered on canvas below the button */}
419
+ {showSuggestions && data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && nodeId && (
420
+ <AISuggestionsPanel
421
+ suggestions={data.formData?.aiSuggestions || [
422
+ {
423
+ id: '1',
424
+ title: 'Add Citation Extraction',
425
+ description: 'Automatically extract and format citations from article content.',
426
+ tags: ['classification', 'enhancement'],
427
+ },
428
+ {
429
+ id: '2',
430
+ title: 'Generate Bullet Summary',
431
+ description: 'Create a concise bullet-point summary of the article\'s main points.',
432
+ tags: ['classification', 'enhancement'],
433
+ },
434
+ ]}
435
+ parentNodeId={nodeId}
436
+ onSuggestionClick={(suggestion) => {
437
+ console.log('Suggestion clicked:', suggestion);
438
+ // Handle suggestion selection here
439
+ }}
440
+ onClose={() => setShowSuggestions(false)}
441
+ />
442
+ )}
337
443
  </Box>
338
444
  );
339
445
  };
@@ -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
  Psychology as PsychologyIcon,
7
7
  AccessTime as AccessTimeIcon,
@@ -9,13 +9,16 @@ import {
9
9
  FilterList as FilterIcon,
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 AutomationFormattingNodeProps {
21
24
  data: {
@@ -51,6 +54,7 @@ interface AutomationFormattingNodeProps {
51
54
  label: string;
52
55
  iconColor: string;
53
56
  }>;
57
+ aiSuggestionsCount?: number; // Number of AI suggestions available
54
58
  [key: string]: any;
55
59
  }; // Include formData for configuration
56
60
  };
@@ -60,6 +64,7 @@ interface AutomationFormattingNodeProps {
60
64
  export const AutomationFormattingNode: React.FC<AutomationFormattingNodeProps> = ({ data, selected }) => {
61
65
  const { t } = useTranslation();
62
66
  const [isJsonOpen, setIsJsonOpen] = useState(false);
67
+ const [showSuggestions, setShowSuggestions] = useState(false);
63
68
  const rootRef = useRef<any>(null);
64
69
  const portalRef = useRef<HTMLDivElement | null>(null);
65
70
  const nodeRef = useRef<HTMLDivElement | null>(null);
@@ -269,35 +274,42 @@ export const AutomationFormattingNode: React.FC<AutomationFormattingNodeProps> =
269
274
 
270
275
  return (
271
276
  <Box
272
- ref={nodeRef}
273
277
  sx={{
274
- width: '336px',
275
- minHeight: '150px',
276
- backgroundColor: '#181C25', // New background color from image
277
- border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
278
- borderRadius: '12px',
279
- color: '#ffffff',
280
278
  position: 'relative',
281
- boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
282
- transition: 'all 0.2s ease',
283
- cursor: 'pointer',
284
- overflow: 'hidden',
285
- ...(data.status === 'Running' && {
286
- animation: 'pulse-glow 2s ease-in-out infinite',
287
- '@keyframes pulse-glow': {
288
- '0%, 100%': {
289
- boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
290
- borderColor: 'rgba(251, 191, 36, 0.6)',
291
- },
292
- '50%': {
293
- boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
294
- borderColor: 'rgba(251, 191, 36, 0.9)',
295
- },
296
- },
297
- }),
279
+ width: '336px',
280
+ overflow: 'visible',
298
281
  }}
299
- onClick={handleJsonClick}
300
282
  >
283
+ <Box
284
+ ref={nodeRef}
285
+ sx={{
286
+ width: '336px',
287
+ minHeight: '150px',
288
+ backgroundColor: '#181C25', // New background color from image
289
+ border: selected ? '2px solid #3b82f6' : '1px solid #1e293b',
290
+ borderRadius: '12px',
291
+ color: '#ffffff',
292
+ position: 'relative',
293
+ boxShadow: selected ? '0 0 0 2px rgba(59, 130, 246, 0.5)' : '0 4px 8px rgba(0, 0, 0, 0.3)',
294
+ transition: 'all 0.2s ease',
295
+ cursor: 'pointer',
296
+ overflow: 'hidden',
297
+ ...(data.status === 'Running' && {
298
+ animation: 'pulse-glow 2s ease-in-out infinite',
299
+ '@keyframes pulse-glow': {
300
+ '0%, 100%': {
301
+ boxShadow: '0 0 20px rgba(251, 191, 36, 0.4), 0 0 40px rgba(251, 191, 36, 0.2)',
302
+ borderColor: 'rgba(251, 191, 36, 0.6)',
303
+ },
304
+ '50%': {
305
+ boxShadow: '0 0 30px rgba(251, 191, 36, 0.6), 0 0 60px rgba(251, 191, 36, 0.3)',
306
+ borderColor: 'rgba(251, 191, 36, 0.9)',
307
+ },
308
+ },
309
+ }),
310
+ }}
311
+ onClick={handleJsonClick}
312
+ >
301
313
  {/* Top Header Section */}
302
314
  <Box sx={{
303
315
  backgroundColor: "rgba(67, 93, 132, 0.1)",
@@ -573,6 +585,99 @@ export const AutomationFormattingNode: React.FC<AutomationFormattingNodeProps> =
573
585
  opacity: 0, // Hidden but functional
574
586
  }}
575
587
  />
588
+ </Box>
589
+
590
+ {/* AI Suggestions Button - Positioned below the node box */}
591
+ {data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
592
+ <Box
593
+ sx={{
594
+ position: 'absolute',
595
+ top: '100%',
596
+ left: '50%',
597
+ transform: 'translateX(-50%)',
598
+ marginTop: '12px',
599
+ zIndex: 10,
600
+ whiteSpace: 'nowrap',
601
+ }}
602
+ onClick={(e) => {
603
+ e.stopPropagation();
604
+ // Toggle AI Suggestions panel
605
+ setShowSuggestions(!showSuggestions);
606
+ }}
607
+ >
608
+ <Button
609
+ variant="contained"
610
+ startIcon={<LightbulbIcon sx={{ fontSize: '12px' }} />}
611
+ sx={{
612
+ backgroundColor: '#2563EB',
613
+ color: '#ffffff',
614
+ borderRadius: '20px',
615
+ textTransform: 'none',
616
+ fontSize: '10px',
617
+ fontWeight: 400,
618
+ padding: '8px 16px',
619
+ whiteSpace: 'nowrap',
620
+ display: 'inline-flex',
621
+ alignItems: 'center',
622
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
623
+ '&:hover': {
624
+ backgroundColor: '#2563eb',
625
+ },
626
+ '& .MuiButton-startIcon': {
627
+ marginRight: '8px',
628
+ }
629
+ }}
630
+ >
631
+ AI Suggestions
632
+ <Box
633
+ component="span"
634
+ sx={{
635
+ marginLeft: '8px',
636
+ backgroundColor: '#FFFFFF26',
637
+ color: '#ffffff',
638
+ fontSize: '10px',
639
+ fontWeight: 400,
640
+ minWidth: '18px',
641
+ height: '18px',
642
+ borderRadius: '9px',
643
+ display: 'inline-flex',
644
+ alignItems: 'center',
645
+ justifyContent: 'center',
646
+ padding: '0 6px',
647
+ border: '1px solid rgba(255, 255, 255, 0.2)',
648
+ }}
649
+ >
650
+ {data.formData.aiSuggestionsCount}
651
+ </Box>
652
+ </Button>
653
+ </Box>
654
+ )}
655
+
656
+ {/* AI Suggestions Panel - Rendered on canvas below the button */}
657
+ {showSuggestions && data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && nodeId && (
658
+ <AISuggestionsPanel
659
+ suggestions={data.formData?.aiSuggestions || [
660
+ {
661
+ id: '1',
662
+ title: 'Add Citation Extraction',
663
+ description: 'Automatically extract and format citations from article content.',
664
+ tags: ['classification', 'enhancement'],
665
+ },
666
+ {
667
+ id: '2',
668
+ title: 'Generate Bullet Summary',
669
+ description: 'Create a concise bullet-point summary of the article\'s main points.',
670
+ tags: ['classification', 'enhancement'],
671
+ },
672
+ ]}
673
+ parentNodeId={nodeId}
674
+ onSuggestionClick={(suggestion) => {
675
+ console.log('Suggestion clicked:', suggestion);
676
+ // Handle suggestion selection here
677
+ }}
678
+ onClose={() => setShowSuggestions(false)}
679
+ />
680
+ )}
576
681
  </Box>
577
682
  );
578
683
  };
@@ -1,8 +1,10 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { Handle, Position } from '@xyflow/react';
3
- import { Box, Typography } from '@mui/material';
4
- import { Description as DescriptionIcon } from '@mui/icons-material';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Handle, Position, useNodeId } from '@xyflow/react';
3
+ import { Box, Typography, Button } from '@mui/material';
4
+ import { Description as DescriptionIcon, Lightbulb as LightbulbIcon } from '@mui/icons-material';
5
5
  import { getIconByName } from '../../utils/iconMapper';
6
+ import { AISuggestion } from './AISuggestionsModal';
7
+ import { AISuggestionsPanel } from './AISuggestionsPanel';
6
8
 
7
9
  interface AutomationNoteNodeProps {
8
10
  data: {
@@ -13,13 +15,18 @@ interface AutomationNoteNodeProps {
13
15
  borderColor?: string;
14
16
  iconName?: string;
15
17
  noteType?: 'info' | 'warning' | 'note' | 'purpose';
16
- formData?: any;
18
+ formData?: {
19
+ aiSuggestionsCount?: number; // Number of AI suggestions available
20
+ [key: string]: any;
21
+ };
17
22
  };
18
23
  selected?: boolean;
19
24
  }
20
25
 
21
26
  export const AutomationNoteNode: React.FC<AutomationNoteNodeProps> = ({ data, selected }) => {
22
27
  const nodeRef = useRef<HTMLDivElement | null>(null);
28
+ const [showSuggestions, setShowSuggestions] = useState(false);
29
+ const nodeId = useNodeId();
23
30
 
24
31
  // Get the icon component based on the iconName, default to DescriptionIcon
25
32
  const IconComponent = getIconByName(data.iconName || 'Description');
@@ -63,22 +70,29 @@ export const AutomationNoteNode: React.FC<AutomationNoteNodeProps> = ({ data, se
63
70
 
64
71
  return (
65
72
  <Box
66
- ref={nodeRef}
67
73
  sx={{
68
- width: '336px',
69
- minHeight: '150px',
70
- backgroundColor: colors.backgroundColor,
71
- border: selected ? `2px solid ${colors.borderColor}` : `1px solid ${colors.borderColor}`,
72
- borderRadius: '12px',
73
- padding: '0',
74
- color: colors.textColor,
75
74
  position: 'relative',
76
- boxShadow: selected ? `0 0 0 2px rgba(59, 130, 246, 0.5)` : '0 4px 8px rgba(0, 0, 0, 0.3)',
77
- transition: 'all 0.2s ease',
78
- cursor: 'pointer',
79
- overflow: 'hidden',
75
+ width: '336px',
76
+ overflow: 'visible',
80
77
  }}
81
78
  >
79
+ <Box
80
+ ref={nodeRef}
81
+ sx={{
82
+ width: '336px',
83
+ minHeight: '150px',
84
+ backgroundColor: colors.backgroundColor,
85
+ border: selected ? `2px solid ${colors.borderColor}` : `1px solid ${colors.borderColor}`,
86
+ borderRadius: '12px',
87
+ padding: '0',
88
+ color: colors.textColor,
89
+ position: 'relative',
90
+ boxShadow: selected ? `0 0 0 2px rgba(59, 130, 246, 0.5)` : '0 4px 8px rgba(0, 0, 0, 0.3)',
91
+ transition: 'all 0.2s ease',
92
+ cursor: 'pointer',
93
+ overflow: 'hidden',
94
+ }}
95
+ >
82
96
  {/* Header */}
83
97
  <Box sx={{
84
98
  display: 'flex',
@@ -163,6 +177,99 @@ export const AutomationNoteNode: React.FC<AutomationNoteNodeProps> = ({ data, se
163
177
  opacity: 0, // Hidden but functional
164
178
  }}
165
179
  />
180
+ </Box>
181
+
182
+ {/* AI Suggestions Button - Positioned below the node box */}
183
+ {data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && (
184
+ <Box
185
+ sx={{
186
+ position: 'absolute',
187
+ top: '100%',
188
+ left: '50%',
189
+ transform: 'translateX(-50%)',
190
+ marginTop: '12px',
191
+ zIndex: 10,
192
+ whiteSpace: 'nowrap',
193
+ }}
194
+ onClick={(e) => {
195
+ e.stopPropagation();
196
+ // Toggle AI Suggestions panel
197
+ setShowSuggestions(!showSuggestions);
198
+ }}
199
+ >
200
+ <Button
201
+ variant="contained"
202
+ startIcon={<LightbulbIcon sx={{ fontSize: '12px' }} />}
203
+ sx={{
204
+ backgroundColor: '#2563EB',
205
+ color: '#ffffff',
206
+ borderRadius: '20px',
207
+ textTransform: 'none',
208
+ fontSize: '10px',
209
+ fontWeight: 400,
210
+ padding: '8px 16px',
211
+ whiteSpace: 'nowrap',
212
+ display: 'inline-flex',
213
+ alignItems: 'center',
214
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
215
+ '&:hover': {
216
+ backgroundColor: '#2563eb',
217
+ },
218
+ '& .MuiButton-startIcon': {
219
+ marginRight: '8px',
220
+ }
221
+ }}
222
+ >
223
+ AI Suggestions
224
+ <Box
225
+ component="span"
226
+ sx={{
227
+ marginLeft: '8px',
228
+ backgroundColor: '#FFFFFF26',
229
+ color: '#ffffff',
230
+ fontSize: '10px',
231
+ fontWeight: 400,
232
+ minWidth: '18px',
233
+ height: '18px',
234
+ borderRadius: '9px',
235
+ display: 'inline-flex',
236
+ alignItems: 'center',
237
+ justifyContent: 'center',
238
+ padding: '0 6px',
239
+ border: '1px solid rgba(255, 255, 255, 0.2)',
240
+ }}
241
+ >
242
+ {data.formData.aiSuggestionsCount}
243
+ </Box>
244
+ </Button>
245
+ </Box>
246
+ )}
247
+
248
+ {/* AI Suggestions Panel - Rendered on canvas below the button */}
249
+ {showSuggestions && data.formData?.aiSuggestionsCount !== undefined && data.formData.aiSuggestionsCount > 0 && nodeId && (
250
+ <AISuggestionsPanel
251
+ suggestions={data.formData?.aiSuggestions || [
252
+ {
253
+ id: '1',
254
+ title: 'Add Citation Extraction',
255
+ description: 'Automatically extract and format citations from article content.',
256
+ tags: ['classification', 'enhancement'],
257
+ },
258
+ {
259
+ id: '2',
260
+ title: 'Generate Bullet Summary',
261
+ description: 'Create a concise bullet-point summary of the article\'s main points.',
262
+ tags: ['classification', 'enhancement'],
263
+ },
264
+ ]}
265
+ parentNodeId={nodeId}
266
+ onSuggestionClick={(suggestion) => {
267
+ console.log('Suggestion clicked:', suggestion);
268
+ // Handle suggestion selection here
269
+ }}
270
+ onClose={() => setShowSuggestions(false)}
271
+ />
272
+ )}
166
273
  </Box>
167
274
  );
168
275
  };