@flowuent-org/diagramming-core 1.0.5 → 1.0.7
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/TRANSLATION_FIX_SUMMARY.md +118 -0
- package/apps/diagramming/src/DiagramTabs.tsx +205 -205
- package/apps/diagramming/src/sample-workflow-content.ts +55 -54
- package/package.json +116 -116
- package/packages/diagrams/I18N_SETUP.md +126 -0
- package/packages/diagrams/NODE_DATA_UPDATE_API.md +430 -430
- package/packages/diagrams/README.md +443 -3
- package/packages/diagrams/UNDO_REDO_API.md +306 -306
- package/packages/diagrams/locales/en/translation.json +713 -0
- package/packages/diagrams/package.json +5 -23
- package/packages/diagrams/pnpm-lock.yaml +2606 -0
- package/packages/diagrams/project.json +42 -38
- package/packages/diagrams/rollup.config.js +5 -10
- package/packages/diagrams/src/index.ts +116 -113
- package/packages/diagrams/src/lib/atoms/CardEditableTitle.tsx +76 -76
- package/packages/diagrams/src/lib/components/automation/AutomationApiNode.tsx +24 -3
- package/packages/diagrams/src/lib/components/automation/AutomationEndNode.tsx +23 -2
- package/packages/diagrams/src/lib/components/automation/AutomationFormattingNode.tsx +24 -3
- package/packages/diagrams/src/lib/components/automation/AutomationStartNode.tsx +24 -3
- package/packages/diagrams/src/lib/contexts/onWorkflowNodeDelete.ts +1 -1
- package/packages/diagrams/src/lib/i18n.ts +42 -0
- package/packages/diagrams/src/lib/organisms/CustomEdge/useCreateBendPoint.tsx +121 -119
- package/packages/diagrams/src/lib/organisms/WorkFlowNode/NodeActionButtons.tsx +1 -1
- package/packages/diagrams/src/lib/templates/node-forms/CallForm.tsx +370 -370
- package/packages/diagrams/src/lib/types/node-types.ts +29 -29
- package/packages/diagrams/src/lib/utils/AutomationExecutionEngine.ts +1168 -1162
- package/packages/diagrams/tsconfig.lib.json +1 -3
- package/tsconfig.base.json +1 -1
|
@@ -1,430 +1,430 @@
|
|
|
1
|
-
# Node Data Update API Documentation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The diagramming library provides comprehensive node data management functionality that allows external applications to read and update node configurations dynamically. This is particularly useful for automation diagrams where nodes contain configuration data like API endpoints, AI model settings, authentication keys, and other execution parameters.
|
|
6
|
-
|
|
7
|
-
## How Node Data Management Works
|
|
8
|
-
|
|
9
|
-
### Internal Implementation
|
|
10
|
-
|
|
11
|
-
1. **Node Data Storage**: Each node contains a `data` property that holds its configuration
|
|
12
|
-
2. **State Management**: Node data is managed through the Zustand store
|
|
13
|
-
3. **Real-time Updates**: Changes are immediately reflected in the diagram
|
|
14
|
-
4. **History Tracking**: Node data changes are tracked in the undo/redo system
|
|
15
|
-
|
|
16
|
-
### Key Components
|
|
17
|
-
|
|
18
|
-
- **DiagrammingPageRef**: Exposes node data management methods
|
|
19
|
-
- **Node Data Types**: Structured interfaces for different node types
|
|
20
|
-
- **Update Methods**: Functions to modify node data externally
|
|
21
|
-
|
|
22
|
-
## External Node Data Control
|
|
23
|
-
|
|
24
|
-
### Method 1: Using Ref-based API (Recommended)
|
|
25
|
-
|
|
26
|
-
The `DiagrammingPage` component exposes node data management through a ref:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
import React, { useRef, useState, useEffect } from 'react';
|
|
30
|
-
import { DiagrammingPage, DiagrammingPageRef } from '@flowuent-
|
|
31
|
-
|
|
32
|
-
const MyComponent = () => {
|
|
33
|
-
const diagramRef = useRef<DiagrammingPageRef>(null);
|
|
34
|
-
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
35
|
-
const [nodeData, setNodeData] = useState<any>(null);
|
|
36
|
-
|
|
37
|
-
// Monitor node selection changes
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const interval = setInterval(() => {
|
|
40
|
-
if (diagramRef.current) {
|
|
41
|
-
const currentSelected = diagramRef.current.getSelectedNode();
|
|
42
|
-
if (currentSelected !== selectedNodeId) {
|
|
43
|
-
setSelectedNodeId(currentSelected);
|
|
44
|
-
if (currentSelected) {
|
|
45
|
-
const data = diagramRef.current.getNodeData(currentSelected);
|
|
46
|
-
setNodeData(data);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}, 100);
|
|
51
|
-
|
|
52
|
-
return () => clearInterval(interval);
|
|
53
|
-
}, [selectedNodeId]);
|
|
54
|
-
|
|
55
|
-
const handleUpdateNode = (newData: any) => {
|
|
56
|
-
if (selectedNodeId && diagramRef.current) {
|
|
57
|
-
const success = diagramRef.current.updateNodeData(selectedNodeId, newData);
|
|
58
|
-
if (success) {
|
|
59
|
-
console.log('Node updated successfully');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<div>
|
|
66
|
-
{/* Your external configuration panel */}
|
|
67
|
-
<YourConfigurationPanel
|
|
68
|
-
nodeData={nodeData}
|
|
69
|
-
onUpdate={handleUpdateNode}
|
|
70
|
-
/>
|
|
71
|
-
|
|
72
|
-
{/* The diagram */}
|
|
73
|
-
<DiagrammingPage
|
|
74
|
-
ref={diagramRef}
|
|
75
|
-
diagramType="automation"
|
|
76
|
-
defaultNodes={nodes}
|
|
77
|
-
defaultEdges={edges}
|
|
78
|
-
availableFunctions={[]}
|
|
79
|
-
id={1}
|
|
80
|
-
/>
|
|
81
|
-
</div>
|
|
82
|
-
);
|
|
83
|
-
};
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Available Methods
|
|
87
|
-
|
|
88
|
-
The `DiagrammingPageRef` interface provides these node data management methods:
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
interface DiagrammingPageRef {
|
|
92
|
-
// Undo/Redo methods (from previous API)
|
|
93
|
-
undo: () => void;
|
|
94
|
-
redo: () => void;
|
|
95
|
-
canUndo: () => boolean;
|
|
96
|
-
canRedo: () => boolean;
|
|
97
|
-
reset: () => void;
|
|
98
|
-
getHistoryLength: () => number;
|
|
99
|
-
getHistoryIndex: () => number;
|
|
100
|
-
|
|
101
|
-
// Node data management methods
|
|
102
|
-
getNodeData: (nodeId: string) => any | null; // Get node data by ID
|
|
103
|
-
updateNodeData: (nodeId: string, data: any) => boolean; // Update node data
|
|
104
|
-
getSelectedNode: () => string | null; // Get currently selected node ID
|
|
105
|
-
getNodes: () => any[]; // Get all nodes
|
|
106
|
-
getEdges: () => any[]; // Get all edges
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Node Data Structure Examples
|
|
111
|
-
|
|
112
|
-
### Automation API Node
|
|
113
|
-
```typescript
|
|
114
|
-
interface AutomationApiNodeData {
|
|
115
|
-
label: string;
|
|
116
|
-
description: string;
|
|
117
|
-
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
118
|
-
url: string;
|
|
119
|
-
headers: Array<{
|
|
120
|
-
key: string;
|
|
121
|
-
value: string;
|
|
122
|
-
enabled: boolean;
|
|
123
|
-
}>;
|
|
124
|
-
queryParams: Array<{
|
|
125
|
-
key: string;
|
|
126
|
-
value: string;
|
|
127
|
-
enabled: boolean;
|
|
128
|
-
}>;
|
|
129
|
-
body?: string;
|
|
130
|
-
timeout: number;
|
|
131
|
-
retryCount: number;
|
|
132
|
-
// ... other API-specific fields
|
|
133
|
-
}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Automation AI Formatting Node
|
|
137
|
-
```typescript
|
|
138
|
-
interface AutomationFormattingNodeData {
|
|
139
|
-
label: string;
|
|
140
|
-
description: string;
|
|
141
|
-
formattingType: 'basic' | 'ai-powered' | 'template';
|
|
142
|
-
aiConfig?: {
|
|
143
|
-
apiUrl: string;
|
|
144
|
-
apiKey: string;
|
|
145
|
-
model: string; // e.g., "GPT-5 Thinking mini"
|
|
146
|
-
instruction: string;
|
|
147
|
-
temperature: number; // e.g., 0.95
|
|
148
|
-
maxTokens?: number; // e.g., 2048
|
|
149
|
-
systemPrompt?: string;
|
|
150
|
-
};
|
|
151
|
-
outputVariable: string;
|
|
152
|
-
outputDataType: 'String' | 'Object' | 'Array';
|
|
153
|
-
// ... other formatting-specific fields
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Automation Start Node
|
|
158
|
-
```typescript
|
|
159
|
-
interface AutomationStartNodeData {
|
|
160
|
-
label: string;
|
|
161
|
-
description: string;
|
|
162
|
-
triggerType: 'manual' | 'scheduled' | 'event';
|
|
163
|
-
scheduleConfig?: {
|
|
164
|
-
frequency: 'hourly' | 'daily' | 'weekly' | 'monthly';
|
|
165
|
-
time?: string;
|
|
166
|
-
cron?: string;
|
|
167
|
-
timezone?: string;
|
|
168
|
-
};
|
|
169
|
-
eventConfig?: {
|
|
170
|
-
webhookUrl?: string;
|
|
171
|
-
eventType?: string;
|
|
172
|
-
filters?: Array<{
|
|
173
|
-
key: string;
|
|
174
|
-
value: string;
|
|
175
|
-
operator: 'equals' | 'contains' | 'startsWith' | 'endsWith';
|
|
176
|
-
}>;
|
|
177
|
-
};
|
|
178
|
-
// ... other start-specific fields
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## Complete Example: AI Model Configuration Panel
|
|
183
|
-
|
|
184
|
-
Here's a complete example showing how to create an external configuration panel for AI model settings:
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
import React, { useRef, useState, useEffect } from 'react';
|
|
188
|
-
import {
|
|
189
|
-
Box,
|
|
190
|
-
Typography,
|
|
191
|
-
TextField,
|
|
192
|
-
Button,
|
|
193
|
-
Card,
|
|
194
|
-
CardContent,
|
|
195
|
-
Grid,
|
|
196
|
-
Select,
|
|
197
|
-
MenuItem,
|
|
198
|
-
FormControl,
|
|
199
|
-
InputLabel,
|
|
200
|
-
Chip,
|
|
201
|
-
Alert
|
|
202
|
-
} from '@mui/material';
|
|
203
|
-
import { DiagrammingPage, DiagrammingPageRef } from '@flowuent-
|
|
204
|
-
|
|
205
|
-
const AIModelConfigurationPanel: React.FC = () => {
|
|
206
|
-
const diagramRef = useRef<DiagrammingPageRef>(null);
|
|
207
|
-
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
208
|
-
const [nodeData, setNodeData] = useState<any>(null);
|
|
209
|
-
const [formData, setFormData] = useState<any>({});
|
|
210
|
-
const [updateStatus, setUpdateStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
211
|
-
|
|
212
|
-
// Monitor node selection changes
|
|
213
|
-
useEffect(() => {
|
|
214
|
-
const interval = setInterval(() => {
|
|
215
|
-
if (diagramRef.current) {
|
|
216
|
-
const currentSelected = diagramRef.current.getSelectedNode();
|
|
217
|
-
if (currentSelected !== selectedNodeId) {
|
|
218
|
-
setSelectedNodeId(currentSelected);
|
|
219
|
-
if (currentSelected) {
|
|
220
|
-
const data = diagramRef.current.getNodeData(currentSelected);
|
|
221
|
-
setNodeData(data);
|
|
222
|
-
setFormData(data || {});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}, 100);
|
|
227
|
-
|
|
228
|
-
return () => clearInterval(interval);
|
|
229
|
-
}, [selectedNodeId]);
|
|
230
|
-
|
|
231
|
-
const handleFormChange = (field: string, value: any) => {
|
|
232
|
-
setFormData(prev => ({
|
|
233
|
-
...prev,
|
|
234
|
-
[field]: value
|
|
235
|
-
}));
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const handleUpdateNode = () => {
|
|
239
|
-
if (!selectedNodeId || !diagramRef.current) return;
|
|
240
|
-
|
|
241
|
-
const success = diagramRef.current.updateNodeData(selectedNodeId, formData);
|
|
242
|
-
if (success) {
|
|
243
|
-
setUpdateStatus('success');
|
|
244
|
-
setTimeout(() => setUpdateStatus('idle'), 2000);
|
|
245
|
-
} else {
|
|
246
|
-
setUpdateStatus('error');
|
|
247
|
-
setTimeout(() => setUpdateStatus('idle'), 2000);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
const renderAIConfiguration = () => {
|
|
252
|
-
if (!selectedNodeId || !nodeData) {
|
|
253
|
-
return (
|
|
254
|
-
<Card>
|
|
255
|
-
<CardContent>
|
|
256
|
-
<Typography variant="h6" color="text.secondary">
|
|
257
|
-
Select an AI Formatting node to configure
|
|
258
|
-
</Typography>
|
|
259
|
-
</CardContent>
|
|
260
|
-
</Card>
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
return (
|
|
265
|
-
<Card>
|
|
266
|
-
<CardContent>
|
|
267
|
-
<Typography variant="h6" gutterBottom>
|
|
268
|
-
AI Model Configuration
|
|
269
|
-
</Typography>
|
|
270
|
-
|
|
271
|
-
<Chip
|
|
272
|
-
label={`Node ID: ${selectedNodeId}`}
|
|
273
|
-
size="small"
|
|
274
|
-
sx={{ mb: 2 }}
|
|
275
|
-
/>
|
|
276
|
-
|
|
277
|
-
{updateStatus === 'success' && (
|
|
278
|
-
<Alert severity="success" sx={{ mb: 2 }}>
|
|
279
|
-
Configuration updated successfully!
|
|
280
|
-
</Alert>
|
|
281
|
-
)}
|
|
282
|
-
|
|
283
|
-
<Grid container spacing={2}>
|
|
284
|
-
<Grid item xs={12}>
|
|
285
|
-
<TextField
|
|
286
|
-
fullWidth
|
|
287
|
-
label="Model"
|
|
288
|
-
value={formData.aiConfig?.model || ''}
|
|
289
|
-
onChange={(e) => handleFormChange('aiConfig', {
|
|
290
|
-
...formData.aiConfig,
|
|
291
|
-
model: e.target.value
|
|
292
|
-
})}
|
|
293
|
-
/>
|
|
294
|
-
</Grid>
|
|
295
|
-
|
|
296
|
-
<Grid item xs={6}>
|
|
297
|
-
<TextField
|
|
298
|
-
fullWidth
|
|
299
|
-
label="Max Tokens"
|
|
300
|
-
type="number"
|
|
301
|
-
value={formData.aiConfig?.maxTokens || 2048}
|
|
302
|
-
onChange={(e) => handleFormChange('aiConfig', {
|
|
303
|
-
...formData.aiConfig,
|
|
304
|
-
maxTokens: parseInt(e.target.value)
|
|
305
|
-
})}
|
|
306
|
-
/>
|
|
307
|
-
</Grid>
|
|
308
|
-
|
|
309
|
-
<Grid item xs={6}>
|
|
310
|
-
<TextField
|
|
311
|
-
fullWidth
|
|
312
|
-
label="Temperature"
|
|
313
|
-
type="number"
|
|
314
|
-
step="0.1"
|
|
315
|
-
value={formData.aiConfig?.temperature || 0.95}
|
|
316
|
-
onChange={(e) => handleFormChange('aiConfig', {
|
|
317
|
-
...formData.aiConfig,
|
|
318
|
-
temperature: parseFloat(e.target.value)
|
|
319
|
-
})}
|
|
320
|
-
/>
|
|
321
|
-
</Grid>
|
|
322
|
-
|
|
323
|
-
<Grid item xs={12}>
|
|
324
|
-
<TextField
|
|
325
|
-
fullWidth
|
|
326
|
-
label="Instruction"
|
|
327
|
-
multiline
|
|
328
|
-
rows={3}
|
|
329
|
-
value={formData.aiConfig?.instruction || ''}
|
|
330
|
-
onChange={(e) => handleFormChange('aiConfig', {
|
|
331
|
-
...formData.aiConfig,
|
|
332
|
-
instruction: e.target.value
|
|
333
|
-
})}
|
|
334
|
-
/>
|
|
335
|
-
</Grid>
|
|
336
|
-
|
|
337
|
-
<Grid item xs={12}>
|
|
338
|
-
<TextField
|
|
339
|
-
fullWidth
|
|
340
|
-
label="API Key"
|
|
341
|
-
type="password"
|
|
342
|
-
value={formData.aiConfig?.apiKey || ''}
|
|
343
|
-
onChange={(e) => handleFormChange('aiConfig', {
|
|
344
|
-
...formData.aiConfig,
|
|
345
|
-
apiKey: e.target.value
|
|
346
|
-
})}
|
|
347
|
-
/>
|
|
348
|
-
</Grid>
|
|
349
|
-
</Grid>
|
|
350
|
-
|
|
351
|
-
<Box sx={{ mt: 3 }}>
|
|
352
|
-
<Button
|
|
353
|
-
variant="contained"
|
|
354
|
-
onClick={handleUpdateNode}
|
|
355
|
-
fullWidth
|
|
356
|
-
>
|
|
357
|
-
Update Configuration
|
|
358
|
-
</Button>
|
|
359
|
-
</Box>
|
|
360
|
-
</CardContent>
|
|
361
|
-
</Card>
|
|
362
|
-
);
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
return (
|
|
366
|
-
<Box sx={{ height: '100vh', display: 'flex' }}>
|
|
367
|
-
{/* Configuration Panel */}
|
|
368
|
-
<Box sx={{
|
|
369
|
-
width: 400,
|
|
370
|
-
borderRight: '1px solid #ddd',
|
|
371
|
-
bgcolor: '#fafafa',
|
|
372
|
-
overflow: 'auto'
|
|
373
|
-
}}>
|
|
374
|
-
{renderAIConfiguration()}
|
|
375
|
-
</Box>
|
|
376
|
-
|
|
377
|
-
{/* Diagram */}
|
|
378
|
-
<Box sx={{ flex: 1 }}>
|
|
379
|
-
<DiagrammingPage
|
|
380
|
-
ref={diagramRef}
|
|
381
|
-
diagramType="automation"
|
|
382
|
-
defaultNodes={nodes}
|
|
383
|
-
defaultEdges={edges}
|
|
384
|
-
availableFunctions={[]}
|
|
385
|
-
id={1}
|
|
386
|
-
/>
|
|
387
|
-
</Box>
|
|
388
|
-
</Box>
|
|
389
|
-
);
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
export default AIModelConfigurationPanel;
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
## Integration Steps for Your Team Member
|
|
396
|
-
|
|
397
|
-
1. **Install the updated library** with the new node data management API
|
|
398
|
-
2. **Create a ref** to the DiagrammingPage component
|
|
399
|
-
3. **Monitor node selection** to detect when a node is selected
|
|
400
|
-
4. **Read node data** using `getNodeData(nodeId)` method
|
|
401
|
-
5. **Create configuration UI** based on the node type and data structure
|
|
402
|
-
6. **Update node data** using `updateNodeData(nodeId, newData)` method
|
|
403
|
-
7. **Handle success/error states** appropriately
|
|
404
|
-
|
|
405
|
-
## Key Benefits
|
|
406
|
-
|
|
407
|
-
- **Real-time Updates**: Changes are immediately reflected in the diagram
|
|
408
|
-
- **Type Safety**: Structured data interfaces for different node types
|
|
409
|
-
- **Flexible Configuration**: Support for any node data structure
|
|
410
|
-
- **History Integration**: Node data changes are tracked in undo/redo
|
|
411
|
-
- **Selection Awareness**: Know which node is currently selected
|
|
412
|
-
- **Error Handling**: Methods return success/failure status
|
|
413
|
-
|
|
414
|
-
## Common Use Cases
|
|
415
|
-
|
|
416
|
-
1. **AI Model Configuration**: Update model, tokens, temperature, instructions
|
|
417
|
-
2. **API Configuration**: Modify endpoints, headers, authentication
|
|
418
|
-
3. **Workflow Settings**: Change trigger types, schedules, conditions
|
|
419
|
-
4. **Data Formatting**: Update formatting rules, templates, variables
|
|
420
|
-
5. **Authentication**: Manage API keys, tokens, credentials
|
|
421
|
-
6. **Execution Parameters**: Modify timeouts, retry counts, error handling
|
|
422
|
-
|
|
423
|
-
## Notes
|
|
424
|
-
|
|
425
|
-
- Node data updates are immediately reflected in the diagram
|
|
426
|
-
- Changes are tracked in the undo/redo history
|
|
427
|
-
- The API supports partial updates (only changed fields need to be provided)
|
|
428
|
-
- Node selection changes are detected automatically
|
|
429
|
-
- The system handles invalid node IDs gracefully
|
|
430
|
-
- All node types are supported with their specific data structures
|
|
1
|
+
# Node Data Update API Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The diagramming library provides comprehensive node data management functionality that allows external applications to read and update node configurations dynamically. This is particularly useful for automation diagrams where nodes contain configuration data like API endpoints, AI model settings, authentication keys, and other execution parameters.
|
|
6
|
+
|
|
7
|
+
## How Node Data Management Works
|
|
8
|
+
|
|
9
|
+
### Internal Implementation
|
|
10
|
+
|
|
11
|
+
1. **Node Data Storage**: Each node contains a `data` property that holds its configuration
|
|
12
|
+
2. **State Management**: Node data is managed through the Zustand store
|
|
13
|
+
3. **Real-time Updates**: Changes are immediately reflected in the diagram
|
|
14
|
+
4. **History Tracking**: Node data changes are tracked in the undo/redo system
|
|
15
|
+
|
|
16
|
+
### Key Components
|
|
17
|
+
|
|
18
|
+
- **DiagrammingPageRef**: Exposes node data management methods
|
|
19
|
+
- **Node Data Types**: Structured interfaces for different node types
|
|
20
|
+
- **Update Methods**: Functions to modify node data externally
|
|
21
|
+
|
|
22
|
+
## External Node Data Control
|
|
23
|
+
|
|
24
|
+
### Method 1: Using Ref-based API (Recommended)
|
|
25
|
+
|
|
26
|
+
The `DiagrammingPage` component exposes node data management through a ref:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import React, { useRef, useState, useEffect } from 'react';
|
|
30
|
+
import { DiagrammingPage, DiagrammingPageRef } from '@flowuent-labs/diagrams';
|
|
31
|
+
|
|
32
|
+
const MyComponent = () => {
|
|
33
|
+
const diagramRef = useRef<DiagrammingPageRef>(null);
|
|
34
|
+
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
35
|
+
const [nodeData, setNodeData] = useState<any>(null);
|
|
36
|
+
|
|
37
|
+
// Monitor node selection changes
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const interval = setInterval(() => {
|
|
40
|
+
if (diagramRef.current) {
|
|
41
|
+
const currentSelected = diagramRef.current.getSelectedNode();
|
|
42
|
+
if (currentSelected !== selectedNodeId) {
|
|
43
|
+
setSelectedNodeId(currentSelected);
|
|
44
|
+
if (currentSelected) {
|
|
45
|
+
const data = diagramRef.current.getNodeData(currentSelected);
|
|
46
|
+
setNodeData(data);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, 100);
|
|
51
|
+
|
|
52
|
+
return () => clearInterval(interval);
|
|
53
|
+
}, [selectedNodeId]);
|
|
54
|
+
|
|
55
|
+
const handleUpdateNode = (newData: any) => {
|
|
56
|
+
if (selectedNodeId && diagramRef.current) {
|
|
57
|
+
const success = diagramRef.current.updateNodeData(selectedNodeId, newData);
|
|
58
|
+
if (success) {
|
|
59
|
+
console.log('Node updated successfully');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div>
|
|
66
|
+
{/* Your external configuration panel */}
|
|
67
|
+
<YourConfigurationPanel
|
|
68
|
+
nodeData={nodeData}
|
|
69
|
+
onUpdate={handleUpdateNode}
|
|
70
|
+
/>
|
|
71
|
+
|
|
72
|
+
{/* The diagram */}
|
|
73
|
+
<DiagrammingPage
|
|
74
|
+
ref={diagramRef}
|
|
75
|
+
diagramType="automation"
|
|
76
|
+
defaultNodes={nodes}
|
|
77
|
+
defaultEdges={edges}
|
|
78
|
+
availableFunctions={[]}
|
|
79
|
+
id={1}
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Available Methods
|
|
87
|
+
|
|
88
|
+
The `DiagrammingPageRef` interface provides these node data management methods:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
interface DiagrammingPageRef {
|
|
92
|
+
// Undo/Redo methods (from previous API)
|
|
93
|
+
undo: () => void;
|
|
94
|
+
redo: () => void;
|
|
95
|
+
canUndo: () => boolean;
|
|
96
|
+
canRedo: () => boolean;
|
|
97
|
+
reset: () => void;
|
|
98
|
+
getHistoryLength: () => number;
|
|
99
|
+
getHistoryIndex: () => number;
|
|
100
|
+
|
|
101
|
+
// Node data management methods
|
|
102
|
+
getNodeData: (nodeId: string) => any | null; // Get node data by ID
|
|
103
|
+
updateNodeData: (nodeId: string, data: any) => boolean; // Update node data
|
|
104
|
+
getSelectedNode: () => string | null; // Get currently selected node ID
|
|
105
|
+
getNodes: () => any[]; // Get all nodes
|
|
106
|
+
getEdges: () => any[]; // Get all edges
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Node Data Structure Examples
|
|
111
|
+
|
|
112
|
+
### Automation API Node
|
|
113
|
+
```typescript
|
|
114
|
+
interface AutomationApiNodeData {
|
|
115
|
+
label: string;
|
|
116
|
+
description: string;
|
|
117
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
118
|
+
url: string;
|
|
119
|
+
headers: Array<{
|
|
120
|
+
key: string;
|
|
121
|
+
value: string;
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
}>;
|
|
124
|
+
queryParams: Array<{
|
|
125
|
+
key: string;
|
|
126
|
+
value: string;
|
|
127
|
+
enabled: boolean;
|
|
128
|
+
}>;
|
|
129
|
+
body?: string;
|
|
130
|
+
timeout: number;
|
|
131
|
+
retryCount: number;
|
|
132
|
+
// ... other API-specific fields
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Automation AI Formatting Node
|
|
137
|
+
```typescript
|
|
138
|
+
interface AutomationFormattingNodeData {
|
|
139
|
+
label: string;
|
|
140
|
+
description: string;
|
|
141
|
+
formattingType: 'basic' | 'ai-powered' | 'template';
|
|
142
|
+
aiConfig?: {
|
|
143
|
+
apiUrl: string;
|
|
144
|
+
apiKey: string;
|
|
145
|
+
model: string; // e.g., "GPT-5 Thinking mini"
|
|
146
|
+
instruction: string;
|
|
147
|
+
temperature: number; // e.g., 0.95
|
|
148
|
+
maxTokens?: number; // e.g., 2048
|
|
149
|
+
systemPrompt?: string;
|
|
150
|
+
};
|
|
151
|
+
outputVariable: string;
|
|
152
|
+
outputDataType: 'String' | 'Object' | 'Array';
|
|
153
|
+
// ... other formatting-specific fields
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Automation Start Node
|
|
158
|
+
```typescript
|
|
159
|
+
interface AutomationStartNodeData {
|
|
160
|
+
label: string;
|
|
161
|
+
description: string;
|
|
162
|
+
triggerType: 'manual' | 'scheduled' | 'event';
|
|
163
|
+
scheduleConfig?: {
|
|
164
|
+
frequency: 'hourly' | 'daily' | 'weekly' | 'monthly';
|
|
165
|
+
time?: string;
|
|
166
|
+
cron?: string;
|
|
167
|
+
timezone?: string;
|
|
168
|
+
};
|
|
169
|
+
eventConfig?: {
|
|
170
|
+
webhookUrl?: string;
|
|
171
|
+
eventType?: string;
|
|
172
|
+
filters?: Array<{
|
|
173
|
+
key: string;
|
|
174
|
+
value: string;
|
|
175
|
+
operator: 'equals' | 'contains' | 'startsWith' | 'endsWith';
|
|
176
|
+
}>;
|
|
177
|
+
};
|
|
178
|
+
// ... other start-specific fields
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Complete Example: AI Model Configuration Panel
|
|
183
|
+
|
|
184
|
+
Here's a complete example showing how to create an external configuration panel for AI model settings:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import React, { useRef, useState, useEffect } from 'react';
|
|
188
|
+
import {
|
|
189
|
+
Box,
|
|
190
|
+
Typography,
|
|
191
|
+
TextField,
|
|
192
|
+
Button,
|
|
193
|
+
Card,
|
|
194
|
+
CardContent,
|
|
195
|
+
Grid,
|
|
196
|
+
Select,
|
|
197
|
+
MenuItem,
|
|
198
|
+
FormControl,
|
|
199
|
+
InputLabel,
|
|
200
|
+
Chip,
|
|
201
|
+
Alert
|
|
202
|
+
} from '@mui/material';
|
|
203
|
+
import { DiagrammingPage, DiagrammingPageRef } from '@flowuent-labs/diagrams';
|
|
204
|
+
|
|
205
|
+
const AIModelConfigurationPanel: React.FC = () => {
|
|
206
|
+
const diagramRef = useRef<DiagrammingPageRef>(null);
|
|
207
|
+
const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
|
|
208
|
+
const [nodeData, setNodeData] = useState<any>(null);
|
|
209
|
+
const [formData, setFormData] = useState<any>({});
|
|
210
|
+
const [updateStatus, setUpdateStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
211
|
+
|
|
212
|
+
// Monitor node selection changes
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
const interval = setInterval(() => {
|
|
215
|
+
if (diagramRef.current) {
|
|
216
|
+
const currentSelected = diagramRef.current.getSelectedNode();
|
|
217
|
+
if (currentSelected !== selectedNodeId) {
|
|
218
|
+
setSelectedNodeId(currentSelected);
|
|
219
|
+
if (currentSelected) {
|
|
220
|
+
const data = diagramRef.current.getNodeData(currentSelected);
|
|
221
|
+
setNodeData(data);
|
|
222
|
+
setFormData(data || {});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}, 100);
|
|
227
|
+
|
|
228
|
+
return () => clearInterval(interval);
|
|
229
|
+
}, [selectedNodeId]);
|
|
230
|
+
|
|
231
|
+
const handleFormChange = (field: string, value: any) => {
|
|
232
|
+
setFormData(prev => ({
|
|
233
|
+
...prev,
|
|
234
|
+
[field]: value
|
|
235
|
+
}));
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const handleUpdateNode = () => {
|
|
239
|
+
if (!selectedNodeId || !diagramRef.current) return;
|
|
240
|
+
|
|
241
|
+
const success = diagramRef.current.updateNodeData(selectedNodeId, formData);
|
|
242
|
+
if (success) {
|
|
243
|
+
setUpdateStatus('success');
|
|
244
|
+
setTimeout(() => setUpdateStatus('idle'), 2000);
|
|
245
|
+
} else {
|
|
246
|
+
setUpdateStatus('error');
|
|
247
|
+
setTimeout(() => setUpdateStatus('idle'), 2000);
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const renderAIConfiguration = () => {
|
|
252
|
+
if (!selectedNodeId || !nodeData) {
|
|
253
|
+
return (
|
|
254
|
+
<Card>
|
|
255
|
+
<CardContent>
|
|
256
|
+
<Typography variant="h6" color="text.secondary">
|
|
257
|
+
Select an AI Formatting node to configure
|
|
258
|
+
</Typography>
|
|
259
|
+
</CardContent>
|
|
260
|
+
</Card>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<Card>
|
|
266
|
+
<CardContent>
|
|
267
|
+
<Typography variant="h6" gutterBottom>
|
|
268
|
+
AI Model Configuration
|
|
269
|
+
</Typography>
|
|
270
|
+
|
|
271
|
+
<Chip
|
|
272
|
+
label={`Node ID: ${selectedNodeId}`}
|
|
273
|
+
size="small"
|
|
274
|
+
sx={{ mb: 2 }}
|
|
275
|
+
/>
|
|
276
|
+
|
|
277
|
+
{updateStatus === 'success' && (
|
|
278
|
+
<Alert severity="success" sx={{ mb: 2 }}>
|
|
279
|
+
Configuration updated successfully!
|
|
280
|
+
</Alert>
|
|
281
|
+
)}
|
|
282
|
+
|
|
283
|
+
<Grid container spacing={2}>
|
|
284
|
+
<Grid item xs={12}>
|
|
285
|
+
<TextField
|
|
286
|
+
fullWidth
|
|
287
|
+
label="Model"
|
|
288
|
+
value={formData.aiConfig?.model || ''}
|
|
289
|
+
onChange={(e) => handleFormChange('aiConfig', {
|
|
290
|
+
...formData.aiConfig,
|
|
291
|
+
model: e.target.value
|
|
292
|
+
})}
|
|
293
|
+
/>
|
|
294
|
+
</Grid>
|
|
295
|
+
|
|
296
|
+
<Grid item xs={6}>
|
|
297
|
+
<TextField
|
|
298
|
+
fullWidth
|
|
299
|
+
label="Max Tokens"
|
|
300
|
+
type="number"
|
|
301
|
+
value={formData.aiConfig?.maxTokens || 2048}
|
|
302
|
+
onChange={(e) => handleFormChange('aiConfig', {
|
|
303
|
+
...formData.aiConfig,
|
|
304
|
+
maxTokens: parseInt(e.target.value)
|
|
305
|
+
})}
|
|
306
|
+
/>
|
|
307
|
+
</Grid>
|
|
308
|
+
|
|
309
|
+
<Grid item xs={6}>
|
|
310
|
+
<TextField
|
|
311
|
+
fullWidth
|
|
312
|
+
label="Temperature"
|
|
313
|
+
type="number"
|
|
314
|
+
step="0.1"
|
|
315
|
+
value={formData.aiConfig?.temperature || 0.95}
|
|
316
|
+
onChange={(e) => handleFormChange('aiConfig', {
|
|
317
|
+
...formData.aiConfig,
|
|
318
|
+
temperature: parseFloat(e.target.value)
|
|
319
|
+
})}
|
|
320
|
+
/>
|
|
321
|
+
</Grid>
|
|
322
|
+
|
|
323
|
+
<Grid item xs={12}>
|
|
324
|
+
<TextField
|
|
325
|
+
fullWidth
|
|
326
|
+
label="Instruction"
|
|
327
|
+
multiline
|
|
328
|
+
rows={3}
|
|
329
|
+
value={formData.aiConfig?.instruction || ''}
|
|
330
|
+
onChange={(e) => handleFormChange('aiConfig', {
|
|
331
|
+
...formData.aiConfig,
|
|
332
|
+
instruction: e.target.value
|
|
333
|
+
})}
|
|
334
|
+
/>
|
|
335
|
+
</Grid>
|
|
336
|
+
|
|
337
|
+
<Grid item xs={12}>
|
|
338
|
+
<TextField
|
|
339
|
+
fullWidth
|
|
340
|
+
label="API Key"
|
|
341
|
+
type="password"
|
|
342
|
+
value={formData.aiConfig?.apiKey || ''}
|
|
343
|
+
onChange={(e) => handleFormChange('aiConfig', {
|
|
344
|
+
...formData.aiConfig,
|
|
345
|
+
apiKey: e.target.value
|
|
346
|
+
})}
|
|
347
|
+
/>
|
|
348
|
+
</Grid>
|
|
349
|
+
</Grid>
|
|
350
|
+
|
|
351
|
+
<Box sx={{ mt: 3 }}>
|
|
352
|
+
<Button
|
|
353
|
+
variant="contained"
|
|
354
|
+
onClick={handleUpdateNode}
|
|
355
|
+
fullWidth
|
|
356
|
+
>
|
|
357
|
+
Update Configuration
|
|
358
|
+
</Button>
|
|
359
|
+
</Box>
|
|
360
|
+
</CardContent>
|
|
361
|
+
</Card>
|
|
362
|
+
);
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
<Box sx={{ height: '100vh', display: 'flex' }}>
|
|
367
|
+
{/* Configuration Panel */}
|
|
368
|
+
<Box sx={{
|
|
369
|
+
width: 400,
|
|
370
|
+
borderRight: '1px solid #ddd',
|
|
371
|
+
bgcolor: '#fafafa',
|
|
372
|
+
overflow: 'auto'
|
|
373
|
+
}}>
|
|
374
|
+
{renderAIConfiguration()}
|
|
375
|
+
</Box>
|
|
376
|
+
|
|
377
|
+
{/* Diagram */}
|
|
378
|
+
<Box sx={{ flex: 1 }}>
|
|
379
|
+
<DiagrammingPage
|
|
380
|
+
ref={diagramRef}
|
|
381
|
+
diagramType="automation"
|
|
382
|
+
defaultNodes={nodes}
|
|
383
|
+
defaultEdges={edges}
|
|
384
|
+
availableFunctions={[]}
|
|
385
|
+
id={1}
|
|
386
|
+
/>
|
|
387
|
+
</Box>
|
|
388
|
+
</Box>
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
export default AIModelConfigurationPanel;
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Integration Steps for Your Team Member
|
|
396
|
+
|
|
397
|
+
1. **Install the updated library** with the new node data management API
|
|
398
|
+
2. **Create a ref** to the DiagrammingPage component
|
|
399
|
+
3. **Monitor node selection** to detect when a node is selected
|
|
400
|
+
4. **Read node data** using `getNodeData(nodeId)` method
|
|
401
|
+
5. **Create configuration UI** based on the node type and data structure
|
|
402
|
+
6. **Update node data** using `updateNodeData(nodeId, newData)` method
|
|
403
|
+
7. **Handle success/error states** appropriately
|
|
404
|
+
|
|
405
|
+
## Key Benefits
|
|
406
|
+
|
|
407
|
+
- **Real-time Updates**: Changes are immediately reflected in the diagram
|
|
408
|
+
- **Type Safety**: Structured data interfaces for different node types
|
|
409
|
+
- **Flexible Configuration**: Support for any node data structure
|
|
410
|
+
- **History Integration**: Node data changes are tracked in undo/redo
|
|
411
|
+
- **Selection Awareness**: Know which node is currently selected
|
|
412
|
+
- **Error Handling**: Methods return success/failure status
|
|
413
|
+
|
|
414
|
+
## Common Use Cases
|
|
415
|
+
|
|
416
|
+
1. **AI Model Configuration**: Update model, tokens, temperature, instructions
|
|
417
|
+
2. **API Configuration**: Modify endpoints, headers, authentication
|
|
418
|
+
3. **Workflow Settings**: Change trigger types, schedules, conditions
|
|
419
|
+
4. **Data Formatting**: Update formatting rules, templates, variables
|
|
420
|
+
5. **Authentication**: Manage API keys, tokens, credentials
|
|
421
|
+
6. **Execution Parameters**: Modify timeouts, retry counts, error handling
|
|
422
|
+
|
|
423
|
+
## Notes
|
|
424
|
+
|
|
425
|
+
- Node data updates are immediately reflected in the diagram
|
|
426
|
+
- Changes are tracked in the undo/redo history
|
|
427
|
+
- The API supports partial updates (only changed fields need to be provided)
|
|
428
|
+
- Node selection changes are detected automatically
|
|
429
|
+
- The system handles invalid node IDs gracefully
|
|
430
|
+
- All node types are supported with their specific data structures
|