@principal-ai/principal-view-react 0.7.11 → 0.7.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/dist/components/TestEventPanel.d.ts +11 -0
- package/dist/components/TestEventPanel.d.ts.map +1 -1
- package/dist/components/TestEventPanel.js +182 -68
- package/dist/components/TestEventPanel.js.map +1 -1
- package/package.json +1 -1
- package/src/components/TestEventPanel.tsx +265 -47
- package/src/stories/RealTestExecution.stories.tsx +37 -24
- package/src/stories/data/graph-converter-test-execution.json +326 -204
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useMemo } from 'react';
|
|
2
2
|
import { useTheme } from '@principal-ade/industry-theme';
|
|
3
3
|
import { HelpCircle } from 'lucide-react';
|
|
4
4
|
|
|
@@ -20,23 +20,115 @@ interface TestSpan {
|
|
|
20
20
|
errorMessage?: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// OTEL Log types
|
|
24
|
+
export type OtelSeverity = 'TRACE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL';
|
|
25
|
+
|
|
26
|
+
export interface OtelLog {
|
|
27
|
+
timestamp: number;
|
|
28
|
+
severity: OtelSeverity;
|
|
29
|
+
body: string | Record<string, unknown>;
|
|
30
|
+
resource: Record<string, string | number>;
|
|
31
|
+
attributes?: Record<string, any>;
|
|
32
|
+
traceId?: string;
|
|
33
|
+
spanId?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Timeline item (event or log)
|
|
37
|
+
interface TimelineItem {
|
|
38
|
+
type: 'event' | 'log';
|
|
39
|
+
time: number;
|
|
40
|
+
// For events
|
|
41
|
+
name?: string;
|
|
42
|
+
attributes?: Record<string, any>;
|
|
43
|
+
// For logs
|
|
44
|
+
severity?: OtelSeverity;
|
|
45
|
+
body?: string | Record<string, unknown>;
|
|
46
|
+
resource?: Record<string, string | number>;
|
|
47
|
+
}
|
|
48
|
+
|
|
23
49
|
export interface TestEventPanelProps {
|
|
24
50
|
spans: TestSpan[];
|
|
51
|
+
logs?: OtelLog[]; // Optional for backward compatibility
|
|
25
52
|
currentSpanIndex: number;
|
|
26
53
|
currentEventIndex: number;
|
|
27
54
|
highlightedPhase?: string; // 'setup' | 'execution' | 'assertion'
|
|
28
55
|
}
|
|
29
56
|
|
|
57
|
+
// Helper functions for log severity
|
|
58
|
+
function getSeverityColor(severity: OtelSeverity): string {
|
|
59
|
+
const colors = {
|
|
60
|
+
TRACE: '#6b7280',
|
|
61
|
+
DEBUG: '#60a5fa',
|
|
62
|
+
INFO: '#4ade80',
|
|
63
|
+
WARN: '#fbbf24',
|
|
64
|
+
ERROR: '#f87171',
|
|
65
|
+
FATAL: '#dc2626',
|
|
66
|
+
};
|
|
67
|
+
return colors[severity] || '#9ca3af';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getSeverityIcon(severity: OtelSeverity): string {
|
|
71
|
+
const icons = {
|
|
72
|
+
TRACE: '○',
|
|
73
|
+
DEBUG: '◐',
|
|
74
|
+
INFO: '●',
|
|
75
|
+
WARN: '⚠',
|
|
76
|
+
ERROR: '✕',
|
|
77
|
+
FATAL: '☠',
|
|
78
|
+
};
|
|
79
|
+
return icons[severity] || '•';
|
|
80
|
+
}
|
|
81
|
+
|
|
30
82
|
export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
31
83
|
spans,
|
|
84
|
+
logs = [],
|
|
32
85
|
currentSpanIndex,
|
|
33
86
|
currentEventIndex,
|
|
34
87
|
highlightedPhase,
|
|
35
88
|
}) => {
|
|
36
89
|
const { theme } = useTheme();
|
|
37
90
|
const [showHelp, setShowHelp] = useState(false);
|
|
91
|
+
const [viewMode, setViewMode] = useState<'all' | 'events' | 'logs'>('all');
|
|
92
|
+
|
|
38
93
|
const currentSpan = spans[currentSpanIndex];
|
|
39
|
-
|
|
94
|
+
|
|
95
|
+
// Build interleaved timeline
|
|
96
|
+
const timeline = useMemo(() => {
|
|
97
|
+
if (!currentSpan) return [];
|
|
98
|
+
|
|
99
|
+
const items: TimelineItem[] = [
|
|
100
|
+
// Span events
|
|
101
|
+
...currentSpan.events.slice(0, currentEventIndex + 1).map((event) => ({
|
|
102
|
+
type: 'event' as const,
|
|
103
|
+
time: event.time,
|
|
104
|
+
name: event.name,
|
|
105
|
+
attributes: event.attributes,
|
|
106
|
+
})),
|
|
107
|
+
|
|
108
|
+
// Correlated logs (matching current span's traceId)
|
|
109
|
+
...logs
|
|
110
|
+
.filter((log) => log.traceId === currentSpan.id)
|
|
111
|
+
.map((log) => ({
|
|
112
|
+
type: 'log' as const,
|
|
113
|
+
time: typeof log.timestamp === 'number' ? log.timestamp : new Date(log.timestamp).getTime(),
|
|
114
|
+
severity: log.severity,
|
|
115
|
+
body: log.body,
|
|
116
|
+
resource: log.resource,
|
|
117
|
+
attributes: log.attributes,
|
|
118
|
+
})),
|
|
119
|
+
].sort((a, b) => a.time - b.time);
|
|
120
|
+
|
|
121
|
+
return items;
|
|
122
|
+
}, [currentSpan, currentEventIndex, logs]);
|
|
123
|
+
|
|
124
|
+
// Filter timeline based on view mode
|
|
125
|
+
const filteredTimeline = useMemo(() => {
|
|
126
|
+
if (viewMode === 'all') return timeline;
|
|
127
|
+
return timeline.filter((item) => item.type === viewMode.slice(0, -1)); // 'events' -> 'event', 'logs' -> 'log'
|
|
128
|
+
}, [timeline, viewMode]);
|
|
129
|
+
|
|
130
|
+
const eventCount = timeline.filter((i) => i.type === 'event').length;
|
|
131
|
+
const logCount = timeline.filter((i) => i.type === 'log').length;
|
|
40
132
|
|
|
41
133
|
return (
|
|
42
134
|
<div
|
|
@@ -54,7 +146,7 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
54
146
|
>
|
|
55
147
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '15px' }}>
|
|
56
148
|
<div style={{ fontWeight: 'bold', fontSize: '18px' }}>
|
|
57
|
-
|
|
149
|
+
Execution Timeline
|
|
58
150
|
</div>
|
|
59
151
|
<button
|
|
60
152
|
onClick={() => setShowHelp(true)}
|
|
@@ -77,6 +169,56 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
77
169
|
<HelpCircle size={20} />
|
|
78
170
|
</button>
|
|
79
171
|
</div>
|
|
172
|
+
|
|
173
|
+
{/* Filter Tabs */}
|
|
174
|
+
<div style={{ display: 'flex', gap: '8px', marginBottom: '12px' }}>
|
|
175
|
+
<button
|
|
176
|
+
onClick={() => setViewMode('all')}
|
|
177
|
+
style={{
|
|
178
|
+
padding: '6px 12px',
|
|
179
|
+
background: viewMode === 'all' ? theme.colors.primary : 'transparent',
|
|
180
|
+
border: `1px solid ${theme.colors.border}`,
|
|
181
|
+
borderRadius: '4px',
|
|
182
|
+
color: viewMode === 'all' ? '#ffffff' : theme.colors.text,
|
|
183
|
+
cursor: 'pointer',
|
|
184
|
+
fontSize: '12px',
|
|
185
|
+
fontWeight: 500,
|
|
186
|
+
}}
|
|
187
|
+
>
|
|
188
|
+
All ({timeline.length})
|
|
189
|
+
</button>
|
|
190
|
+
<button
|
|
191
|
+
onClick={() => setViewMode('events')}
|
|
192
|
+
style={{
|
|
193
|
+
padding: '6px 12px',
|
|
194
|
+
background: viewMode === 'events' ? theme.colors.primary : 'transparent',
|
|
195
|
+
border: `1px solid ${theme.colors.border}`,
|
|
196
|
+
borderRadius: '4px',
|
|
197
|
+
color: viewMode === 'events' ? '#ffffff' : theme.colors.text,
|
|
198
|
+
cursor: 'pointer',
|
|
199
|
+
fontSize: '12px',
|
|
200
|
+
fontWeight: 500,
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
Events ({eventCount})
|
|
204
|
+
</button>
|
|
205
|
+
<button
|
|
206
|
+
onClick={() => setViewMode('logs')}
|
|
207
|
+
style={{
|
|
208
|
+
padding: '6px 12px',
|
|
209
|
+
background: viewMode === 'logs' ? theme.colors.primary : 'transparent',
|
|
210
|
+
border: `1px solid ${theme.colors.border}`,
|
|
211
|
+
borderRadius: '4px',
|
|
212
|
+
color: viewMode === 'logs' ? '#ffffff' : theme.colors.text,
|
|
213
|
+
cursor: 'pointer',
|
|
214
|
+
fontSize: '12px',
|
|
215
|
+
fontWeight: 500,
|
|
216
|
+
}}
|
|
217
|
+
>
|
|
218
|
+
Logs ({logCount})
|
|
219
|
+
</button>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
80
222
|
<div style={{ fontSize: '13px', color: theme.colors.textMuted, marginBottom: '15px' }}>
|
|
81
223
|
Test: {currentSpan?.name || 'Loading...'}
|
|
82
224
|
</div>
|
|
@@ -114,9 +256,15 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
114
256
|
</div>
|
|
115
257
|
<div style={{ fontSize: '14px', marginBottom: '16px', lineHeight: '1.6' }}>
|
|
116
258
|
<p style={{ marginBottom: '12px' }}>
|
|
117
|
-
<strong>
|
|
259
|
+
<strong>Timeline shows both events and logs:</strong>
|
|
118
260
|
</p>
|
|
119
261
|
<ul style={{ marginLeft: '20px', marginBottom: '16px' }}>
|
|
262
|
+
<li style={{ marginBottom: '8px' }}>
|
|
263
|
+
<span style={{ color: '#f59e0b' }}>🟧 Events</span> - Structured lifecycle points
|
|
264
|
+
</li>
|
|
265
|
+
<li style={{ marginBottom: '8px' }}>
|
|
266
|
+
<span style={{ color: '#4ade80' }}>● Logs</span> - Standalone log records (color = severity)
|
|
267
|
+
</li>
|
|
120
268
|
<li style={{ marginBottom: '8px' }}>
|
|
121
269
|
<span style={{ color: '#60a5fa' }}>Blue = Test file</span>
|
|
122
270
|
</li>
|
|
@@ -125,30 +273,20 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
125
273
|
</li>
|
|
126
274
|
</ul>
|
|
127
275
|
<p style={{ marginBottom: '12px' }}>
|
|
128
|
-
<strong>
|
|
276
|
+
<strong>Use filter tabs to focus:</strong>
|
|
129
277
|
</p>
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
fontSize: '13px',
|
|
136
|
-
overflow: 'auto',
|
|
137
|
-
}}
|
|
138
|
-
>
|
|
139
|
-
{`{
|
|
140
|
-
"test.file": "GraphConverter.test.ts",
|
|
141
|
-
"test.suite": "GraphConverter",
|
|
142
|
-
"test.result": "pass"
|
|
143
|
-
}`}
|
|
144
|
-
</pre>
|
|
278
|
+
<ul style={{ marginLeft: '20px' }}>
|
|
279
|
+
<li>All - Interleaved timeline</li>
|
|
280
|
+
<li>Events - Span events only</li>
|
|
281
|
+
<li>Logs - OTEL logs only</li>
|
|
282
|
+
</ul>
|
|
145
283
|
</div>
|
|
146
284
|
<button
|
|
147
285
|
onClick={() => setShowHelp(false)}
|
|
148
286
|
style={{
|
|
149
287
|
padding: '8px 16px',
|
|
150
288
|
backgroundColor: theme.colors.primary,
|
|
151
|
-
color:
|
|
289
|
+
color: '#ffffff',
|
|
152
290
|
border: 'none',
|
|
153
291
|
borderRadius: '4px',
|
|
154
292
|
cursor: 'pointer',
|
|
@@ -162,27 +300,18 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
162
300
|
</div>
|
|
163
301
|
)}
|
|
164
302
|
|
|
303
|
+
{/* Timeline Items */}
|
|
165
304
|
{currentSpan && (
|
|
166
|
-
|
|
167
|
-
{
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
fontWeight: 'bold',
|
|
173
|
-
marginBottom: '8px',
|
|
174
|
-
fontSize: '15px',
|
|
175
|
-
}}
|
|
176
|
-
>
|
|
177
|
-
Event Timeline (Context Mutations)
|
|
178
|
-
</div>
|
|
179
|
-
{eventsUpToNow.map((event, idx) => {
|
|
180
|
-
const filepath = event.attributes['code.filepath'] as string;
|
|
181
|
-
const lineno = event.attributes['code.lineno'] as number;
|
|
305
|
+
<div>
|
|
306
|
+
{filteredTimeline.map((item, idx) => {
|
|
307
|
+
if (item.type === 'event') {
|
|
308
|
+
// SPAN EVENT RENDERING
|
|
309
|
+
const filepath = item.attributes?.['code.filepath'] as string;
|
|
310
|
+
const lineno = item.attributes?.['code.lineno'] as number;
|
|
182
311
|
const isCodeUnderTest = filepath && filepath !== 'GraphConverter.test.ts';
|
|
183
312
|
|
|
184
313
|
// Determine which phase this event belongs to
|
|
185
|
-
const eventPhase =
|
|
314
|
+
const eventPhase = item.name?.split('.')[0]; // 'setup', 'execution', 'assertion'
|
|
186
315
|
const isHighlighted = highlightedPhase === eventPhase;
|
|
187
316
|
|
|
188
317
|
return (
|
|
@@ -191,12 +320,14 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
191
320
|
style={{
|
|
192
321
|
marginBottom: '12px',
|
|
193
322
|
paddingBottom: '12px',
|
|
194
|
-
|
|
323
|
+
paddingLeft: '12px',
|
|
324
|
+
borderBottom: idx < filteredTimeline.length - 1 ? `1px solid ${theme.colors.border}` : 'none',
|
|
325
|
+
borderLeft: '3px solid #f59e0b',
|
|
195
326
|
opacity: highlightedPhase && !isHighlighted ? 0.4 : 1,
|
|
196
327
|
transition: 'opacity 0.2s ease',
|
|
197
328
|
transform: isHighlighted ? 'scale(1.02)' : 'scale(1)',
|
|
198
329
|
backgroundColor: isHighlighted ? theme.colors.surface : 'transparent',
|
|
199
|
-
padding: isHighlighted ? '8px' : '0',
|
|
330
|
+
padding: isHighlighted ? '8px 8px 8px 12px' : '0 0 12px 12px',
|
|
200
331
|
borderRadius: '4px',
|
|
201
332
|
}}
|
|
202
333
|
>
|
|
@@ -209,8 +340,8 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
209
340
|
gap: '8px',
|
|
210
341
|
}}
|
|
211
342
|
>
|
|
212
|
-
<div style={{ color: '#f59e0b', fontSize: '13px', flexShrink: 0 }}>
|
|
213
|
-
|
|
343
|
+
<div style={{ color: '#f59e0b', fontSize: '13px', fontWeight: 'bold', flexShrink: 0 }}>
|
|
344
|
+
EVENT: {item.name}
|
|
214
345
|
</div>
|
|
215
346
|
{filepath && (
|
|
216
347
|
<div
|
|
@@ -247,7 +378,7 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
247
378
|
>
|
|
248
379
|
{JSON.stringify(
|
|
249
380
|
Object.fromEntries(
|
|
250
|
-
Object.entries(
|
|
381
|
+
Object.entries(item.attributes || {}).filter(
|
|
251
382
|
([key]) => key !== 'code.filepath' && key !== 'code.lineno'
|
|
252
383
|
)
|
|
253
384
|
),
|
|
@@ -257,9 +388,96 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
257
388
|
</pre>
|
|
258
389
|
</div>
|
|
259
390
|
);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
391
|
+
} else {
|
|
392
|
+
// OTEL LOG RENDERING
|
|
393
|
+
const serviceName = item.resource?.['service.name'];
|
|
394
|
+
const severityColor = getSeverityColor(item.severity!);
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
<div
|
|
398
|
+
key={idx}
|
|
399
|
+
style={{
|
|
400
|
+
marginBottom: '12px',
|
|
401
|
+
paddingBottom: '12px',
|
|
402
|
+
paddingLeft: '12px',
|
|
403
|
+
borderBottom: idx < filteredTimeline.length - 1 ? `1px solid ${theme.colors.border}` : 'none',
|
|
404
|
+
borderLeft: `3px solid ${severityColor}`,
|
|
405
|
+
}}
|
|
406
|
+
>
|
|
407
|
+
<div
|
|
408
|
+
style={{
|
|
409
|
+
display: 'flex',
|
|
410
|
+
justifyContent: 'space-between',
|
|
411
|
+
alignItems: 'center',
|
|
412
|
+
marginBottom: '4px',
|
|
413
|
+
}}
|
|
414
|
+
>
|
|
415
|
+
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
|
|
416
|
+
<span style={{ fontSize: '16px' }}>{getSeverityIcon(item.severity!)}</span>
|
|
417
|
+
<span
|
|
418
|
+
style={{
|
|
419
|
+
color: severityColor,
|
|
420
|
+
fontSize: '13px',
|
|
421
|
+
fontWeight: 'bold',
|
|
422
|
+
}}
|
|
423
|
+
>
|
|
424
|
+
LOG: {item.severity}
|
|
425
|
+
</span>
|
|
426
|
+
</div>
|
|
427
|
+
{serviceName && (
|
|
428
|
+
<div
|
|
429
|
+
style={{
|
|
430
|
+
fontSize: '12px',
|
|
431
|
+
color: '#9ca3af',
|
|
432
|
+
background: '#1e293b',
|
|
433
|
+
padding: '2px 6px',
|
|
434
|
+
borderRadius: '3px',
|
|
435
|
+
}}
|
|
436
|
+
>
|
|
437
|
+
{serviceName}
|
|
438
|
+
</div>
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
|
|
442
|
+
{/* Log body */}
|
|
443
|
+
<div
|
|
444
|
+
style={{
|
|
445
|
+
background: theme.colors.surface,
|
|
446
|
+
padding: '8px',
|
|
447
|
+
borderRadius: '4px',
|
|
448
|
+
marginBottom: item.attributes && Object.keys(item.attributes).length > 0 ? '8px' : '0',
|
|
449
|
+
fontSize: '13px',
|
|
450
|
+
}}
|
|
451
|
+
>
|
|
452
|
+
{typeof item.body === 'string' ? (
|
|
453
|
+
item.body
|
|
454
|
+
) : (
|
|
455
|
+
<pre style={{ margin: 0, fontSize: '12px' }}>
|
|
456
|
+
{JSON.stringify(item.body, null, 2)}
|
|
457
|
+
</pre>
|
|
458
|
+
)}
|
|
459
|
+
</div>
|
|
460
|
+
|
|
461
|
+
{/* Log attributes */}
|
|
462
|
+
{item.attributes && Object.keys(item.attributes).length > 0 && (
|
|
463
|
+
<pre
|
|
464
|
+
style={{
|
|
465
|
+
background: theme.colors.surface,
|
|
466
|
+
padding: '8px',
|
|
467
|
+
borderRadius: '4px',
|
|
468
|
+
margin: 0,
|
|
469
|
+
fontSize: '11px',
|
|
470
|
+
opacity: 0.8,
|
|
471
|
+
}}
|
|
472
|
+
>
|
|
473
|
+
{JSON.stringify(item.attributes, null, 2)}
|
|
474
|
+
</pre>
|
|
475
|
+
)}
|
|
476
|
+
</div>
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
})}
|
|
480
|
+
</div>
|
|
263
481
|
)}
|
|
264
482
|
|
|
265
483
|
<div
|
|
@@ -275,7 +493,7 @@ export const TestEventPanel: React.FC<TestEventPanelProps> = ({
|
|
|
275
493
|
<strong>Total tests:</strong> {spans.length}
|
|
276
494
|
</div>
|
|
277
495
|
<div style={{ marginBottom: '8px' }}>
|
|
278
|
-
<strong>
|
|
496
|
+
<strong>Timeline:</strong> {eventCount} events, {logCount} logs
|
|
279
497
|
</div>
|
|
280
498
|
<div>
|
|
281
499
|
<strong>Status:</strong>{' '}
|
|
@@ -193,11 +193,27 @@ const AnimatedTestExecution = () => {
|
|
|
193
193
|
const [currentEventIndex] = useState(999);
|
|
194
194
|
const [highlightedPhase, setHighlightedPhase] = useState<string | undefined>();
|
|
195
195
|
|
|
196
|
+
// Extract spans and logs from test data
|
|
197
|
+
const testData = testSpans as any;
|
|
198
|
+
const spans = Array.isArray(testData) ? testData : testData.spans || testData;
|
|
199
|
+
const logs = testData.logs || [];
|
|
200
|
+
|
|
196
201
|
return (
|
|
197
202
|
<div style={{ display: 'flex', width: '100vw', height: '100vh' }}>
|
|
198
|
-
{/*
|
|
203
|
+
{/* Event Panel - Left Side */}
|
|
204
|
+
<div style={{ flex: '0 0 50%', height: '100%', borderRight: `1px solid #333`, overflow: 'hidden' }}>
|
|
205
|
+
<TestEventPanel
|
|
206
|
+
spans={spans}
|
|
207
|
+
logs={logs}
|
|
208
|
+
currentSpanIndex={currentSpanIndex}
|
|
209
|
+
currentEventIndex={currentEventIndex}
|
|
210
|
+
highlightedPhase={highlightedPhase}
|
|
211
|
+
/>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
{/* Graph Visualization - Right Side */}
|
|
199
215
|
<div
|
|
200
|
-
style={{ flex: '0 0
|
|
216
|
+
style={{ flex: '0 0 50%', height: '100%', position: 'relative' }}
|
|
201
217
|
onMouseLeave={() => setHighlightedPhase(undefined)}
|
|
202
218
|
>
|
|
203
219
|
<div
|
|
@@ -218,16 +234,6 @@ const AnimatedTestExecution = () => {
|
|
|
218
234
|
/>
|
|
219
235
|
</div>
|
|
220
236
|
</div>
|
|
221
|
-
|
|
222
|
-
{/* Event Panel - Right Side */}
|
|
223
|
-
<div style={{ flex: '0 0 40%', height: '100%', borderLeft: `1px solid #333`, overflow: 'hidden' }}>
|
|
224
|
-
<TestEventPanel
|
|
225
|
-
spans={testSpans as any}
|
|
226
|
-
currentSpanIndex={currentSpanIndex}
|
|
227
|
-
currentEventIndex={currentEventIndex}
|
|
228
|
-
highlightedPhase={highlightedPhase}
|
|
229
|
-
/>
|
|
230
|
-
</div>
|
|
231
237
|
</div>
|
|
232
238
|
);
|
|
233
239
|
};
|
|
@@ -263,18 +269,25 @@ export const StaticView: Story = {
|
|
|
263
269
|
/**
|
|
264
270
|
* Event panel component showing test execution narrative with file/line information.
|
|
265
271
|
*
|
|
266
|
-
* Shows how events
|
|
267
|
-
* capture from stack traces and
|
|
272
|
+
* Shows how events and logs are interleaved in chronological order, with automatic
|
|
273
|
+
* file/line capture from stack traces and severity-based color coding for logs.
|
|
268
274
|
*/
|
|
269
275
|
export const EventPanelOnly: StoryObj = {
|
|
270
|
-
render: () =>
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
276
|
+
render: () => {
|
|
277
|
+
const testData = testSpans as any;
|
|
278
|
+
const spans = Array.isArray(testData) ? testData : testData.spans || testData;
|
|
279
|
+
const logs = testData.logs || [];
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<div style={{ width: '600px', height: '100vh' }}>
|
|
283
|
+
<TestEventPanel
|
|
284
|
+
spans={spans}
|
|
285
|
+
logs={logs}
|
|
286
|
+
currentSpanIndex={0}
|
|
287
|
+
currentEventIndex={999} // Show all events
|
|
288
|
+
highlightedPhase={undefined}
|
|
289
|
+
/>
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
},
|
|
280
293
|
};
|