@workflow/web-shared 5.0.0-beta.4 → 5.0.0-beta.40

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 (517) hide show
  1. package/README.md +5 -13
  2. package/dist/components/error-boundary.js +1 -1
  3. package/dist/components/event-list-view.d.ts +46 -1
  4. package/dist/components/event-list-view.d.ts.map +1 -1
  5. package/dist/components/event-list-view.js +235 -97
  6. package/dist/components/hook-actions.js +1 -1
  7. package/dist/components/index.d.ts +8 -5
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/components/index.js +6 -4
  10. package/dist/components/sidebar/attribute-panel.d.ts +4 -1
  11. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  12. package/dist/components/sidebar/attribute-panel.js +173 -119
  13. package/dist/components/sidebar/attributes-block.d.ts +40 -0
  14. package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
  15. package/dist/components/sidebar/attributes-block.js +140 -0
  16. package/dist/components/sidebar/conversation-view.js +1 -1
  17. package/dist/components/sidebar/copyable-data-block.d.ts +2 -0
  18. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  19. package/dist/components/sidebar/copyable-data-block.js +17 -16
  20. package/dist/components/sidebar/entity-detail-panel.d.ts +11 -11
  21. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  22. package/dist/components/sidebar/entity-detail-panel.js +37 -71
  23. package/dist/components/sidebar/events-list.d.ts +6 -2
  24. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  25. package/dist/components/sidebar/events-list.js +77 -63
  26. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  27. package/dist/components/sidebar/sidebar-data-context.d.ts +10 -7
  28. package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -1
  29. package/dist/components/sidebar/sidebar-data-context.js +1 -1
  30. package/dist/components/sidebar/span-detail-merge.d.ts +31 -0
  31. package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
  32. package/dist/components/sidebar/span-detail-merge.js +92 -0
  33. package/dist/components/sidebar/use-selected-span-detail.d.ts +16 -0
  34. package/dist/components/sidebar/use-selected-span-detail.d.ts.map +1 -0
  35. package/dist/components/sidebar/use-selected-span-detail.js +93 -0
  36. package/dist/components/stream-viewer-skeleton.d.ts +2 -0
  37. package/dist/components/stream-viewer-skeleton.d.ts.map +1 -0
  38. package/dist/components/stream-viewer-skeleton.js +12 -0
  39. package/dist/components/stream-viewer.d.ts +1 -1
  40. package/dist/components/stream-viewer.d.ts.map +1 -1
  41. package/dist/components/stream-viewer.js +9 -26
  42. package/dist/components/trace-viewer/components/copy-button.d.ts.map +1 -0
  43. package/dist/components/trace-viewer/components/copy-button.js +27 -0
  44. package/dist/components/trace-viewer/components/detail-panel-width.d.ts +34 -0
  45. package/dist/components/trace-viewer/components/detail-panel-width.d.ts.map +1 -0
  46. package/dist/components/trace-viewer/components/detail-panel-width.js +67 -0
  47. package/dist/components/trace-viewer/components/detail-panel.d.ts +14 -0
  48. package/dist/components/trace-viewer/components/detail-panel.d.ts.map +1 -0
  49. package/dist/components/trace-viewer/components/detail-panel.js +122 -0
  50. package/dist/components/trace-viewer/components/draggable-border.d.ts +31 -0
  51. package/dist/components/trace-viewer/components/draggable-border.d.ts.map +1 -0
  52. package/dist/components/trace-viewer/components/draggable-border.js +140 -0
  53. package/dist/components/trace-viewer/components/event-list.d.ts +10 -0
  54. package/dist/components/trace-viewer/components/event-list.d.ts.map +1 -0
  55. package/dist/components/trace-viewer/components/event-list.js +47 -0
  56. package/dist/components/trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
  57. package/dist/components/trace-viewer/components/middle-truncate/copy-selection.js +54 -0
  58. package/dist/components/trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
  59. package/dist/components/trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
  60. package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/truncate.d.ts +1 -1
  61. package/dist/components/trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
  62. package/dist/components/trace-viewer/components/middle-truncate/truncate.js +101 -0
  63. package/dist/components/trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
  64. package/dist/components/trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
  65. package/dist/components/trace-viewer/components/minimap.d.ts +14 -0
  66. package/dist/components/trace-viewer/components/minimap.d.ts.map +1 -0
  67. package/dist/components/trace-viewer/components/minimap.js +337 -0
  68. package/dist/components/trace-viewer/components/pane-constants.d.ts +14 -0
  69. package/dist/components/trace-viewer/components/pane-constants.d.ts.map +1 -0
  70. package/dist/components/trace-viewer/components/pane-constants.js +16 -0
  71. package/dist/components/trace-viewer/components/span-markers.d.ts +46 -0
  72. package/dist/components/trace-viewer/components/span-markers.d.ts.map +1 -0
  73. package/dist/components/trace-viewer/components/span-markers.js +85 -0
  74. package/dist/components/trace-viewer/components/split-pane.d.ts +10 -0
  75. package/dist/components/trace-viewer/components/split-pane.d.ts.map +1 -0
  76. package/dist/components/trace-viewer/components/split-pane.js +41 -0
  77. package/dist/components/trace-viewer/components/timeline.d.ts +42 -0
  78. package/dist/components/trace-viewer/components/timeline.d.ts.map +1 -0
  79. package/dist/components/trace-viewer/components/timeline.js +321 -0
  80. package/dist/components/trace-viewer/components/timeline.module.css +46 -0
  81. package/dist/components/trace-viewer/components/trace-shortcut-helper.d.ts +5 -0
  82. package/dist/components/trace-viewer/components/trace-shortcut-helper.d.ts.map +1 -0
  83. package/dist/components/trace-viewer/components/trace-shortcut-helper.js +55 -0
  84. package/dist/components/trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  85. package/dist/components/trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
  86. package/dist/components/trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
  87. package/dist/components/trace-viewer/components/trace-viewer-skeleton.js +26 -0
  88. package/dist/components/trace-viewer/components/use-element-width.d.ts +8 -0
  89. package/dist/components/trace-viewer/components/use-element-width.d.ts.map +1 -0
  90. package/dist/components/trace-viewer/components/use-element-width.js +25 -0
  91. package/dist/components/trace-viewer/components/use-row-window.d.ts +34 -0
  92. package/dist/components/trace-viewer/components/use-row-window.d.ts.map +1 -0
  93. package/dist/components/trace-viewer/components/use-row-window.js +107 -0
  94. package/dist/components/trace-viewer/context.d.ts +14 -182
  95. package/dist/components/trace-viewer/context.d.ts.map +1 -1
  96. package/dist/components/trace-viewer/context.js +44 -351
  97. package/dist/components/trace-viewer/icons.d.ts.map +1 -0
  98. package/dist/components/trace-viewer/icons.js +15 -0
  99. package/dist/components/trace-viewer/search.d.ts +19 -0
  100. package/dist/components/trace-viewer/search.d.ts.map +1 -0
  101. package/dist/components/trace-viewer/search.js +134 -0
  102. package/dist/components/trace-viewer/trace-viewer.d.ts +7 -28
  103. package/dist/components/trace-viewer/trace-viewer.d.ts.map +1 -1
  104. package/dist/components/trace-viewer/trace-viewer.js +306 -356
  105. package/dist/components/trace-viewer/types.d.ts +2 -211
  106. package/dist/components/trace-viewer/types.d.ts.map +1 -1
  107. package/dist/components/trace-viewer/types.js +1 -1
  108. package/dist/components/trace-viewer/util/timing.d.ts +2 -2
  109. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
  110. package/dist/components/trace-viewer/util/timing.js +3 -3
  111. package/dist/components/trace-viewer/utils.d.ts +111 -0
  112. package/dist/components/trace-viewer/utils.d.ts.map +1 -0
  113. package/dist/components/trace-viewer/utils.js +430 -0
  114. package/dist/components/{trace-viewer-new.d.ts → trace-viewer.d.ts} +7 -3
  115. package/dist/components/trace-viewer.d.ts.map +1 -0
  116. package/dist/components/trace-viewer.js +21 -0
  117. package/dist/components/ui/alert.js +3 -3
  118. package/dist/components/ui/button.d.ts +10 -0
  119. package/dist/components/ui/button.d.ts.map +1 -0
  120. package/dist/components/ui/button.js +46 -0
  121. package/dist/components/ui/card.d.ts.map +1 -1
  122. package/dist/components/ui/card.js +4 -4
  123. package/dist/components/ui/collapsible.d.ts +46 -0
  124. package/dist/components/ui/collapsible.d.ts.map +1 -0
  125. package/dist/components/ui/collapsible.js +66 -0
  126. package/dist/components/ui/context-card.d.ts +47 -0
  127. package/dist/components/ui/context-card.d.ts.map +1 -0
  128. package/dist/components/ui/context-card.js +471 -0
  129. package/dist/components/ui/data-inspector.d.ts +7 -6
  130. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  131. package/dist/components/ui/data-inspector.js +232 -99
  132. package/dist/components/ui/data-inspector.styles.d.ts +29 -0
  133. package/dist/components/ui/data-inspector.styles.d.ts.map +1 -0
  134. package/dist/components/ui/data-inspector.styles.js +95 -0
  135. package/dist/components/ui/decrypt-button.js +1 -1
  136. package/dist/components/ui/error-card.js +3 -3
  137. package/dist/components/ui/error-stack-block.d.ts +17 -10
  138. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  139. package/dist/components/ui/error-stack-block.js +49 -30
  140. package/dist/components/ui/icon-button.d.ts +19 -0
  141. package/dist/components/ui/icon-button.d.ts.map +1 -0
  142. package/dist/components/ui/icon-button.js +29 -0
  143. package/dist/components/ui/kbd.d.ts +10 -0
  144. package/dist/components/ui/kbd.d.ts.map +1 -0
  145. package/dist/components/ui/kbd.js +25 -0
  146. package/dist/components/ui/load-more-button.js +1 -1
  147. package/dist/components/ui/menu-dropdown.js +1 -1
  148. package/dist/components/ui/skeleton.js +2 -2
  149. package/dist/components/ui/spinner.js +1 -1
  150. package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
  151. package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
  152. package/dist/components/ui/timestamp-tooltip.js +80 -132
  153. package/dist/components/ui/tooltip.d.ts +10 -0
  154. package/dist/components/ui/tooltip.d.ts.map +1 -0
  155. package/dist/components/ui/tooltip.js +12 -0
  156. package/dist/components/workflow-traces/event-colors.d.ts +2 -1
  157. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
  158. package/dist/components/workflow-traces/event-colors.js +15 -7
  159. package/dist/components/workflow-traces/trace-span-construction.d.ts +6 -3
  160. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
  161. package/dist/components/workflow-traces/trace-span-construction.js +71 -30
  162. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  163. package/dist/hooks/use-dark-mode.js +1 -1
  164. package/dist/hooks/use-intersection-observer.d.ts +17 -0
  165. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  166. package/dist/hooks/use-intersection-observer.js +29 -0
  167. package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
  168. package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
  169. package/dist/hooks/use-load-more-on-scroll.js +28 -0
  170. package/dist/hooks/use-reduced-motion.d.ts +10 -0
  171. package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
  172. package/dist/hooks/use-reduced-motion.js +29 -0
  173. package/dist/index.d.ts +4 -3
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +4 -3
  176. package/dist/lib/cn.d.ts +10 -0
  177. package/dist/lib/cn.d.ts.map +1 -0
  178. package/dist/lib/cn.js +83 -0
  179. package/dist/lib/event-analysis.d.ts +1 -1
  180. package/dist/lib/event-analysis.d.ts.map +1 -1
  181. package/dist/lib/event-analysis.js +3 -2
  182. package/dist/lib/event-materialization.d.ts +1 -1
  183. package/dist/lib/event-materialization.d.ts.map +1 -1
  184. package/dist/lib/event-materialization.js +29 -21
  185. package/dist/lib/exact-event-search-id.d.ts +25 -0
  186. package/dist/lib/exact-event-search-id.d.ts.map +1 -0
  187. package/dist/lib/exact-event-search-id.js +39 -0
  188. package/dist/lib/hydration.d.ts +17 -2
  189. package/dist/lib/hydration.d.ts.map +1 -1
  190. package/dist/lib/hydration.js +194 -23
  191. package/dist/lib/stream-display.js +1 -1
  192. package/dist/lib/toast.js +1 -1
  193. package/dist/lib/trace-builder.d.ts +17 -5
  194. package/dist/lib/trace-builder.d.ts.map +1 -1
  195. package/dist/lib/trace-builder.js +32 -14
  196. package/dist/lib/trace-types.d.ts +54 -0
  197. package/dist/lib/trace-types.d.ts.map +1 -0
  198. package/dist/lib/trace-types.js +2 -0
  199. package/dist/lib/utils.d.ts +14 -2
  200. package/dist/lib/utils.d.ts.map +1 -1
  201. package/dist/lib/utils.js +46 -6
  202. package/dist/lib/zstd-browser-decoder.d.ts +7 -0
  203. package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
  204. package/dist/lib/zstd-browser-decoder.js +41 -0
  205. package/dist/styles.css +210 -139
  206. package/package.json +11 -8
  207. package/src/components/event-list-view.tsx +385 -123
  208. package/src/components/index.ts +14 -8
  209. package/src/components/sidebar/attribute-panel.tsx +331 -282
  210. package/src/components/sidebar/attributes-block.tsx +326 -0
  211. package/src/components/sidebar/copyable-data-block.tsx +50 -28
  212. package/src/components/sidebar/entity-detail-panel.tsx +92 -126
  213. package/src/components/sidebar/events-list.tsx +197 -179
  214. package/src/components/sidebar/sidebar-data-context.tsx +11 -11
  215. package/src/components/sidebar/span-detail-merge.ts +134 -0
  216. package/src/components/sidebar/use-selected-span-detail.ts +146 -0
  217. package/src/components/stream-viewer-skeleton.tsx +34 -0
  218. package/src/components/stream-viewer.tsx +34 -106
  219. package/src/components/{new-trace-viewer → trace-viewer}/components/copy-button.tsx +2 -2
  220. package/src/components/trace-viewer/components/detail-panel-width.test.ts +123 -0
  221. package/src/components/trace-viewer/components/detail-panel-width.ts +76 -0
  222. package/src/components/trace-viewer/components/detail-panel.tsx +273 -0
  223. package/src/components/trace-viewer/components/draggable-border.tsx +216 -0
  224. package/src/components/trace-viewer/components/event-list.tsx +144 -0
  225. package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/middle-truncate.tsx +8 -8
  226. package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/truncate.ts +1 -1
  227. package/src/components/trace-viewer/components/minimap.tsx +556 -0
  228. package/src/components/trace-viewer/components/pane-constants.ts +19 -0
  229. package/src/components/trace-viewer/components/span-markers.tsx +173 -0
  230. package/src/components/trace-viewer/components/split-pane.tsx +141 -0
  231. package/src/components/trace-viewer/components/timeline.module.css +46 -0
  232. package/src/components/trace-viewer/components/timeline.tsx +850 -0
  233. package/src/components/trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  234. package/src/components/trace-viewer/components/trace-shortcut-helper.tsx +116 -0
  235. package/src/components/trace-viewer/components/trace-viewer-skeleton.tsx +114 -0
  236. package/src/components/trace-viewer/components/use-element-width.ts +29 -0
  237. package/src/components/trace-viewer/components/use-row-window.ts +140 -0
  238. package/src/components/trace-viewer/context.tsx +63 -656
  239. package/src/components/{new-trace-viewer → trace-viewer}/icons.tsx +2 -2
  240. package/src/components/trace-viewer/search.ts +178 -0
  241. package/src/components/trace-viewer/trace-viewer.tsx +563 -531
  242. package/src/components/trace-viewer/types.ts +2 -234
  243. package/src/components/trace-viewer/util/timing.ts +2 -2
  244. package/src/components/trace-viewer/utils.test.ts +458 -0
  245. package/src/components/{new-trace-viewer → trace-viewer}/utils.ts +271 -50
  246. package/src/components/{trace-viewer-new.tsx → trace-viewer.tsx} +24 -18
  247. package/src/components/ui/alert.tsx +2 -2
  248. package/src/components/ui/button.tsx +68 -0
  249. package/src/components/ui/card.tsx +3 -10
  250. package/src/components/ui/collapsible.tsx +219 -0
  251. package/src/components/ui/context-card.tsx +784 -0
  252. package/src/components/ui/data-inspector.styles.ts +96 -0
  253. package/src/components/ui/data-inspector.tsx +501 -204
  254. package/src/components/ui/error-card.tsx +4 -4
  255. package/src/components/ui/error-stack-block.tsx +84 -55
  256. package/src/components/ui/icon-button.tsx +53 -0
  257. package/src/components/ui/kbd.tsx +43 -0
  258. package/src/components/ui/skeleton.tsx +1 -1
  259. package/src/components/ui/timestamp-tooltip.tsx +132 -194
  260. package/src/components/ui/tooltip.tsx +47 -0
  261. package/src/components/workflow-traces/event-colors.ts +15 -11
  262. package/src/components/workflow-traces/trace-span-construction.test.ts +85 -0
  263. package/src/components/workflow-traces/trace-span-construction.ts +97 -32
  264. package/src/hooks/use-intersection-observer.ts +57 -0
  265. package/src/hooks/use-load-more-on-scroll.ts +49 -0
  266. package/src/hooks/use-reduced-motion.ts +34 -0
  267. package/src/index.ts +10 -4
  268. package/src/lib/cn.ts +93 -0
  269. package/src/lib/event-analysis.ts +6 -4
  270. package/src/lib/event-materialization.ts +35 -21
  271. package/src/lib/exact-event-search-id.ts +67 -0
  272. package/src/lib/hydration.ts +210 -30
  273. package/src/lib/trace-builder.ts +43 -19
  274. package/src/lib/trace-types.ts +56 -0
  275. package/src/lib/utils.test.ts +33 -0
  276. package/src/lib/utils.ts +53 -6
  277. package/src/lib/zstd-browser-decoder.ts +42 -0
  278. package/src/styles.css +210 -139
  279. package/dist/components/error-boundary.js.map +0 -1
  280. package/dist/components/event-list-view.js.map +0 -1
  281. package/dist/components/hook-actions.js.map +0 -1
  282. package/dist/components/index.js.map +0 -1
  283. package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +0 -1
  284. package/dist/components/new-trace-viewer/components/copy-button.js +0 -27
  285. package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
  286. package/dist/components/new-trace-viewer/components/event-list.d.ts +0 -8
  287. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +0 -1
  288. package/dist/components/new-trace-viewer/components/event-list.js +0 -38
  289. package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
  290. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +0 -1
  291. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +0 -54
  292. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js.map +0 -1
  293. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +0 -1
  294. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +0 -81
  295. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js.map +0 -1
  296. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +0 -1
  297. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +0 -101
  298. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js.map +0 -1
  299. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +0 -1
  300. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +0 -114
  301. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js.map +0 -1
  302. package/dist/components/new-trace-viewer/components/split-pane.d.ts +0 -14
  303. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +0 -1
  304. package/dist/components/new-trace-viewer/components/split-pane.js +0 -99
  305. package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
  306. package/dist/components/new-trace-viewer/components/timeline.d.ts +0 -31
  307. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +0 -1
  308. package/dist/components/new-trace-viewer/components/timeline.js +0 -138
  309. package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
  310. package/dist/components/new-trace-viewer/context.d.ts +0 -15
  311. package/dist/components/new-trace-viewer/context.d.ts.map +0 -1
  312. package/dist/components/new-trace-viewer/context.js +0 -47
  313. package/dist/components/new-trace-viewer/context.js.map +0 -1
  314. package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
  315. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
  316. package/dist/components/new-trace-viewer/detail-panel.js +0 -12
  317. package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
  318. package/dist/components/new-trace-viewer/icons.d.ts.map +0 -1
  319. package/dist/components/new-trace-viewer/icons.js +0 -15
  320. package/dist/components/new-trace-viewer/icons.js.map +0 -1
  321. package/dist/components/new-trace-viewer/trace-viewer.d.ts +0 -8
  322. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +0 -1
  323. package/dist/components/new-trace-viewer/trace-viewer.js +0 -349
  324. package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
  325. package/dist/components/new-trace-viewer/types.d.ts +0 -1
  326. package/dist/components/new-trace-viewer/types.d.ts.map +0 -1
  327. package/dist/components/new-trace-viewer/types.js +0 -2
  328. package/dist/components/new-trace-viewer/types.js.map +0 -1
  329. package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
  330. package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
  331. package/dist/components/new-trace-viewer/util/constants.js +0 -2
  332. package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
  333. package/dist/components/new-trace-viewer/utils.d.ts +0 -42
  334. package/dist/components/new-trace-viewer/utils.d.ts.map +0 -1
  335. package/dist/components/new-trace-viewer/utils.js +0 -305
  336. package/dist/components/new-trace-viewer/utils.js.map +0 -1
  337. package/dist/components/run-trace-view.d.ts +0 -25
  338. package/dist/components/run-trace-view.d.ts.map +0 -1
  339. package/dist/components/run-trace-view.js +0 -11
  340. package/dist/components/run-trace-view.js.map +0 -1
  341. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  342. package/dist/components/sidebar/conversation-view.js.map +0 -1
  343. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  344. package/dist/components/sidebar/detail-card.d.ts +0 -14
  345. package/dist/components/sidebar/detail-card.d.ts.map +0 -1
  346. package/dist/components/sidebar/detail-card.js +0 -20
  347. package/dist/components/sidebar/detail-card.js.map +0 -1
  348. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  349. package/dist/components/sidebar/events-list.js.map +0 -1
  350. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  351. package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
  352. package/dist/components/stream-viewer.js.map +0 -1
  353. package/dist/components/trace-viewer/components/map.d.ts +0 -8
  354. package/dist/components/trace-viewer/components/map.d.ts.map +0 -1
  355. package/dist/components/trace-viewer/components/map.js +0 -162
  356. package/dist/components/trace-viewer/components/map.js.map +0 -1
  357. package/dist/components/trace-viewer/components/markers.d.ts +0 -23
  358. package/dist/components/trace-viewer/components/markers.d.ts.map +0 -1
  359. package/dist/components/trace-viewer/components/markers.js +0 -416
  360. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  361. package/dist/components/trace-viewer/components/node.d.ts +0 -35
  362. package/dist/components/trace-viewer/components/node.d.ts.map +0 -1
  363. package/dist/components/trace-viewer/components/node.js +0 -285
  364. package/dist/components/trace-viewer/components/node.js.map +0 -1
  365. package/dist/components/trace-viewer/components/search-input.d.ts +0 -9
  366. package/dist/components/trace-viewer/components/search-input.d.ts.map +0 -1
  367. package/dist/components/trace-viewer/components/search-input.js +0 -9
  368. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  369. package/dist/components/trace-viewer/components/search.d.ts +0 -3
  370. package/dist/components/trace-viewer/components/search.d.ts.map +0 -1
  371. package/dist/components/trace-viewer/components/search.js +0 -25
  372. package/dist/components/trace-viewer/components/search.js.map +0 -1
  373. package/dist/components/trace-viewer/components/span-content.d.ts +0 -19
  374. package/dist/components/trace-viewer/components/span-content.d.ts.map +0 -1
  375. package/dist/components/trace-viewer/components/span-content.js +0 -137
  376. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  377. package/dist/components/trace-viewer/components/span-detail-panel.d.ts +0 -10
  378. package/dist/components/trace-viewer/components/span-detail-panel.d.ts.map +0 -1
  379. package/dist/components/trace-viewer/components/span-detail-panel.js +0 -285
  380. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  381. package/dist/components/trace-viewer/components/span-segments.d.ts +0 -50
  382. package/dist/components/trace-viewer/components/span-segments.d.ts.map +0 -1
  383. package/dist/components/trace-viewer/components/span-segments.js +0 -445
  384. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  385. package/dist/components/trace-viewer/components/span-strategies.d.ts +0 -46
  386. package/dist/components/trace-viewer/components/span-strategies.d.ts.map +0 -1
  387. package/dist/components/trace-viewer/components/span-strategies.js +0 -108
  388. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  389. package/dist/components/trace-viewer/components/ui.d.ts +0 -28
  390. package/dist/components/trace-viewer/components/ui.d.ts.map +0 -1
  391. package/dist/components/trace-viewer/components/ui.js +0 -39
  392. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  393. package/dist/components/trace-viewer/components/zoom-button.d.ts +0 -3
  394. package/dist/components/trace-viewer/components/zoom-button.d.ts.map +0 -1
  395. package/dist/components/trace-viewer/components/zoom-button.js +0 -29
  396. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  397. package/dist/components/trace-viewer/components/zoom-icons.d.ts +0 -11
  398. package/dist/components/trace-viewer/components/zoom-icons.d.ts.map +0 -1
  399. package/dist/components/trace-viewer/components/zoom-icons.js +0 -11
  400. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  401. package/dist/components/trace-viewer/context.js.map +0 -1
  402. package/dist/components/trace-viewer/index.d.ts +0 -5
  403. package/dist/components/trace-viewer/index.d.ts.map +0 -1
  404. package/dist/components/trace-viewer/index.js +0 -4
  405. package/dist/components/trace-viewer/index.js.map +0 -1
  406. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  407. package/dist/components/trace-viewer/trace-viewer.module.css +0 -1465
  408. package/dist/components/trace-viewer/types.js.map +0 -1
  409. package/dist/components/trace-viewer/util/constants.d.ts +0 -9
  410. package/dist/components/trace-viewer/util/constants.d.ts.map +0 -1
  411. package/dist/components/trace-viewer/util/constants.js +0 -9
  412. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  413. package/dist/components/trace-viewer/util/scrollbar-width.d.ts +0 -2
  414. package/dist/components/trace-viewer/util/scrollbar-width.d.ts.map +0 -1
  415. package/dist/components/trace-viewer/util/scrollbar-width.js +0 -14
  416. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  417. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  418. package/dist/components/trace-viewer/util/tree.d.ts +0 -13
  419. package/dist/components/trace-viewer/util/tree.d.ts.map +0 -1
  420. package/dist/components/trace-viewer/util/tree.js +0 -227
  421. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  422. package/dist/components/trace-viewer/util/use-immediate-style.d.ts +0 -15
  423. package/dist/components/trace-viewer/util/use-immediate-style.d.ts.map +0 -1
  424. package/dist/components/trace-viewer/util/use-immediate-style.js +0 -23
  425. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  426. package/dist/components/trace-viewer/util/use-streaming-spans.d.ts +0 -8
  427. package/dist/components/trace-viewer/util/use-streaming-spans.d.ts.map +0 -1
  428. package/dist/components/trace-viewer/util/use-streaming-spans.js +0 -345
  429. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  430. package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts +0 -6
  431. package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts.map +0 -1
  432. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +0 -39
  433. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  434. package/dist/components/trace-viewer/worker.d.ts +0 -2
  435. package/dist/components/trace-viewer/worker.d.ts.map +0 -1
  436. package/dist/components/trace-viewer/worker.js +0 -109
  437. package/dist/components/trace-viewer/worker.js.map +0 -1
  438. package/dist/components/trace-viewer-new.d.ts.map +0 -1
  439. package/dist/components/trace-viewer-new.js +0 -23
  440. package/dist/components/trace-viewer-new.js.map +0 -1
  441. package/dist/components/ui/alert.js.map +0 -1
  442. package/dist/components/ui/card.js.map +0 -1
  443. package/dist/components/ui/data-inspector.js.map +0 -1
  444. package/dist/components/ui/decrypt-button.js.map +0 -1
  445. package/dist/components/ui/error-card.js.map +0 -1
  446. package/dist/components/ui/error-stack-block.js.map +0 -1
  447. package/dist/components/ui/inspector-theme.d.ts +0 -95
  448. package/dist/components/ui/inspector-theme.d.ts.map +0 -1
  449. package/dist/components/ui/inspector-theme.js +0 -82
  450. package/dist/components/ui/inspector-theme.js.map +0 -1
  451. package/dist/components/ui/load-more-button.js.map +0 -1
  452. package/dist/components/ui/menu-dropdown.js.map +0 -1
  453. package/dist/components/ui/skeleton.js.map +0 -1
  454. package/dist/components/ui/spinner.js.map +0 -1
  455. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  456. package/dist/components/workflow-trace-view.d.ts +0 -40
  457. package/dist/components/workflow-trace-view.d.ts.map +0 -1
  458. package/dist/components/workflow-trace-view.js +0 -695
  459. package/dist/components/workflow-trace-view.js.map +0 -1
  460. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  461. package/dist/components/workflow-traces/trace-colors.d.ts +0 -15
  462. package/dist/components/workflow-traces/trace-colors.d.ts.map +0 -1
  463. package/dist/components/workflow-traces/trace-colors.js +0 -87
  464. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  465. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  466. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  467. package/dist/hooks/use-dark-mode.js.map +0 -1
  468. package/dist/index.js.map +0 -1
  469. package/dist/lib/event-analysis.js.map +0 -1
  470. package/dist/lib/event-materialization.js.map +0 -1
  471. package/dist/lib/hydration.js.map +0 -1
  472. package/dist/lib/stream-display.js.map +0 -1
  473. package/dist/lib/toast.js.map +0 -1
  474. package/dist/lib/trace-builder.js.map +0 -1
  475. package/dist/lib/utils.js.map +0 -1
  476. package/src/components/new-trace-viewer/components/event-list.tsx +0 -116
  477. package/src/components/new-trace-viewer/components/split-pane.tsx +0 -185
  478. package/src/components/new-trace-viewer/components/timeline.tsx +0 -382
  479. package/src/components/new-trace-viewer/context.tsx +0 -92
  480. package/src/components/new-trace-viewer/detail-panel.tsx +0 -58
  481. package/src/components/new-trace-viewer/trace-viewer.tsx +0 -645
  482. package/src/components/new-trace-viewer/types.ts +0 -0
  483. package/src/components/new-trace-viewer/util/constants.ts +0 -0
  484. package/src/components/run-trace-view.tsx +0 -84
  485. package/src/components/sidebar/detail-card.tsx +0 -65
  486. package/src/components/trace-viewer/components/map.tsx +0 -226
  487. package/src/components/trace-viewer/components/markers.tsx +0 -612
  488. package/src/components/trace-viewer/components/node.tsx +0 -505
  489. package/src/components/trace-viewer/components/search-input.tsx +0 -52
  490. package/src/components/trace-viewer/components/search.tsx +0 -47
  491. package/src/components/trace-viewer/components/span-content.tsx +0 -247
  492. package/src/components/trace-viewer/components/span-detail-panel.tsx +0 -655
  493. package/src/components/trace-viewer/components/span-segments.ts +0 -585
  494. package/src/components/trace-viewer/components/span-strategies.ts +0 -205
  495. package/src/components/trace-viewer/components/ui.tsx +0 -156
  496. package/src/components/trace-viewer/components/zoom-button.tsx +0 -61
  497. package/src/components/trace-viewer/components/zoom-icons.tsx +0 -65
  498. package/src/components/trace-viewer/index.tsx +0 -4
  499. package/src/components/trace-viewer/trace-viewer.module.css +0 -1465
  500. package/src/components/trace-viewer/util/constants.ts +0 -8
  501. package/src/components/trace-viewer/util/scrollbar-width.ts +0 -13
  502. package/src/components/trace-viewer/util/tree.ts +0 -277
  503. package/src/components/trace-viewer/util/use-immediate-style.ts +0 -38
  504. package/src/components/trace-viewer/util/use-streaming-spans.ts +0 -426
  505. package/src/components/trace-viewer/util/use-trackpad-zoom.tsx +0 -51
  506. package/src/components/trace-viewer/worker.ts +0 -131
  507. package/src/components/ui/inspector-theme.ts +0 -110
  508. package/src/components/workflow-trace-view.tsx +0 -1171
  509. package/src/components/workflow-traces/trace-colors.ts +0 -112
  510. /package/dist/components/{new-trace-viewer → trace-viewer}/components/copy-button.d.ts +0 -0
  511. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/copy-selection.d.ts +0 -0
  512. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/middle-truncate.d.ts +0 -0
  513. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/use-middle-truncate.d.ts +0 -0
  514. /package/dist/components/{new-trace-viewer → trace-viewer}/icons.d.ts +0 -0
  515. /package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/copy-selection.ts +0 -0
  516. /package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/use-middle-truncate.ts +0 -0
  517. /package/src/{components/trace-viewer/modules.d.ts → modules.d.ts} +0 -0
@@ -0,0 +1,850 @@
1
+ 'use client';
2
+
3
+ import { ArrowLeft, ArrowRight } from 'lucide-react';
4
+ import type { CSSProperties, ReactNode } from 'react';
5
+ import {
6
+ Fragment,
7
+ memo,
8
+ useCallback,
9
+ useEffect,
10
+ useMemo,
11
+ useRef,
12
+ useState,
13
+ } from 'react';
14
+ import { cn } from '../../../lib/cn';
15
+ import { isSpanDimmedBySearch, type SpanSearchResult } from '../search';
16
+ import type { Span } from '../types';
17
+ import { formatDurationPrecise, getHighResInMs } from '../util/timing';
18
+ import type {
19
+ OffscreenMarkers,
20
+ Segment,
21
+ SegmentStatus,
22
+ SpanDelta,
23
+ TimeMarker,
24
+ } from '../utils';
25
+ import {
26
+ computeOffscreenMarkers,
27
+ computeSpanDelta,
28
+ computeSpanGaps,
29
+ computeSpanMarkers,
30
+ computeSpanSegments,
31
+ getResourceColor,
32
+ getSpanDurationMs,
33
+ isSpanErrored,
34
+ } from '../utils';
35
+ import {
36
+ cullCollidingMarkers,
37
+ MarkerLayer,
38
+ OffscreenMarkerIndicator,
39
+ projectMarkers,
40
+ } from './span-markers';
41
+ import styles from './timeline.module.css';
42
+ import { ROW_HEIGHT_PX, useRowWindow } from './use-row-window';
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // Constants
46
+ // ---------------------------------------------------------------------------
47
+
48
+ const TINY_BAR_BOX_SIZE_PX = 24;
49
+ const TINY_BAR_WIDTH_PX = 4;
50
+ export const TIMELINE_PADDING_PX = 16;
51
+
52
+ const SEGMENT_CLASSES: Record<SegmentStatus, string> = {
53
+ queued: 'bg-gray-400 border border-gray-500',
54
+ pending: 'bg-gray-200 border border-gray-500',
55
+ retrying: 'bg-gray-400 border border-gray-500',
56
+ waiting: 'bg-gray-200 border border-gray-500',
57
+ running: 'bg-blue-200 border border-blue-500',
58
+ completed: 'bg-blue-200 border border-blue-500',
59
+ failed: 'bg-red-200 border border-red-500',
60
+ succeeded: 'bg-green-200 border border-green-500',
61
+ sleeping: 'bg-gray-400 border border-gray-500',
62
+ received: 'bg-blue-200 border border-blue-500',
63
+ };
64
+
65
+ const TIMELINE_INSET_STYLE: CSSProperties = {
66
+ left: TIMELINE_PADDING_PX,
67
+ right: TIMELINE_PADDING_PX,
68
+ };
69
+
70
+ const STRIPED_SEGMENT_STATUSES: ReadonlySet<SegmentStatus> = new Set([
71
+ 'pending',
72
+ 'running',
73
+ 'received',
74
+ ]);
75
+
76
+ function AnimatedStripes({ status }: { status: SegmentStatus }): ReactNode {
77
+ return (
78
+ <div
79
+ aria-hidden
80
+ className={
81
+ status === 'pending' ? styles.pendingStripes : styles.runningStripes
82
+ }
83
+ />
84
+ );
85
+ }
86
+
87
+ // ---------------------------------------------------------------------------
88
+ // Bar geometry
89
+ // ---------------------------------------------------------------------------
90
+
91
+ type BarMode =
92
+ | { kind: 'arrow'; direction: 'left' | 'right' }
93
+ | { kind: 'tiny' }
94
+ | { kind: 'full' };
95
+
96
+ interface BarGeometry {
97
+ mode: BarMode;
98
+ leftPct: number;
99
+ widthPct: number;
100
+ visibleStartMs: number;
101
+ visibleEndMs: number;
102
+ visiblePixelWidth: number;
103
+ }
104
+
105
+ /**
106
+ * Compute the bar's geometry inside the timeline viewport. Percentages are
107
+ * always in [0, 100] so we never emit CSS values that exceed browser layout
108
+ * limits at extreme zoom.
109
+ */
110
+ function computeBarGeometry(
111
+ startMs: number,
112
+ endMs: number,
113
+ viewStart: number,
114
+ viewEnd: number,
115
+ containerWidth: number
116
+ ): BarGeometry {
117
+ const viewDuration = viewEnd - viewStart;
118
+ const visibleStartMs = Math.max(startMs, viewStart);
119
+ const visibleEndMs = Math.min(endMs, viewEnd);
120
+ const visibleDurationMs = Math.max(0, visibleEndMs - visibleStartMs);
121
+ const widthFrac = viewDuration > 0 ? visibleDurationMs / viewDuration : 0;
122
+ const visiblePixelWidth = widthFrac * containerWidth;
123
+
124
+ const isTiny = containerWidth > 0 && visiblePixelWidth < TINY_BAR_BOX_SIZE_PX;
125
+ const extendsOffLeft = startMs < viewStart;
126
+ const extendsOffRight = endMs > viewEnd;
127
+
128
+ const mode: BarMode =
129
+ isTiny && (extendsOffLeft || extendsOffRight)
130
+ ? { kind: 'arrow', direction: extendsOffRight ? 'right' : 'left' }
131
+ : isTiny
132
+ ? { kind: 'tiny' }
133
+ : { kind: 'full' };
134
+
135
+ return {
136
+ mode,
137
+ leftPct:
138
+ viewDuration > 0
139
+ ? ((visibleStartMs - viewStart) / viewDuration) * 100
140
+ : 0,
141
+ widthPct: widthFrac * 100,
142
+ visibleStartMs,
143
+ visibleEndMs,
144
+ visiblePixelWidth,
145
+ };
146
+ }
147
+
148
+ function getBarPositionStyle(geometry: BarGeometry): {
149
+ left: string;
150
+ width: string;
151
+ } {
152
+ switch (geometry.mode.kind) {
153
+ case 'arrow':
154
+ return {
155
+ left:
156
+ geometry.mode.direction === 'right'
157
+ ? `calc(100% - ${TINY_BAR_BOX_SIZE_PX}px)`
158
+ : '0px',
159
+ width: `${TINY_BAR_BOX_SIZE_PX}px`,
160
+ };
161
+ case 'tiny':
162
+ return {
163
+ left: `min(${geometry.leftPct}%, calc(100% - ${TINY_BAR_WIDTH_PX}px))`,
164
+ width: `${TINY_BAR_WIDTH_PX}px`,
165
+ };
166
+ case 'full':
167
+ return {
168
+ left: `${geometry.leftPct}%`,
169
+ width: `max(${geometry.widthPct}%, 4px)`,
170
+ };
171
+ }
172
+ }
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // Segment projection
176
+ // ---------------------------------------------------------------------------
177
+
178
+ interface VisibleSegment {
179
+ status: SegmentStatus;
180
+ leftPct: number;
181
+ widthPct: number;
182
+ pixelWidth: number;
183
+ fullDurationMs: number;
184
+ }
185
+
186
+ /**
187
+ * Project status segments onto the visible portion of a bar. Segments fully
188
+ * outside the visible window are dropped; segments crossing the edge are
189
+ * clipped to [0%, 100%] of the visible bar.
190
+ */
191
+ function projectSegments(
192
+ segments: Segment[],
193
+ spanStartMs: number,
194
+ spanDurationMs: number,
195
+ geometry: BarGeometry
196
+ ): VisibleSegment[] {
197
+ const visibleDurationMs = geometry.visibleEndMs - geometry.visibleStartMs;
198
+ if (visibleDurationMs <= 0) return [];
199
+
200
+ return segments.flatMap((seg) => {
201
+ const segStartMs = spanStartMs + seg.startFraction * spanDurationMs;
202
+ const segEndMs = spanStartMs + seg.endFraction * spanDurationMs;
203
+ const startMs = Math.max(segStartMs, geometry.visibleStartMs);
204
+ const endMs = Math.min(segEndMs, geometry.visibleEndMs);
205
+ if (endMs <= startMs) return [];
206
+
207
+ const widthFrac = (endMs - startMs) / visibleDurationMs;
208
+ return [
209
+ {
210
+ status: seg.status,
211
+ leftPct:
212
+ ((startMs - geometry.visibleStartMs) / visibleDurationMs) * 100,
213
+ widthPct: widthFrac * 100,
214
+ pixelWidth: widthFrac * geometry.visiblePixelWidth,
215
+ fullDurationMs: (seg.endFraction - seg.startFraction) * spanDurationMs,
216
+ },
217
+ ];
218
+ });
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Small render helpers
223
+ // ---------------------------------------------------------------------------
224
+
225
+ /** Estimated rendered width of a 10px-mono duration label (6px/glyph + padding). */
226
+ function estimateLabelWidthPx(label: string): number {
227
+ return label.length * 6 + 12;
228
+ }
229
+
230
+ function DurationLabel({
231
+ label,
232
+ className,
233
+ }: {
234
+ label: string;
235
+ className?: string;
236
+ }): ReactNode {
237
+ return (
238
+ <span
239
+ className={cn(
240
+ 'pointer-events-none absolute inset-0 flex items-center justify-start overflow-hidden px-1 text-[10px] font-mono font-medium leading-none whitespace-nowrap text-left text-gray-1000 tabular-nums opacity-0 group-hover/timeline-row:opacity-100',
241
+ className
242
+ )}
243
+ >
244
+ {label}
245
+ </span>
246
+ );
247
+ }
248
+
249
+ function BoundaryArrow({
250
+ direction,
251
+ }: {
252
+ direction: 'left' | 'right';
253
+ }): ReactNode {
254
+ const Icon = direction === 'right' ? ArrowRight : ArrowLeft;
255
+ return (
256
+ <div className="flex h-6 w-6 items-center justify-center rounded-[0.25rem]">
257
+ <Icon className="size-3 text-gray-900" />
258
+ </div>
259
+ );
260
+ }
261
+
262
+ function PlainBar({
263
+ bg,
264
+ border,
265
+ label,
266
+ }: {
267
+ bg: string;
268
+ border: string;
269
+ label: string | null;
270
+ }): ReactNode {
271
+ return (
272
+ <div
273
+ className="relative h-6 w-full min-w-1 rounded-[0.25rem] border"
274
+ style={{ background: bg, borderColor: border }}
275
+ >
276
+ {label ? <DurationLabel label={label} /> : null}
277
+ </div>
278
+ );
279
+ }
280
+
281
+ function LeadInConnector({
282
+ leftPct,
283
+ widthPct,
284
+ label,
285
+ }: {
286
+ leftPct: number;
287
+ widthPct: number;
288
+ label: string | null;
289
+ }): ReactNode {
290
+ return (
291
+ <div
292
+ className="absolute top-1/2 h-6 -translate-y-1/2"
293
+ style={{
294
+ left: `calc(${leftPct}% + 0.5px)`,
295
+ width: `calc(${widthPct}% - 1px)`,
296
+ }}
297
+ >
298
+ <div className="absolute left-0 top-1/2 h-4 w-px -translate-y-1/2 bg-gray-500" />
299
+ <div className="absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-gray-500" />
300
+ {label ? <DurationLabel label={label} /> : null}
301
+ </div>
302
+ );
303
+ }
304
+
305
+ function SegmentBar({
306
+ segments,
307
+ showLabels = true,
308
+ }: {
309
+ segments: VisibleSegment[];
310
+ /**
311
+ * When false, segment duration labels are suppressed. Used when a separate
312
+ * top layer (e.g. the resumption-marker duration overlay) renders the label
313
+ * above the markers instead, so we don't draw it twice.
314
+ */
315
+ showLabels?: boolean;
316
+ }): ReactNode {
317
+ return (
318
+ <div className="relative h-6 w-full">
319
+ {segments.map((seg, i) => {
320
+ if (seg.status === 'queued') {
321
+ const leadInLabel = formatDurationPrecise(seg.fullDurationMs);
322
+ const showLeadInLabel =
323
+ showLabels &&
324
+ seg.pixelWidth >= Math.max(40, estimateLabelWidthPx(leadInLabel));
325
+ const isFullWidthQueued = segments.length === 1;
326
+ return (
327
+ <Fragment key={i}>
328
+ <LeadInConnector
329
+ leftPct={seg.leftPct}
330
+ widthPct={seg.widthPct}
331
+ label={showLeadInLabel ? leadInLabel : null}
332
+ />
333
+ {isFullWidthQueued ? (
334
+ <div
335
+ className="absolute top-1/2 h-4 w-px -translate-y-1/2 bg-gray-500"
336
+ style={{
337
+ left: `calc(${seg.leftPct + seg.widthPct}% - 1.5px)`,
338
+ }}
339
+ />
340
+ ) : null}
341
+ </Fragment>
342
+ );
343
+ }
344
+
345
+ const label = formatDurationPrecise(seg.fullDurationMs);
346
+ // Only render the label when there's enough room for it without clipping.
347
+ const showLabel =
348
+ showLabels &&
349
+ seg.pixelWidth >= Math.max(40, estimateLabelWidthPx(label));
350
+
351
+ return (
352
+ <div
353
+ key={i}
354
+ className={cn(
355
+ 'absolute h-full overflow-hidden rounded-[0.25rem]',
356
+ SEGMENT_CLASSES[seg.status]
357
+ )}
358
+ style={{
359
+ // 1px gap between adjacent segments, distributed equally.
360
+ left: `calc(${seg.leftPct}% + 0.5px)`,
361
+ width: `calc(${seg.widthPct}% - 1px)`,
362
+ minWidth: 1,
363
+ }}
364
+ >
365
+ {STRIPED_SEGMENT_STATUSES.has(seg.status) ? (
366
+ <AnimatedStripes status={seg.status} />
367
+ ) : null}
368
+ {showLabel ? <DurationLabel label={label} /> : null}
369
+ </div>
370
+ );
371
+ })}
372
+ </div>
373
+ );
374
+ }
375
+
376
+ // ---------------------------------------------------------------------------
377
+ // TimelineBar
378
+ // ---------------------------------------------------------------------------
379
+
380
+ const TimelineBar = memo(function TimelineBar({
381
+ span,
382
+ viewStart,
383
+ viewDuration,
384
+ containerWidth,
385
+ isSelected,
386
+ isDimmed,
387
+ onSelect,
388
+ onRevealTime,
389
+ }: {
390
+ span: Span;
391
+ viewStart: number;
392
+ viewDuration: number;
393
+ containerWidth: number;
394
+ isSelected: boolean;
395
+ isDimmed?: boolean;
396
+ onSelect: (spanId: string) => void;
397
+ onRevealTime?: (timeMs: number) => void;
398
+ }): ReactNode {
399
+ const startMs = getHighResInMs(span.startTime);
400
+ const endMs = getHighResInMs(span.endTime);
401
+ const totalDurationMs = getSpanDurationMs(span);
402
+
403
+ const geometry = useMemo(
404
+ () =>
405
+ computeBarGeometry(
406
+ startMs,
407
+ endMs,
408
+ viewStart,
409
+ viewStart + viewDuration,
410
+ containerWidth
411
+ ),
412
+ [startMs, endMs, viewStart, viewDuration, containerWidth]
413
+ );
414
+
415
+ const baseSegments = useMemo(() => computeSpanSegments(span), [span]);
416
+ const segments = useMemo(
417
+ () =>
418
+ geometry.mode.kind === 'full'
419
+ ? projectSegments(baseSegments, startMs, totalDurationMs, geometry)
420
+ : [],
421
+ [geometry, baseSegments, startMs, totalDurationMs]
422
+ );
423
+
424
+ const baseMarkers = useMemo(() => computeSpanMarkers(span), [span]);
425
+ const markers = useMemo(
426
+ () =>
427
+ geometry.mode.kind === 'full'
428
+ ? cullCollidingMarkers(
429
+ projectMarkers(
430
+ baseMarkers,
431
+ geometry.visibleStartMs,
432
+ geometry.visibleEndMs
433
+ ),
434
+ geometry.visiblePixelWidth
435
+ )
436
+ : [],
437
+ [geometry, baseMarkers]
438
+ );
439
+
440
+ // Markers that fall outside the visible window (scrolled off while zoomed in)
441
+ // — surfaced as edge indicators so they aren't silently lost.
442
+ const offscreen = useMemo<OffscreenMarkers>(
443
+ () =>
444
+ geometry.mode.kind === 'full'
445
+ ? computeOffscreenMarkers(
446
+ baseMarkers,
447
+ geometry.visibleStartMs,
448
+ geometry.visibleEndMs
449
+ )
450
+ : { left: null, right: null },
451
+ [geometry, baseMarkers]
452
+ );
453
+
454
+ // Markers (visible or off-screen) move the duration label into the overlay,
455
+ // so the in-bar segment label is suppressed.
456
+ const hasMarkers =
457
+ markers.length > 0 || offscreen.left !== null || offscreen.right !== null;
458
+
459
+ const isErrored = isSpanErrored(span);
460
+ const colors = getResourceColor(span.resource);
461
+ const fallbackBg = isErrored
462
+ ? (colors.errorBg ?? 'var(--ds-red-200)')
463
+ : colors.bg;
464
+ const fallbackBorder = isErrored
465
+ ? (colors.errorBorder ?? 'var(--ds-red-500)')
466
+ : colors.border;
467
+
468
+ const totalLabel = formatDurationPrecise(totalDurationMs);
469
+ const showTotalLabel =
470
+ geometry.visiblePixelWidth >=
471
+ Math.max(40, estimateLabelWidthPx(totalLabel));
472
+
473
+ const handleClick = useCallback(() => {
474
+ onSelect(span.spanId);
475
+ }, [onSelect, span.spanId]);
476
+
477
+ return (
478
+ <div
479
+ role="treeitem"
480
+ aria-selected={isSelected}
481
+ aria-expanded={isSelected}
482
+ aria-level={1}
483
+ className={cn(
484
+ 'group/timeline-row h-10 relative flex items-center hover:bg-gray-100 aria-selected:bg-gray-100 aria-selected:hover:bg-gray-200 transition-opacity',
485
+ isDimmed && 'opacity-35'
486
+ )}
487
+ onClick={handleClick}
488
+ >
489
+ <div className="absolute inset-y-0" style={TIMELINE_INSET_STYLE}>
490
+ <div
491
+ className="absolute top-1/2 h-6 -translate-y-1/2 overflow-hidden rounded-[0.25rem]"
492
+ style={getBarPositionStyle(geometry)}
493
+ >
494
+ {geometry.mode.kind === 'arrow' ? (
495
+ <BoundaryArrow direction={geometry.mode.direction} />
496
+ ) : geometry.mode.kind === 'tiny' ? (
497
+ <div
498
+ className="h-6 rounded-[0.25rem] border"
499
+ style={{ background: fallbackBg, borderColor: fallbackBorder }}
500
+ />
501
+ ) : segments.length > 0 ? (
502
+ <SegmentBar segments={segments} showLabels={!hasMarkers} />
503
+ ) : (
504
+ <PlainBar
505
+ bg={fallbackBg}
506
+ border={fallbackBorder}
507
+ label={showTotalLabel ? totalLabel : null}
508
+ />
509
+ )}
510
+ </div>
511
+ {/* Overlay (not clipped): ticks, off-screen indicators, then the duration label on top. */}
512
+ {hasMarkers ? (
513
+ <div
514
+ className="pointer-events-none absolute top-1/2 h-6 -translate-y-1/2"
515
+ style={getBarPositionStyle(geometry)}
516
+ >
517
+ {markers.length > 0 ? <MarkerLayer markers={markers} /> : null}
518
+ {offscreen.left ? (
519
+ <OffscreenMarkerIndicator
520
+ direction="left"
521
+ count={offscreen.left.count}
522
+ targetMs={offscreen.left.nearestMs}
523
+ onReveal={onRevealTime}
524
+ />
525
+ ) : null}
526
+ {offscreen.right ? (
527
+ <OffscreenMarkerIndicator
528
+ direction="right"
529
+ count={offscreen.right.count}
530
+ targetMs={offscreen.right.nearestMs}
531
+ onReveal={onRevealTime}
532
+ />
533
+ ) : null}
534
+ {showTotalLabel ? (
535
+ <DurationLabel
536
+ label={totalLabel}
537
+ // Shift clear of the left edge indicator so it isn't covered.
538
+ className={offscreen.left ? 'pl-10' : undefined}
539
+ />
540
+ ) : null}
541
+ </div>
542
+ ) : null}
543
+ </div>
544
+ </div>
545
+ );
546
+ });
547
+
548
+ export { TimelineBar };
549
+
550
+ // ---------------------------------------------------------------------------
551
+ // DeltaMeasureLine (Alt-key measurement overlays: the selected ↔ hovered
552
+ // measurement, and the ambient consecutive-gap indicators shown without a
553
+ // selection)
554
+ // ---------------------------------------------------------------------------
555
+
556
+ // Horizontal distance between the anchor bar's measured edge and the vertical
557
+ // guide — also the width of the connector stub bridging the two.
558
+ const MEASURE_GUIDE_OUTSET_PX = 4;
559
+
560
+ const DeltaMeasureLine = memo(function DeltaMeasureLine({
561
+ delta,
562
+ anchorRowIndex,
563
+ hoveredRowIndex,
564
+ timelineWidth,
565
+ }: {
566
+ delta: SpanDelta;
567
+ anchorRowIndex: number;
568
+ hoveredRowIndex: number;
569
+ timelineWidth: number;
570
+ }) {
571
+ // Both ends of the measurement align with the vertical middle of the bars
572
+ // (bars are centered in their rows, so bar center == row center).
573
+ const anchorCenterY = anchorRowIndex * ROW_HEIGHT_PX + ROW_HEIGHT_PX / 2;
574
+ const lineY = hoveredRowIndex * ROW_HEIGHT_PX + ROW_HEIGHT_PX / 2;
575
+
576
+ // Guide connecting the middle of the anchor bar down/up to the line, so
577
+ // the measurement's origin stays legible when the rows are far apart.
578
+ // It sits just outside the anchor bar's measured edge (so it doesn't blend
579
+ // into the bar's border), joined to the bar by a short horizontal stub. The
580
+ // line runs from the elbow corner (the guide's x) to the hovered span's
581
+ // measured edge — pulled short of the edge arrow when the hovered span is
582
+ // fully off-screen.
583
+ const guideTop = Math.min(anchorCenterY, lineY);
584
+ const guideBottom = Math.max(anchorCenterY, lineY);
585
+ const anchorX = delta.anchorFrac * timelineWidth;
586
+ const guideX =
587
+ anchorX +
588
+ (delta.anchorEdge === 'end'
589
+ ? MEASURE_GUIDE_OUTSET_PX
590
+ : -MEASURE_GUIDE_OUTSET_PX);
591
+ const arrowClearance =
592
+ delta.hoveredOffscreen === 'right'
593
+ ? -(TINY_BAR_BOX_SIZE_PX + 4)
594
+ : delta.hoveredOffscreen === 'left'
595
+ ? TINY_BAR_BOX_SIZE_PX + 4
596
+ : 0;
597
+ const hoveredX = delta.hoveredFrac * timelineWidth + arrowClearance;
598
+ const startX = Math.min(guideX, hoveredX);
599
+ const endX = Math.max(guideX, hoveredX);
600
+
601
+ const label = formatDurationPrecise(delta.deltaMs);
602
+ const labelWidthPx = estimateLabelWidthPx(label);
603
+ // Center the label on the line; when the line is too short, place it beside
604
+ // the right endpoint, flipping left near the viewport's right edge.
605
+ const labelPlacement =
606
+ endX - startX >= labelWidthPx
607
+ ? { left: (startX + endX) / 2, translate: '-translate-x-1/2' }
608
+ : endX + 4 + labelWidthPx <= timelineWidth
609
+ ? { left: endX + 4, translate: '' }
610
+ : { left: startX - 4, translate: '-translate-x-full' };
611
+
612
+ return (
613
+ <>
614
+ <div
615
+ className="absolute h-px bg-amber-800"
616
+ style={{
617
+ left: Math.min(anchorX, guideX),
618
+ width: MEASURE_GUIDE_OUTSET_PX,
619
+ top: anchorCenterY,
620
+ }}
621
+ />
622
+ <div
623
+ className="absolute w-px bg-amber-800"
624
+ style={{
625
+ left: guideX,
626
+ top: guideTop,
627
+ height: guideBottom - guideTop,
628
+ }}
629
+ />
630
+ <div
631
+ className="absolute h-px bg-amber-800"
632
+ style={{ left: startX, width: Math.max(endX - startX, 1), top: lineY }}
633
+ />
634
+ <span
635
+ className={cn(
636
+ 'absolute -translate-y-1/2 font-mono text-[10px] font-medium leading-none tabular-nums whitespace-nowrap rounded-xs bg-background-100 px-1 py-0.5 text-amber-800',
637
+ labelPlacement.translate
638
+ )}
639
+ style={{ left: labelPlacement.left, top: lineY }}
640
+ >
641
+ {label}
642
+ </span>
643
+ </>
644
+ );
645
+ });
646
+
647
+ // ---------------------------------------------------------------------------
648
+ // TimelineHeader
649
+ // ---------------------------------------------------------------------------
650
+
651
+ export function TimelineHeader({
652
+ markers,
653
+ hoverInfo,
654
+ }: {
655
+ markers: TimeMarker[];
656
+ hoverInfo?: { fraction: number; label: string } | null;
657
+ }): ReactNode {
658
+ return (
659
+ <div className="relative bg-background-100 border-b border-gray-alpha-400 h-10 min-h-10 flex items-end px-4 pb-1">
660
+ <div className="relative h-full flex-1">
661
+ {markers.map((m) => (
662
+ <span
663
+ key={String(m.value)}
664
+ className="absolute bottom-1 text-label-12-mono text-gray-900 whitespace-nowrap"
665
+ style={{ left: `${m.position * 100}%` }}
666
+ >
667
+ {m.label}
668
+ </span>
669
+ ))}
670
+ {hoverInfo && (
671
+ <span
672
+ className="absolute top-1 pointer-events-none z-10 font-mono text-[11px] leading-4 text-gray-1000 whitespace-nowrap bg-background-100 border border-gray-alpha-400 rounded px-1 -translate-x-1/2"
673
+ style={{ left: `${hoverInfo.fraction * 100}%` }}
674
+ >
675
+ {hoverInfo.label}
676
+ </span>
677
+ )}
678
+ </div>
679
+ </div>
680
+ );
681
+ }
682
+
683
+ // ---------------------------------------------------------------------------
684
+ // Timeline
685
+ // ---------------------------------------------------------------------------
686
+
687
+ export interface TimelineHover {
688
+ /** Pointer x as a fraction of the timeline's content width, in [0, 1]. */
689
+ fraction: number;
690
+ /** Row index under the pointer; may be past the last row — not validated. */
691
+ rowIndex: number;
692
+ }
693
+
694
+ export function Timeline({
695
+ spans,
696
+ viewStart,
697
+ viewEnd,
698
+ markers,
699
+ selectedId,
700
+ searchResult,
701
+ onSelect,
702
+ onRevealTime,
703
+ hover,
704
+ altHeld = false,
705
+ }: {
706
+ spans: Span[];
707
+ viewStart: number;
708
+ viewEnd: number;
709
+ markers: TimeMarker[];
710
+ selectedId: string | null;
711
+ searchResult: SpanSearchResult;
712
+ onSelect: (spanId: string) => void;
713
+ onRevealTime?: (timeMs: number) => void;
714
+ hover?: TimelineHover | null;
715
+ altHeld?: boolean;
716
+ }): ReactNode {
717
+ const containerRef = useRef<HTMLDivElement>(null);
718
+ const [containerWidth, setContainerWidth] = useState(0);
719
+ const viewDuration = viewEnd - viewStart;
720
+ const timelineWidth = Math.max(0, containerWidth - TIMELINE_PADDING_PX * 2);
721
+ const { start, end } = useRowWindow(
722
+ containerRef,
723
+ spans.length,
724
+ ROW_HEIGHT_PX
725
+ );
726
+
727
+ useEffect(() => {
728
+ const el = containerRef.current;
729
+ if (!el) return;
730
+ const ro = new ResizeObserver(([entry]) => {
731
+ setContainerWidth(entry.contentRect.width);
732
+ });
733
+ ro.observe(el);
734
+ return () => ro.disconnect();
735
+ }, []);
736
+
737
+ // Each consecutive gap renders as a measurement from the earlier span's end
738
+ // edge to the next span's start, in the same visual language as the
739
+ // selected ↔ hovered measurement.
740
+ const gapMeasurements = useMemo(
741
+ () =>
742
+ computeSpanGaps(spans, viewStart, viewEnd).map((gap) => ({
743
+ delta: {
744
+ deltaMs: gap.gapMs,
745
+ anchorFrac: gap.leftFrac,
746
+ hoveredFrac: gap.rightFrac,
747
+ anchorEdge: 'end',
748
+ hoveredOffscreen: null,
749
+ } satisfies SpanDelta,
750
+ anchorRowIndex: gap.rowIndex,
751
+ hoveredRowIndex: gap.rowIndex + 1,
752
+ })),
753
+ [spans, viewStart, viewEnd]
754
+ );
755
+
756
+ // With a span selected, Alt+hover measures selected ↔ hovered instead of
757
+ // showing the all-sibling-gaps overlay.
758
+ const anchorIndex = useMemo(
759
+ () => (selectedId ? spans.findIndex((s) => s.spanId === selectedId) : -1),
760
+ [spans, selectedId]
761
+ );
762
+
763
+ const measurement = useMemo(() => {
764
+ if (!altHeld || hover == null || hover.rowIndex === anchorIndex) {
765
+ return null;
766
+ }
767
+ const anchorSpan = spans[anchorIndex];
768
+ const hoveredSpan = spans[hover.rowIndex];
769
+ if (!anchorSpan || !hoveredSpan) return null;
770
+ const delta = computeSpanDelta(anchorSpan, hoveredSpan, viewStart, viewEnd);
771
+ return delta
772
+ ? { delta, anchorRowIndex: anchorIndex, hoveredRowIndex: hover.rowIndex }
773
+ : null;
774
+ }, [altHeld, anchorIndex, hover, spans, viewStart, viewEnd]);
775
+
776
+ return (
777
+ <div
778
+ ref={containerRef}
779
+ className="relative h-full overflow-hidden"
780
+ style={{ minHeight: spans.length * ROW_HEIGHT_PX }}
781
+ >
782
+ <div
783
+ aria-hidden
784
+ className="absolute inset-y-0 pointer-events-none"
785
+ style={TIMELINE_INSET_STYLE}
786
+ >
787
+ {markers.map((marker) =>
788
+ // Skip the "0s" origin marker since the left edge already implies it.
789
+ Math.abs(marker.value) > 0.000001 ? (
790
+ <div
791
+ key={String(marker.value)}
792
+ className="absolute top-0 bottom-0 w-px bg-gray-alpha-300"
793
+ style={{ left: `${marker.position * 100}%` }}
794
+ />
795
+ ) : null
796
+ )}
797
+ </div>
798
+ {hover != null && (
799
+ <div
800
+ className="absolute inset-y-0 pointer-events-none z-10"
801
+ style={TIMELINE_INSET_STYLE}
802
+ >
803
+ <div
804
+ className="absolute top-0 bottom-0 w-px bg-gray-alpha-500"
805
+ style={{ left: `${hover.fraction * 100}%` }}
806
+ />
807
+ </div>
808
+ )}
809
+ <div style={{ transform: `translateY(${start * ROW_HEIGHT_PX}px)` }}>
810
+ {spans.slice(start, end).map((span) => (
811
+ <TimelineBar
812
+ key={span.spanId}
813
+ span={span}
814
+ viewStart={viewStart}
815
+ viewDuration={viewDuration}
816
+ containerWidth={timelineWidth}
817
+ isSelected={selectedId === span.spanId}
818
+ isDimmed={isSpanDimmedBySearch(span.spanId, searchResult)}
819
+ onSelect={onSelect}
820
+ onRevealTime={onRevealTime}
821
+ />
822
+ ))}
823
+ </div>
824
+ {altHeld && anchorIndex < 0 && (
825
+ <div
826
+ aria-hidden
827
+ className="absolute inset-y-0 pointer-events-none"
828
+ style={TIMELINE_INSET_STYLE}
829
+ >
830
+ {gapMeasurements.map((gap) => (
831
+ <DeltaMeasureLine
832
+ key={gap.anchorRowIndex}
833
+ {...gap}
834
+ timelineWidth={timelineWidth}
835
+ />
836
+ ))}
837
+ </div>
838
+ )}
839
+ {measurement && (
840
+ <div
841
+ aria-hidden
842
+ className="absolute inset-y-0 pointer-events-none z-20"
843
+ style={TIMELINE_INSET_STYLE}
844
+ >
845
+ <DeltaMeasureLine {...measurement} timelineWidth={timelineWidth} />
846
+ </div>
847
+ )}
848
+ </div>
849
+ );
850
+ }