@principal-ai/principal-view-react 0.14.21 → 0.14.23
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 +23 -10
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/state-view/PipelineView.d.ts +13 -0
- package/dist/components/state-view/PipelineView.d.ts.map +1 -0
- package/dist/components/state-view/PipelineView.js +195 -0
- package/dist/components/state-view/PipelineView.js.map +1 -0
- package/dist/components/state-view/index.d.ts +14 -0
- package/dist/components/state-view/index.d.ts.map +1 -0
- package/dist/components/state-view/index.js +12 -0
- package/dist/components/state-view/index.js.map +1 -0
- package/dist/components/state-view/types.d.ts +188 -0
- package/dist/components/state-view/types.d.ts.map +1 -0
- package/dist/components/state-view/types.js +10 -0
- package/dist/components/state-view/types.js.map +1 -0
- package/dist/components/state-view/useStateView.d.ts +32 -0
- package/dist/components/state-view/useStateView.d.ts.map +1 -0
- package/dist/components/state-view/useStateView.js +129 -0
- package/dist/components/state-view/useStateView.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/nodes/CustomNode.js +8 -8
- package/dist/nodes/CustomNode.js.map +1 -1
- package/dist/nodes/otel/OtelBoundaryNode.d.ts.map +1 -1
- package/dist/nodes/otel/OtelBoundaryNode.js +5 -3
- package/dist/nodes/otel/OtelBoundaryNode.js.map +1 -1
- package/dist/nodes/otel/OtelEventNode.d.ts.map +1 -1
- package/dist/nodes/otel/OtelEventNode.js +5 -3
- package/dist/nodes/otel/OtelEventNode.js.map +1 -1
- package/dist/nodes/otel/OtelResourceNode.d.ts.map +1 -1
- package/dist/nodes/otel/OtelResourceNode.js +5 -3
- package/dist/nodes/otel/OtelResourceNode.js.map +1 -1
- package/dist/nodes/otel/OtelScopeNode.d.ts.map +1 -1
- package/dist/nodes/otel/OtelScopeNode.js +5 -3
- package/dist/nodes/otel/OtelScopeNode.js.map +1 -1
- package/dist/nodes/otel/OtelSpanConventionNode.d.ts.map +1 -1
- package/dist/nodes/otel/OtelSpanConventionNode.js +5 -3
- package/dist/nodes/otel/OtelSpanConventionNode.js.map +1 -1
- package/package.json +2 -2
- package/src/components/GraphRenderer.tsx +24 -10
- package/src/components/state-view/PipelineView.tsx +347 -0
- package/src/components/state-view/index.ts +14 -0
- package/src/components/state-view/types.ts +261 -0
- package/src/components/state-view/useStateView.ts +205 -0
- package/src/index.ts +36 -0
- package/src/nodes/CustomNode.tsx +8 -8
- package/src/nodes/otel/OtelBoundaryNode.tsx +5 -3
- package/src/nodes/otel/OtelEventNode.tsx +5 -3
- package/src/nodes/otel/OtelResourceNode.tsx +5 -3
- package/src/nodes/otel/OtelScopeNode.tsx +5 -3
- package/src/nodes/otel/OtelSpanConventionNode.tsx +5 -4
- package/src/stories/CanvasEdgeTypes.stories.tsx +23 -27
- package/src/stories/GraphRenderer.stories.tsx +144 -200
- package/src/stories/StateView.stories.tsx +417 -0
- package/src/stories/__traces__/test-run.canvas.json +27 -30
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
PipelineView,
|
|
5
|
+
type PipelineEvent,
|
|
6
|
+
type EventSource,
|
|
7
|
+
type PipelineEventType,
|
|
8
|
+
} from '../components/state-view';
|
|
9
|
+
|
|
10
|
+
const meta = {
|
|
11
|
+
title: 'State View/Pipeline',
|
|
12
|
+
component: PipelineView,
|
|
13
|
+
parameters: {
|
|
14
|
+
layout: 'centered',
|
|
15
|
+
},
|
|
16
|
+
tags: ['autodocs'],
|
|
17
|
+
} satisfies Meta<typeof PipelineView>;
|
|
18
|
+
|
|
19
|
+
export default meta;
|
|
20
|
+
type Story = StoryObj<typeof meta>;
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Event Simulation Helpers
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
function createPipelineEvent(
|
|
27
|
+
type: PipelineEventType,
|
|
28
|
+
payload: PipelineEvent['payload'] = {}
|
|
29
|
+
): PipelineEvent {
|
|
30
|
+
return {
|
|
31
|
+
type,
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
payload,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function simulatePipelineFlow(
|
|
38
|
+
emit: (event: PipelineEvent) => void,
|
|
39
|
+
repo: string
|
|
40
|
+
) {
|
|
41
|
+
// Simulate: FS change -> Watch -> Cache -> Event
|
|
42
|
+
const delays = [0, 100, 200, 350];
|
|
43
|
+
|
|
44
|
+
setTimeout(() => emit(createPipelineEvent('FS_CHANGE', { repo })), delays[0]);
|
|
45
|
+
setTimeout(() => emit(createPipelineEvent('WATCH_DETECTED', { repo })), delays[1]);
|
|
46
|
+
setTimeout(() => emit(createPipelineEvent('CACHE_REBUILD', { repo, slice: 'fileTree' })), delays[2]);
|
|
47
|
+
setTimeout(() => emit(createPipelineEvent('EVENT_BROADCAST', { repo, eventType: 'commit' })), delays[3]);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// =============================================================================
|
|
51
|
+
// Live Event Source (simulated)
|
|
52
|
+
// =============================================================================
|
|
53
|
+
|
|
54
|
+
function useLiveEventSource(): {
|
|
55
|
+
eventSource: EventSource<PipelineEvent>;
|
|
56
|
+
triggerEvent: (type: PipelineEventType, payload?: PipelineEvent['payload']) => void;
|
|
57
|
+
triggerFlow: (repo: string) => void;
|
|
58
|
+
} {
|
|
59
|
+
const listenersRef = useRef<Set<(event: PipelineEvent) => void>>(new Set());
|
|
60
|
+
|
|
61
|
+
const eventSource: EventSource<PipelineEvent> = {
|
|
62
|
+
mode: 'live',
|
|
63
|
+
subscribe: (handler) => {
|
|
64
|
+
listenersRef.current.add(handler);
|
|
65
|
+
return () => listenersRef.current.delete(handler);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const emit = useCallback((event: PipelineEvent) => {
|
|
70
|
+
listenersRef.current.forEach((handler) => handler(event));
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
const triggerEvent = useCallback(
|
|
74
|
+
(type: PipelineEventType, payload: PipelineEvent['payload'] = {}) => {
|
|
75
|
+
emit(createPipelineEvent(type, payload));
|
|
76
|
+
},
|
|
77
|
+
[emit]
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const triggerFlow = useCallback(
|
|
81
|
+
(repo: string) => {
|
|
82
|
+
simulatePipelineFlow(emit, repo);
|
|
83
|
+
},
|
|
84
|
+
[emit]
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return { eventSource, triggerEvent, triggerFlow };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// =============================================================================
|
|
91
|
+
// Replay Event Source
|
|
92
|
+
// =============================================================================
|
|
93
|
+
|
|
94
|
+
interface ReplayEventSourceOptions {
|
|
95
|
+
events: PipelineEvent[];
|
|
96
|
+
speed?: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function useReplayEventSource({ events, speed = 1 }: ReplayEventSourceOptions): {
|
|
100
|
+
eventSource: EventSource<PipelineEvent>;
|
|
101
|
+
controls: {
|
|
102
|
+
play: () => void;
|
|
103
|
+
pause: () => void;
|
|
104
|
+
reset: () => void;
|
|
105
|
+
isPlaying: boolean;
|
|
106
|
+
};
|
|
107
|
+
} {
|
|
108
|
+
const listenersRef = useRef<Set<(event: PipelineEvent) => void>>(new Set());
|
|
109
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
110
|
+
const indexRef = useRef(0);
|
|
111
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
112
|
+
|
|
113
|
+
const eventSource: EventSource<PipelineEvent> = {
|
|
114
|
+
mode: 'replay',
|
|
115
|
+
subscribe: (handler) => {
|
|
116
|
+
listenersRef.current.add(handler);
|
|
117
|
+
return () => listenersRef.current.delete(handler);
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const emit = useCallback((event: PipelineEvent) => {
|
|
122
|
+
// Update timestamp to "now" for display purposes
|
|
123
|
+
const adjustedEvent = { ...event, timestamp: Date.now() };
|
|
124
|
+
listenersRef.current.forEach((handler) => handler(adjustedEvent));
|
|
125
|
+
}, []);
|
|
126
|
+
|
|
127
|
+
const playNext = useCallback(() => {
|
|
128
|
+
if (indexRef.current >= events.length) {
|
|
129
|
+
setIsPlaying(false);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const currentEvent = events[indexRef.current];
|
|
134
|
+
emit(currentEvent);
|
|
135
|
+
indexRef.current++;
|
|
136
|
+
|
|
137
|
+
if (indexRef.current < events.length) {
|
|
138
|
+
const nextEvent = events[indexRef.current];
|
|
139
|
+
const delay = (nextEvent.timestamp - currentEvent.timestamp) / speed;
|
|
140
|
+
timeoutRef.current = setTimeout(playNext, Math.max(50, delay));
|
|
141
|
+
} else {
|
|
142
|
+
setIsPlaying(false);
|
|
143
|
+
}
|
|
144
|
+
}, [events, speed, emit]);
|
|
145
|
+
|
|
146
|
+
const play = useCallback(() => {
|
|
147
|
+
if (isPlaying) return;
|
|
148
|
+
setIsPlaying(true);
|
|
149
|
+
playNext();
|
|
150
|
+
}, [isPlaying, playNext]);
|
|
151
|
+
|
|
152
|
+
const pause = useCallback(() => {
|
|
153
|
+
setIsPlaying(false);
|
|
154
|
+
if (timeoutRef.current) {
|
|
155
|
+
clearTimeout(timeoutRef.current);
|
|
156
|
+
timeoutRef.current = null;
|
|
157
|
+
}
|
|
158
|
+
}, []);
|
|
159
|
+
|
|
160
|
+
const reset = useCallback(() => {
|
|
161
|
+
pause();
|
|
162
|
+
indexRef.current = 0;
|
|
163
|
+
}, [pause]);
|
|
164
|
+
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
return () => {
|
|
167
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
168
|
+
};
|
|
169
|
+
}, []);
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
eventSource,
|
|
173
|
+
controls: { play, pause, reset, isPlaying },
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// =============================================================================
|
|
178
|
+
// Stories
|
|
179
|
+
// =============================================================================
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Interactive demo with manual event triggering.
|
|
183
|
+
* Click buttons to simulate events flowing through the pipeline.
|
|
184
|
+
*/
|
|
185
|
+
export const Interactive: Story = {
|
|
186
|
+
render: () => {
|
|
187
|
+
const { eventSource, triggerEvent, triggerFlow } = useLiveEventSource();
|
|
188
|
+
const [selectedRepo, setSelectedRepo] = useState('myorg/backend');
|
|
189
|
+
|
|
190
|
+
const repos = ['myorg/backend', 'myorg/frontend', 'myorg/shared-lib'];
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
194
|
+
<PipelineView eventSource={eventSource} title="Repository Monitoring Pipeline" />
|
|
195
|
+
|
|
196
|
+
{/* Control Panel */}
|
|
197
|
+
<div
|
|
198
|
+
style={{
|
|
199
|
+
padding: 16,
|
|
200
|
+
backgroundColor: '#111827',
|
|
201
|
+
borderRadius: 8,
|
|
202
|
+
fontFamily: 'system-ui, sans-serif',
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
<div style={{ color: '#9ca3af', fontSize: 12, marginBottom: 12 }}>
|
|
206
|
+
Event Controls
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<div style={{ display: 'flex', gap: 8, marginBottom: 12, flexWrap: 'wrap' }}>
|
|
210
|
+
<select
|
|
211
|
+
value={selectedRepo}
|
|
212
|
+
onChange={(e) => setSelectedRepo(e.target.value)}
|
|
213
|
+
style={{
|
|
214
|
+
padding: '8px 12px',
|
|
215
|
+
borderRadius: 4,
|
|
216
|
+
border: 'none',
|
|
217
|
+
backgroundColor: '#374151',
|
|
218
|
+
color: 'white',
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
{repos.map((repo) => (
|
|
222
|
+
<option key={repo} value={repo}>
|
|
223
|
+
{repo}
|
|
224
|
+
</option>
|
|
225
|
+
))}
|
|
226
|
+
</select>
|
|
227
|
+
|
|
228
|
+
<button
|
|
229
|
+
onClick={() => triggerFlow(selectedRepo)}
|
|
230
|
+
style={{
|
|
231
|
+
padding: '8px 16px',
|
|
232
|
+
borderRadius: 4,
|
|
233
|
+
border: 'none',
|
|
234
|
+
backgroundColor: '#3b82f6',
|
|
235
|
+
color: 'white',
|
|
236
|
+
cursor: 'pointer',
|
|
237
|
+
fontWeight: 'bold',
|
|
238
|
+
}}
|
|
239
|
+
>
|
|
240
|
+
Simulate Full Flow
|
|
241
|
+
</button>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
|
245
|
+
<button
|
|
246
|
+
onClick={() => triggerEvent('FS_CHANGE', { repo: selectedRepo })}
|
|
247
|
+
style={buttonStyle('#10b981')}
|
|
248
|
+
>
|
|
249
|
+
FS Change
|
|
250
|
+
</button>
|
|
251
|
+
<button
|
|
252
|
+
onClick={() => triggerEvent('WATCH_DETECTED', { repo: selectedRepo })}
|
|
253
|
+
style={buttonStyle('#6366f1')}
|
|
254
|
+
>
|
|
255
|
+
Watch Detect
|
|
256
|
+
</button>
|
|
257
|
+
<button
|
|
258
|
+
onClick={() => triggerEvent('CACHE_REBUILD', { repo: selectedRepo, slice: 'fileTree' })}
|
|
259
|
+
style={buttonStyle('#f59e0b')}
|
|
260
|
+
>
|
|
261
|
+
Cache Rebuild
|
|
262
|
+
</button>
|
|
263
|
+
<button
|
|
264
|
+
onClick={() => triggerEvent('EVENT_BROADCAST', { repo: selectedRepo, eventType: 'commit' })}
|
|
265
|
+
style={buttonStyle('#ef4444')}
|
|
266
|
+
>
|
|
267
|
+
Event Broadcast
|
|
268
|
+
</button>
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
);
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Auto-playing demo that continuously simulates pipeline activity.
|
|
278
|
+
*/
|
|
279
|
+
export const AutoSimulation: Story = {
|
|
280
|
+
render: () => {
|
|
281
|
+
const { eventSource, triggerFlow } = useLiveEventSource();
|
|
282
|
+
const [isRunning, setIsRunning] = useState(true);
|
|
283
|
+
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
284
|
+
|
|
285
|
+
const repos = ['myorg/backend', 'myorg/frontend', 'myorg/shared-lib', 'myorg/docs'];
|
|
286
|
+
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
if (isRunning) {
|
|
289
|
+
intervalRef.current = setInterval(() => {
|
|
290
|
+
const randomRepo = repos[Math.floor(Math.random() * repos.length)];
|
|
291
|
+
triggerFlow(randomRepo);
|
|
292
|
+
}, 1500);
|
|
293
|
+
} else {
|
|
294
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return () => {
|
|
298
|
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
299
|
+
};
|
|
300
|
+
}, [isRunning, triggerFlow]);
|
|
301
|
+
|
|
302
|
+
return (
|
|
303
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
304
|
+
<PipelineView eventSource={eventSource} title="Auto-Simulation" />
|
|
305
|
+
|
|
306
|
+
<div style={{ textAlign: 'center' }}>
|
|
307
|
+
<button
|
|
308
|
+
onClick={() => setIsRunning(!isRunning)}
|
|
309
|
+
style={{
|
|
310
|
+
padding: '8px 24px',
|
|
311
|
+
borderRadius: 4,
|
|
312
|
+
border: 'none',
|
|
313
|
+
backgroundColor: isRunning ? '#ef4444' : '#10b981',
|
|
314
|
+
color: 'white',
|
|
315
|
+
cursor: 'pointer',
|
|
316
|
+
fontWeight: 'bold',
|
|
317
|
+
}}
|
|
318
|
+
>
|
|
319
|
+
{isRunning ? 'Stop Simulation' : 'Start Simulation'}
|
|
320
|
+
</button>
|
|
321
|
+
</div>
|
|
322
|
+
</div>
|
|
323
|
+
);
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Replay mode - plays back a recorded sequence of events.
|
|
329
|
+
*/
|
|
330
|
+
export const Replay: Story = {
|
|
331
|
+
render: () => {
|
|
332
|
+
// Pre-recorded events
|
|
333
|
+
const recordedEvents: PipelineEvent[] = [
|
|
334
|
+
{ type: 'FS_CHANGE', timestamp: 0, payload: { repo: 'myorg/backend' } },
|
|
335
|
+
{ type: 'WATCH_DETECTED', timestamp: 100, payload: { repo: 'myorg/backend' } },
|
|
336
|
+
{ type: 'CACHE_REBUILD', timestamp: 200, payload: { repo: 'myorg/backend', slice: 'fileTree' } },
|
|
337
|
+
{ type: 'EVENT_BROADCAST', timestamp: 350, payload: { repo: 'myorg/backend', eventType: 'commit' } },
|
|
338
|
+
|
|
339
|
+
{ type: 'FS_CHANGE', timestamp: 800, payload: { repo: 'myorg/frontend' } },
|
|
340
|
+
{ type: 'WATCH_DETECTED', timestamp: 900, payload: { repo: 'myorg/frontend' } },
|
|
341
|
+
{ type: 'CACHE_HIT', timestamp: 950, payload: { repo: 'myorg/frontend', slice: 'fileTree' } },
|
|
342
|
+
{ type: 'EVENT_BROADCAST', timestamp: 1000, payload: { repo: 'myorg/frontend', eventType: 'branch-switch' } },
|
|
343
|
+
|
|
344
|
+
{ type: 'FS_CHANGE', timestamp: 1500, payload: { repo: 'myorg/backend' } },
|
|
345
|
+
{ type: 'WATCH_DETECTED', timestamp: 1600, payload: { repo: 'myorg/backend' } },
|
|
346
|
+
{ type: 'CACHE_REBUILD', timestamp: 1700, payload: { repo: 'myorg/backend', slice: 'packages' } },
|
|
347
|
+
{ type: 'EVENT_BROADCAST', timestamp: 1850, payload: { repo: 'myorg/backend', eventType: 'dirty-change' } },
|
|
348
|
+
];
|
|
349
|
+
|
|
350
|
+
const { eventSource, controls } = useReplayEventSource({
|
|
351
|
+
events: recordedEvents,
|
|
352
|
+
speed: 1,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
357
|
+
<PipelineView eventSource={eventSource} title="Replay Mode" />
|
|
358
|
+
|
|
359
|
+
<div
|
|
360
|
+
style={{
|
|
361
|
+
display: 'flex',
|
|
362
|
+
justifyContent: 'center',
|
|
363
|
+
gap: 8,
|
|
364
|
+
padding: 16,
|
|
365
|
+
backgroundColor: '#111827',
|
|
366
|
+
borderRadius: 8,
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<button
|
|
370
|
+
onClick={controls.isPlaying ? controls.pause : controls.play}
|
|
371
|
+
style={{
|
|
372
|
+
padding: '8px 24px',
|
|
373
|
+
borderRadius: 4,
|
|
374
|
+
border: 'none',
|
|
375
|
+
backgroundColor: controls.isPlaying ? '#f59e0b' : '#10b981',
|
|
376
|
+
color: 'white',
|
|
377
|
+
cursor: 'pointer',
|
|
378
|
+
fontWeight: 'bold',
|
|
379
|
+
}}
|
|
380
|
+
>
|
|
381
|
+
{controls.isPlaying ? 'Pause' : 'Play'}
|
|
382
|
+
</button>
|
|
383
|
+
<button
|
|
384
|
+
onClick={controls.reset}
|
|
385
|
+
style={{
|
|
386
|
+
padding: '8px 24px',
|
|
387
|
+
borderRadius: 4,
|
|
388
|
+
border: 'none',
|
|
389
|
+
backgroundColor: '#374151',
|
|
390
|
+
color: 'white',
|
|
391
|
+
cursor: 'pointer',
|
|
392
|
+
}}
|
|
393
|
+
>
|
|
394
|
+
Reset
|
|
395
|
+
</button>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div style={{ color: '#9ca3af', fontSize: 12, textAlign: 'center' }}>
|
|
399
|
+
Replaying {recordedEvents.length} recorded events
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
);
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// Helper style function
|
|
407
|
+
function buttonStyle(color: string): React.CSSProperties {
|
|
408
|
+
return {
|
|
409
|
+
padding: '6px 12px',
|
|
410
|
+
borderRadius: 4,
|
|
411
|
+
border: 'none',
|
|
412
|
+
backgroundColor: color,
|
|
413
|
+
color: 'white',
|
|
414
|
+
cursor: 'pointer',
|
|
415
|
+
fontSize: 12,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
{
|
|
2
|
+
"name": "Trace: principal-view-core-tests",
|
|
3
|
+
"description": "Exported at 2025-12-26T01:11:11.110Z",
|
|
4
|
+
"nodeTypes": {
|
|
5
|
+
"span": {
|
|
6
|
+
"description": "OpenTelemetry span from trace",
|
|
7
|
+
"shape": "rectangle"
|
|
8
|
+
},
|
|
9
|
+
"service": {
|
|
10
|
+
"description": "Service grouping",
|
|
11
|
+
"icon": "server",
|
|
12
|
+
"shape": "rectangle"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"edgeTypes": {
|
|
16
|
+
"span-child": {
|
|
17
|
+
"label": "Child span",
|
|
18
|
+
"directed": true
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"display": {
|
|
22
|
+
"layout": "manual",
|
|
23
|
+
"animations": {
|
|
24
|
+
"enabled": true,
|
|
25
|
+
"speed": 1
|
|
26
|
+
}
|
|
27
|
+
},
|
|
2
28
|
"nodes": [
|
|
3
29
|
{
|
|
4
30
|
"id": "service-principal-view-core-tests",
|
|
@@ -211,34 +237,5 @@
|
|
|
211
237
|
}
|
|
212
238
|
}
|
|
213
239
|
],
|
|
214
|
-
"edges": []
|
|
215
|
-
"pv": {
|
|
216
|
-
"version": "1.0.0",
|
|
217
|
-
"name": "Trace: principal-view-core-tests",
|
|
218
|
-
"description": "Exported at 2025-12-26T01:11:11.110Z",
|
|
219
|
-
"nodeTypes": {
|
|
220
|
-
"span": {
|
|
221
|
-
"description": "OpenTelemetry span from trace",
|
|
222
|
-
"shape": "rectangle"
|
|
223
|
-
},
|
|
224
|
-
"service": {
|
|
225
|
-
"description": "Service grouping",
|
|
226
|
-
"icon": "server",
|
|
227
|
-
"shape": "rectangle"
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
"edgeTypes": {
|
|
231
|
-
"span-child": {
|
|
232
|
-
"label": "Child span",
|
|
233
|
-
"directed": true
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
"display": {
|
|
237
|
-
"layout": "manual",
|
|
238
|
-
"animations": {
|
|
239
|
-
"enabled": true,
|
|
240
|
-
"speed": 1
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
240
|
+
"edges": []
|
|
244
241
|
}
|