@workflow/web-shared 5.0.0-beta.7 → 5.0.0-beta.9

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 (211) hide show
  1. package/dist/components/error-boundary.js +1 -1
  2. package/dist/components/event-list-view.d.ts +12 -0
  3. package/dist/components/event-list-view.d.ts.map +1 -1
  4. package/dist/components/event-list-view.js +26 -13
  5. package/dist/components/hook-actions.js +1 -1
  6. package/dist/components/index.d.ts +1 -0
  7. package/dist/components/index.d.ts.map +1 -1
  8. package/dist/components/index.js +2 -1
  9. package/dist/components/new-trace-viewer/components/copy-button.js +2 -2
  10. package/dist/components/new-trace-viewer/components/event-list.d.ts +3 -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 +8 -7
  13. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +1 -1
  14. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +1 -1
  15. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +1 -1
  16. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +1 -1
  17. package/dist/components/new-trace-viewer/components/split-pane.js +1 -1
  18. package/dist/components/new-trace-viewer/components/timeline.d.ts +4 -1
  19. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
  20. package/dist/components/new-trace-viewer/components/timeline.js +6 -5
  21. package/dist/components/new-trace-viewer/context.js +1 -1
  22. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +1 -1
  23. package/dist/components/new-trace-viewer/detail-panel.js +3 -2
  24. package/dist/components/new-trace-viewer/icons.js +1 -1
  25. package/dist/components/new-trace-viewer/search.d.ts +19 -0
  26. package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
  27. package/dist/components/new-trace-viewer/search.js +134 -0
  28. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
  29. package/dist/components/new-trace-viewer/trace-viewer.js +62 -35
  30. package/dist/components/new-trace-viewer/types.js +1 -1
  31. package/dist/components/new-trace-viewer/util/constants.js +1 -1
  32. package/dist/components/new-trace-viewer/utils.js +1 -1
  33. package/dist/components/run-trace-view.js +1 -1
  34. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  35. package/dist/components/sidebar/attribute-panel.js +99 -73
  36. package/dist/components/sidebar/conversation-view.js +1 -1
  37. package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
  38. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  39. package/dist/components/sidebar/copyable-data-block.js +16 -15
  40. package/dist/components/sidebar/detail-card.d.ts +5 -6
  41. package/dist/components/sidebar/detail-card.d.ts.map +1 -1
  42. package/dist/components/sidebar/detail-card.js +32 -16
  43. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  44. package/dist/components/sidebar/entity-detail-panel.js +6 -3
  45. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  46. package/dist/components/sidebar/events-list.js +21 -15
  47. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  48. package/dist/components/sidebar/sidebar-data-context.js +1 -1
  49. package/dist/components/stream-viewer.js +1 -1
  50. package/dist/components/trace-viewer/components/map.js +1 -1
  51. package/dist/components/trace-viewer/components/markers.js +1 -1
  52. package/dist/components/trace-viewer/components/node.js +1 -1
  53. package/dist/components/trace-viewer/components/search-input.js +1 -1
  54. package/dist/components/trace-viewer/components/search.js +1 -1
  55. package/dist/components/trace-viewer/components/span-content.js +1 -1
  56. package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
  57. package/dist/components/trace-viewer/components/span-segments.js +1 -1
  58. package/dist/components/trace-viewer/components/span-strategies.js +1 -1
  59. package/dist/components/trace-viewer/components/ui.js +1 -1
  60. package/dist/components/trace-viewer/components/zoom-button.js +1 -1
  61. package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
  62. package/dist/components/trace-viewer/context.js +1 -1
  63. package/dist/components/trace-viewer/index.js +1 -1
  64. package/dist/components/trace-viewer/trace-viewer.js +1 -1
  65. package/dist/components/trace-viewer/types.js +1 -1
  66. package/dist/components/trace-viewer/util/constants.js +1 -1
  67. package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
  68. package/dist/components/trace-viewer/util/timing.js +1 -1
  69. package/dist/components/trace-viewer/util/tree.js +1 -1
  70. package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
  71. package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
  72. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
  73. package/dist/components/trace-viewer/worker.js +1 -1
  74. package/dist/components/trace-viewer-new.js +1 -1
  75. package/dist/components/ui/alert.js +1 -1
  76. package/dist/components/ui/button.d.ts +10 -0
  77. package/dist/components/ui/button.d.ts.map +1 -0
  78. package/dist/components/ui/button.js +46 -0
  79. package/dist/components/ui/card.js +1 -1
  80. package/dist/components/ui/data-inspector.d.ts +1 -0
  81. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  82. package/dist/components/ui/data-inspector.js +4 -9
  83. package/dist/components/ui/decrypt-button.js +1 -1
  84. package/dist/components/ui/error-card.js +1 -1
  85. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  86. package/dist/components/ui/error-stack-block.js +4 -18
  87. package/dist/components/ui/icon-button.d.ts +13 -0
  88. package/dist/components/ui/icon-button.d.ts.map +1 -0
  89. package/dist/components/ui/icon-button.js +29 -0
  90. package/dist/components/ui/inspector-theme.js +1 -1
  91. package/dist/components/ui/load-more-button.js +1 -1
  92. package/dist/components/ui/menu-dropdown.js +1 -1
  93. package/dist/components/ui/skeleton.js +1 -1
  94. package/dist/components/ui/spinner.js +1 -1
  95. package/dist/components/ui/timestamp-tooltip.js +1 -1
  96. package/dist/components/workflow-trace-view.js +1 -1
  97. package/dist/components/workflow-traces/event-colors.js +1 -1
  98. package/dist/components/workflow-traces/trace-colors.js +1 -1
  99. package/dist/components/workflow-traces/trace-span-construction.js +1 -1
  100. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  101. package/dist/hooks/use-dark-mode.js +1 -1
  102. package/dist/hooks/use-reduced-motion.js +1 -1
  103. package/dist/index.js +1 -1
  104. package/dist/lib/event-analysis.js +1 -1
  105. package/dist/lib/event-materialization.js +1 -1
  106. package/dist/lib/hydration.js +1 -1
  107. package/dist/lib/stream-display.js +1 -1
  108. package/dist/lib/toast.js +1 -1
  109. package/dist/lib/trace-builder.js +1 -1
  110. package/dist/lib/utils.js +1 -1
  111. package/dist/styles.css +5 -0
  112. package/package.json +5 -5
  113. package/src/components/event-list-view.tsx +29 -13
  114. package/src/components/index.ts +1 -0
  115. package/src/components/new-trace-viewer/components/copy-button.tsx +1 -1
  116. package/src/components/new-trace-viewer/components/event-list.tsx +17 -6
  117. package/src/components/new-trace-viewer/components/timeline.tsx +11 -2
  118. package/src/components/new-trace-viewer/detail-panel.tsx +3 -6
  119. package/src/components/new-trace-viewer/search.ts +178 -0
  120. package/src/components/new-trace-viewer/trace-viewer.tsx +123 -89
  121. package/src/components/sidebar/attribute-panel.tsx +212 -235
  122. package/src/components/sidebar/copyable-data-block.tsx +49 -27
  123. package/src/components/sidebar/detail-card.tsx +119 -41
  124. package/src/components/sidebar/entity-detail-panel.tsx +28 -28
  125. package/src/components/sidebar/events-list.tsx +51 -79
  126. package/src/components/ui/button.tsx +68 -0
  127. package/src/components/ui/data-inspector.tsx +9 -18
  128. package/src/components/ui/error-stack-block.tsx +7 -26
  129. package/src/components/ui/icon-button.tsx +57 -0
  130. package/src/styles.css +5 -0
  131. package/dist/components/error-boundary.js.map +0 -1
  132. package/dist/components/event-list-view.js.map +0 -1
  133. package/dist/components/hook-actions.js.map +0 -1
  134. package/dist/components/index.js.map +0 -1
  135. package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
  136. package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
  137. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js.map +0 -1
  138. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js.map +0 -1
  139. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js.map +0 -1
  140. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js.map +0 -1
  141. package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
  142. package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
  143. package/dist/components/new-trace-viewer/context.js.map +0 -1
  144. package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
  145. package/dist/components/new-trace-viewer/icons.js.map +0 -1
  146. package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
  147. package/dist/components/new-trace-viewer/types.js.map +0 -1
  148. package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
  149. package/dist/components/new-trace-viewer/utils.js.map +0 -1
  150. package/dist/components/run-trace-view.js.map +0 -1
  151. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  152. package/dist/components/sidebar/conversation-view.js.map +0 -1
  153. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  154. package/dist/components/sidebar/detail-card.js.map +0 -1
  155. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  156. package/dist/components/sidebar/events-list.js.map +0 -1
  157. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  158. package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
  159. package/dist/components/stream-viewer.js.map +0 -1
  160. package/dist/components/trace-viewer/components/map.js.map +0 -1
  161. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  162. package/dist/components/trace-viewer/components/node.js.map +0 -1
  163. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  164. package/dist/components/trace-viewer/components/search.js.map +0 -1
  165. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  166. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  167. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  168. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  169. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  170. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  171. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  172. package/dist/components/trace-viewer/context.js.map +0 -1
  173. package/dist/components/trace-viewer/index.js.map +0 -1
  174. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  175. package/dist/components/trace-viewer/types.js.map +0 -1
  176. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  177. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  178. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  179. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  180. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  181. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  182. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  183. package/dist/components/trace-viewer/worker.js.map +0 -1
  184. package/dist/components/trace-viewer-new.js.map +0 -1
  185. package/dist/components/ui/alert.js.map +0 -1
  186. package/dist/components/ui/card.js.map +0 -1
  187. package/dist/components/ui/data-inspector.js.map +0 -1
  188. package/dist/components/ui/decrypt-button.js.map +0 -1
  189. package/dist/components/ui/error-card.js.map +0 -1
  190. package/dist/components/ui/error-stack-block.js.map +0 -1
  191. package/dist/components/ui/inspector-theme.js.map +0 -1
  192. package/dist/components/ui/load-more-button.js.map +0 -1
  193. package/dist/components/ui/menu-dropdown.js.map +0 -1
  194. package/dist/components/ui/skeleton.js.map +0 -1
  195. package/dist/components/ui/spinner.js.map +0 -1
  196. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  197. package/dist/components/workflow-trace-view.js.map +0 -1
  198. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  199. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  200. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  201. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  202. package/dist/hooks/use-dark-mode.js.map +0 -1
  203. package/dist/hooks/use-reduced-motion.js.map +0 -1
  204. package/dist/index.js.map +0 -1
  205. package/dist/lib/event-analysis.js.map +0 -1
  206. package/dist/lib/event-materialization.js.map +0 -1
  207. package/dist/lib/hydration.js.map +0 -1
  208. package/dist/lib/stream-display.js.map +0 -1
  209. package/dist/lib/toast.js.map +0 -1
  210. package/dist/lib/trace-builder.js.map +0 -1
  211. package/dist/lib/utils.js.map +0 -1
@@ -1,10 +1,19 @@
1
1
  'use client';
2
2
 
3
3
  import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
4
- import { RotateCcw, Search, X, ZoomIn, ZoomOut } from 'lucide-react';
4
+ import {
5
+ ChevronDown,
6
+ ChevronUp,
7
+ RotateCcw,
8
+ Search,
9
+ X,
10
+ ZoomIn,
11
+ ZoomOut,
12
+ } from 'lucide-react';
5
13
  import {
6
14
  type ReactNode,
7
15
  useCallback,
16
+ useDeferredValue,
8
17
  useEffect,
9
18
  useMemo,
10
19
  useRef,
@@ -19,16 +28,17 @@ import {
19
28
  import { useSidebarDataOptional } from '../sidebar/sidebar-data-context';
20
29
  import type { Trace } from '../trace-viewer/types';
21
30
  import { formatDuration, getHighResInMs } from '../trace-viewer/util/timing';
22
- import { CopyButton } from './components/copy-button';
31
+ import { IconButton } from '../ui/icon-button';
23
32
  import EventList from './components/event-list';
24
33
  import { SplitPane } from './components/split-pane';
25
34
  import {
35
+ TIMELINE_PADDING_PX,
26
36
  Timeline,
27
37
  TimelineHeader,
28
- TIMELINE_PADDING_PX,
29
38
  } from './components/timeline';
30
39
  import { ActiveSpanProvider, useActiveSpan } from './context';
31
40
  import { DetailPanel } from './detail-panel';
41
+ import { searchSpans } from './search';
32
42
  import { computeRootBounds, computeTimeMarkers } from './utils';
33
43
 
34
44
  interface NewTraceViewerProps {
@@ -135,7 +145,7 @@ function useSelectedSpanInfo(): SelectedSpanInfo | null {
135
145
  spanId: activeSpan.spanId,
136
146
  rawEvents,
137
147
  };
138
- }, [activeSpan, sidebar?.events]);
148
+ }, [activeSpan, sidebar]);
139
149
  }
140
150
 
141
151
  // ---------------------------------------------------------------------------
@@ -158,15 +168,12 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
158
168
  const selectedSpan = useSelectedSpanInfo();
159
169
 
160
170
  const [searchQuery, setSearchQuery] = useState('');
171
+ const deferredSearchQuery = useDeferredValue(searchQuery);
161
172
 
162
- const filteredSpans = useMemo(() => {
163
- const q = searchQuery.trim().toLowerCase();
164
- if (!q) return trace.spans;
165
- return trace.spans.filter(
166
- (s) =>
167
- s.name.toLowerCase().includes(q) || s.resource.toLowerCase().includes(q)
168
- );
169
- }, [trace.spans, searchQuery]);
173
+ const searchResult = useMemo(
174
+ () => searchSpans(trace.spans, deferredSearchQuery),
175
+ [trace.spans, deferredSearchQuery]
176
+ );
170
177
 
171
178
  const root = useMemo(() => computeRootBounds(trace.spans), [trace.spans]);
172
179
 
@@ -197,7 +204,7 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
197
204
  });
198
205
 
199
206
  prevRootRef.current = { start: newStart, end: newEnd };
200
- }, [root.startTime, root.duration]);
207
+ }, [root.startTime, root.duration, setViewport]);
201
208
 
202
209
  const viewDuration = viewport.end - viewport.start;
203
210
 
@@ -307,13 +314,31 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
307
314
  const [altHeld, setAltHeld] = useState(false);
308
315
 
309
316
  useEffect(() => {
317
+ const handleSidebarNavKey = (e: KeyboardEvent): void => {
318
+ const target = e.target as HTMLElement | null;
319
+ if (
320
+ target instanceof HTMLInputElement ||
321
+ target instanceof HTMLTextAreaElement ||
322
+ target?.isContentEditable
323
+ ) {
324
+ return;
325
+ }
326
+ const targetId =
327
+ e.key === 'k' ? prevSpanIdRef.current : nextSpanIdRef.current;
328
+ if (targetId) {
329
+ e.preventDefault();
330
+ handleSelectSpanRef.current(targetId);
331
+ }
332
+ };
333
+
310
334
  const onKeyDown = (e: KeyboardEvent): void => {
311
335
  if (e.key === 'Escape') {
312
336
  clearActiveSpan();
313
- }
314
- if (e.key === 'Alt') {
337
+ } else if (e.key === 'Alt') {
315
338
  e.preventDefault();
316
339
  setAltHeld(true);
340
+ } else if (e.key === 'j' || e.key === 'k') {
341
+ handleSidebarNavKey(e);
317
342
  }
318
343
  };
319
344
  const onKeyUp = (e: KeyboardEvent): void => {
@@ -395,7 +420,8 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
395
420
  (e.clientX - rect.left - TIMELINE_PADDING_PX) / contentWidth
396
421
  )
397
422
  );
398
- const scaleFactor = Math.pow(2, dy / 200);
423
+ const isMouseWheel = e.deltaMode === 1 || Math.abs(e.deltaY) >= 50;
424
+ const scaleFactor = Math.pow(2, dy / (isMouseWheel ? 200 : 60));
399
425
 
400
426
  setViewport((prev) => {
401
427
  const prevDuration = prev.end - prev.start;
@@ -446,7 +472,7 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
446
472
 
447
473
  el.addEventListener('wheel', onWheel, { passive: false });
448
474
  return () => el.removeEventListener('wheel', onWheel);
449
- }, [root.startTime, root.duration]);
475
+ }, [root.startTime, root.duration, setViewport]);
450
476
 
451
477
  // Derive the selected span name and metadata for the panel header
452
478
  const selectedSpanName = useMemo(() => {
@@ -468,21 +494,30 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
468
494
  );
469
495
  }, [selectedSpan?.data, selectedSpan?.resource]);
470
496
 
471
- const selectedResource = selectedSpan?.resource as string | undefined;
472
- const selectedResourceId = useMemo(() => {
473
- if (!selectedSpan?.data) return undefined;
474
- const data = selectedSpan.data as Record<string, unknown>;
475
- if (selectedSpan.resource === 'hook') {
476
- return (data.hookId as string | undefined) ?? selectedSpan.spanId;
477
- }
497
+ const { prevSpanId, nextSpanId } = useMemo(() => {
498
+ if (!activeSpanId) return { prevSpanId: null, nextSpanId: null };
499
+ const i = trace.spans.findIndex((s) => s.spanId === activeSpanId);
500
+ if (i === -1) return { prevSpanId: null, nextSpanId: null };
501
+ return {
502
+ prevSpanId: trace.spans[i - 1]?.spanId ?? null,
503
+ nextSpanId: trace.spans[i + 1]?.spanId ?? null,
504
+ };
505
+ }, [activeSpanId, trace.spans]);
478
506
 
479
- return (
480
- (data.stepId as string) ??
481
- (data.runId as string) ??
482
- (data.hookId as string) ??
483
- selectedSpan.spanId
484
- );
485
- }, [selectedSpan?.data, selectedSpan?.resource, selectedSpan?.spanId]);
507
+ const handleSelectPrevSpan = useCallback(() => {
508
+ if (prevSpanId) handleSelectSpan(prevSpanId);
509
+ }, [prevSpanId, handleSelectSpan]);
510
+
511
+ const handleSelectNextSpan = useCallback(() => {
512
+ if (nextSpanId) handleSelectSpan(nextSpanId);
513
+ }, [nextSpanId, handleSelectSpan]);
514
+
515
+ const prevSpanIdRef = useRef(prevSpanId);
516
+ const nextSpanIdRef = useRef(nextSpanId);
517
+ const handleSelectSpanRef = useRef(handleSelectSpan);
518
+ prevSpanIdRef.current = prevSpanId;
519
+ nextSpanIdRef.current = nextSpanId;
520
+ handleSelectSpanRef.current = handleSelectSpan;
486
521
 
487
522
  return (
488
523
  <div
@@ -496,7 +531,7 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
496
531
  >
497
532
  <SplitPane
498
533
  startHeader={
499
- <div className="bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-center px-2 gap-1.5">
534
+ <div className="bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-center pl-4 pr-2 gap-1.5">
500
535
  <Search className="w-3.5 h-3.5 shrink-0 text-gray-800" />
501
536
  <input
502
537
  id="trace-viewer-search"
@@ -504,6 +539,13 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
504
539
  type="text"
505
540
  value={searchQuery}
506
541
  onChange={(e) => setSearchQuery(e.target.value)}
542
+ onKeyDown={(e) => {
543
+ if (e.key === 'Escape' && searchQuery) {
544
+ e.preventDefault();
545
+ e.stopPropagation();
546
+ setSearchQuery('');
547
+ }
548
+ }}
507
549
  placeholder="Search spans..."
508
550
  aria-label="Search spans"
509
551
  className="flex-1 min-w-0 bg-transparent text-sm text-gray-1000 placeholder:text-gray-800 outline-none"
@@ -511,10 +553,13 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
511
553
  {searchQuery && (
512
554
  <button
513
555
  type="button"
556
+ aria-label="Clear search"
514
557
  onClick={() => setSearchQuery('')}
515
- className="shrink-0 p-0.5 rounded-sm text-gray-800 hover:text-gray-1000 hover:bg-gray-200 transition-colors"
558
+ className="-mr-2 hidden h-full max-w-full shrink-0 cursor-pointer items-center rounded-r-md border-0 bg-transparent px-2.5 font-inherit text-base text-gray-900 no-underline transition-colors duration-150 ease-in hover:text-gray-1000 focus-visible:-outline-offset-1 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] min-[961px]:flex"
516
559
  >
517
- <X className="w-3 h-3" />
560
+ <kbd className="inline-flex h-5 min-h-5 min-w-5 items-center justify-center rounded border border-gray-alpha-400 bg-background-100 px-1 font-sans text-[13px] font-medium leading-[1.7em] text-gray-900">
561
+ Esc
562
+ </kbd>
518
563
  </button>
519
564
  )}
520
565
  </div>
@@ -525,11 +570,13 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
525
570
  >
526
571
  <div className="block overflow-visible">
527
572
  <EventList
528
- spans={filteredSpans}
573
+ spans={trace.spans}
529
574
  activeSpanId={activeSpanId}
575
+ searchResult={searchResult}
530
576
  onSelectSpan={handleSelectSpan}
531
577
  />
532
578
  </div>
579
+ {/* biome-ignore lint/a11y/noStaticElementInteractions: timeline hover and wheel gestures are pointer-only annotations */}
533
580
  <div
534
581
  ref={timelineRef}
535
582
  className="block min-h-0 overflow-visible relative"
@@ -538,42 +585,43 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
538
585
  onMouseLeave={handleTimelineMouseLeave}
539
586
  >
540
587
  <Timeline
541
- spans={filteredSpans}
588
+ spans={trace.spans}
542
589
  viewStart={viewport.start}
543
590
  viewEnd={viewport.end}
544
591
  markers={timeMarkers}
545
592
  selectedId={activeSpanId}
593
+ searchResult={searchResult}
546
594
  onSelect={handleSelectSpan}
547
595
  hoverFraction={hoverFraction}
548
596
  altHeld={altHeld}
549
597
  />
550
598
  </div>
551
599
  </SplitPane>
552
- <div className="absolute right-3 bottom-3 z-[5] flex items-center border border-gray-alpha-400 rounded-lg bg-background-100 shadow-sm overflow-hidden divide-x divide-gray-alpha-400">
553
- <button
554
- type="button"
555
- className="flex items-center justify-center w-8 h-8 text-gray-900 cursor-pointer transition-colors duration-[time:120ms] ease-in-out hover:text-gray-1000 hover:bg-gray-alpha-100"
600
+ <div className="absolute right-3 bottom-3 z-[5] flex items-center border border-gray-alpha-400 rounded-md bg-background-100 shadow-sm overflow-hidden divide-x divide-gray-alpha-400">
601
+ <IconButton
602
+ variant="muted"
603
+ size="small"
556
604
  onClick={zoomOut}
557
605
  aria-label="Zoom out"
558
606
  >
559
607
  <ZoomOut className="w-4 h-4" />
560
- </button>
561
- <button
562
- type="button"
563
- className="flex items-center justify-center w-8 h-8 text-gray-900 cursor-pointer transition-colors duration-[time:120ms] ease-in-out hover:text-gray-1000 hover:bg-gray-alpha-100"
608
+ </IconButton>
609
+ <IconButton
610
+ variant="muted"
611
+ size="small"
564
612
  onClick={resetZoom}
565
613
  aria-label="Reset zoom"
566
614
  >
567
615
  <RotateCcw className="w-3.5 h-3.5" />
568
- </button>
569
- <button
570
- type="button"
571
- className="flex items-center justify-center w-8 h-8 text-gray-900 cursor-pointer transition-colors duration-[time:120ms] ease-in-out hover:text-gray-1000 hover:bg-gray-alpha-100"
616
+ </IconButton>
617
+ <IconButton
618
+ variant="muted"
619
+ size="small"
572
620
  onClick={zoomIn}
573
621
  aria-label="Zoom in"
574
622
  >
575
623
  <ZoomIn className="w-4 h-4" />
576
- </button>
624
+ </IconButton>
577
625
  </div>
578
626
  </div>
579
627
 
@@ -581,49 +629,35 @@ function NewTraceViewerContent({ trace }: NewTraceViewerProps): ReactNode {
581
629
  {activeSpan && sidebar ? (
582
630
  <aside className="flex flex-col h-full max-h-full bg-background-100 border-l border-gray-alpha-400 overflow-auto">
583
631
  {/* Panel header */}
584
- <div className="flex-shrink-0 px-4 pt-4 pb-3">
585
- <div className="flex items-start justify-between gap-2">
586
- <div className="min-w-0 flex-1">
587
- <span className="text-[15px] font-semibold text-gray-1000 truncate block">
588
- {selectedSpanName}
589
- </span>
590
- {selectedResourceId && (
591
- <div className="mt-1 flex items-center gap-2">
592
- {selectedResource && (
593
- <span
594
- className={`inline-flex items-center rounded-md px-1.5 py-0.5 text-[11px] font-medium leading-none shrink-0 ${
595
- selectedResource === 'step'
596
- ? 'bg-green-200 text-green-900'
597
- : selectedResource === 'run'
598
- ? 'bg-blue-200 text-blue-900'
599
- : 'bg-gray-200 text-gray-900'
600
- }`}
601
- >
602
- {selectedResource.charAt(0).toUpperCase() +
603
- selectedResource.slice(1)}
604
- </span>
605
- )}
606
- <div
607
- className="flex items-center gap-1 text-[13px] font-mono text-gray-700 min-w-0"
608
- title={selectedResourceId}
609
- >
610
- <span className="truncate">{selectedResourceId}</span>
611
- <CopyButton
612
- copyText={selectedResourceId}
613
- ariaLabel="Copy ID"
614
- className="shrink-0"
615
- />
616
- </div>
617
- </div>
618
- )}
619
- </div>
620
- <button
621
- type="button"
622
- className="p-1 rounded-md text-gray-900 hover:text-gray-1000 hover:bg-gray-alpha-200 transition-colors shrink-0"
632
+ <div className="flex items-center justify-between gap-2 shrink-0 px-4 pt-3 pb-3">
633
+ <span className="text-label-14 font-medium text-gray-1000 truncate block">
634
+ {selectedSpanName}
635
+ </span>
636
+ <div className="flex items-center gap-0.5 shrink-0">
637
+ <IconButton
638
+ aria-label="Navigate to previous span"
639
+ aria-keyshortcuts="K"
640
+ onClick={handleSelectPrevSpan}
641
+ disabled={!prevSpanId}
642
+ >
643
+ <ChevronUp className="w-4 h-4" />
644
+ </IconButton>
645
+ <IconButton
646
+ aria-label="Navigate to next span"
647
+ aria-keyshortcuts="J"
648
+ onClick={handleSelectNextSpan}
649
+ disabled={!nextSpanId}
650
+ >
651
+ <ChevronDown className="w-4 h-4" />
652
+ </IconButton>
653
+ <div aria-hidden className="w-px h-4 bg-gray-alpha-400 mx-1" />
654
+ <IconButton
655
+ aria-label="Close span details"
656
+ aria-keyshortcuts="Escape"
623
657
  onClick={clearActiveSpan}
624
658
  >
625
659
  <X className="w-4 h-4" />
626
- </button>
660
+ </IconButton>
627
661
  </div>
628
662
  </div>
629
663
  {/* Panel body */}