@principal-ai/principal-view-react 0.6.6
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 +111 -0
- package/dist/components/ConfigurationSelector.d.ts +37 -0
- package/dist/components/ConfigurationSelector.d.ts.map +1 -0
- package/dist/components/ConfigurationSelector.js +67 -0
- package/dist/components/ConfigurationSelector.js.map +1 -0
- package/dist/components/EdgeInfoPanel.d.ts +16 -0
- package/dist/components/EdgeInfoPanel.d.ts.map +1 -0
- package/dist/components/EdgeInfoPanel.js +85 -0
- package/dist/components/EdgeInfoPanel.js.map +1 -0
- package/dist/components/EventLog.d.ts +20 -0
- package/dist/components/EventLog.d.ts.map +1 -0
- package/dist/components/EventLog.js +13 -0
- package/dist/components/EventLog.js.map +1 -0
- package/dist/components/EventLog.test.d.ts +2 -0
- package/dist/components/EventLog.test.d.ts.map +1 -0
- package/dist/components/EventLog.test.js +73 -0
- package/dist/components/EventLog.test.js.map +1 -0
- package/dist/components/GraphRenderer.d.ts +121 -0
- package/dist/components/GraphRenderer.d.ts.map +1 -0
- package/dist/components/GraphRenderer.js +809 -0
- package/dist/components/GraphRenderer.js.map +1 -0
- package/dist/components/GraphRenderer.test.d.ts +2 -0
- package/dist/components/GraphRenderer.test.d.ts.map +1 -0
- package/dist/components/GraphRenderer.test.js +88 -0
- package/dist/components/GraphRenderer.test.js.map +1 -0
- package/dist/components/MetricsDashboard.d.ts +14 -0
- package/dist/components/MetricsDashboard.d.ts.map +1 -0
- package/dist/components/MetricsDashboard.js +13 -0
- package/dist/components/MetricsDashboard.js.map +1 -0
- package/dist/components/NodeInfoPanel.d.ts +21 -0
- package/dist/components/NodeInfoPanel.d.ts.map +1 -0
- package/dist/components/NodeInfoPanel.js +217 -0
- package/dist/components/NodeInfoPanel.js.map +1 -0
- package/dist/edges/CustomEdge.d.ts +16 -0
- package/dist/edges/CustomEdge.d.ts.map +1 -0
- package/dist/edges/CustomEdge.js +200 -0
- package/dist/edges/CustomEdge.js.map +1 -0
- package/dist/edges/GenericEdge.d.ts +18 -0
- package/dist/edges/GenericEdge.d.ts.map +1 -0
- package/dist/edges/GenericEdge.js +14 -0
- package/dist/edges/GenericEdge.js.map +1 -0
- package/dist/hooks/usePathBasedEvents.d.ts +42 -0
- package/dist/hooks/usePathBasedEvents.d.ts.map +1 -0
- package/dist/hooks/usePathBasedEvents.js +122 -0
- package/dist/hooks/usePathBasedEvents.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/CustomNode.d.ts +18 -0
- package/dist/nodes/CustomNode.d.ts.map +1 -0
- package/dist/nodes/CustomNode.js +298 -0
- package/dist/nodes/CustomNode.js.map +1 -0
- package/dist/nodes/GenericNode.d.ts +20 -0
- package/dist/nodes/GenericNode.d.ts.map +1 -0
- package/dist/nodes/GenericNode.js +24 -0
- package/dist/nodes/GenericNode.js.map +1 -0
- package/dist/utils/animationMapping.d.ts +53 -0
- package/dist/utils/animationMapping.d.ts.map +1 -0
- package/dist/utils/animationMapping.js +133 -0
- package/dist/utils/animationMapping.js.map +1 -0
- package/dist/utils/graphConverter.d.ts +22 -0
- package/dist/utils/graphConverter.d.ts.map +1 -0
- package/dist/utils/graphConverter.js +176 -0
- package/dist/utils/graphConverter.js.map +1 -0
- package/dist/utils/iconResolver.d.ts +29 -0
- package/dist/utils/iconResolver.d.ts.map +1 -0
- package/dist/utils/iconResolver.js +68 -0
- package/dist/utils/iconResolver.js.map +1 -0
- package/package.json +61 -0
- package/src/components/ConfigurationSelector.tsx +147 -0
- package/src/components/EdgeInfoPanel.tsx +198 -0
- package/src/components/EventLog.test.tsx +85 -0
- package/src/components/EventLog.tsx +51 -0
- package/src/components/GraphRenderer.test.tsx +118 -0
- package/src/components/GraphRenderer.tsx +1222 -0
- package/src/components/MetricsDashboard.tsx +40 -0
- package/src/components/NodeInfoPanel.tsx +425 -0
- package/src/edges/CustomEdge.tsx +344 -0
- package/src/edges/GenericEdge.tsx +40 -0
- package/src/hooks/usePathBasedEvents.ts +182 -0
- package/src/index.ts +67 -0
- package/src/nodes/CustomNode.tsx +432 -0
- package/src/nodes/GenericNode.tsx +54 -0
- package/src/stories/AnimationWorkshop.stories.tsx +608 -0
- package/src/stories/EventDrivenAnimations.stories.tsx +499 -0
- package/src/stories/EventLog.stories.tsx +161 -0
- package/src/stories/GraphRenderer.stories.tsx +628 -0
- package/src/stories/Introduction.mdx +51 -0
- package/src/stories/MetricsDashboard.stories.tsx +227 -0
- package/src/stories/MultiConfig.stories.tsx +531 -0
- package/src/stories/MultiDirectionalConnections.stories.tsx +345 -0
- package/src/stories/NodeShapes.stories.tsx +769 -0
- package/src/utils/animationMapping.ts +170 -0
- package/src/utils/graphConverter.ts +218 -0
- package/src/utils/iconResolver.tsx +49 -0
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { GraphRenderer } from '../components/GraphRenderer';
|
|
4
|
+
import type { GraphRendererHandle, PendingChanges } from '../components/GraphRenderer';
|
|
5
|
+
import type { ExtendedCanvas } from '@principal-ai/principal-view-core';
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'Components/GraphRenderer',
|
|
9
|
+
component: GraphRenderer,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'centered',
|
|
12
|
+
},
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
} satisfies Meta<typeof GraphRenderer>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
type Story = StoryObj<typeof meta>;
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Sample Canvas Documents
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Basic canvas with process and data nodes
|
|
25
|
+
*/
|
|
26
|
+
const sampleCanvas: ExtendedCanvas = {
|
|
27
|
+
nodes: [
|
|
28
|
+
{
|
|
29
|
+
id: 'node-1',
|
|
30
|
+
type: 'text',
|
|
31
|
+
x: 100,
|
|
32
|
+
y: 100,
|
|
33
|
+
width: 140,
|
|
34
|
+
height: 70,
|
|
35
|
+
text: 'Input Processor',
|
|
36
|
+
color: '#4A90E2',
|
|
37
|
+
vv: {
|
|
38
|
+
nodeType: 'process',
|
|
39
|
+
shape: 'rectangle',
|
|
40
|
+
icon: 'Settings',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'node-2',
|
|
45
|
+
type: 'text',
|
|
46
|
+
x: 300,
|
|
47
|
+
y: 100,
|
|
48
|
+
width: 100,
|
|
49
|
+
height: 100,
|
|
50
|
+
text: 'Database',
|
|
51
|
+
color: '#7B68EE',
|
|
52
|
+
vv: {
|
|
53
|
+
nodeType: 'data',
|
|
54
|
+
shape: 'circle',
|
|
55
|
+
icon: 'Database',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'node-3',
|
|
60
|
+
type: 'text',
|
|
61
|
+
x: 500,
|
|
62
|
+
y: 100,
|
|
63
|
+
width: 140,
|
|
64
|
+
height: 70,
|
|
65
|
+
text: 'Output Handler',
|
|
66
|
+
color: '#4A90E2',
|
|
67
|
+
vv: {
|
|
68
|
+
nodeType: 'process',
|
|
69
|
+
shape: 'rectangle',
|
|
70
|
+
icon: 'Settings',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
edges: [
|
|
75
|
+
{
|
|
76
|
+
id: 'edge-1',
|
|
77
|
+
fromNode: 'node-1',
|
|
78
|
+
toNode: 'node-2',
|
|
79
|
+
vv: { edgeType: 'dataflow' },
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: 'edge-2',
|
|
83
|
+
fromNode: 'node-2',
|
|
84
|
+
toNode: 'node-3',
|
|
85
|
+
vv: { edgeType: 'dataflow' },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
vv: {
|
|
89
|
+
version: '1.0.0',
|
|
90
|
+
name: 'Sample Validation Graph',
|
|
91
|
+
description: 'Example graph configuration',
|
|
92
|
+
edgeTypes: {
|
|
93
|
+
dataflow: {
|
|
94
|
+
style: 'solid',
|
|
95
|
+
color: '#50E3C2',
|
|
96
|
+
directed: true,
|
|
97
|
+
},
|
|
98
|
+
dependency: {
|
|
99
|
+
style: 'dashed',
|
|
100
|
+
color: '#F5A623',
|
|
101
|
+
directed: true,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Empty canvas
|
|
109
|
+
*/
|
|
110
|
+
const emptyCanvas: ExtendedCanvas = {
|
|
111
|
+
nodes: [],
|
|
112
|
+
edges: [],
|
|
113
|
+
vv: {
|
|
114
|
+
version: '1.0.0',
|
|
115
|
+
name: 'Empty Graph',
|
|
116
|
+
edgeTypes: {},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Single node canvas
|
|
122
|
+
*/
|
|
123
|
+
const singleNodeCanvas: ExtendedCanvas = {
|
|
124
|
+
nodes: [
|
|
125
|
+
{
|
|
126
|
+
id: 'node-1',
|
|
127
|
+
type: 'text',
|
|
128
|
+
x: 100,
|
|
129
|
+
y: 100,
|
|
130
|
+
width: 140,
|
|
131
|
+
height: 70,
|
|
132
|
+
text: 'Input Processor',
|
|
133
|
+
color: '#4A90E2',
|
|
134
|
+
vv: {
|
|
135
|
+
nodeType: 'process',
|
|
136
|
+
shape: 'rectangle',
|
|
137
|
+
icon: 'Settings',
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
edges: [],
|
|
142
|
+
vv: {
|
|
143
|
+
version: '1.0.0',
|
|
144
|
+
name: 'Single Node',
|
|
145
|
+
edgeTypes: {},
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Larger canvas with more nodes
|
|
151
|
+
*/
|
|
152
|
+
const largeCanvas: ExtendedCanvas = {
|
|
153
|
+
nodes: [
|
|
154
|
+
{
|
|
155
|
+
id: 'node-1',
|
|
156
|
+
type: 'text',
|
|
157
|
+
x: 100,
|
|
158
|
+
y: 100,
|
|
159
|
+
width: 140,
|
|
160
|
+
height: 70,
|
|
161
|
+
text: 'Input Processor',
|
|
162
|
+
color: '#4A90E2',
|
|
163
|
+
vv: {
|
|
164
|
+
nodeType: 'process',
|
|
165
|
+
shape: 'rectangle',
|
|
166
|
+
icon: 'Settings',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
id: 'node-2',
|
|
171
|
+
type: 'text',
|
|
172
|
+
x: 300,
|
|
173
|
+
y: 100,
|
|
174
|
+
width: 100,
|
|
175
|
+
height: 100,
|
|
176
|
+
text: 'Database',
|
|
177
|
+
color: '#7B68EE',
|
|
178
|
+
vv: {
|
|
179
|
+
nodeType: 'data',
|
|
180
|
+
shape: 'circle',
|
|
181
|
+
icon: 'Database',
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'node-3',
|
|
186
|
+
type: 'text',
|
|
187
|
+
x: 500,
|
|
188
|
+
y: 100,
|
|
189
|
+
width: 140,
|
|
190
|
+
height: 70,
|
|
191
|
+
text: 'Output Handler',
|
|
192
|
+
color: '#4A90E2',
|
|
193
|
+
vv: {
|
|
194
|
+
nodeType: 'process',
|
|
195
|
+
shape: 'rectangle',
|
|
196
|
+
icon: 'Settings',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: 'node-4',
|
|
201
|
+
type: 'text',
|
|
202
|
+
x: 200,
|
|
203
|
+
y: 250,
|
|
204
|
+
width: 140,
|
|
205
|
+
height: 70,
|
|
206
|
+
text: 'Validator',
|
|
207
|
+
color: '#4A90E2',
|
|
208
|
+
vv: {
|
|
209
|
+
nodeType: 'process',
|
|
210
|
+
shape: 'rectangle',
|
|
211
|
+
icon: 'Check',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: 'node-5',
|
|
216
|
+
type: 'text',
|
|
217
|
+
x: 400,
|
|
218
|
+
y: 250,
|
|
219
|
+
width: 100,
|
|
220
|
+
height: 100,
|
|
221
|
+
text: 'Cache',
|
|
222
|
+
color: '#7B68EE',
|
|
223
|
+
vv: {
|
|
224
|
+
nodeType: 'data',
|
|
225
|
+
shape: 'circle',
|
|
226
|
+
icon: 'Zap',
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
edges: [
|
|
231
|
+
{
|
|
232
|
+
id: 'edge-1',
|
|
233
|
+
fromNode: 'node-1',
|
|
234
|
+
toNode: 'node-2',
|
|
235
|
+
vv: { edgeType: 'dataflow' },
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: 'edge-2',
|
|
239
|
+
fromNode: 'node-2',
|
|
240
|
+
toNode: 'node-3',
|
|
241
|
+
vv: { edgeType: 'dataflow' },
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
id: 'edge-3',
|
|
245
|
+
fromNode: 'node-1',
|
|
246
|
+
toNode: 'node-4',
|
|
247
|
+
vv: { edgeType: 'dataflow' },
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
id: 'edge-4',
|
|
251
|
+
fromNode: 'node-4',
|
|
252
|
+
toNode: 'node-5',
|
|
253
|
+
vv: { edgeType: 'dataflow' },
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
vv: {
|
|
257
|
+
version: '1.0.0',
|
|
258
|
+
name: 'Large Graph',
|
|
259
|
+
edgeTypes: {
|
|
260
|
+
dataflow: {
|
|
261
|
+
style: 'solid',
|
|
262
|
+
color: '#50E3C2',
|
|
263
|
+
directed: true,
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Service architecture canvas (richer example)
|
|
271
|
+
*/
|
|
272
|
+
const serviceArchitectureCanvas: ExtendedCanvas = {
|
|
273
|
+
nodes: [
|
|
274
|
+
{
|
|
275
|
+
id: 'client',
|
|
276
|
+
type: 'text',
|
|
277
|
+
x: 100,
|
|
278
|
+
y: 200,
|
|
279
|
+
width: 120,
|
|
280
|
+
height: 120,
|
|
281
|
+
text: '# Client',
|
|
282
|
+
color: 5, // cyan preset
|
|
283
|
+
vv: {
|
|
284
|
+
nodeType: 'client',
|
|
285
|
+
shape: 'circle',
|
|
286
|
+
icon: 'user',
|
|
287
|
+
states: {
|
|
288
|
+
idle: { color: '#94a3b8', icon: 'user' },
|
|
289
|
+
connected: { color: '#22c55e', icon: 'user-check' },
|
|
290
|
+
error: { color: '#ef4444', icon: 'user-x' },
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: 'api-server',
|
|
296
|
+
type: 'text',
|
|
297
|
+
x: 350,
|
|
298
|
+
y: 180,
|
|
299
|
+
width: 200,
|
|
300
|
+
height: 140,
|
|
301
|
+
text: '# API Server\n\nHandles REST endpoints',
|
|
302
|
+
color: 6, // purple preset
|
|
303
|
+
vv: {
|
|
304
|
+
nodeType: 'api-server',
|
|
305
|
+
shape: 'rectangle',
|
|
306
|
+
icon: 'server',
|
|
307
|
+
states: {
|
|
308
|
+
idle: { color: '#94a3b8' },
|
|
309
|
+
processing: { color: '#3b82f6' },
|
|
310
|
+
error: { color: '#ef4444' },
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
id: 'database',
|
|
316
|
+
type: 'text',
|
|
317
|
+
x: 620,
|
|
318
|
+
y: 200,
|
|
319
|
+
width: 150,
|
|
320
|
+
height: 100,
|
|
321
|
+
text: '# Database',
|
|
322
|
+
color: 4, // green preset
|
|
323
|
+
vv: {
|
|
324
|
+
nodeType: 'database',
|
|
325
|
+
shape: 'hexagon',
|
|
326
|
+
icon: 'database',
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: 'cache',
|
|
331
|
+
type: 'text',
|
|
332
|
+
x: 350,
|
|
333
|
+
y: 380,
|
|
334
|
+
width: 140,
|
|
335
|
+
height: 80,
|
|
336
|
+
text: '# Cache',
|
|
337
|
+
color: 2, // orange preset
|
|
338
|
+
vv: {
|
|
339
|
+
nodeType: 'cache',
|
|
340
|
+
shape: 'diamond',
|
|
341
|
+
icon: 'zap',
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
edges: [
|
|
346
|
+
{
|
|
347
|
+
id: 'client-to-api',
|
|
348
|
+
fromNode: 'client',
|
|
349
|
+
toNode: 'api-server',
|
|
350
|
+
fromSide: 'right',
|
|
351
|
+
toSide: 'left',
|
|
352
|
+
label: 'HTTP',
|
|
353
|
+
vv: {
|
|
354
|
+
edgeType: 'http-request',
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: 'api-to-db',
|
|
359
|
+
fromNode: 'api-server',
|
|
360
|
+
toNode: 'database',
|
|
361
|
+
fromSide: 'right',
|
|
362
|
+
toSide: 'left',
|
|
363
|
+
label: 'SQL',
|
|
364
|
+
vv: {
|
|
365
|
+
edgeType: 'db-query',
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
id: 'api-to-cache',
|
|
370
|
+
fromNode: 'api-server',
|
|
371
|
+
toNode: 'cache',
|
|
372
|
+
fromSide: 'bottom',
|
|
373
|
+
toSide: 'top',
|
|
374
|
+
label: 'GET/SET',
|
|
375
|
+
vv: {
|
|
376
|
+
edgeType: 'cache-access',
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
vv: {
|
|
381
|
+
version: '1.0.0',
|
|
382
|
+
name: 'Simple Service Architecture',
|
|
383
|
+
description: 'A basic client-server architecture with caching',
|
|
384
|
+
edgeTypes: {
|
|
385
|
+
'http-request': {
|
|
386
|
+
style: 'solid',
|
|
387
|
+
color: '#3b82f6',
|
|
388
|
+
width: 3,
|
|
389
|
+
directed: true,
|
|
390
|
+
animation: {
|
|
391
|
+
type: 'flow',
|
|
392
|
+
duration: 1500,
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
'db-query': {
|
|
396
|
+
style: 'dashed',
|
|
397
|
+
color: '#22c55e',
|
|
398
|
+
width: 2,
|
|
399
|
+
directed: true,
|
|
400
|
+
},
|
|
401
|
+
'cache-access': {
|
|
402
|
+
style: 'dotted',
|
|
403
|
+
color: '#f97316',
|
|
404
|
+
width: 2,
|
|
405
|
+
directed: true,
|
|
406
|
+
animation: {
|
|
407
|
+
type: 'pulse',
|
|
408
|
+
duration: 1000,
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
display: {
|
|
413
|
+
layout: 'manual',
|
|
414
|
+
animations: {
|
|
415
|
+
enabled: true,
|
|
416
|
+
speed: 1.0,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
// ============================================================================
|
|
423
|
+
// Stories
|
|
424
|
+
// ============================================================================
|
|
425
|
+
|
|
426
|
+
export const Default: Story = {
|
|
427
|
+
args: {
|
|
428
|
+
canvas: sampleCanvas,
|
|
429
|
+
width: 800,
|
|
430
|
+
height: 600,
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
export const EmptyGraph: Story = {
|
|
435
|
+
args: {
|
|
436
|
+
canvas: emptyCanvas,
|
|
437
|
+
width: 800,
|
|
438
|
+
height: 600,
|
|
439
|
+
},
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
export const SingleNode: Story = {
|
|
443
|
+
args: {
|
|
444
|
+
canvas: singleNodeCanvas,
|
|
445
|
+
width: 800,
|
|
446
|
+
height: 600,
|
|
447
|
+
},
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
export const LargeGraph: Story = {
|
|
451
|
+
args: {
|
|
452
|
+
canvas: largeCanvas,
|
|
453
|
+
width: 800,
|
|
454
|
+
height: 600,
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
export const ServiceArchitecture: Story = {
|
|
459
|
+
args: {
|
|
460
|
+
canvas: serviceArchitectureCanvas,
|
|
461
|
+
width: 900,
|
|
462
|
+
height: 600,
|
|
463
|
+
},
|
|
464
|
+
parameters: {
|
|
465
|
+
docs: {
|
|
466
|
+
description: {
|
|
467
|
+
story: `
|
|
468
|
+
**Service Architecture** - A realistic example showing:
|
|
469
|
+
- Multiple node shapes (circle, rectangle, hexagon, diamond)
|
|
470
|
+
- Edge types with different styles (solid, dashed, dotted)
|
|
471
|
+
- Edge animations (flow, pulse)
|
|
472
|
+
- State definitions for dynamic coloring
|
|
473
|
+
`,
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
// Interactive story with editable mode
|
|
480
|
+
const EditableTemplate = () => {
|
|
481
|
+
const graphRef = React.useRef<GraphRendererHandle>(null);
|
|
482
|
+
const [hasChanges, setHasChanges] = React.useState(false);
|
|
483
|
+
const [lastSavedChanges, setLastSavedChanges] = React.useState<PendingChanges | null>(null);
|
|
484
|
+
|
|
485
|
+
const handleSave = () => {
|
|
486
|
+
const changes = graphRef.current?.getPendingChanges();
|
|
487
|
+
if (changes?.hasChanges) {
|
|
488
|
+
console.log('Saving changes:', changes);
|
|
489
|
+
setLastSavedChanges(changes);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
const handleReset = () => {
|
|
494
|
+
graphRef.current?.resetEditState();
|
|
495
|
+
setHasChanges(false);
|
|
496
|
+
setLastSavedChanges(null);
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<div>
|
|
501
|
+
<div style={{ marginBottom: 16, padding: 12, backgroundColor: '#f5f5f5', borderRadius: 4 }}>
|
|
502
|
+
<strong>Interactive Graph Editor</strong>
|
|
503
|
+
<div style={{ marginTop: 8, fontSize: 12, color: '#666' }}>
|
|
504
|
+
<ul style={{ margin: '4px 0', paddingLeft: 20 }}>
|
|
505
|
+
<li>Drag nodes to reposition them</li>
|
|
506
|
+
<li>Drag from a node handle to another node to create an edge</li>
|
|
507
|
+
<li>Click an edge to view info and delete it</li>
|
|
508
|
+
<li>Click a node to view info, edit name/type, or delete it</li>
|
|
509
|
+
</ul>
|
|
510
|
+
</div>
|
|
511
|
+
<div style={{ marginTop: 12, display: 'flex', gap: 8, alignItems: 'center' }}>
|
|
512
|
+
<button
|
|
513
|
+
onClick={handleSave}
|
|
514
|
+
disabled={!hasChanges}
|
|
515
|
+
style={{
|
|
516
|
+
padding: '6px 12px',
|
|
517
|
+
backgroundColor: hasChanges ? '#4A90E2' : '#ccc',
|
|
518
|
+
color: 'white',
|
|
519
|
+
border: 'none',
|
|
520
|
+
borderRadius: 4,
|
|
521
|
+
cursor: hasChanges ? 'pointer' : 'not-allowed',
|
|
522
|
+
}}
|
|
523
|
+
>
|
|
524
|
+
Save Changes
|
|
525
|
+
</button>
|
|
526
|
+
<button
|
|
527
|
+
onClick={handleReset}
|
|
528
|
+
style={{
|
|
529
|
+
padding: '6px 12px',
|
|
530
|
+
backgroundColor: '#f0f0f0',
|
|
531
|
+
color: '#333',
|
|
532
|
+
border: '1px solid #ccc',
|
|
533
|
+
borderRadius: 4,
|
|
534
|
+
cursor: 'pointer',
|
|
535
|
+
}}
|
|
536
|
+
>
|
|
537
|
+
Reset
|
|
538
|
+
</button>
|
|
539
|
+
{hasChanges && (
|
|
540
|
+
<span style={{ fontSize: 12, color: '#f5a623', fontStyle: 'italic' }}>Unsaved changes</span>
|
|
541
|
+
)}
|
|
542
|
+
</div>
|
|
543
|
+
{lastSavedChanges && (
|
|
544
|
+
<div style={{ marginTop: 12 }}>
|
|
545
|
+
<div style={{ fontSize: 11, fontWeight: 'bold', color: '#666' }}>Last saved changes:</div>
|
|
546
|
+
<pre
|
|
547
|
+
style={{
|
|
548
|
+
marginTop: 4,
|
|
549
|
+
fontSize: 10,
|
|
550
|
+
backgroundColor: '#fff',
|
|
551
|
+
padding: 8,
|
|
552
|
+
borderRadius: 4,
|
|
553
|
+
maxHeight: 150,
|
|
554
|
+
overflow: 'auto',
|
|
555
|
+
}}
|
|
556
|
+
>
|
|
557
|
+
{JSON.stringify(lastSavedChanges, null, 2)}
|
|
558
|
+
</pre>
|
|
559
|
+
</div>
|
|
560
|
+
)}
|
|
561
|
+
</div>
|
|
562
|
+
<GraphRenderer
|
|
563
|
+
ref={graphRef}
|
|
564
|
+
canvas={sampleCanvas}
|
|
565
|
+
width={800}
|
|
566
|
+
height={500}
|
|
567
|
+
editable={true}
|
|
568
|
+
onPendingChangesChange={setHasChanges}
|
|
569
|
+
/>
|
|
570
|
+
</div>
|
|
571
|
+
);
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
export const Editable: Story = {
|
|
575
|
+
render: () => <EditableTemplate />,
|
|
576
|
+
parameters: {
|
|
577
|
+
docs: {
|
|
578
|
+
description: {
|
|
579
|
+
story:
|
|
580
|
+
'Full editing mode with internal state management. Drag nodes, create/delete edges, delete nodes, and edit node properties. Changes are tracked internally and can be retrieved via the ref when saving.',
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
const ServiceArchitectureEditableTemplate = () => {
|
|
587
|
+
const graphRef = React.useRef<GraphRendererHandle>(null);
|
|
588
|
+
const [hasChanges, setHasChanges] = React.useState(false);
|
|
589
|
+
|
|
590
|
+
return (
|
|
591
|
+
<div>
|
|
592
|
+
<div
|
|
593
|
+
style={{
|
|
594
|
+
marginBottom: 16,
|
|
595
|
+
padding: 12,
|
|
596
|
+
backgroundColor: '#f0f9ff',
|
|
597
|
+
borderRadius: 4,
|
|
598
|
+
border: '1px solid #3b82f6',
|
|
599
|
+
}}
|
|
600
|
+
>
|
|
601
|
+
<strong style={{ color: '#1e40af' }}>Service Architecture + Editing</strong>
|
|
602
|
+
<div style={{ marginTop: 8, fontSize: 12, color: '#1e40af' }}>
|
|
603
|
+
This graph is rendered from an ExtendedCanvas document. You can edit it interactively.
|
|
604
|
+
{hasChanges && <span style={{ marginLeft: 8, color: '#f97316' }}>(unsaved changes)</span>}
|
|
605
|
+
</div>
|
|
606
|
+
</div>
|
|
607
|
+
<GraphRenderer
|
|
608
|
+
ref={graphRef}
|
|
609
|
+
canvas={serviceArchitectureCanvas}
|
|
610
|
+
width={900}
|
|
611
|
+
height={500}
|
|
612
|
+
editable={true}
|
|
613
|
+
onPendingChangesChange={setHasChanges}
|
|
614
|
+
/>
|
|
615
|
+
</div>
|
|
616
|
+
);
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
export const ServiceArchitectureEditable: Story = {
|
|
620
|
+
render: () => <ServiceArchitectureEditableTemplate />,
|
|
621
|
+
parameters: {
|
|
622
|
+
docs: {
|
|
623
|
+
description: {
|
|
624
|
+
story: 'Service architecture canvas with editing enabled. Edit nodes, create edges, and track changes.',
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Meta } from '@storybook/blocks';
|
|
2
|
+
|
|
3
|
+
<Meta title="Introduction" />
|
|
4
|
+
|
|
5
|
+
# Visual Validation React Library
|
|
6
|
+
|
|
7
|
+
Welcome to the Visual Validation React component library! This library provides UI building blocks for creating graph visualization panels for validation workflows.
|
|
8
|
+
|
|
9
|
+
## Components
|
|
10
|
+
|
|
11
|
+
### GraphRenderer
|
|
12
|
+
The core graph visualization component that displays nodes and edges based on your configuration.
|
|
13
|
+
|
|
14
|
+
- Configure node and edge types
|
|
15
|
+
- Define validation rules
|
|
16
|
+
- Visualize graph structures
|
|
17
|
+
|
|
18
|
+
### EventLog
|
|
19
|
+
Display a log of graph events with violation highlighting.
|
|
20
|
+
|
|
21
|
+
- Track all graph operations
|
|
22
|
+
- Highlight violations and warnings
|
|
23
|
+
- Filter and search events
|
|
24
|
+
|
|
25
|
+
### MetricsDashboard
|
|
26
|
+
Show metrics and statistics about your validation graph.
|
|
27
|
+
|
|
28
|
+
- Node and edge counts
|
|
29
|
+
- Event rates
|
|
30
|
+
- Validation health score
|
|
31
|
+
- Performance metrics
|
|
32
|
+
|
|
33
|
+
## Getting Started
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import {
|
|
37
|
+
GraphRenderer,
|
|
38
|
+
EventLog,
|
|
39
|
+
MetricsDashboard,
|
|
40
|
+
} from '@principal-ai/visual-validation-react';
|
|
41
|
+
|
|
42
|
+
// Use the components in your application
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
Browse the stories in the sidebar to see examples of each component with different configurations and states.
|
|
48
|
+
|
|
49
|
+
## Development Status
|
|
50
|
+
|
|
51
|
+
This library is currently in early development. Many components show placeholder UI with TODO items for planned features.
|