@principal-ai/principal-view-react 0.6.10 → 0.6.11
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/README.md +2 -5
- package/dist/components/ConfigurationSelector.js +4 -2
- package/dist/components/ConfigurationSelector.js.map +1 -1
- package/dist/components/EdgeInfoPanel.d.ts.map +1 -1
- package/dist/components/EdgeInfoPanel.js +43 -13
- package/dist/components/EdgeInfoPanel.js.map +1 -1
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +133 -83
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/NodeInfoPanel.d.ts.map +1 -1
- package/dist/components/NodeInfoPanel.js +143 -45
- package/dist/components/NodeInfoPanel.js.map +1 -1
- package/dist/edges/CustomEdge.d.ts.map +1 -1
- package/dist/edges/CustomEdge.js +2 -2
- package/dist/edges/CustomEdge.js.map +1 -1
- package/dist/edges/GenericEdge.d.ts.map +1 -1
- package/dist/edges/GenericEdge.js +2 -2
- package/dist/edges/GenericEdge.js.map +1 -1
- package/dist/hooks/usePathBasedEvents.d.ts +1 -1
- package/dist/hooks/usePathBasedEvents.d.ts.map +1 -1
- package/dist/hooks/usePathBasedEvents.js +9 -9
- package/dist/hooks/usePathBasedEvents.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +61 -44
- package/dist/nodes/CustomNode.js.map +1 -1
- package/dist/nodes/GenericNode.d.ts.map +1 -1
- package/dist/nodes/GenericNode.js.map +1 -1
- package/dist/utils/animationMapping.d.ts.map +1 -1
- package/dist/utils/animationMapping.js +12 -12
- package/dist/utils/animationMapping.js.map +1 -1
- package/dist/utils/graphConverter.d.ts.map +1 -1
- package/dist/utils/graphConverter.js +23 -17
- package/dist/utils/graphConverter.js.map +1 -1
- package/dist/utils/iconResolver.d.ts.map +1 -1
- package/dist/utils/iconResolver.js +1 -1
- package/dist/utils/iconResolver.js.map +1 -1
- package/package.json +2 -1
- package/src/components/ConfigurationSelector.tsx +5 -5
- package/src/components/EdgeInfoPanel.tsx +79 -37
- package/src/components/GraphRenderer.tsx +526 -365
- package/src/components/NodeInfoPanel.tsx +209 -86
- package/src/edges/CustomEdge.tsx +6 -4
- package/src/edges/GenericEdge.tsx +2 -6
- package/src/hooks/usePathBasedEvents.ts +54 -45
- package/src/index.ts +11 -2
- package/src/nodes/CustomNode.tsx +132 -106
- package/src/nodes/GenericNode.tsx +4 -3
- package/src/stories/AnimationWorkshop.stories.tsx +131 -12
- package/src/stories/CanvasNodeTypes.stories.tsx +898 -0
- package/src/stories/ColorPriority.stories.tsx +20 -10
- package/src/stories/EventDrivenAnimations.stories.tsx +8 -0
- package/src/stories/EventLog.stories.tsx +1 -1
- package/src/stories/GraphRenderer.stories.tsx +23 -10
- package/src/stories/IndustryThemes.stories.tsx +481 -0
- package/src/stories/MultiConfig.stories.tsx +8 -0
- package/src/stories/MultiDirectionalConnections.stories.tsx +8 -0
- package/src/stories/NodeFieldsAudit.stories.tsx +124 -37
- package/src/stories/NodeShapes.stories.tsx +73 -59
- package/src/utils/animationMapping.ts +19 -23
- package/src/utils/graphConverter.ts +35 -19
- package/src/utils/iconResolver.tsx +5 -1
|
@@ -1,17 +1,57 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import type { NodeState, NodeTypeDefinition } from '@principal-ai/principal-view-core';
|
|
3
|
+
import { useTheme } from '@principal-ade/industry-theme';
|
|
3
4
|
import { resolveIcon } from '../utils/iconResolver';
|
|
4
5
|
|
|
5
6
|
// Common icons for the icon selector
|
|
6
7
|
const COMMON_ICONS = [
|
|
7
|
-
'Settings',
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
8
|
+
'Settings',
|
|
9
|
+
'Database',
|
|
10
|
+
'Package',
|
|
11
|
+
'Server',
|
|
12
|
+
'Cloud',
|
|
13
|
+
'Globe',
|
|
14
|
+
'File',
|
|
15
|
+
'Folder',
|
|
16
|
+
'Code',
|
|
17
|
+
'Terminal',
|
|
18
|
+
'Cpu',
|
|
19
|
+
'HardDrive',
|
|
20
|
+
'Network',
|
|
21
|
+
'Wifi',
|
|
22
|
+
'Lock',
|
|
23
|
+
'Unlock',
|
|
24
|
+
'Key',
|
|
25
|
+
'Shield',
|
|
26
|
+
'User',
|
|
27
|
+
'Users',
|
|
28
|
+
'Mail',
|
|
29
|
+
'MessageSquare',
|
|
30
|
+
'Bell',
|
|
31
|
+
'Calendar',
|
|
32
|
+
'Clock',
|
|
33
|
+
'Timer',
|
|
34
|
+
'Zap',
|
|
35
|
+
'Activity',
|
|
36
|
+
'BarChart',
|
|
37
|
+
'PieChart',
|
|
38
|
+
'CheckCircle',
|
|
39
|
+
'XCircle',
|
|
40
|
+
'AlertCircle',
|
|
41
|
+
'Info',
|
|
42
|
+
'HelpCircle',
|
|
43
|
+
'Play',
|
|
44
|
+
'Pause',
|
|
45
|
+
'Square',
|
|
46
|
+
'Circle',
|
|
47
|
+
'Triangle',
|
|
48
|
+
'Hexagon',
|
|
49
|
+
'Box',
|
|
50
|
+
'Layers',
|
|
51
|
+
'GitBranch',
|
|
52
|
+
'GitCommit',
|
|
53
|
+
'GitMerge',
|
|
54
|
+
'GitPullRequest',
|
|
15
55
|
];
|
|
16
56
|
|
|
17
57
|
export interface NodeInfoPanelProps {
|
|
@@ -37,7 +77,10 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
37
77
|
onDelete,
|
|
38
78
|
onUpdate,
|
|
39
79
|
}) => {
|
|
40
|
-
const
|
|
80
|
+
const { theme } = useTheme();
|
|
81
|
+
|
|
82
|
+
// Color priority: node data color > type definition color > theme primary
|
|
83
|
+
const nodeColor = (node.data?.color as string) || typeDefinition?.color || theme.colors.primary;
|
|
41
84
|
const canEdit = Boolean(onUpdate);
|
|
42
85
|
|
|
43
86
|
// Local state for UI
|
|
@@ -65,7 +108,29 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
65
108
|
|
|
66
109
|
// Always show basic node data if no schema is defined
|
|
67
110
|
const hasSchemaFields = displayFields.length > 0;
|
|
68
|
-
|
|
111
|
+
// Internal fields that should not be displayed in the popup
|
|
112
|
+
const internalFields = [
|
|
113
|
+
'icon',
|
|
114
|
+
'name',
|
|
115
|
+
'description',
|
|
116
|
+
'sources',
|
|
117
|
+
'color',
|
|
118
|
+
'stroke',
|
|
119
|
+
'width',
|
|
120
|
+
'height',
|
|
121
|
+
'canvasType',
|
|
122
|
+
'text',
|
|
123
|
+
'file',
|
|
124
|
+
'url',
|
|
125
|
+
'shape',
|
|
126
|
+
'states',
|
|
127
|
+
'actions',
|
|
128
|
+
'nodeType',
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const nodeDataEntries = node.data
|
|
132
|
+
? Object.entries(node.data).filter(([key]) => !internalFields.includes(key))
|
|
133
|
+
: [];
|
|
69
134
|
|
|
70
135
|
// Get sources from node data
|
|
71
136
|
const sources = (node.data?.sources as string[]) || [];
|
|
@@ -91,26 +156,30 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
91
156
|
position: 'absolute',
|
|
92
157
|
top: '60px',
|
|
93
158
|
right: '20px',
|
|
94
|
-
backgroundColor:
|
|
159
|
+
backgroundColor: theme.colors.background,
|
|
160
|
+
color: theme.colors.text,
|
|
95
161
|
borderRadius: '8px',
|
|
96
162
|
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
|
97
163
|
padding: '16px',
|
|
98
164
|
minWidth: '250px',
|
|
99
165
|
maxWidth: '350px',
|
|
100
166
|
zIndex: 1000,
|
|
167
|
+
border: `1px solid ${theme.colors.border}`,
|
|
101
168
|
}}
|
|
102
169
|
>
|
|
103
170
|
{/* Header - shows node name */}
|
|
104
|
-
<div
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
171
|
+
<div
|
|
172
|
+
style={{
|
|
173
|
+
display: 'flex',
|
|
174
|
+
justifyContent: 'space-between',
|
|
175
|
+
alignItems: 'center',
|
|
176
|
+
marginBottom: '12px',
|
|
177
|
+
paddingBottom: '8px',
|
|
178
|
+
borderBottom: `2px solid ${nodeColor}`,
|
|
179
|
+
}}
|
|
180
|
+
>
|
|
181
|
+
<div style={{ fontWeight: 'bold', fontSize: '14px', color: nodeColor }}>
|
|
182
|
+
{node.name || node.id}
|
|
114
183
|
</div>
|
|
115
184
|
<button
|
|
116
185
|
onClick={onClose}
|
|
@@ -119,7 +188,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
119
188
|
background: 'none',
|
|
120
189
|
cursor: 'pointer',
|
|
121
190
|
fontSize: '18px',
|
|
122
|
-
color:
|
|
191
|
+
color: theme.colors.textSecondary,
|
|
123
192
|
padding: '0',
|
|
124
193
|
width: '24px',
|
|
125
194
|
height: '24px',
|
|
@@ -135,22 +204,17 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
135
204
|
{/* Description - first field under header */}
|
|
136
205
|
{node.data?.description && (
|
|
137
206
|
<div style={{ marginBottom: '12px' }}>
|
|
138
|
-
<div style={{ fontSize: '10px', color:
|
|
207
|
+
<div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
|
|
139
208
|
Description
|
|
140
209
|
</div>
|
|
141
|
-
<div style={{
|
|
142
|
-
fontSize: '12px',
|
|
143
|
-
color: '#333',
|
|
144
|
-
}}>
|
|
145
|
-
{String(node.data.description)}
|
|
146
|
-
</div>
|
|
210
|
+
<div style={{ fontSize: '12px' }}>{String(node.data.description)}</div>
|
|
147
211
|
</div>
|
|
148
212
|
)}
|
|
149
213
|
|
|
150
214
|
{/* Sources - shown after description */}
|
|
151
215
|
{sources.length > 0 && (
|
|
152
216
|
<div style={{ marginBottom: '12px' }}>
|
|
153
|
-
<div style={{ fontSize: '10px', color:
|
|
217
|
+
<div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
|
|
154
218
|
Sources
|
|
155
219
|
</div>
|
|
156
220
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
|
|
@@ -160,9 +224,9 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
160
224
|
style={{
|
|
161
225
|
fontSize: '11px',
|
|
162
226
|
padding: '2px 8px',
|
|
163
|
-
backgroundColor:
|
|
227
|
+
backgroundColor: theme.colors.muted,
|
|
164
228
|
borderRadius: '4px',
|
|
165
|
-
color:
|
|
229
|
+
color: theme.colors.textSecondary,
|
|
166
230
|
}}
|
|
167
231
|
>
|
|
168
232
|
{source}
|
|
@@ -178,12 +242,12 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
178
242
|
style={{
|
|
179
243
|
width: '100%',
|
|
180
244
|
padding: '8px',
|
|
181
|
-
backgroundColor:
|
|
182
|
-
border:
|
|
245
|
+
backgroundColor: theme.colors.surface,
|
|
246
|
+
border: `1px solid ${theme.colors.border}`,
|
|
183
247
|
borderRadius: '4px',
|
|
184
248
|
cursor: 'pointer',
|
|
185
249
|
fontSize: '12px',
|
|
186
|
-
color:
|
|
250
|
+
color: theme.colors.textSecondary,
|
|
187
251
|
display: 'flex',
|
|
188
252
|
alignItems: 'center',
|
|
189
253
|
justifyContent: 'center',
|
|
@@ -191,7 +255,12 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
191
255
|
marginBottom: showDetails ? '12px' : '0',
|
|
192
256
|
}}
|
|
193
257
|
>
|
|
194
|
-
<span
|
|
258
|
+
<span
|
|
259
|
+
style={{
|
|
260
|
+
transform: showDetails ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
261
|
+
transition: 'transform 0.2s',
|
|
262
|
+
}}
|
|
263
|
+
>
|
|
195
264
|
▼
|
|
196
265
|
</span>
|
|
197
266
|
{showDetails ? 'Hide Details' : 'Show Details'}
|
|
@@ -202,7 +271,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
202
271
|
<>
|
|
203
272
|
{/* Icon Selector */}
|
|
204
273
|
<div style={{ marginBottom: '12px' }}>
|
|
205
|
-
<div style={{ fontSize: '10px', color:
|
|
274
|
+
<div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
|
|
206
275
|
Icon
|
|
207
276
|
</div>
|
|
208
277
|
<div style={{ position: 'relative' }}>
|
|
@@ -214,20 +283,27 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
214
283
|
alignItems: 'center',
|
|
215
284
|
gap: '8px',
|
|
216
285
|
padding: '6px 10px',
|
|
217
|
-
backgroundColor:
|
|
218
|
-
border: canEdit
|
|
286
|
+
backgroundColor: theme.colors.surface,
|
|
287
|
+
border: canEdit
|
|
288
|
+
? `1px dashed ${theme.colors.border}`
|
|
289
|
+
: `1px solid ${theme.colors.border}`,
|
|
219
290
|
borderRadius: '4px',
|
|
220
291
|
cursor: canEdit ? 'pointer' : 'default',
|
|
221
292
|
fontSize: '12px',
|
|
222
293
|
width: '100%',
|
|
223
294
|
justifyContent: 'flex-start',
|
|
295
|
+
color: theme.colors.text,
|
|
224
296
|
}}
|
|
225
297
|
>
|
|
226
298
|
<span style={{ display: 'flex', alignItems: 'center' }}>
|
|
227
299
|
{resolveIcon(currentIcon, 18)}
|
|
228
300
|
</span>
|
|
229
301
|
<span>{currentIcon || 'No icon'}</span>
|
|
230
|
-
{canEdit &&
|
|
302
|
+
{canEdit && (
|
|
303
|
+
<span style={{ marginLeft: 'auto', color: theme.colors.textMuted, fontSize: '10px' }}>
|
|
304
|
+
✎
|
|
305
|
+
</span>
|
|
306
|
+
)}
|
|
231
307
|
</button>
|
|
232
308
|
|
|
233
309
|
{/* Icon Picker Dropdown */}
|
|
@@ -239,8 +315,8 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
239
315
|
left: 0,
|
|
240
316
|
right: 0,
|
|
241
317
|
marginTop: '4px',
|
|
242
|
-
backgroundColor:
|
|
243
|
-
border:
|
|
318
|
+
backgroundColor: theme.colors.background,
|
|
319
|
+
border: `1px solid ${theme.colors.border}`,
|
|
244
320
|
borderRadius: '4px',
|
|
245
321
|
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
|
246
322
|
padding: '8px',
|
|
@@ -256,20 +332,25 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
256
332
|
gap: '4px',
|
|
257
333
|
}}
|
|
258
334
|
>
|
|
259
|
-
{COMMON_ICONS.map(iconName => (
|
|
335
|
+
{COMMON_ICONS.map((iconName) => (
|
|
260
336
|
<button
|
|
261
337
|
key={iconName}
|
|
262
338
|
onClick={() => handleIconSelect(iconName)}
|
|
263
339
|
title={iconName}
|
|
264
340
|
style={{
|
|
265
341
|
padding: '6px',
|
|
266
|
-
border:
|
|
342
|
+
border:
|
|
343
|
+
currentIcon === iconName
|
|
344
|
+
? `2px solid ${nodeColor}`
|
|
345
|
+
: `1px solid ${theme.colors.border}`,
|
|
267
346
|
borderRadius: '4px',
|
|
268
|
-
backgroundColor:
|
|
347
|
+
backgroundColor:
|
|
348
|
+
currentIcon === iconName ? theme.colors.highlight : theme.colors.background,
|
|
269
349
|
cursor: 'pointer',
|
|
270
350
|
display: 'flex',
|
|
271
351
|
alignItems: 'center',
|
|
272
352
|
justifyContent: 'center',
|
|
353
|
+
color: theme.colors.text,
|
|
273
354
|
}}
|
|
274
355
|
>
|
|
275
356
|
{resolveIcon(iconName, 16)}
|
|
@@ -283,7 +364,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
283
364
|
|
|
284
365
|
{/* Node Type - Editable if availableNodeTypes provided */}
|
|
285
366
|
<div style={{ marginBottom: '12px' }}>
|
|
286
|
-
<div style={{ fontSize: '10px', color:
|
|
367
|
+
<div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
|
|
287
368
|
Type
|
|
288
369
|
</div>
|
|
289
370
|
{canEdit && availableNodeTypes && Object.keys(availableNodeTypes).length > 1 ? (
|
|
@@ -294,8 +375,9 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
294
375
|
fontSize: '12px',
|
|
295
376
|
padding: '4px 8px',
|
|
296
377
|
borderRadius: '4px',
|
|
297
|
-
border:
|
|
298
|
-
backgroundColor:
|
|
378
|
+
border: `1px solid ${theme.colors.border}`,
|
|
379
|
+
backgroundColor: theme.colors.background,
|
|
380
|
+
color: theme.colors.text,
|
|
299
381
|
cursor: 'pointer',
|
|
300
382
|
width: '100%',
|
|
301
383
|
}}
|
|
@@ -307,14 +389,16 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
307
389
|
))}
|
|
308
390
|
</select>
|
|
309
391
|
) : (
|
|
310
|
-
<div
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
392
|
+
<div
|
|
393
|
+
style={{
|
|
394
|
+
fontSize: '12px',
|
|
395
|
+
padding: '4px 8px',
|
|
396
|
+
backgroundColor: nodeColor,
|
|
397
|
+
color: theme.colors.background,
|
|
398
|
+
borderRadius: '4px',
|
|
399
|
+
display: 'inline-block',
|
|
400
|
+
}}
|
|
401
|
+
>
|
|
318
402
|
{node.type}
|
|
319
403
|
</div>
|
|
320
404
|
)}
|
|
@@ -323,57 +407,88 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
323
407
|
{/* Node State */}
|
|
324
408
|
{node.state && (
|
|
325
409
|
<div style={{ marginBottom: '12px' }}>
|
|
326
|
-
<div style={{ fontSize: '10px', color:
|
|
410
|
+
<div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
|
|
327
411
|
State
|
|
328
412
|
</div>
|
|
329
|
-
<div
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
413
|
+
<div
|
|
414
|
+
style={{
|
|
415
|
+
fontSize: '12px',
|
|
416
|
+
padding: '4px 8px',
|
|
417
|
+
backgroundColor:
|
|
418
|
+
typeDefinition?.states?.[node.state]?.color || theme.colors.secondary,
|
|
419
|
+
color: theme.colors.background,
|
|
420
|
+
borderRadius: '4px',
|
|
421
|
+
display: 'inline-block',
|
|
422
|
+
}}
|
|
423
|
+
>
|
|
337
424
|
{typeDefinition?.states?.[node.state]?.label || node.state}
|
|
338
425
|
</div>
|
|
339
426
|
</div>
|
|
340
427
|
)}
|
|
341
428
|
|
|
342
429
|
{/* Display other schema-defined fields (non-editable for now) */}
|
|
343
|
-
{hasSchemaFields && displayFields.filter(f => f.field !== nameField).length > 0 && (
|
|
430
|
+
{hasSchemaFields && displayFields.filter((f) => f.field !== nameField).length > 0 && (
|
|
344
431
|
<div style={{ marginBottom: '12px' }}>
|
|
345
|
-
<div
|
|
432
|
+
<div
|
|
433
|
+
style={{
|
|
434
|
+
fontSize: '10px',
|
|
435
|
+
color: theme.colors.textSecondary,
|
|
436
|
+
marginBottom: '8px',
|
|
437
|
+
fontWeight: 'bold',
|
|
438
|
+
}}
|
|
439
|
+
>
|
|
346
440
|
Properties
|
|
347
441
|
</div>
|
|
348
|
-
{displayFields
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
442
|
+
{displayFields
|
|
443
|
+
.filter((f) => f.field !== nameField)
|
|
444
|
+
.map(({ field, label, value }) => (
|
|
445
|
+
<div key={field} style={{ marginBottom: '8px' }}>
|
|
446
|
+
<div
|
|
447
|
+
style={{
|
|
448
|
+
fontSize: '10px',
|
|
449
|
+
color: theme.colors.textSecondary,
|
|
450
|
+
marginBottom: '2px',
|
|
451
|
+
}}
|
|
452
|
+
>
|
|
453
|
+
{label}
|
|
454
|
+
</div>
|
|
455
|
+
<div style={{ fontSize: '12px' }}>
|
|
456
|
+
{value !== undefined && value !== null
|
|
457
|
+
? typeof value === 'object'
|
|
458
|
+
? JSON.stringify(value, null, 2)
|
|
459
|
+
: String(value)
|
|
460
|
+
: '-'}
|
|
461
|
+
</div>
|
|
359
462
|
</div>
|
|
360
|
-
|
|
361
|
-
))}
|
|
463
|
+
))}
|
|
362
464
|
</div>
|
|
363
465
|
)}
|
|
364
466
|
|
|
365
467
|
{/* Show all node data if no schema is defined */}
|
|
366
468
|
{!hasSchemaFields && nodeDataEntries.length > 0 && (
|
|
367
469
|
<div style={{ marginBottom: '12px' }}>
|
|
368
|
-
<div
|
|
470
|
+
<div
|
|
471
|
+
style={{
|
|
472
|
+
fontSize: '10px',
|
|
473
|
+
color: theme.colors.textSecondary,
|
|
474
|
+
marginBottom: '8px',
|
|
475
|
+
fontWeight: 'bold',
|
|
476
|
+
}}
|
|
477
|
+
>
|
|
369
478
|
Data
|
|
370
479
|
</div>
|
|
371
480
|
{nodeDataEntries.map(([key, value]) => (
|
|
372
481
|
<div key={key} style={{ marginBottom: '8px' }}>
|
|
373
|
-
<div
|
|
482
|
+
<div
|
|
483
|
+
style={{
|
|
484
|
+
fontSize: '10px',
|
|
485
|
+
color: theme.colors.textSecondary,
|
|
486
|
+
marginBottom: '2px',
|
|
487
|
+
}}
|
|
488
|
+
>
|
|
374
489
|
{key}
|
|
375
490
|
</div>
|
|
376
|
-
<div style={{ fontSize: '12px',
|
|
491
|
+
<div style={{ fontSize: '12px', wordBreak: 'break-word' }}>
|
|
377
492
|
{value !== undefined && value !== null
|
|
378
493
|
? typeof value === 'object'
|
|
379
494
|
? JSON.stringify(value, null, 2)
|
|
@@ -386,7 +501,15 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
386
501
|
)}
|
|
387
502
|
|
|
388
503
|
{/* Metadata */}
|
|
389
|
-
<div
|
|
504
|
+
<div
|
|
505
|
+
style={{
|
|
506
|
+
fontSize: '10px',
|
|
507
|
+
color: theme.colors.textMuted,
|
|
508
|
+
marginTop: '12px',
|
|
509
|
+
paddingTop: '8px',
|
|
510
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
511
|
+
}}
|
|
512
|
+
>
|
|
390
513
|
ID: {node.id}
|
|
391
514
|
</div>
|
|
392
515
|
</>
|
|
@@ -403,8 +526,8 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
|
|
|
403
526
|
marginTop: '12px',
|
|
404
527
|
width: '100%',
|
|
405
528
|
padding: '8px 12px',
|
|
406
|
-
backgroundColor:
|
|
407
|
-
color:
|
|
529
|
+
backgroundColor: theme.colors.error,
|
|
530
|
+
color: theme.colors.background,
|
|
408
531
|
border: 'none',
|
|
409
532
|
borderRadius: '4px',
|
|
410
533
|
cursor: 'pointer',
|
package/src/edges/CustomEdge.tsx
CHANGED
|
@@ -36,7 +36,7 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
|
|
|
36
36
|
data: edgeData,
|
|
37
37
|
animationType,
|
|
38
38
|
animationDuration = 1000,
|
|
39
|
-
animationDirection = 'forward'
|
|
39
|
+
animationDirection = 'forward',
|
|
40
40
|
} = edgeProps || ({} as CustomEdgeData);
|
|
41
41
|
|
|
42
42
|
const [particlePosition, setParticlePosition] = useState(0);
|
|
@@ -64,7 +64,7 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
|
|
|
64
64
|
|
|
65
65
|
// Color priority: violations > edge data color > type definition color > default
|
|
66
66
|
const edgeColor = edgeData?.color as string | undefined;
|
|
67
|
-
const color = hasViolations ? '#D0021B' :
|
|
67
|
+
const color = hasViolations ? '#D0021B' : edgeColor || typeDefinition.color || '#888';
|
|
68
68
|
const width = typeDefinition.width || 2;
|
|
69
69
|
|
|
70
70
|
// Get Bezier path
|
|
@@ -127,7 +127,8 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
|
|
|
127
127
|
const getParticleTransform = () => {
|
|
128
128
|
if (!pathRef.current) {
|
|
129
129
|
// Fallback to linear interpolation if path ref not available yet
|
|
130
|
-
const progress =
|
|
130
|
+
const progress =
|
|
131
|
+
animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
|
|
131
132
|
const x = sourceX + (targetX - sourceX) * progress;
|
|
132
133
|
const y = sourceY + (targetY - sourceY) * progress;
|
|
133
134
|
return { x, y };
|
|
@@ -135,7 +136,8 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
|
|
|
135
136
|
|
|
136
137
|
// Use actual path to get point along the curve
|
|
137
138
|
const pathLength = pathRef.current.getTotalLength();
|
|
138
|
-
const progress =
|
|
139
|
+
const progress =
|
|
140
|
+
animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
|
|
139
141
|
const distance = pathLength * progress;
|
|
140
142
|
const point = pathRef.current.getPointAtLength(distance);
|
|
141
143
|
|
|
@@ -19,12 +19,8 @@ export interface GenericEdgeProps {
|
|
|
19
19
|
* Generic edge renderer that adapts based on EdgeTypeDefinition
|
|
20
20
|
* TODO: Implement different styles, animations, and labels
|
|
21
21
|
*/
|
|
22
|
-
export const GenericEdge: React.FC<GenericEdgeProps> = ({
|
|
23
|
-
|
|
24
|
-
typeDefinition,
|
|
25
|
-
hasViolations,
|
|
26
|
-
}) => {
|
|
27
|
-
const color = hasViolations ? 'red' : (typeDefinition.color || '#888');
|
|
22
|
+
export const GenericEdge: React.FC<GenericEdgeProps> = ({ id, typeDefinition, hasViolations }) => {
|
|
23
|
+
const color = hasViolations ? 'red' : typeDefinition.color || '#888';
|
|
28
24
|
|
|
29
25
|
return (
|
|
30
26
|
<div>
|