@principal-ai/principal-view-react 0.6.10 → 0.6.12
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 +1 -0
- package/dist/edges/CustomEdge.d.ts.map +1 -1
- package/dist/edges/CustomEdge.js +18 -4
- 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 +62 -45
- 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 +47 -19
- 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 +40 -7
- 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 +137 -109
- package/src/nodes/GenericNode.tsx +4 -3
- package/src/stories/AnimationWorkshop.stories.tsx +131 -12
- package/src/stories/CanvasEdgeTypes.stories.tsx +980 -0
- 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 +61 -21
- package/src/utils/iconResolver.tsx +5 -1
|
@@ -13,7 +13,7 @@ import type { LogLevel } from '@principal-ai/principal-view-core';
|
|
|
13
13
|
export interface NodeAnimation {
|
|
14
14
|
type: 'pulse' | 'flash' | 'shake' | 'entry';
|
|
15
15
|
duration: number;
|
|
16
|
-
intensity?: number;
|
|
16
|
+
intensity?: number; // 0-1 scale
|
|
17
17
|
color?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -43,7 +43,7 @@ export function logLevelToNodeAnimation(level: LogLevel): NodeAnimation {
|
|
|
43
43
|
type: 'pulse',
|
|
44
44
|
duration: 800,
|
|
45
45
|
intensity: 0.3,
|
|
46
|
-
color: '#94a3b8' // slate-400
|
|
46
|
+
color: '#94a3b8', // slate-400
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
case 'info':
|
|
@@ -51,7 +51,7 @@ export function logLevelToNodeAnimation(level: LogLevel): NodeAnimation {
|
|
|
51
51
|
type: 'pulse',
|
|
52
52
|
duration: 1000,
|
|
53
53
|
intensity: 0.5,
|
|
54
|
-
color: '#3b82f6' // blue-500
|
|
54
|
+
color: '#3b82f6', // blue-500
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
case 'warn':
|
|
@@ -59,7 +59,7 @@ export function logLevelToNodeAnimation(level: LogLevel): NodeAnimation {
|
|
|
59
59
|
type: 'pulse',
|
|
60
60
|
duration: 1200,
|
|
61
61
|
intensity: 1.0,
|
|
62
|
-
color: '#f59e0b' // amber-500
|
|
62
|
+
color: '#f59e0b', // amber-500
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
case 'error':
|
|
@@ -67,7 +67,7 @@ export function logLevelToNodeAnimation(level: LogLevel): NodeAnimation {
|
|
|
67
67
|
type: 'flash', // More dramatic animation for errors
|
|
68
68
|
duration: 1500,
|
|
69
69
|
intensity: 1.0,
|
|
70
|
-
color: '#ef4444' // red-500
|
|
70
|
+
color: '#ef4444', // red-500
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
}
|
|
@@ -75,10 +75,7 @@ export function logLevelToNodeAnimation(level: LogLevel): NodeAnimation {
|
|
|
75
75
|
/**
|
|
76
76
|
* Map component action to node animation (Milestone 2)
|
|
77
77
|
*/
|
|
78
|
-
export function actionToNodeAnimation(
|
|
79
|
-
_action: string,
|
|
80
|
-
state?: string
|
|
81
|
-
): NodeAnimation {
|
|
78
|
+
export function actionToNodeAnimation(_action: string, state?: string): NodeAnimation {
|
|
82
79
|
// Default mapping - can be overridden by configuration
|
|
83
80
|
switch (state) {
|
|
84
81
|
case 'acquired':
|
|
@@ -88,7 +85,7 @@ export function actionToNodeAnimation(
|
|
|
88
85
|
type: 'pulse',
|
|
89
86
|
duration: 1000,
|
|
90
87
|
intensity: 0.8,
|
|
91
|
-
color: '#22c55e' // green-500
|
|
88
|
+
color: '#22c55e', // green-500
|
|
92
89
|
};
|
|
93
90
|
|
|
94
91
|
case 'waiting':
|
|
@@ -97,7 +94,7 @@ export function actionToNodeAnimation(
|
|
|
97
94
|
type: 'pulse',
|
|
98
95
|
duration: 1500,
|
|
99
96
|
intensity: 0.5,
|
|
100
|
-
color: '#eab308' // yellow-500
|
|
97
|
+
color: '#eab308', // yellow-500
|
|
101
98
|
};
|
|
102
99
|
|
|
103
100
|
case 'error':
|
|
@@ -106,7 +103,7 @@ export function actionToNodeAnimation(
|
|
|
106
103
|
type: 'shake',
|
|
107
104
|
duration: 600,
|
|
108
105
|
intensity: 1.0,
|
|
109
|
-
color: '#ef4444' // red-500
|
|
106
|
+
color: '#ef4444', // red-500
|
|
110
107
|
};
|
|
111
108
|
|
|
112
109
|
case 'completed':
|
|
@@ -115,7 +112,7 @@ export function actionToNodeAnimation(
|
|
|
115
112
|
type: 'flash',
|
|
116
113
|
duration: 800,
|
|
117
114
|
intensity: 0.7,
|
|
118
|
-
color: '#22c55e' // green-500
|
|
115
|
+
color: '#22c55e', // green-500
|
|
119
116
|
};
|
|
120
117
|
|
|
121
118
|
default:
|
|
@@ -124,7 +121,7 @@ export function actionToNodeAnimation(
|
|
|
124
121
|
type: 'pulse',
|
|
125
122
|
duration: 1000,
|
|
126
123
|
intensity: 0.6,
|
|
127
|
-
color: '#3b82f6' // blue-500
|
|
124
|
+
color: '#3b82f6', // blue-500
|
|
128
125
|
};
|
|
129
126
|
}
|
|
130
127
|
}
|
|
@@ -132,16 +129,15 @@ export function actionToNodeAnimation(
|
|
|
132
129
|
/**
|
|
133
130
|
* Get animation config for edge based on action (Milestone 2)
|
|
134
131
|
*/
|
|
135
|
-
export function actionToEdgeAnimation(
|
|
136
|
-
_action: string,
|
|
137
|
-
edgeConfig?: EdgeAnimation
|
|
138
|
-
): EdgeAnimation {
|
|
132
|
+
export function actionToEdgeAnimation(_action: string, edgeConfig?: EdgeAnimation): EdgeAnimation {
|
|
139
133
|
// Use edge config if provided, otherwise default
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
return (
|
|
135
|
+
edgeConfig || {
|
|
136
|
+
type: 'flow',
|
|
137
|
+
duration: 2000,
|
|
138
|
+
direction: 'forward',
|
|
139
|
+
}
|
|
140
|
+
);
|
|
145
141
|
}
|
|
146
142
|
|
|
147
143
|
/**
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { MarkerType, type Node, type Edge } from '@xyflow/react';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
NodeState,
|
|
4
|
+
EdgeState,
|
|
5
|
+
GraphConfiguration,
|
|
6
|
+
Violation,
|
|
7
|
+
} from '@principal-ai/principal-view-core';
|
|
3
8
|
import type { CustomNodeData } from '../nodes/CustomNode';
|
|
4
9
|
import type { CustomEdgeData } from '../edges/CustomEdge';
|
|
5
10
|
|
|
@@ -19,14 +24,19 @@ export function convertToXYFlowNodes(
|
|
|
19
24
|
console.warn(`Node type "${node.type}" not found in configuration for node "${node.id}"`);
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
const hasViolations = violations.some(v => v.context?.nodeId === node.id);
|
|
27
|
+
const hasViolations = violations.some((v) => v.context?.nodeId === node.id);
|
|
28
|
+
|
|
29
|
+
// Groups should render behind other nodes and edges
|
|
30
|
+
const isGroup = node.data?.canvasType === 'group';
|
|
23
31
|
|
|
24
32
|
return {
|
|
25
33
|
id: node.id,
|
|
26
34
|
type: 'custom',
|
|
27
35
|
position: node.position || { x: 0, y: 0 },
|
|
36
|
+
// Groups have lower zIndex to render behind edges
|
|
37
|
+
zIndex: isGroup ? -1 : undefined,
|
|
28
38
|
data: {
|
|
29
|
-
name:
|
|
39
|
+
name: node.name || node.id,
|
|
30
40
|
typeDefinition,
|
|
31
41
|
state: node.state,
|
|
32
42
|
hasViolations,
|
|
@@ -42,6 +52,23 @@ export interface EdgeStateWithHandles extends EdgeState {
|
|
|
42
52
|
targetHandle?: string;
|
|
43
53
|
}
|
|
44
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Map canvas side to source handle ID
|
|
57
|
+
* Source handles use '-out' suffix
|
|
58
|
+
*/
|
|
59
|
+
function sideToSourceHandle(side?: string): string | undefined {
|
|
60
|
+
if (!side) return undefined;
|
|
61
|
+
return `${side}-out`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Map canvas side to target handle ID
|
|
66
|
+
* Target handles use the side name directly
|
|
67
|
+
*/
|
|
68
|
+
function sideToTargetHandle(side?: string): string | undefined {
|
|
69
|
+
return side;
|
|
70
|
+
}
|
|
71
|
+
|
|
45
72
|
/**
|
|
46
73
|
* Convert our EdgeState to xyflow Edge format
|
|
47
74
|
*/
|
|
@@ -58,25 +85,34 @@ export function convertToXYFlowEdges(
|
|
|
58
85
|
console.warn(`Edge type "${edge.type}" not found in configuration for edge "${edge.id}"`);
|
|
59
86
|
}
|
|
60
87
|
|
|
61
|
-
const hasViolations = violations.some(v => v.context?.edgeId === edge.id);
|
|
88
|
+
const hasViolations = violations.some((v) => v.context?.edgeId === edge.id);
|
|
62
89
|
const edgeWithHandles = edge as EdgeStateWithHandles;
|
|
63
90
|
|
|
91
|
+
// Get handle IDs from edge data (fromSide/toSide) or explicit handles
|
|
92
|
+
const fromSide = edge.data?.fromSide as string | undefined;
|
|
93
|
+
const toSide = edge.data?.toSide as string | undefined;
|
|
94
|
+
const sourceHandle = edgeWithHandles.sourceHandle || sideToSourceHandle(fromSide);
|
|
95
|
+
const targetHandle = edgeWithHandles.targetHandle || sideToTargetHandle(toSide);
|
|
96
|
+
|
|
64
97
|
// Add arrow marker if edge type is directed
|
|
65
98
|
// Color priority: edge data color > type definition color > default
|
|
66
99
|
const edgeColor = edge.data?.color as string | undefined;
|
|
67
|
-
const markerEnd =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
100
|
+
const markerEnd =
|
|
101
|
+
typeDefinition?.directed !== false
|
|
102
|
+
? {
|
|
103
|
+
type: MarkerType.ArrowClosed,
|
|
104
|
+
color: edgeColor || typeDefinition?.color || '#888',
|
|
105
|
+
width: 20,
|
|
106
|
+
height: 20,
|
|
107
|
+
}
|
|
108
|
+
: undefined;
|
|
73
109
|
|
|
74
110
|
return {
|
|
75
111
|
id: edge.id,
|
|
76
112
|
source: edge.from,
|
|
77
113
|
target: edge.to,
|
|
78
|
-
sourceHandle
|
|
79
|
-
targetHandle
|
|
114
|
+
sourceHandle,
|
|
115
|
+
targetHandle,
|
|
80
116
|
type: 'custom',
|
|
81
117
|
animated: typeDefinition?.style === 'animated',
|
|
82
118
|
markerEnd,
|
|
@@ -84,6 +120,7 @@ export function convertToXYFlowEdges(
|
|
|
84
120
|
typeDefinition,
|
|
85
121
|
hasViolations,
|
|
86
122
|
data: edge.data,
|
|
123
|
+
edgeType: edge.type,
|
|
87
124
|
},
|
|
88
125
|
};
|
|
89
126
|
});
|
|
@@ -98,7 +135,7 @@ export function autoLayoutNodes<T extends Record<string, unknown>>(
|
|
|
98
135
|
layoutType: 'hierarchical' | 'force-directed' | 'circular' | 'manual' = 'hierarchical'
|
|
99
136
|
): Node<T>[] {
|
|
100
137
|
// Skip if all nodes have positions
|
|
101
|
-
const hasPositions = nodes.every(n => n.position.x !== 0 || n.position.y !== 0);
|
|
138
|
+
const hasPositions = nodes.every((n) => n.position.x !== 0 || n.position.y !== 0);
|
|
102
139
|
if (hasPositions || layoutType === 'manual') {
|
|
103
140
|
return nodes;
|
|
104
141
|
}
|
|
@@ -120,17 +157,20 @@ export function autoLayoutNodes<T extends Record<string, unknown>>(
|
|
|
120
157
|
/**
|
|
121
158
|
* Simple hierarchical layout algorithm
|
|
122
159
|
*/
|
|
123
|
-
function applyHierarchicalLayout<T extends Record<string, unknown>>(
|
|
160
|
+
function applyHierarchicalLayout<T extends Record<string, unknown>>(
|
|
161
|
+
nodes: Node<T>[],
|
|
162
|
+
edges: Edge[]
|
|
163
|
+
): Node<T>[] {
|
|
124
164
|
// Build adjacency list
|
|
125
165
|
const adjacency = new Map<string, string[]>();
|
|
126
166
|
const inDegree = new Map<string, number>();
|
|
127
167
|
|
|
128
|
-
nodes.forEach(node => {
|
|
168
|
+
nodes.forEach((node) => {
|
|
129
169
|
adjacency.set(node.id, []);
|
|
130
170
|
inDegree.set(node.id, 0);
|
|
131
171
|
});
|
|
132
172
|
|
|
133
|
-
edges.forEach(edge => {
|
|
173
|
+
edges.forEach((edge) => {
|
|
134
174
|
const targets = adjacency.get(edge.source) || [];
|
|
135
175
|
targets.push(edge.target);
|
|
136
176
|
adjacency.set(edge.source, targets);
|
|
@@ -160,7 +200,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
160
200
|
visited.add(nodeId);
|
|
161
201
|
|
|
162
202
|
const neighbors = adjacency.get(nodeId) || [];
|
|
163
|
-
neighbors.forEach(neighbor => {
|
|
203
|
+
neighbors.forEach((neighbor) => {
|
|
164
204
|
const degree = inDegree.get(neighbor)! - 1;
|
|
165
205
|
inDegree.set(neighbor, degree);
|
|
166
206
|
if (degree === 0 && !visited.has(neighbor)) {
|
|
@@ -175,7 +215,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
175
215
|
}
|
|
176
216
|
|
|
177
217
|
// Handle any remaining nodes (cycles or disconnected)
|
|
178
|
-
const remainingNodes = nodes.filter(n => !visited.has(n.id)).map(n => n.id);
|
|
218
|
+
const remainingNodes = nodes.filter((n) => !visited.has(n.id)).map((n) => n.id);
|
|
179
219
|
if (remainingNodes.length > 0) {
|
|
180
220
|
layers.push(remainingNodes);
|
|
181
221
|
}
|
|
@@ -184,8 +224,8 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
184
224
|
const LAYER_HEIGHT = 150;
|
|
185
225
|
const NODE_WIDTH = 200;
|
|
186
226
|
|
|
187
|
-
return nodes.map(node => {
|
|
188
|
-
const layerIndex = layers.findIndex(layer => layer.includes(node.id));
|
|
227
|
+
return nodes.map((node) => {
|
|
228
|
+
const layerIndex = layers.findIndex((layer) => layer.includes(node.id));
|
|
189
229
|
const layer = layers[layerIndex] || [];
|
|
190
230
|
const positionInLayer = layer.indexOf(node.id);
|
|
191
231
|
const layerWidth = layer.length * NODE_WIDTH;
|
|
@@ -193,7 +233,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
193
233
|
return {
|
|
194
234
|
...node,
|
|
195
235
|
position: {
|
|
196
|
-
x:
|
|
236
|
+
x: positionInLayer * NODE_WIDTH + NODE_WIDTH / 2 - layerWidth / 2,
|
|
197
237
|
y: layerIndex * LAYER_HEIGHT,
|
|
198
238
|
},
|
|
199
239
|
};
|
|
@@ -38,7 +38,11 @@ export function resolveIcon(icon?: string, size: number = 20, className?: string
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Fall back to rendering as text (emoji or unicode)
|
|
41
|
-
return
|
|
41
|
+
return (
|
|
42
|
+
<span className={className} style={{ fontSize: `${size}px` }}>
|
|
43
|
+
{icon}
|
|
44
|
+
</span>
|
|
45
|
+
);
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
/**
|