@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
|
@@ -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,
|
|
@@ -58,18 +68,21 @@ export function convertToXYFlowEdges(
|
|
|
58
68
|
console.warn(`Edge type "${edge.type}" not found in configuration for edge "${edge.id}"`);
|
|
59
69
|
}
|
|
60
70
|
|
|
61
|
-
const hasViolations = violations.some(v => v.context?.edgeId === edge.id);
|
|
71
|
+
const hasViolations = violations.some((v) => v.context?.edgeId === edge.id);
|
|
62
72
|
const edgeWithHandles = edge as EdgeStateWithHandles;
|
|
63
73
|
|
|
64
74
|
// Add arrow marker if edge type is directed
|
|
65
75
|
// Color priority: edge data color > type definition color > default
|
|
66
76
|
const edgeColor = edge.data?.color as string | undefined;
|
|
67
|
-
const markerEnd =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
const markerEnd =
|
|
78
|
+
typeDefinition?.directed !== false
|
|
79
|
+
? {
|
|
80
|
+
type: MarkerType.ArrowClosed,
|
|
81
|
+
color: edgeColor || typeDefinition?.color || '#888',
|
|
82
|
+
width: 20,
|
|
83
|
+
height: 20,
|
|
84
|
+
}
|
|
85
|
+
: undefined;
|
|
73
86
|
|
|
74
87
|
return {
|
|
75
88
|
id: edge.id,
|
|
@@ -98,7 +111,7 @@ export function autoLayoutNodes<T extends Record<string, unknown>>(
|
|
|
98
111
|
layoutType: 'hierarchical' | 'force-directed' | 'circular' | 'manual' = 'hierarchical'
|
|
99
112
|
): Node<T>[] {
|
|
100
113
|
// Skip if all nodes have positions
|
|
101
|
-
const hasPositions = nodes.every(n => n.position.x !== 0 || n.position.y !== 0);
|
|
114
|
+
const hasPositions = nodes.every((n) => n.position.x !== 0 || n.position.y !== 0);
|
|
102
115
|
if (hasPositions || layoutType === 'manual') {
|
|
103
116
|
return nodes;
|
|
104
117
|
}
|
|
@@ -120,17 +133,20 @@ export function autoLayoutNodes<T extends Record<string, unknown>>(
|
|
|
120
133
|
/**
|
|
121
134
|
* Simple hierarchical layout algorithm
|
|
122
135
|
*/
|
|
123
|
-
function applyHierarchicalLayout<T extends Record<string, unknown>>(
|
|
136
|
+
function applyHierarchicalLayout<T extends Record<string, unknown>>(
|
|
137
|
+
nodes: Node<T>[],
|
|
138
|
+
edges: Edge[]
|
|
139
|
+
): Node<T>[] {
|
|
124
140
|
// Build adjacency list
|
|
125
141
|
const adjacency = new Map<string, string[]>();
|
|
126
142
|
const inDegree = new Map<string, number>();
|
|
127
143
|
|
|
128
|
-
nodes.forEach(node => {
|
|
144
|
+
nodes.forEach((node) => {
|
|
129
145
|
adjacency.set(node.id, []);
|
|
130
146
|
inDegree.set(node.id, 0);
|
|
131
147
|
});
|
|
132
148
|
|
|
133
|
-
edges.forEach(edge => {
|
|
149
|
+
edges.forEach((edge) => {
|
|
134
150
|
const targets = adjacency.get(edge.source) || [];
|
|
135
151
|
targets.push(edge.target);
|
|
136
152
|
adjacency.set(edge.source, targets);
|
|
@@ -160,7 +176,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
160
176
|
visited.add(nodeId);
|
|
161
177
|
|
|
162
178
|
const neighbors = adjacency.get(nodeId) || [];
|
|
163
|
-
neighbors.forEach(neighbor => {
|
|
179
|
+
neighbors.forEach((neighbor) => {
|
|
164
180
|
const degree = inDegree.get(neighbor)! - 1;
|
|
165
181
|
inDegree.set(neighbor, degree);
|
|
166
182
|
if (degree === 0 && !visited.has(neighbor)) {
|
|
@@ -175,7 +191,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
// Handle any remaining nodes (cycles or disconnected)
|
|
178
|
-
const remainingNodes = nodes.filter(n => !visited.has(n.id)).map(n => n.id);
|
|
194
|
+
const remainingNodes = nodes.filter((n) => !visited.has(n.id)).map((n) => n.id);
|
|
179
195
|
if (remainingNodes.length > 0) {
|
|
180
196
|
layers.push(remainingNodes);
|
|
181
197
|
}
|
|
@@ -184,8 +200,8 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
184
200
|
const LAYER_HEIGHT = 150;
|
|
185
201
|
const NODE_WIDTH = 200;
|
|
186
202
|
|
|
187
|
-
return nodes.map(node => {
|
|
188
|
-
const layerIndex = layers.findIndex(layer => layer.includes(node.id));
|
|
203
|
+
return nodes.map((node) => {
|
|
204
|
+
const layerIndex = layers.findIndex((layer) => layer.includes(node.id));
|
|
189
205
|
const layer = layers[layerIndex] || [];
|
|
190
206
|
const positionInLayer = layer.indexOf(node.id);
|
|
191
207
|
const layerWidth = layer.length * NODE_WIDTH;
|
|
@@ -193,7 +209,7 @@ function applyHierarchicalLayout<T extends Record<string, unknown>>(nodes: Node<
|
|
|
193
209
|
return {
|
|
194
210
|
...node,
|
|
195
211
|
position: {
|
|
196
|
-
x:
|
|
212
|
+
x: positionInLayer * NODE_WIDTH + NODE_WIDTH / 2 - layerWidth / 2,
|
|
197
213
|
y: layerIndex * LAYER_HEIGHT,
|
|
198
214
|
},
|
|
199
215
|
};
|
|
@@ -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
|
/**
|