@workflow/web-shared 5.0.0-beta.26 → 5.0.0-beta.28
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/new-trace-viewer/components/detail-panel-width.d.ts +34 -0
- package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/detail-panel-width.js +67 -0
- package/dist/components/new-trace-viewer/components/detail-panel.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/detail-panel.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/detail-panel.js +122 -0
- package/dist/components/new-trace-viewer/components/draggable-border.d.ts +31 -0
- package/dist/components/new-trace-viewer/components/draggable-border.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/draggable-border.js +140 -0
- package/dist/components/new-trace-viewer/components/event-list.d.ts +1 -1
- package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/event-list.js +3 -5
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +2 -2
- package/dist/components/new-trace-viewer/components/minimap.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/minimap.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/minimap.js +337 -0
- package/dist/components/new-trace-viewer/components/pane-constants.d.ts +14 -0
- package/dist/components/new-trace-viewer/components/pane-constants.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/pane-constants.js +16 -0
- package/dist/components/new-trace-viewer/components/split-pane.d.ts +1 -4
- package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/split-pane.js +18 -16
- package/dist/components/new-trace-viewer/components/timeline.d.ts +2 -2
- package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/timeline.js +5 -7
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +10 -3
- package/dist/components/new-trace-viewer/components/use-element-width.d.ts +8 -0
- package/dist/components/new-trace-viewer/components/use-element-width.d.ts.map +1 -0
- package/dist/components/new-trace-viewer/components/use-element-width.js +25 -0
- package/dist/components/new-trace-viewer/context.d.ts +2 -0
- package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/context.js +3 -2
- package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/trace-viewer.js +53 -181
- package/dist/components/new-trace-viewer/utils.d.ts +21 -0
- package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
- package/dist/components/new-trace-viewer/utils.js +44 -3
- package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
- package/dist/components/sidebar/attribute-panel.js +38 -35
- package/dist/components/sidebar/attributes-block.d.ts +18 -7
- package/dist/components/sidebar/attributes-block.d.ts.map +1 -1
- package/dist/components/sidebar/attributes-block.js +76 -18
- package/dist/components/sidebar/events-list.d.ts +1 -1
- package/dist/components/sidebar/events-list.d.ts.map +1 -1
- package/dist/components/sidebar/events-list.js +9 -10
- package/dist/components/trace-viewer/components/map.d.ts +2 -2
- package/dist/components/trace-viewer/components/map.d.ts.map +1 -1
- package/dist/components/trace-viewer/components/node.d.ts +7 -7
- package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
- package/dist/components/ui/collapsible.d.ts +46 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +66 -0
- package/dist/components/ui/data-inspector.js +2 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/hydration.d.ts +12 -2
- package/dist/lib/hydration.d.ts.map +1 -1
- package/dist/lib/hydration.js +41 -18
- package/dist/lib/utils.d.ts +8 -5
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +13 -16
- package/package.json +6 -6
- package/src/components/new-trace-viewer/components/detail-panel-width.test.ts +123 -0
- package/src/components/new-trace-viewer/components/detail-panel-width.ts +76 -0
- package/src/components/new-trace-viewer/components/detail-panel.tsx +272 -0
- package/src/components/new-trace-viewer/components/draggable-border.tsx +216 -0
- package/src/components/new-trace-viewer/components/event-list.tsx +3 -5
- package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +1 -1
- package/src/components/new-trace-viewer/components/minimap.tsx +559 -0
- package/src/components/new-trace-viewer/components/pane-constants.ts +19 -0
- package/src/components/new-trace-viewer/components/split-pane.tsx +44 -55
- package/src/components/new-trace-viewer/components/timeline.tsx +3 -5
- package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +21 -1
- package/src/components/new-trace-viewer/components/use-element-width.ts +29 -0
- package/src/components/new-trace-viewer/context.tsx +4 -1
- package/src/components/new-trace-viewer/trace-viewer.tsx +93 -312
- package/src/components/new-trace-viewer/utils.test.ts +65 -0
- package/src/components/new-trace-viewer/utils.ts +76 -2
- package/src/components/sidebar/attribute-panel.tsx +106 -105
- package/src/components/sidebar/attributes-block.tsx +170 -50
- package/src/components/sidebar/events-list.tsx +107 -92
- package/src/components/ui/collapsible.tsx +219 -0
- package/src/index.ts +8 -7
- package/src/lib/hydration.ts +48 -25
- package/src/lib/utils.test.ts +33 -0
- package/src/lib/utils.ts +12 -16
- package/dist/components/sidebar/detail-card.d.ts +0 -13
- package/dist/components/sidebar/detail-card.d.ts.map +0 -1
- package/dist/components/sidebar/detail-card.js +0 -36
- package/src/components/sidebar/detail-card.tsx +0 -143
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
formatDuration,
|
|
3
|
+
formatDurationPrecise,
|
|
4
|
+
getHighResInMs,
|
|
5
|
+
} from '../trace-viewer/util/timing';
|
|
2
6
|
import type { Span, SpanEvent } from './types';
|
|
3
7
|
|
|
4
8
|
// ---------------------------------------------------------------------------
|
|
@@ -37,6 +41,64 @@ export function getSpanDurationMs(span: Span): number {
|
|
|
37
41
|
);
|
|
38
42
|
}
|
|
39
43
|
|
|
44
|
+
export function isSpanErrored(span: Span): boolean {
|
|
45
|
+
const workflowStatus = (span.attributes.data as Record<string, unknown>)
|
|
46
|
+
?.status as string | undefined;
|
|
47
|
+
return span.status.code === 2 || workflowStatus === 'failed';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Viewport
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
export interface ViewportRange {
|
|
55
|
+
start: number;
|
|
56
|
+
end: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Clamp a candidate viewport to the root extent. The requested duration is
|
|
61
|
+
* preserved where possible (clamped to [minDurationMs, root duration]), then
|
|
62
|
+
* the window is shifted back inside the root bounds.
|
|
63
|
+
*/
|
|
64
|
+
export function clampViewportToRoot(
|
|
65
|
+
next: ViewportRange,
|
|
66
|
+
rootStart: number,
|
|
67
|
+
rootEnd: number,
|
|
68
|
+
minDurationMs: number
|
|
69
|
+
): ViewportRange {
|
|
70
|
+
const rootDuration = Math.max(rootEnd - rootStart, minDurationMs);
|
|
71
|
+
const duration = Math.min(
|
|
72
|
+
rootDuration,
|
|
73
|
+
Math.max(minDurationMs, next.end - next.start)
|
|
74
|
+
);
|
|
75
|
+
const maxStart = rootEnd - duration;
|
|
76
|
+
const start = Math.min(Math.max(next.start, rootStart), maxStart);
|
|
77
|
+
return { start, end: start + duration };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// Wheel gestures — shared between the timeline and the minimap
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
/** Convert a wheel delta to pixel units (line-mode deltas arrive in lines). */
|
|
85
|
+
export function wheelDeltaToPixels(delta: number, deltaMode: number): number {
|
|
86
|
+
return deltaMode === 1 ? delta * 16 : delta;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Exponential zoom factor for a wheel gesture. Coarse mouse-wheel steps are
|
|
91
|
+
* damped harder than trackpad pinches so both feel similar.
|
|
92
|
+
*/
|
|
93
|
+
export function wheelZoomScaleFactor(event: {
|
|
94
|
+
deltaY: number;
|
|
95
|
+
deltaMode: number;
|
|
96
|
+
}): number {
|
|
97
|
+
const dy = wheelDeltaToPixels(event.deltaY, event.deltaMode);
|
|
98
|
+
const isMouseWheel = event.deltaMode === 1 || Math.abs(event.deltaY) >= 50;
|
|
99
|
+
return 2 ** (dy / (isMouseWheel ? 200 : 60));
|
|
100
|
+
}
|
|
101
|
+
|
|
40
102
|
// ---------------------------------------------------------------------------
|
|
41
103
|
// Time markers
|
|
42
104
|
// ---------------------------------------------------------------------------
|
|
@@ -56,6 +118,8 @@ const NICE_INTERVALS = [
|
|
|
56
118
|
|
|
57
119
|
const MAX_MARKERS = 8;
|
|
58
120
|
|
|
121
|
+
const MS_IN_SECOND = 1000;
|
|
122
|
+
|
|
59
123
|
function pickInterval(viewDuration: number, maxTicks: number): number {
|
|
60
124
|
for (const interval of NICE_INTERVALS) {
|
|
61
125
|
if (viewDuration / interval <= maxTicks) return interval;
|
|
@@ -72,6 +136,13 @@ export function computeTimeMarkers(
|
|
|
72
136
|
const maxTicks = 6;
|
|
73
137
|
const interval = pickInterval(viewDuration, maxTicks);
|
|
74
138
|
|
|
139
|
+
// Sub-second steps need fractional labels, or ticks past 1s collide as
|
|
140
|
+
// duplicate whole seconds ("…1s, 2s, 2s, 3s"). Scale decimals to the step.
|
|
141
|
+
const fractionDigits =
|
|
142
|
+
interval >= MS_IN_SECOND
|
|
143
|
+
? 0
|
|
144
|
+
: Math.ceil(-Math.log10(interval / MS_IN_SECOND));
|
|
145
|
+
|
|
75
146
|
const firstTick = Math.ceil(offset / interval) * interval;
|
|
76
147
|
const markers: TimeMarker[] = [];
|
|
77
148
|
|
|
@@ -80,7 +151,10 @@ export function computeTimeMarkers(
|
|
|
80
151
|
if (position < -0.01 || position > 1.01) continue;
|
|
81
152
|
markers.push({
|
|
82
153
|
position: Math.min(Math.max(position, 0), 1),
|
|
83
|
-
label:
|
|
154
|
+
label:
|
|
155
|
+
fractionDigits === 0
|
|
156
|
+
? formatDuration(Math.abs(t), true)
|
|
157
|
+
: formatDurationPrecise(Math.abs(t), fractionDigits),
|
|
84
158
|
value: t,
|
|
85
159
|
});
|
|
86
160
|
if (markers.length >= MAX_MARKERS) break;
|
|
@@ -8,8 +8,12 @@ import type { KeyboardEvent, ReactNode } from 'react';
|
|
|
8
8
|
import { useCallback, useContext, useMemo, useState } from 'react';
|
|
9
9
|
import { isEncryptedMarker, isExpiredMarker } from '../../lib/hydration';
|
|
10
10
|
import { extractConversation, isDoStreamStep } from '../../lib/utils';
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
Collapsible,
|
|
13
|
+
CollapsibleContent,
|
|
14
|
+
CollapsibleRoot,
|
|
15
|
+
CollapsibleTrigger,
|
|
16
|
+
} from '../ui/collapsible';
|
|
13
17
|
import { ContextCardProvider } from '../ui/context-card';
|
|
14
18
|
import {
|
|
15
19
|
DecryptClickContext,
|
|
@@ -20,10 +24,13 @@ import { ErrorCard } from '../ui/error-card';
|
|
|
20
24
|
import { ErrorStackBlock, isStructuredError } from '../ui/error-stack-block';
|
|
21
25
|
import { Skeleton } from '../ui/skeleton';
|
|
22
26
|
import { TimestampTooltip } from '../ui/timestamp-tooltip';
|
|
23
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
DetailMonoKeyValueRow,
|
|
29
|
+
RunAttributesCard,
|
|
30
|
+
RunMetadataCard,
|
|
31
|
+
} from './attributes-block';
|
|
24
32
|
import { ConversationView } from './conversation-view';
|
|
25
33
|
import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
|
|
26
|
-
import { DetailCard } from './detail-card';
|
|
27
34
|
|
|
28
35
|
/**
|
|
29
36
|
* Tab button for conversation/JSON toggle
|
|
@@ -150,7 +157,7 @@ function ConversationWithTabs({
|
|
|
150
157
|
);
|
|
151
158
|
|
|
152
159
|
return (
|
|
153
|
-
<
|
|
160
|
+
<Collapsible label="Input">
|
|
154
161
|
<TabbedContainer
|
|
155
162
|
tabs={conversationTabs}
|
|
156
163
|
activeTab={activeTab}
|
|
@@ -171,7 +178,7 @@ function ConversationWithTabs({
|
|
|
171
178
|
</div>
|
|
172
179
|
)}
|
|
173
180
|
</TabbedContainer>
|
|
174
|
-
</
|
|
181
|
+
</Collapsible>
|
|
175
182
|
);
|
|
176
183
|
}
|
|
177
184
|
|
|
@@ -413,7 +420,7 @@ const attributeToDisplayFn: Record<
|
|
|
413
420
|
environment: (_value: unknown) => null,
|
|
414
421
|
executionContext: (_value: unknown) => null,
|
|
415
422
|
// Attributes — string-string metadata attached to the run.
|
|
416
|
-
// Rendered as key-value rows in its own collapsible
|
|
423
|
+
// Rendered as key-value rows in its own collapsible section;
|
|
417
424
|
// if empty/missing, hidden by the hasDisplayContent gate.
|
|
418
425
|
attributes: (value: unknown) => {
|
|
419
426
|
if (!hasDisplayContent(value)) return null;
|
|
@@ -431,16 +438,28 @@ const attributeToDisplayFn: Record<
|
|
|
431
438
|
// Resolved attributes, won't actually use this function
|
|
432
439
|
metadata: (value: unknown) => {
|
|
433
440
|
if (!hasDisplayContent(value)) return null;
|
|
434
|
-
if (isEncryptedMarker(value))
|
|
435
|
-
|
|
436
|
-
|
|
441
|
+
if (isEncryptedMarker(value)) {
|
|
442
|
+
return (
|
|
443
|
+
<Collapsible label="Metadata">
|
|
444
|
+
<EncryptedDataBlock />
|
|
445
|
+
</Collapsible>
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
if (isExpiredMarker(value)) {
|
|
449
|
+
return (
|
|
450
|
+
<Collapsible label="Metadata">
|
|
451
|
+
<ExpiredFieldBlock />
|
|
452
|
+
</Collapsible>
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
return <RunMetadataCard metadata={value} />;
|
|
437
456
|
},
|
|
438
457
|
input: (value: unknown, context?: DisplayContext) => {
|
|
439
458
|
if (isEncryptedMarker(value)) {
|
|
440
459
|
return (
|
|
441
|
-
<
|
|
460
|
+
<Collapsible label="Input">
|
|
442
461
|
<EncryptedFieldBlock />
|
|
443
|
-
</
|
|
462
|
+
</Collapsible>
|
|
444
463
|
);
|
|
445
464
|
}
|
|
446
465
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
@@ -463,14 +482,14 @@ const attributeToDisplayFn: Record<
|
|
|
463
482
|
<>
|
|
464
483
|
<ConversationWithTabs conversation={conversation} args={args} />
|
|
465
484
|
{hasClosureVars && (
|
|
466
|
-
<
|
|
485
|
+
<Collapsible label="Closure Variables">
|
|
467
486
|
{JsonBlock(closureVars)}
|
|
468
|
-
</
|
|
487
|
+
</Collapsible>
|
|
469
488
|
)}
|
|
470
489
|
{hasThisVal && (
|
|
471
|
-
<
|
|
490
|
+
<Collapsible label="This Value">
|
|
472
491
|
{JsonBlock(thisVal)}
|
|
473
|
-
</
|
|
492
|
+
</Collapsible>
|
|
474
493
|
)}
|
|
475
494
|
</>
|
|
476
495
|
);
|
|
@@ -479,12 +498,12 @@ const attributeToDisplayFn: Record<
|
|
|
479
498
|
|
|
480
499
|
// Don't render an empty "Input (0 arguments)" card when no input exists.
|
|
481
500
|
if (!hasArgs && !hasClosureVars && !hasThisVal) {
|
|
482
|
-
return <
|
|
501
|
+
return <Collapsible label="Input (no data)" disabled />;
|
|
483
502
|
}
|
|
484
503
|
|
|
485
504
|
return (
|
|
486
505
|
<>
|
|
487
|
-
<
|
|
506
|
+
<Collapsible label="Input">
|
|
488
507
|
{Array.isArray(args)
|
|
489
508
|
? args.map((v, i) => (
|
|
490
509
|
<div className="mt-2 first:mt-0" key={i}>
|
|
@@ -492,14 +511,14 @@ const attributeToDisplayFn: Record<
|
|
|
492
511
|
</div>
|
|
493
512
|
))
|
|
494
513
|
: JsonBlock(args)}
|
|
495
|
-
</
|
|
514
|
+
</Collapsible>
|
|
496
515
|
{hasClosureVars && (
|
|
497
|
-
<
|
|
516
|
+
<Collapsible label="Closure Variables">
|
|
498
517
|
{JsonBlock(closureVars)}
|
|
499
|
-
</
|
|
518
|
+
</Collapsible>
|
|
500
519
|
)}
|
|
501
520
|
{hasThisVal && (
|
|
502
|
-
<
|
|
521
|
+
<Collapsible label="Context">{JsonBlock(thisVal)}</Collapsible>
|
|
503
522
|
)}
|
|
504
523
|
</>
|
|
505
524
|
);
|
|
@@ -507,10 +526,10 @@ const attributeToDisplayFn: Record<
|
|
|
507
526
|
|
|
508
527
|
// Fallback: treat as plain array or object
|
|
509
528
|
if (!hasDisplayContent(value)) {
|
|
510
|
-
return <
|
|
529
|
+
return <Collapsible label="Input (no data)" disabled />;
|
|
511
530
|
}
|
|
512
531
|
return (
|
|
513
|
-
<
|
|
532
|
+
<Collapsible label="Input">
|
|
514
533
|
{Array.isArray(value)
|
|
515
534
|
? value.map((v, i) => (
|
|
516
535
|
<div className="mt-2 first:mt-0" key={i}>
|
|
@@ -518,27 +537,27 @@ const attributeToDisplayFn: Record<
|
|
|
518
537
|
</div>
|
|
519
538
|
))
|
|
520
539
|
: JsonBlock(value)}
|
|
521
|
-
</
|
|
540
|
+
</Collapsible>
|
|
522
541
|
);
|
|
523
542
|
},
|
|
524
543
|
output: (value: unknown) => {
|
|
525
544
|
if (isEncryptedMarker(value)) {
|
|
526
545
|
return (
|
|
527
|
-
<
|
|
546
|
+
<Collapsible label="Output">
|
|
528
547
|
<EncryptedFieldBlock />
|
|
529
|
-
</
|
|
548
|
+
</Collapsible>
|
|
530
549
|
);
|
|
531
550
|
}
|
|
532
551
|
if (!hasDisplayContent(value)) return null;
|
|
533
552
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
534
|
-
return <
|
|
553
|
+
return <Collapsible label="Output">{JsonBlock(value)}</Collapsible>;
|
|
535
554
|
},
|
|
536
555
|
error: (value: unknown) => {
|
|
537
556
|
if (isEncryptedMarker(value)) {
|
|
538
557
|
return (
|
|
539
|
-
<
|
|
558
|
+
<Collapsible label="Error" defaultOpen>
|
|
540
559
|
<EncryptedFieldBlock />
|
|
541
|
-
</
|
|
560
|
+
</Collapsible>
|
|
542
561
|
);
|
|
543
562
|
}
|
|
544
563
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
@@ -548,32 +567,32 @@ const attributeToDisplayFn: Record<
|
|
|
548
567
|
// `{ message, stack }`. Render both with the dedicated error block.
|
|
549
568
|
if (isStructuredError(value)) {
|
|
550
569
|
return (
|
|
551
|
-
<
|
|
570
|
+
<Collapsible label="Error" defaultOpen>
|
|
552
571
|
<ErrorStackBlock value={value} />
|
|
553
|
-
</
|
|
572
|
+
</Collapsible>
|
|
554
573
|
);
|
|
555
574
|
}
|
|
556
575
|
|
|
557
576
|
return (
|
|
558
|
-
<
|
|
577
|
+
<Collapsible label="Error" defaultOpen>
|
|
559
578
|
{JsonBlock(value)}
|
|
560
|
-
</
|
|
579
|
+
</Collapsible>
|
|
561
580
|
);
|
|
562
581
|
},
|
|
563
582
|
eventData: (value: unknown) => {
|
|
564
583
|
if (isEncryptedMarker(value)) {
|
|
565
584
|
return (
|
|
566
|
-
<
|
|
585
|
+
<Collapsible label="Event Data" defaultOpen>
|
|
567
586
|
<EncryptedFieldBlock />
|
|
568
|
-
</
|
|
587
|
+
</Collapsible>
|
|
569
588
|
);
|
|
570
589
|
}
|
|
571
590
|
if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
|
|
572
591
|
if (!hasDisplayContent(value)) return null;
|
|
573
592
|
return (
|
|
574
|
-
<
|
|
593
|
+
<Collapsible label="Event Data" defaultOpen>
|
|
575
594
|
{JsonBlock(value)}
|
|
576
|
-
</
|
|
595
|
+
</Collapsible>
|
|
577
596
|
);
|
|
578
597
|
},
|
|
579
598
|
errorCode: (value: unknown) => {
|
|
@@ -591,12 +610,13 @@ const resolvableAttributes = [
|
|
|
591
610
|
'eventData',
|
|
592
611
|
];
|
|
593
612
|
|
|
594
|
-
// Attributes whose displayFn renders its own section header via
|
|
613
|
+
// Attributes whose displayFn renders its own section header via Collapsible,
|
|
595
614
|
// so the outer AttributeBlock should not duplicate the label.
|
|
596
615
|
const selfHeaderedAttributes = new Set([
|
|
597
616
|
'input',
|
|
598
617
|
'output',
|
|
599
618
|
'error',
|
|
619
|
+
'metadata',
|
|
600
620
|
'attributes',
|
|
601
621
|
'eventData',
|
|
602
622
|
]);
|
|
@@ -649,12 +669,12 @@ export const AttributeBlock = ({
|
|
|
649
669
|
: 'Input';
|
|
650
670
|
if (decryptCtx?.hasEncryptedData) {
|
|
651
671
|
return (
|
|
652
|
-
<
|
|
672
|
+
<Collapsible label={label} defaultOpen={attribute === 'eventData'}>
|
|
653
673
|
<EncryptedFieldBlock />
|
|
654
|
-
</
|
|
674
|
+
</Collapsible>
|
|
655
675
|
);
|
|
656
676
|
}
|
|
657
|
-
return <
|
|
677
|
+
return <Collapsible label={label} />;
|
|
658
678
|
}
|
|
659
679
|
|
|
660
680
|
const displayFn =
|
|
@@ -835,61 +855,44 @@ export const AttributePanel = ({
|
|
|
835
855
|
<StreamClickContext.Provider value={onStreamClick}>
|
|
836
856
|
<DecryptClickContext.Provider value={decryptValue}>
|
|
837
857
|
{visibleBasicAttributes.length > 0 && (
|
|
838
|
-
<
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
858
|
+
<CollapsibleRoot defaultOpen>
|
|
859
|
+
<CollapsibleTrigger>Metadata</CollapsibleTrigger>
|
|
860
|
+
<CollapsibleContent className="mt-0 mb-2">
|
|
861
|
+
<div className="flex flex-col">
|
|
862
|
+
{orderedBasicAttributes.map((attribute) => {
|
|
863
|
+
const displayValue = attributeToDisplayFn[
|
|
864
|
+
attribute as keyof typeof attributeToDisplayFn
|
|
865
|
+
]?.(displayData[attribute as keyof typeof displayData]);
|
|
866
|
+
const isCopyableBasicAttribute =
|
|
867
|
+
copyableBasicAttributes.has(
|
|
868
|
+
attribute as AttributeKey
|
|
869
|
+
) && typeof displayValue === 'string';
|
|
870
|
+
const label = getAttributeDisplayName(attribute);
|
|
871
|
+
|
|
872
|
+
return (
|
|
873
|
+
<DetailMonoKeyValueRow
|
|
874
|
+
key={attribute}
|
|
875
|
+
label={label}
|
|
876
|
+
value={displayValue}
|
|
877
|
+
copyText={
|
|
878
|
+
isCopyableBasicAttribute ? displayValue : undefined
|
|
879
|
+
}
|
|
880
|
+
/>
|
|
881
|
+
);
|
|
882
|
+
})}
|
|
883
|
+
{isLoading &&
|
|
884
|
+
resource === 'sleep' &&
|
|
885
|
+
!displayData.resumeAt && (
|
|
886
|
+
<div className="flex items-center justify-between gap-3 py-0.5">
|
|
887
|
+
<span className="text-label-13 text-gray-900">
|
|
888
|
+
Resume
|
|
889
|
+
</span>
|
|
890
|
+
<Skeleton className="h-4 w-[55%]" />
|
|
870
891
|
</div>
|
|
871
|
-
) : (
|
|
872
|
-
<span className="text-right text-label-13 font-mono">
|
|
873
|
-
{displayValue}
|
|
874
|
-
</span>
|
|
875
892
|
)}
|
|
876
|
-
</div>
|
|
877
|
-
);
|
|
878
|
-
})}
|
|
879
|
-
{isLoading && resource === 'sleep' && !displayData.resumeAt && (
|
|
880
|
-
<div className="py-1">
|
|
881
|
-
<div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
|
|
882
|
-
<span
|
|
883
|
-
className="text-[14px] first-letter:uppercase"
|
|
884
|
-
style={{ color: 'var(--ds-gray-700)' }}
|
|
885
|
-
>
|
|
886
|
-
resumeAt
|
|
887
|
-
</span>
|
|
888
|
-
<Skeleton className="h-4 w-[55%]" />
|
|
889
|
-
</div>
|
|
890
893
|
</div>
|
|
891
|
-
|
|
892
|
-
</
|
|
894
|
+
</CollapsibleContent>
|
|
895
|
+
</CollapsibleRoot>
|
|
893
896
|
)}
|
|
894
897
|
{error ? (
|
|
895
898
|
<ErrorCard
|
|
@@ -900,17 +903,15 @@ export const AttributePanel = ({
|
|
|
900
903
|
) : hasExpired ? (
|
|
901
904
|
<ExpiredDataMessage />
|
|
902
905
|
) : resolvedAttributes.length > 0 ? (
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
))}
|
|
913
|
-
</>
|
|
906
|
+
resolvedAttributes.map((attribute) => (
|
|
907
|
+
<AttributeBlock
|
|
908
|
+
isLoading={isLoading}
|
|
909
|
+
key={attribute}
|
|
910
|
+
attribute={attribute}
|
|
911
|
+
value={displayData[attribute as keyof typeof displayData]}
|
|
912
|
+
context={displayContext}
|
|
913
|
+
/>
|
|
914
|
+
))
|
|
914
915
|
) : null}
|
|
915
916
|
</DecryptClickContext.Provider>
|
|
916
917
|
</StreamClickContext.Provider>
|