@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.
Files changed (94) hide show
  1. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts +34 -0
  2. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts.map +1 -0
  3. package/dist/components/new-trace-viewer/components/detail-panel-width.js +67 -0
  4. package/dist/components/new-trace-viewer/components/detail-panel.d.ts +14 -0
  5. package/dist/components/new-trace-viewer/components/detail-panel.d.ts.map +1 -0
  6. package/dist/components/new-trace-viewer/components/detail-panel.js +122 -0
  7. package/dist/components/new-trace-viewer/components/draggable-border.d.ts +31 -0
  8. package/dist/components/new-trace-viewer/components/draggable-border.d.ts.map +1 -0
  9. package/dist/components/new-trace-viewer/components/draggable-border.js +140 -0
  10. package/dist/components/new-trace-viewer/components/event-list.d.ts +1 -1
  11. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
  12. package/dist/components/new-trace-viewer/components/event-list.js +3 -5
  13. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +1 -1
  14. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -1
  15. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +2 -2
  16. package/dist/components/new-trace-viewer/components/minimap.d.ts +14 -0
  17. package/dist/components/new-trace-viewer/components/minimap.d.ts.map +1 -0
  18. package/dist/components/new-trace-viewer/components/minimap.js +337 -0
  19. package/dist/components/new-trace-viewer/components/pane-constants.d.ts +14 -0
  20. package/dist/components/new-trace-viewer/components/pane-constants.d.ts.map +1 -0
  21. package/dist/components/new-trace-viewer/components/pane-constants.js +16 -0
  22. package/dist/components/new-trace-viewer/components/split-pane.d.ts +1 -4
  23. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -1
  24. package/dist/components/new-trace-viewer/components/split-pane.js +18 -16
  25. package/dist/components/new-trace-viewer/components/timeline.d.ts +2 -2
  26. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
  27. package/dist/components/new-trace-viewer/components/timeline.js +5 -7
  28. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -1
  29. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +10 -3
  30. package/dist/components/new-trace-viewer/components/use-element-width.d.ts +8 -0
  31. package/dist/components/new-trace-viewer/components/use-element-width.d.ts.map +1 -0
  32. package/dist/components/new-trace-viewer/components/use-element-width.js +25 -0
  33. package/dist/components/new-trace-viewer/context.d.ts +2 -0
  34. package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
  35. package/dist/components/new-trace-viewer/context.js +3 -2
  36. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
  37. package/dist/components/new-trace-viewer/trace-viewer.js +53 -181
  38. package/dist/components/new-trace-viewer/utils.d.ts +21 -0
  39. package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
  40. package/dist/components/new-trace-viewer/utils.js +44 -3
  41. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  42. package/dist/components/sidebar/attribute-panel.js +38 -35
  43. package/dist/components/sidebar/attributes-block.d.ts +18 -7
  44. package/dist/components/sidebar/attributes-block.d.ts.map +1 -1
  45. package/dist/components/sidebar/attributes-block.js +76 -18
  46. package/dist/components/sidebar/events-list.d.ts +1 -1
  47. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  48. package/dist/components/sidebar/events-list.js +9 -10
  49. package/dist/components/trace-viewer/components/map.d.ts +2 -2
  50. package/dist/components/trace-viewer/components/map.d.ts.map +1 -1
  51. package/dist/components/trace-viewer/components/node.d.ts +7 -7
  52. package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
  53. package/dist/components/ui/collapsible.d.ts +46 -0
  54. package/dist/components/ui/collapsible.d.ts.map +1 -0
  55. package/dist/components/ui/collapsible.js +66 -0
  56. package/dist/components/ui/data-inspector.js +2 -7
  57. package/dist/index.d.ts +2 -2
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +3 -3
  60. package/dist/lib/hydration.d.ts +12 -2
  61. package/dist/lib/hydration.d.ts.map +1 -1
  62. package/dist/lib/hydration.js +41 -18
  63. package/dist/lib/utils.d.ts +8 -5
  64. package/dist/lib/utils.d.ts.map +1 -1
  65. package/dist/lib/utils.js +13 -16
  66. package/package.json +6 -6
  67. package/src/components/new-trace-viewer/components/detail-panel-width.test.ts +123 -0
  68. package/src/components/new-trace-viewer/components/detail-panel-width.ts +76 -0
  69. package/src/components/new-trace-viewer/components/detail-panel.tsx +272 -0
  70. package/src/components/new-trace-viewer/components/draggable-border.tsx +216 -0
  71. package/src/components/new-trace-viewer/components/event-list.tsx +3 -5
  72. package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +1 -1
  73. package/src/components/new-trace-viewer/components/minimap.tsx +559 -0
  74. package/src/components/new-trace-viewer/components/pane-constants.ts +19 -0
  75. package/src/components/new-trace-viewer/components/split-pane.tsx +44 -55
  76. package/src/components/new-trace-viewer/components/timeline.tsx +3 -5
  77. package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +21 -1
  78. package/src/components/new-trace-viewer/components/use-element-width.ts +29 -0
  79. package/src/components/new-trace-viewer/context.tsx +4 -1
  80. package/src/components/new-trace-viewer/trace-viewer.tsx +93 -312
  81. package/src/components/new-trace-viewer/utils.test.ts +65 -0
  82. package/src/components/new-trace-viewer/utils.ts +76 -2
  83. package/src/components/sidebar/attribute-panel.tsx +106 -105
  84. package/src/components/sidebar/attributes-block.tsx +170 -50
  85. package/src/components/sidebar/events-list.tsx +107 -92
  86. package/src/components/ui/collapsible.tsx +219 -0
  87. package/src/index.ts +8 -7
  88. package/src/lib/hydration.ts +48 -25
  89. package/src/lib/utils.test.ts +33 -0
  90. package/src/lib/utils.ts +12 -16
  91. package/dist/components/sidebar/detail-card.d.ts +0 -13
  92. package/dist/components/sidebar/detail-card.d.ts.map +0 -1
  93. package/dist/components/sidebar/detail-card.js +0 -36
  94. package/src/components/sidebar/detail-card.tsx +0 -143
@@ -11,20 +11,17 @@ import {
11
11
  useState,
12
12
  } from 'react';
13
13
  import { cn } from '../../../lib/cn';
14
-
15
- const GUTTER_PX = 1;
16
- const MIN_PX = 50;
17
- const DEFAULT_START_PX = 340;
18
-
19
- export function Divider() {
20
- return <div aria-hidden className="h-full w-px shrink-0 bg-gray-alpha-400" />;
21
- }
14
+ import {
15
+ DEFAULT_START_PX,
16
+ GUTTER_PX,
17
+ MIN_PX,
18
+ paneColTemplate,
19
+ } from './pane-constants';
20
+ import { useElementWidth } from './use-element-width';
22
21
 
23
22
  export interface SplitPaneProps {
24
23
  children: ReactNode;
25
24
  className?: string;
26
- /** Fixed pixel width for the start (left) pane. Default 220. */
27
- defaultStartWidth?: number;
28
25
  /** Fixed (non-scrolling) header rendered above the start pane. */
29
26
  startHeader?: ReactNode;
30
27
  /** Fixed (non-scrolling) header rendered above the end pane. */
@@ -35,7 +32,6 @@ export interface SplitPaneProps {
35
32
  export function SplitPane({
36
33
  children,
37
34
  className,
38
- defaultStartWidth = DEFAULT_START_PX,
39
35
  startHeader,
40
36
  endHeader,
41
37
  scrollContainerRef,
@@ -46,13 +42,18 @@ export function SplitPane({
46
42
  }
47
43
  const [start, end] = parts;
48
44
 
49
- const [startPx, setStartPx] = useState(defaultStartWidth);
45
+ // `startPx` is the user's preferred width; the rendered width is derived by
46
+ // clamping against the live container width (same model as the detail
47
+ // panel), so shrinking the container compresses the pane without destroying
48
+ // the preference, and re-growing restores it.
49
+ const [startPx, setStartPx] = useState(DEFAULT_START_PX);
50
50
  const [isDragging, setIsDragging] = useState(false);
51
51
  const containerRef = useRef<HTMLDivElement>(null);
52
52
  const gutterRef = useRef<HTMLDivElement>(null);
53
53
  const rafRef = useRef<number | null>(null);
54
- const pendingPx = useRef(defaultStartWidth);
54
+ const pendingPx = useRef(DEFAULT_START_PX);
55
55
  const pointerIdRef = useRef<number | null>(null);
56
+ const containerWidth = useElementWidth(containerRef);
56
57
 
57
58
  useEffect(() => {
58
59
  return () => {
@@ -134,8 +135,14 @@ export function SplitPane({
134
135
  }
135
136
  };
136
137
 
137
- const colTemplate = `${startPx}px ${GUTTER_PX}px minmax(${MIN_PX}px, 1fr)`;
138
- const hasHeaders = startHeader != null || endHeader != null;
138
+ // Floor applied last so the start column can never collapse below MIN_PX
139
+ // (which would produce an invalid negative grid track on tiny containers).
140
+ const effectiveStartPx =
141
+ containerWidth > 0
142
+ ? Math.max(MIN_PX, Math.min(containerWidth - MIN_PX - GUTTER_PX, startPx))
143
+ : startPx;
144
+
145
+ const colTemplate = paneColTemplate(effectiveStartPx);
139
146
 
140
147
  const gutter = (
141
148
  <div
@@ -151,48 +158,30 @@ export function SplitPane({
151
158
  </div>
152
159
  );
153
160
 
154
- if (hasHeaders) {
155
- return (
156
- <div className={cn('flex flex-col h-full min-h-0', className)}>
157
- <div
158
- className="shrink-0 grid"
159
- style={{ gridTemplateColumns: colTemplate }}
160
- >
161
- <div>{startHeader}</div>
162
- <div className="flex justify-center">
163
- <span className="h-full w-px bg-gray-alpha-400" aria-hidden />
164
- </div>
165
- <div>{endHeader}</div>
166
- </div>
167
- <div
168
- ref={setContainerRef}
169
- className={cn(
170
- 'grid flex-1 min-h-0 overflow-x-hidden overflow-y-auto',
171
- isDragging && 'select-none'
172
- )}
173
- style={{ gridTemplateColumns: colTemplate }}
174
- >
175
- {start}
176
- {gutter}
177
- {end}
161
+ return (
162
+ <div className={cn('flex flex-col h-full min-h-0', className)}>
163
+ <div
164
+ className="shrink-0 grid"
165
+ style={{ gridTemplateColumns: colTemplate }}
166
+ >
167
+ <div>{startHeader}</div>
168
+ <div className="flex justify-center">
169
+ <span className="h-full w-px bg-gray-alpha-400" aria-hidden />
178
170
  </div>
171
+ <div>{endHeader}</div>
172
+ </div>
173
+ <div
174
+ ref={setContainerRef}
175
+ className={cn(
176
+ 'grid flex-1 min-h-0 overflow-x-hidden overflow-y-auto',
177
+ isDragging && 'select-none'
178
+ )}
179
+ style={{ gridTemplateColumns: colTemplate }}
180
+ >
181
+ {start}
182
+ {gutter}
183
+ {end}
179
184
  </div>
180
- );
181
- }
182
-
183
- return (
184
- <div
185
- ref={setContainerRef}
186
- className={cn(
187
- 'grid h-full min-h-0 content-start overflow-x-hidden overflow-y-auto',
188
- isDragging && 'select-none',
189
- className
190
- )}
191
- style={{ gridTemplateColumns: colTemplate, height: '100%' }}
192
- >
193
- {start}
194
- {gutter}
195
- {end}
196
185
  </div>
197
186
  );
198
187
  }
@@ -13,7 +13,6 @@ import {
13
13
  } from 'react';
14
14
  import { cn } from '../../../lib/cn';
15
15
  import {
16
- formatDuration,
17
16
  formatDurationPrecise,
18
17
  getHighResInMs,
19
18
  } from '../../trace-viewer/util/timing';
@@ -32,6 +31,7 @@ import {
32
31
  computeSpanSegments,
33
32
  getResourceColor,
34
33
  getSpanDurationMs,
34
+ isSpanErrored,
35
35
  } from '../utils';
36
36
  import {
37
37
  cullCollidingMarkers,
@@ -451,9 +451,7 @@ const TimelineBar = memo(function TimelineBar({
451
451
  const hasMarkers =
452
452
  markers.length > 0 || offscreen.left !== null || offscreen.right !== null;
453
453
 
454
- const workflowStatus = (span.attributes.data as Record<string, unknown>)
455
- ?.status as string | undefined;
456
- const isErrored = span.status.code === 2 || workflowStatus === 'failed';
454
+ const isErrored = isSpanErrored(span);
457
455
  const colors = getResourceColor(span.resource);
458
456
  const fallbackBg = isErrored
459
457
  ? (colors.errorBg ?? 'var(--ds-red-200)')
@@ -733,7 +731,7 @@ export function Timeline({
733
731
  key={gap.rowIndex}
734
732
  leftFrac={gap.leftFrac}
735
733
  rightFrac={gap.rightFrac}
736
- label={formatDuration(gap.gapMs, true)}
734
+ label={formatDurationPrecise(gap.gapMs)}
737
735
  rowIndex={gap.rowIndex}
738
736
  />
739
737
  ))}
@@ -1,6 +1,9 @@
1
1
  import { Skeleton } from '../../ui/skeleton';
2
+ import { DEFAULT_START_PX, paneColTemplate } from './pane-constants';
2
3
 
3
- const COL_TEMPLATE = '340px 1px minmax(50px, 1fr)';
4
+ // Mirrors SplitPane's initial column template so the skeleton lines up with
5
+ // the real viewer's first paint.
6
+ const COL_TEMPLATE = paneColTemplate(DEFAULT_START_PX);
4
7
 
5
8
  const ROWS: { id: string; name: number; off: number; bar: number }[] = [
6
9
  { id: 'r0', name: 62, off: 0, bar: 72 },
@@ -30,6 +33,23 @@ export function TraceViewerSkeleton() {
30
33
  >
31
34
  <span className="sr-only">Loading trace…</span>
32
35
 
36
+ {/* Minimap strip: thin density lines tracing the same shape as the bars */}
37
+ <div className="relative h-10 min-h-10 shrink-0 border-b border-gray-alpha-400">
38
+ <div className="absolute inset-x-4 top-[6px]">
39
+ {ROWS.map((row, index) => (
40
+ <Skeleton
41
+ key={row.id}
42
+ className="absolute h-[3px] rounded-full"
43
+ style={{
44
+ left: `${row.off}%`,
45
+ width: `${row.bar}%`,
46
+ top: index * 3.5,
47
+ }}
48
+ />
49
+ ))}
50
+ </div>
51
+ </div>
52
+
33
53
  {/* Header row: search header | divider | timeline header */}
34
54
  <div
35
55
  className="shrink-0 grid"
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+
3
+ import { type RefObject, useLayoutEffect, useState } from 'react';
4
+
5
+ /**
6
+ * Observed width (px) of `ref`'s element. Measures synchronously before paint
7
+ * when (re-)enabled, then tracks resizes. While disabled it keeps the last
8
+ * measured value; re-enabling re-measures before the next paint.
9
+ */
10
+ export function useElementWidth(
11
+ ref: RefObject<HTMLElement | null>,
12
+ enabled = true
13
+ ): number {
14
+ const [width, setWidth] = useState(0);
15
+
16
+ useLayoutEffect(() => {
17
+ if (!enabled) return;
18
+ const el = ref.current;
19
+ if (!el) return;
20
+ setWidth(Math.round(el.getBoundingClientRect().width));
21
+ const observer = new ResizeObserver(([entry]) => {
22
+ setWidth(Math.round(entry?.contentRect.width ?? 0));
23
+ });
24
+ observer.observe(el);
25
+ return () => observer.disconnect();
26
+ }, [ref, enabled]);
27
+
28
+ return width;
29
+ }
@@ -14,6 +14,8 @@ import type { Span } from './types';
14
14
  interface ActiveSpanContextValue {
15
15
  activeSpanId: string | null;
16
16
  activeSpan: Span | null;
17
+ /** The full span list the selection lives in (ordered as rendered). */
18
+ spans: Span[];
17
19
  setActiveSpan: (spanId: string) => void;
18
20
  clearActiveSpan: () => void;
19
21
  }
@@ -67,10 +69,11 @@ export function ActiveSpanProvider({
67
69
  () => ({
68
70
  activeSpanId,
69
71
  activeSpan,
72
+ spans,
70
73
  setActiveSpan,
71
74
  clearActiveSpan,
72
75
  }),
73
- [activeSpanId, activeSpan, setActiveSpan, clearActiveSpan]
76
+ [activeSpanId, activeSpan, spans, setActiveSpan, clearActiveSpan]
74
77
  );
75
78
 
76
79
  return (