@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,331 +1,331 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Box, Button } from '@mui/material';
|
|
3
|
-
import UndoIcon from '@mui/icons-material/Undo';
|
|
4
|
-
import RedoIcon from '@mui/icons-material/Redo';
|
|
5
|
-
import UploadIcon from '@mui/icons-material/Upload';
|
|
6
|
-
import SettingsIcon from '@mui/icons-material/Settings';
|
|
7
|
-
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
|
8
|
-
import ZoomOutIcon from '@mui/icons-material/ZoomOut';
|
|
9
|
-
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
|
10
|
-
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
11
|
-
import { useReactFlow, Panel } from '@xyflow/react';
|
|
12
|
-
|
|
13
|
-
export interface DiagramPanelProps {
|
|
14
|
-
// History controls
|
|
15
|
-
historyIndex: number;
|
|
16
|
-
historyLength: number;
|
|
17
|
-
onUndo: () => void;
|
|
18
|
-
onRedo: () => void;
|
|
19
|
-
onClear: () => void;
|
|
20
|
-
|
|
21
|
-
// Import/Export
|
|
22
|
-
onImport: (data: any) => void;
|
|
23
|
-
|
|
24
|
-
// Settings
|
|
25
|
-
isSettingsOpen: boolean;
|
|
26
|
-
onToggleSettings: () => void;
|
|
27
|
-
|
|
28
|
-
// Optional custom controls
|
|
29
|
-
showCustomControls?: boolean;
|
|
30
|
-
onGridLayout?: () => void;
|
|
31
|
-
onTreeLayout?: () => void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Custom controls component that uses useReactFlow
|
|
35
|
-
const CustomControls: React.FC<{
|
|
36
|
-
onGridLayout?: () => void;
|
|
37
|
-
onTreeLayout?: () => void;
|
|
38
|
-
}> = ({ onGridLayout, onTreeLayout }) => {
|
|
39
|
-
const { zoomIn, zoomOut } = useReactFlow();
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Box
|
|
43
|
-
sx={{
|
|
44
|
-
display: 'flex',
|
|
45
|
-
alignItems: 'center',
|
|
46
|
-
gap: 0.5,
|
|
47
|
-
bgcolor: '#2a2a2a',
|
|
48
|
-
borderRadius: '8px',
|
|
49
|
-
padding: '4px 8px',
|
|
50
|
-
border: '1px solid #404040',
|
|
51
|
-
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
|
52
|
-
}}
|
|
53
|
-
>
|
|
54
|
-
{/* Zoom Out */}
|
|
55
|
-
<Button
|
|
56
|
-
variant="text"
|
|
57
|
-
size="small"
|
|
58
|
-
onClick={() => zoomOut()}
|
|
59
|
-
sx={{
|
|
60
|
-
minWidth: '32px',
|
|
61
|
-
width: '32px',
|
|
62
|
-
height: '32px',
|
|
63
|
-
padding: 0,
|
|
64
|
-
color: '#ffffff',
|
|
65
|
-
'&:hover': {
|
|
66
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
67
|
-
borderRadius: '4px',
|
|
68
|
-
},
|
|
69
|
-
}}
|
|
70
|
-
>
|
|
71
|
-
<ZoomOutIcon sx={{ fontSize: '18px' }} />
|
|
72
|
-
</Button>
|
|
73
|
-
|
|
74
|
-
{/* Divider */}
|
|
75
|
-
<Box
|
|
76
|
-
sx={{
|
|
77
|
-
width: '1px',
|
|
78
|
-
height: '24px',
|
|
79
|
-
bgcolor: '#404040',
|
|
80
|
-
mx: 0.5,
|
|
81
|
-
}}
|
|
82
|
-
/>
|
|
83
|
-
|
|
84
|
-
{/* Zoom In */}
|
|
85
|
-
<Button
|
|
86
|
-
variant="text"
|
|
87
|
-
size="small"
|
|
88
|
-
onClick={() => zoomIn()}
|
|
89
|
-
sx={{
|
|
90
|
-
minWidth: '32px',
|
|
91
|
-
width: '32px',
|
|
92
|
-
height: '32px',
|
|
93
|
-
padding: 0,
|
|
94
|
-
color: '#ffffff',
|
|
95
|
-
'&:hover': {
|
|
96
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
97
|
-
borderRadius: '4px',
|
|
98
|
-
},
|
|
99
|
-
}}
|
|
100
|
-
>
|
|
101
|
-
<ZoomInIcon sx={{ fontSize: '18px' }} />
|
|
102
|
-
</Button>
|
|
103
|
-
|
|
104
|
-
{/* Divider */}
|
|
105
|
-
<Box
|
|
106
|
-
sx={{
|
|
107
|
-
width: '1px',
|
|
108
|
-
height: '24px',
|
|
109
|
-
bgcolor: '#404040',
|
|
110
|
-
mx: 0.5,
|
|
111
|
-
}}
|
|
112
|
-
/>
|
|
113
|
-
|
|
114
|
-
{/* Grid Layout */}
|
|
115
|
-
<Button
|
|
116
|
-
variant="text"
|
|
117
|
-
size="small"
|
|
118
|
-
onClick={onGridLayout || (() => console.log('Grid layout clicked'))}
|
|
119
|
-
sx={{
|
|
120
|
-
minWidth: '32px',
|
|
121
|
-
width: '32px',
|
|
122
|
-
height: '32px',
|
|
123
|
-
padding: 0,
|
|
124
|
-
color: '#ffffff',
|
|
125
|
-
'&:hover': {
|
|
126
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
127
|
-
borderRadius: '4px',
|
|
128
|
-
},
|
|
129
|
-
}}
|
|
130
|
-
>
|
|
131
|
-
<ViewModuleIcon sx={{ fontSize: '18px' }} />
|
|
132
|
-
</Button>
|
|
133
|
-
|
|
134
|
-
{/* Tree Layout */}
|
|
135
|
-
<Button
|
|
136
|
-
variant="text"
|
|
137
|
-
size="small"
|
|
138
|
-
onClick={onTreeLayout || (() => console.log('Tree layout clicked'))}
|
|
139
|
-
sx={{
|
|
140
|
-
minWidth: '32px',
|
|
141
|
-
width: '32px',
|
|
142
|
-
height: '32px',
|
|
143
|
-
padding: 0,
|
|
144
|
-
color: '#ffffff',
|
|
145
|
-
'&:hover': {
|
|
146
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
147
|
-
borderRadius: '4px',
|
|
148
|
-
},
|
|
149
|
-
}}
|
|
150
|
-
>
|
|
151
|
-
<AccountTreeIcon sx={{ fontSize: '18px' }} />
|
|
152
|
-
</Button>
|
|
153
|
-
</Box>
|
|
154
|
-
);
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// Divider component for reusability
|
|
158
|
-
const Divider: React.FC = () => (
|
|
159
|
-
<Box
|
|
160
|
-
sx={{
|
|
161
|
-
width: '1px',
|
|
162
|
-
height: '24px',
|
|
163
|
-
bgcolor: '#404040',
|
|
164
|
-
mx: 0.5,
|
|
165
|
-
}}
|
|
166
|
-
/>
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
export default function DiagramPanel({
|
|
170
|
-
historyIndex,
|
|
171
|
-
historyLength,
|
|
172
|
-
onUndo,
|
|
173
|
-
onRedo,
|
|
174
|
-
onClear,
|
|
175
|
-
onImport,
|
|
176
|
-
isSettingsOpen,
|
|
177
|
-
onToggleSettings,
|
|
178
|
-
showCustomControls = true,
|
|
179
|
-
onGridLayout,
|
|
180
|
-
onTreeLayout,
|
|
181
|
-
}: DiagramPanelProps) {
|
|
182
|
-
const handleFileImport = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
183
|
-
const file = event.target.files?.[0];
|
|
184
|
-
if (file) {
|
|
185
|
-
const reader = new FileReader();
|
|
186
|
-
reader.onload = (e) => {
|
|
187
|
-
try {
|
|
188
|
-
const data = JSON.parse(e.target?.result as string);
|
|
189
|
-
if (data.nodes && data.edges) {
|
|
190
|
-
onImport(data);
|
|
191
|
-
}
|
|
192
|
-
} catch (error) {
|
|
193
|
-
console.error('Error importing diagram:', error);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
reader.readAsText(file);
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
return (
|
|
201
|
-
<Panel position="top-left">
|
|
202
|
-
<Box
|
|
203
|
-
sx={{
|
|
204
|
-
display: 'flex',
|
|
205
|
-
alignItems: 'center',
|
|
206
|
-
gap: 1,
|
|
207
|
-
marginTop: '30px', // Add top margin to push buttons down
|
|
208
|
-
}}
|
|
209
|
-
>
|
|
210
|
-
{/* Main Controls Toolbar */}
|
|
211
|
-
<Box
|
|
212
|
-
sx={{
|
|
213
|
-
display: 'flex',
|
|
214
|
-
alignItems: 'center',
|
|
215
|
-
gap: 0.5,
|
|
216
|
-
bgcolor: '#2a2a2a',
|
|
217
|
-
borderRadius: '8px',
|
|
218
|
-
padding: '4px 8px',
|
|
219
|
-
border: '1px solid #404040',
|
|
220
|
-
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
|
221
|
-
}}
|
|
222
|
-
>
|
|
223
|
-
{/* Clear Button */}
|
|
224
|
-
<Button
|
|
225
|
-
variant="text"
|
|
226
|
-
size="small"
|
|
227
|
-
onClick={onClear}
|
|
228
|
-
sx={{
|
|
229
|
-
minWidth: '32px',
|
|
230
|
-
width: '32px',
|
|
231
|
-
height: '32px',
|
|
232
|
-
padding: 0,
|
|
233
|
-
color: '#ffffff',
|
|
234
|
-
fontSize: '12px',
|
|
235
|
-
'&:hover': {
|
|
236
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
237
|
-
borderRadius: '4px',
|
|
238
|
-
},
|
|
239
|
-
}}
|
|
240
|
-
>
|
|
241
|
-
C
|
|
242
|
-
</Button>
|
|
243
|
-
|
|
244
|
-
<Divider />
|
|
245
|
-
|
|
246
|
-
{/* Undo Button */}
|
|
247
|
-
<Button
|
|
248
|
-
variant="text"
|
|
249
|
-
size="small"
|
|
250
|
-
onClick={onUndo}
|
|
251
|
-
disabled={historyIndex <= 0}
|
|
252
|
-
sx={{
|
|
253
|
-
minWidth: '32px',
|
|
254
|
-
width: '32px',
|
|
255
|
-
height: '32px',
|
|
256
|
-
padding: 0,
|
|
257
|
-
color: historyIndex <= 0 ? '#666666' : '#ffffff',
|
|
258
|
-
'&:hover': {
|
|
259
|
-
bgcolor:
|
|
260
|
-
historyIndex <= 0 ? 'transparent' : 'rgba(255,255,255,0.1)',
|
|
261
|
-
borderRadius: '4px',
|
|
262
|
-
},
|
|
263
|
-
}}
|
|
264
|
-
>
|
|
265
|
-
<UndoIcon sx={{ fontSize: '18px' }} />
|
|
266
|
-
</Button>
|
|
267
|
-
|
|
268
|
-
{/* Redo Button */}
|
|
269
|
-
<Button
|
|
270
|
-
variant="text"
|
|
271
|
-
size="small"
|
|
272
|
-
onClick={onRedo}
|
|
273
|
-
disabled={historyIndex >= historyLength - 1}
|
|
274
|
-
sx={{
|
|
275
|
-
minWidth: '32px',
|
|
276
|
-
width: '32px',
|
|
277
|
-
height: '32px',
|
|
278
|
-
padding: 0,
|
|
279
|
-
color: historyIndex >= historyLength - 1 ? '#666666' : '#ffffff',
|
|
280
|
-
'&:hover': {
|
|
281
|
-
bgcolor:
|
|
282
|
-
historyIndex >= historyLength - 1
|
|
283
|
-
? 'transparent'
|
|
284
|
-
: 'rgba(255,255,255,0.1)',
|
|
285
|
-
borderRadius: '4px',
|
|
286
|
-
},
|
|
287
|
-
}}
|
|
288
|
-
>
|
|
289
|
-
<RedoIcon sx={{ fontSize: '18px' }} />
|
|
290
|
-
</Button>
|
|
291
|
-
|
|
292
|
-
<Divider />
|
|
293
|
-
|
|
294
|
-
{/* Import Button */}
|
|
295
|
-
<Button
|
|
296
|
-
variant="text"
|
|
297
|
-
component="label"
|
|
298
|
-
size="small"
|
|
299
|
-
sx={{
|
|
300
|
-
minWidth: '32px',
|
|
301
|
-
width: '32px',
|
|
302
|
-
height: '32px',
|
|
303
|
-
padding: 0,
|
|
304
|
-
color: '#ffffff',
|
|
305
|
-
'&:hover': {
|
|
306
|
-
bgcolor: 'rgba(255,255,255,0.1)',
|
|
307
|
-
borderRadius: '4px',
|
|
308
|
-
},
|
|
309
|
-
}}
|
|
310
|
-
>
|
|
311
|
-
<UploadIcon sx={{ fontSize: '18px' }} />
|
|
312
|
-
<input
|
|
313
|
-
type="file"
|
|
314
|
-
onChange={handleFileImport}
|
|
315
|
-
accept=".json"
|
|
316
|
-
style={{ display: 'none' }}
|
|
317
|
-
/>
|
|
318
|
-
</Button>
|
|
319
|
-
</Box>
|
|
320
|
-
|
|
321
|
-
{/* Custom Controls Toolbar */}
|
|
322
|
-
{showCustomControls && (
|
|
323
|
-
<CustomControls
|
|
324
|
-
onGridLayout={onGridLayout}
|
|
325
|
-
onTreeLayout={onTreeLayout}
|
|
326
|
-
/>
|
|
327
|
-
)}
|
|
328
|
-
</Box>
|
|
329
|
-
</Panel>
|
|
330
|
-
);
|
|
331
|
-
}
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Button } from '@mui/material';
|
|
3
|
+
import UndoIcon from '@mui/icons-material/Undo';
|
|
4
|
+
import RedoIcon from '@mui/icons-material/Redo';
|
|
5
|
+
import UploadIcon from '@mui/icons-material/Upload';
|
|
6
|
+
import SettingsIcon from '@mui/icons-material/Settings';
|
|
7
|
+
import ZoomInIcon from '@mui/icons-material/ZoomIn';
|
|
8
|
+
import ZoomOutIcon from '@mui/icons-material/ZoomOut';
|
|
9
|
+
import ViewModuleIcon from '@mui/icons-material/ViewModule';
|
|
10
|
+
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
11
|
+
import { useReactFlow, Panel } from '@xyflow/react';
|
|
12
|
+
|
|
13
|
+
export interface DiagramPanelProps {
|
|
14
|
+
// History controls
|
|
15
|
+
historyIndex: number;
|
|
16
|
+
historyLength: number;
|
|
17
|
+
onUndo: () => void;
|
|
18
|
+
onRedo: () => void;
|
|
19
|
+
onClear: () => void;
|
|
20
|
+
|
|
21
|
+
// Import/Export
|
|
22
|
+
onImport: (data: any) => void;
|
|
23
|
+
|
|
24
|
+
// Settings
|
|
25
|
+
isSettingsOpen: boolean;
|
|
26
|
+
onToggleSettings: () => void;
|
|
27
|
+
|
|
28
|
+
// Optional custom controls
|
|
29
|
+
showCustomControls?: boolean;
|
|
30
|
+
onGridLayout?: () => void;
|
|
31
|
+
onTreeLayout?: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Custom controls component that uses useReactFlow
|
|
35
|
+
const CustomControls: React.FC<{
|
|
36
|
+
onGridLayout?: () => void;
|
|
37
|
+
onTreeLayout?: () => void;
|
|
38
|
+
}> = ({ onGridLayout, onTreeLayout }) => {
|
|
39
|
+
const { zoomIn, zoomOut } = useReactFlow();
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Box
|
|
43
|
+
sx={{
|
|
44
|
+
display: 'flex',
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
gap: 0.5,
|
|
47
|
+
bgcolor: '#2a2a2a',
|
|
48
|
+
borderRadius: '8px',
|
|
49
|
+
padding: '4px 8px',
|
|
50
|
+
border: '1px solid #404040',
|
|
51
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
{/* Zoom Out */}
|
|
55
|
+
<Button
|
|
56
|
+
variant="text"
|
|
57
|
+
size="small"
|
|
58
|
+
onClick={() => zoomOut()}
|
|
59
|
+
sx={{
|
|
60
|
+
minWidth: '32px',
|
|
61
|
+
width: '32px',
|
|
62
|
+
height: '32px',
|
|
63
|
+
padding: 0,
|
|
64
|
+
color: '#ffffff',
|
|
65
|
+
'&:hover': {
|
|
66
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
67
|
+
borderRadius: '4px',
|
|
68
|
+
},
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<ZoomOutIcon sx={{ fontSize: '18px' }} />
|
|
72
|
+
</Button>
|
|
73
|
+
|
|
74
|
+
{/* Divider */}
|
|
75
|
+
<Box
|
|
76
|
+
sx={{
|
|
77
|
+
width: '1px',
|
|
78
|
+
height: '24px',
|
|
79
|
+
bgcolor: '#404040',
|
|
80
|
+
mx: 0.5,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
|
|
84
|
+
{/* Zoom In */}
|
|
85
|
+
<Button
|
|
86
|
+
variant="text"
|
|
87
|
+
size="small"
|
|
88
|
+
onClick={() => zoomIn()}
|
|
89
|
+
sx={{
|
|
90
|
+
minWidth: '32px',
|
|
91
|
+
width: '32px',
|
|
92
|
+
height: '32px',
|
|
93
|
+
padding: 0,
|
|
94
|
+
color: '#ffffff',
|
|
95
|
+
'&:hover': {
|
|
96
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
97
|
+
borderRadius: '4px',
|
|
98
|
+
},
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<ZoomInIcon sx={{ fontSize: '18px' }} />
|
|
102
|
+
</Button>
|
|
103
|
+
|
|
104
|
+
{/* Divider */}
|
|
105
|
+
<Box
|
|
106
|
+
sx={{
|
|
107
|
+
width: '1px',
|
|
108
|
+
height: '24px',
|
|
109
|
+
bgcolor: '#404040',
|
|
110
|
+
mx: 0.5,
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
|
|
114
|
+
{/* Grid Layout */}
|
|
115
|
+
<Button
|
|
116
|
+
variant="text"
|
|
117
|
+
size="small"
|
|
118
|
+
onClick={onGridLayout || (() => console.log('Grid layout clicked'))}
|
|
119
|
+
sx={{
|
|
120
|
+
minWidth: '32px',
|
|
121
|
+
width: '32px',
|
|
122
|
+
height: '32px',
|
|
123
|
+
padding: 0,
|
|
124
|
+
color: '#ffffff',
|
|
125
|
+
'&:hover': {
|
|
126
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
127
|
+
borderRadius: '4px',
|
|
128
|
+
},
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<ViewModuleIcon sx={{ fontSize: '18px' }} />
|
|
132
|
+
</Button>
|
|
133
|
+
|
|
134
|
+
{/* Tree Layout */}
|
|
135
|
+
<Button
|
|
136
|
+
variant="text"
|
|
137
|
+
size="small"
|
|
138
|
+
onClick={onTreeLayout || (() => console.log('Tree layout clicked'))}
|
|
139
|
+
sx={{
|
|
140
|
+
minWidth: '32px',
|
|
141
|
+
width: '32px',
|
|
142
|
+
height: '32px',
|
|
143
|
+
padding: 0,
|
|
144
|
+
color: '#ffffff',
|
|
145
|
+
'&:hover': {
|
|
146
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
147
|
+
borderRadius: '4px',
|
|
148
|
+
},
|
|
149
|
+
}}
|
|
150
|
+
>
|
|
151
|
+
<AccountTreeIcon sx={{ fontSize: '18px' }} />
|
|
152
|
+
</Button>
|
|
153
|
+
</Box>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Divider component for reusability
|
|
158
|
+
const Divider: React.FC = () => (
|
|
159
|
+
<Box
|
|
160
|
+
sx={{
|
|
161
|
+
width: '1px',
|
|
162
|
+
height: '24px',
|
|
163
|
+
bgcolor: '#404040',
|
|
164
|
+
mx: 0.5,
|
|
165
|
+
}}
|
|
166
|
+
/>
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
export default function DiagramPanel({
|
|
170
|
+
historyIndex,
|
|
171
|
+
historyLength,
|
|
172
|
+
onUndo,
|
|
173
|
+
onRedo,
|
|
174
|
+
onClear,
|
|
175
|
+
onImport,
|
|
176
|
+
isSettingsOpen,
|
|
177
|
+
onToggleSettings,
|
|
178
|
+
showCustomControls = true,
|
|
179
|
+
onGridLayout,
|
|
180
|
+
onTreeLayout,
|
|
181
|
+
}: DiagramPanelProps) {
|
|
182
|
+
const handleFileImport = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
183
|
+
const file = event.target.files?.[0];
|
|
184
|
+
if (file) {
|
|
185
|
+
const reader = new FileReader();
|
|
186
|
+
reader.onload = (e) => {
|
|
187
|
+
try {
|
|
188
|
+
const data = JSON.parse(e.target?.result as string);
|
|
189
|
+
if (data.nodes && data.edges) {
|
|
190
|
+
onImport(data);
|
|
191
|
+
}
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('Error importing diagram:', error);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
reader.readAsText(file);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<Panel position="top-left">
|
|
202
|
+
<Box
|
|
203
|
+
sx={{
|
|
204
|
+
display: 'flex',
|
|
205
|
+
alignItems: 'center',
|
|
206
|
+
gap: 1,
|
|
207
|
+
marginTop: '30px', // Add top margin to push buttons down
|
|
208
|
+
}}
|
|
209
|
+
>
|
|
210
|
+
{/* Main Controls Toolbar */}
|
|
211
|
+
<Box
|
|
212
|
+
sx={{
|
|
213
|
+
display: 'flex',
|
|
214
|
+
alignItems: 'center',
|
|
215
|
+
gap: 0.5,
|
|
216
|
+
bgcolor: '#2a2a2a',
|
|
217
|
+
borderRadius: '8px',
|
|
218
|
+
padding: '4px 8px',
|
|
219
|
+
border: '1px solid #404040',
|
|
220
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
|
221
|
+
}}
|
|
222
|
+
>
|
|
223
|
+
{/* Clear Button */}
|
|
224
|
+
<Button
|
|
225
|
+
variant="text"
|
|
226
|
+
size="small"
|
|
227
|
+
onClick={onClear}
|
|
228
|
+
sx={{
|
|
229
|
+
minWidth: '32px',
|
|
230
|
+
width: '32px',
|
|
231
|
+
height: '32px',
|
|
232
|
+
padding: 0,
|
|
233
|
+
color: '#ffffff',
|
|
234
|
+
fontSize: '12px',
|
|
235
|
+
'&:hover': {
|
|
236
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
237
|
+
borderRadius: '4px',
|
|
238
|
+
},
|
|
239
|
+
}}
|
|
240
|
+
>
|
|
241
|
+
C
|
|
242
|
+
</Button>
|
|
243
|
+
|
|
244
|
+
<Divider />
|
|
245
|
+
|
|
246
|
+
{/* Undo Button */}
|
|
247
|
+
<Button
|
|
248
|
+
variant="text"
|
|
249
|
+
size="small"
|
|
250
|
+
onClick={onUndo}
|
|
251
|
+
disabled={historyIndex <= 0}
|
|
252
|
+
sx={{
|
|
253
|
+
minWidth: '32px',
|
|
254
|
+
width: '32px',
|
|
255
|
+
height: '32px',
|
|
256
|
+
padding: 0,
|
|
257
|
+
color: historyIndex <= 0 ? '#666666' : '#ffffff',
|
|
258
|
+
'&:hover': {
|
|
259
|
+
bgcolor:
|
|
260
|
+
historyIndex <= 0 ? 'transparent' : 'rgba(255,255,255,0.1)',
|
|
261
|
+
borderRadius: '4px',
|
|
262
|
+
},
|
|
263
|
+
}}
|
|
264
|
+
>
|
|
265
|
+
<UndoIcon sx={{ fontSize: '18px' }} />
|
|
266
|
+
</Button>
|
|
267
|
+
|
|
268
|
+
{/* Redo Button */}
|
|
269
|
+
<Button
|
|
270
|
+
variant="text"
|
|
271
|
+
size="small"
|
|
272
|
+
onClick={onRedo}
|
|
273
|
+
disabled={historyIndex >= historyLength - 1}
|
|
274
|
+
sx={{
|
|
275
|
+
minWidth: '32px',
|
|
276
|
+
width: '32px',
|
|
277
|
+
height: '32px',
|
|
278
|
+
padding: 0,
|
|
279
|
+
color: historyIndex >= historyLength - 1 ? '#666666' : '#ffffff',
|
|
280
|
+
'&:hover': {
|
|
281
|
+
bgcolor:
|
|
282
|
+
historyIndex >= historyLength - 1
|
|
283
|
+
? 'transparent'
|
|
284
|
+
: 'rgba(255,255,255,0.1)',
|
|
285
|
+
borderRadius: '4px',
|
|
286
|
+
},
|
|
287
|
+
}}
|
|
288
|
+
>
|
|
289
|
+
<RedoIcon sx={{ fontSize: '18px' }} />
|
|
290
|
+
</Button>
|
|
291
|
+
|
|
292
|
+
<Divider />
|
|
293
|
+
|
|
294
|
+
{/* Import Button */}
|
|
295
|
+
<Button
|
|
296
|
+
variant="text"
|
|
297
|
+
component="label"
|
|
298
|
+
size="small"
|
|
299
|
+
sx={{
|
|
300
|
+
minWidth: '32px',
|
|
301
|
+
width: '32px',
|
|
302
|
+
height: '32px',
|
|
303
|
+
padding: 0,
|
|
304
|
+
color: '#ffffff',
|
|
305
|
+
'&:hover': {
|
|
306
|
+
bgcolor: 'rgba(255,255,255,0.1)',
|
|
307
|
+
borderRadius: '4px',
|
|
308
|
+
},
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
<UploadIcon sx={{ fontSize: '18px' }} />
|
|
312
|
+
<input
|
|
313
|
+
type="file"
|
|
314
|
+
onChange={handleFileImport}
|
|
315
|
+
accept=".json"
|
|
316
|
+
style={{ display: 'none' }}
|
|
317
|
+
/>
|
|
318
|
+
</Button>
|
|
319
|
+
</Box>
|
|
320
|
+
|
|
321
|
+
{/* Custom Controls Toolbar */}
|
|
322
|
+
{showCustomControls && (
|
|
323
|
+
<CustomControls
|
|
324
|
+
onGridLayout={onGridLayout}
|
|
325
|
+
onTreeLayout={onTreeLayout}
|
|
326
|
+
/>
|
|
327
|
+
)}
|
|
328
|
+
</Box>
|
|
329
|
+
</Panel>
|
|
330
|
+
);
|
|
331
|
+
}
|