@principal-ai/principal-view-react 0.7.10 → 0.7.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/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +16 -3
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/TestEventPanel.d.ts.map +1 -1
- package/dist/components/TestEventPanel.js +112 -65
- package/dist/components/TestEventPanel.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +17 -10
- package/dist/nodes/CustomNode.js.map +1 -1
- package/package.json +1 -1
- package/src/components/GraphRenderer.tsx +15 -3
- package/src/components/TestEventPanel.tsx +129 -56
- package/src/nodes/CustomNode.tsx +18 -10
- package/src/stories/MultiConfig.stories.tsx +1 -1
- package/src/stories/MultiDirectionalConnections.stories.tsx +0 -1
- package/src/stories/RealTestExecution.stories.tsx +11 -151
- package/src/stories/ValidatedExecution.stories.tsx +3 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
3
|
import { GraphRenderer } from '../components/GraphRenderer';
|
|
4
4
|
import { TestEventPanel } from '../components/TestEventPanel';
|
|
@@ -183,156 +183,18 @@ const testExecutionCanvas: ExtendedCanvas = {
|
|
|
183
183
|
};
|
|
184
184
|
|
|
185
185
|
// ============================================================================
|
|
186
|
-
//
|
|
187
|
-
// ============================================================================
|
|
188
|
-
|
|
189
|
-
function convertSpansToEvents(spans: typeof testSpans): GraphEvent[] {
|
|
190
|
-
const events: GraphEvent[] = [];
|
|
191
|
-
let time = 0;
|
|
192
|
-
|
|
193
|
-
spans.forEach((testSpan) => {
|
|
194
|
-
// Pulse test suite node at start of each test
|
|
195
|
-
events.push({
|
|
196
|
-
timestamp: time,
|
|
197
|
-
category: 'node',
|
|
198
|
-
operation: 'animate',
|
|
199
|
-
payload: {
|
|
200
|
-
nodeId: 'test-suite',
|
|
201
|
-
animation: { type: 'pulse', duration: 500 },
|
|
202
|
-
},
|
|
203
|
-
});
|
|
204
|
-
time += 600;
|
|
205
|
-
|
|
206
|
-
// Animate through events in the span
|
|
207
|
-
testSpan.events.forEach((event) => {
|
|
208
|
-
const eventName = event.name;
|
|
209
|
-
|
|
210
|
-
// Determine which phase based on event name
|
|
211
|
-
let nodeId = '';
|
|
212
|
-
let edgeId = '';
|
|
213
|
-
|
|
214
|
-
if (eventName.startsWith('setup.')) {
|
|
215
|
-
nodeId = 'setup-phase';
|
|
216
|
-
edgeId = 'suite-to-setup';
|
|
217
|
-
} else if (eventName.startsWith('execution.')) {
|
|
218
|
-
nodeId = 'execution-phase';
|
|
219
|
-
edgeId = 'setup-to-execution';
|
|
220
|
-
} else if (eventName.startsWith('assertion.')) {
|
|
221
|
-
nodeId = 'assertion-phase';
|
|
222
|
-
edgeId = 'execution-to-assertion';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// Animate edge when phase starts
|
|
226
|
-
if (eventName.endsWith('.started') && edgeId) {
|
|
227
|
-
events.push({
|
|
228
|
-
timestamp: time,
|
|
229
|
-
category: 'edge',
|
|
230
|
-
operation: 'animate',
|
|
231
|
-
payload: {
|
|
232
|
-
edgeId,
|
|
233
|
-
animation: { type: 'particle', duration: 500 },
|
|
234
|
-
},
|
|
235
|
-
});
|
|
236
|
-
time += 600;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// Pulse node
|
|
240
|
-
if (nodeId) {
|
|
241
|
-
events.push({
|
|
242
|
-
timestamp: time,
|
|
243
|
-
category: 'node',
|
|
244
|
-
operation: 'animate',
|
|
245
|
-
payload: {
|
|
246
|
-
nodeId,
|
|
247
|
-
animation: { type: 'pulse', duration: 600 },
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
time += 700;
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// Animate to result
|
|
255
|
-
events.push({
|
|
256
|
-
timestamp: time,
|
|
257
|
-
category: 'edge',
|
|
258
|
-
operation: 'animate',
|
|
259
|
-
payload: {
|
|
260
|
-
edgeId: 'assertion-to-result',
|
|
261
|
-
animation: { type: 'particle', duration: 500 },
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
time += 600;
|
|
265
|
-
|
|
266
|
-
events.push({
|
|
267
|
-
timestamp: time,
|
|
268
|
-
category: 'node',
|
|
269
|
-
operation: 'animate',
|
|
270
|
-
payload: {
|
|
271
|
-
nodeId: 'test-result',
|
|
272
|
-
animation: { type: 'pulse', duration: 800 },
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
time += 1200; // Pause between tests
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
return events;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// ============================================================================
|
|
282
|
-
// Animated Story
|
|
186
|
+
// Interactive Story (No Animation)
|
|
283
187
|
// ============================================================================
|
|
284
188
|
|
|
285
189
|
const AnimatedTestExecution = () => {
|
|
286
|
-
const [events
|
|
287
|
-
const [currentSpanIndex
|
|
288
|
-
|
|
190
|
+
const [events] = useState<GraphEvent[]>([]);
|
|
191
|
+
const [currentSpanIndex] = useState(0);
|
|
192
|
+
// Show all events by default - set to a large number
|
|
193
|
+
const [currentEventIndex] = useState(999);
|
|
289
194
|
const [highlightedPhase, setHighlightedPhase] = useState<string | undefined>();
|
|
290
195
|
|
|
291
|
-
useEffect(() => {
|
|
292
|
-
const graphEvents = convertSpansToEvents(testSpans);
|
|
293
|
-
const timers: NodeJS.Timeout[] = [];
|
|
294
|
-
|
|
295
|
-
let spanIndex = 0;
|
|
296
|
-
let eventIndex = 0;
|
|
297
|
-
let eventsPerTest = testSpans[0].events.length * 2 + 2; // ~2 graph events per span event + suite + result
|
|
298
|
-
|
|
299
|
-
graphEvents.forEach((event, index) => {
|
|
300
|
-
const timer = setTimeout(() => {
|
|
301
|
-
setEvents((prev) => [...prev, event]);
|
|
302
|
-
|
|
303
|
-
// Track which span and event we're on
|
|
304
|
-
spanIndex = Math.floor(index / eventsPerTest);
|
|
305
|
-
eventIndex = Math.floor((index % eventsPerTest) / 2);
|
|
306
|
-
|
|
307
|
-
setCurrentSpanIndex(Math.min(spanIndex, testSpans.length - 1));
|
|
308
|
-
setCurrentEventIndex(eventIndex);
|
|
309
|
-
}, event.timestamp);
|
|
310
|
-
timers.push(timer);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
// Reset animation
|
|
314
|
-
const resetTimer = setTimeout(() => {
|
|
315
|
-
setEvents([]);
|
|
316
|
-
setCurrentSpanIndex(0);
|
|
317
|
-
setCurrentEventIndex(0);
|
|
318
|
-
}, graphEvents[graphEvents.length - 1].timestamp + 2000);
|
|
319
|
-
|
|
320
|
-
return () => {
|
|
321
|
-
timers.forEach(clearTimeout);
|
|
322
|
-
clearTimeout(resetTimer);
|
|
323
|
-
};
|
|
324
|
-
}, []);
|
|
325
|
-
|
|
326
|
-
// Map node IDs to phase names
|
|
327
|
-
const getPhaseFromNodeId = (nodeId: string): string | undefined => {
|
|
328
|
-
if (nodeId === 'setup-phase') return 'setup';
|
|
329
|
-
if (nodeId === 'execution-phase') return 'execution';
|
|
330
|
-
if (nodeId === 'assertion-phase') return 'assertion';
|
|
331
|
-
return undefined;
|
|
332
|
-
};
|
|
333
|
-
|
|
334
196
|
return (
|
|
335
|
-
<div style={{ display: 'flex', width: '
|
|
197
|
+
<div style={{ display: 'flex', width: '100vw', height: '100vh' }}>
|
|
336
198
|
{/* Graph Visualization - Left Side */}
|
|
337
199
|
<div
|
|
338
200
|
style={{ flex: '0 0 60%', height: '100%', position: 'relative' }}
|
|
@@ -351,7 +213,6 @@ const AnimatedTestExecution = () => {
|
|
|
351
213
|
>
|
|
352
214
|
<GraphRenderer
|
|
353
215
|
canvas={testExecutionCanvas}
|
|
354
|
-
showMinimap={true}
|
|
355
216
|
showControls={true}
|
|
356
217
|
events={events}
|
|
357
218
|
/>
|
|
@@ -359,7 +220,7 @@ const AnimatedTestExecution = () => {
|
|
|
359
220
|
</div>
|
|
360
221
|
|
|
361
222
|
{/* Event Panel - Right Side */}
|
|
362
|
-
<div style={{ flex: '0 0 40%', height: '100%', borderLeft:
|
|
223
|
+
<div style={{ flex: '0 0 40%', height: '100%', borderLeft: `1px solid #333`, overflow: 'hidden' }}>
|
|
363
224
|
<TestEventPanel
|
|
364
225
|
spans={testSpans as any}
|
|
365
226
|
currentSpanIndex={currentSpanIndex}
|
|
@@ -372,7 +233,7 @@ const AnimatedTestExecution = () => {
|
|
|
372
233
|
};
|
|
373
234
|
|
|
374
235
|
/**
|
|
375
|
-
*
|
|
236
|
+
* Interactive visualization of real test execution data using the "wide event" pattern.
|
|
376
237
|
*
|
|
377
238
|
* This demonstrates the key concept from loggingsucks.com:
|
|
378
239
|
* - ONE comprehensive span per test (not multiple child spans)
|
|
@@ -383,7 +244,7 @@ const AnimatedTestExecution = () => {
|
|
|
383
244
|
* **Interaction:**
|
|
384
245
|
* - Hover over graph nodes (Setup, Execution, Assertion) to highlight related events
|
|
385
246
|
* - Watch the code journey: blue = test file, green = code under test
|
|
386
|
-
* -
|
|
247
|
+
* - All events are shown immediately for easy review
|
|
387
248
|
*/
|
|
388
249
|
export const Animated: Story = {
|
|
389
250
|
render: () => <AnimatedTestExecution />,
|
|
@@ -395,7 +256,6 @@ export const Animated: Story = {
|
|
|
395
256
|
export const StaticView: Story = {
|
|
396
257
|
args: {
|
|
397
258
|
canvas: testExecutionCanvas,
|
|
398
|
-
showMinimap: true,
|
|
399
259
|
showControls: true,
|
|
400
260
|
},
|
|
401
261
|
};
|
|
@@ -412,7 +272,7 @@ export const EventPanelOnly: StoryObj = {
|
|
|
412
272
|
<TestEventPanel
|
|
413
273
|
spans={testSpans as any}
|
|
414
274
|
currentSpanIndex={0}
|
|
415
|
-
currentEventIndex={
|
|
275
|
+
currentEventIndex={999} // Show all events
|
|
416
276
|
highlightedPhase={undefined}
|
|
417
277
|
/>
|
|
418
278
|
</div>
|
|
@@ -52,7 +52,6 @@ type Story = StoryObj<typeof meta>;
|
|
|
52
52
|
export const ExecutionFlow: Story = {
|
|
53
53
|
args: {
|
|
54
54
|
canvas: executionCanvas as ExtendedCanvas,
|
|
55
|
-
showMinimap: true,
|
|
56
55
|
showControls: true,
|
|
57
56
|
},
|
|
58
57
|
};
|
|
@@ -68,7 +67,7 @@ export const ExecutionFlow: Story = {
|
|
|
68
67
|
*
|
|
69
68
|
* All events in this panel passed schema validation.
|
|
70
69
|
*/
|
|
71
|
-
export const ValidatedEvents:
|
|
70
|
+
export const ValidatedEvents: Story = {
|
|
72
71
|
render: () => (
|
|
73
72
|
<div style={{ width: '800px', height: '100vh' }}>
|
|
74
73
|
<TestEventPanel
|
|
@@ -93,14 +92,13 @@ export const ValidatedEvents: StoryObj = {
|
|
|
93
92
|
*
|
|
94
93
|
* This ensures production code emits events that match the architecture.
|
|
95
94
|
*/
|
|
96
|
-
export const FlowWithValidation:
|
|
95
|
+
export const FlowWithValidation: Story = {
|
|
97
96
|
render: () => (
|
|
98
97
|
<div style={{ display: 'flex', width: '100%', height: '100%' }}>
|
|
99
98
|
{/* Graph Visualization - Left Side */}
|
|
100
99
|
<div style={{ flex: '0 0 60%', height: '100%', position: 'relative' }}>
|
|
101
100
|
<GraphRenderer
|
|
102
101
|
canvas={executionCanvas as ExtendedCanvas}
|
|
103
|
-
showMinimap={true}
|
|
104
102
|
showControls={true}
|
|
105
103
|
/>
|
|
106
104
|
</div>
|
|
@@ -136,7 +134,7 @@ export const FlowWithValidation: StoryObj = {
|
|
|
136
134
|
* - Event descriptions
|
|
137
135
|
* - Field schemas with types and requirements
|
|
138
136
|
*/
|
|
139
|
-
export const CanvasSchema:
|
|
137
|
+
export const CanvasSchema: Story = {
|
|
140
138
|
render: () => (
|
|
141
139
|
<div
|
|
142
140
|
style={{
|