@workflow/web-shared 5.0.0-beta.3 → 5.0.0-beta.30

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 (402) hide show
  1. package/README.md +2 -10
  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 +228 -90
  6. package/dist/components/hook-actions.js +1 -1
  7. package/dist/components/index.d.ts +6 -2
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/components/index.js +5 -2
  10. package/dist/components/new-trace-viewer/components/copy-button.js +3 -3
  11. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts +34 -0
  12. package/dist/components/new-trace-viewer/components/detail-panel-width.d.ts.map +1 -0
  13. package/dist/components/new-trace-viewer/components/detail-panel-width.js +67 -0
  14. package/dist/components/new-trace-viewer/components/detail-panel.d.ts +14 -0
  15. package/dist/components/new-trace-viewer/components/detail-panel.d.ts.map +1 -0
  16. package/dist/components/new-trace-viewer/components/detail-panel.js +122 -0
  17. package/dist/components/new-trace-viewer/components/draggable-border.d.ts +31 -0
  18. package/dist/components/new-trace-viewer/components/draggable-border.d.ts.map +1 -0
  19. package/dist/components/new-trace-viewer/components/draggable-border.js +140 -0
  20. package/dist/components/new-trace-viewer/components/event-list.d.ts +4 -2
  21. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
  22. package/dist/components/new-trace-viewer/components/event-list.js +22 -13
  23. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
  24. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
  25. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
  26. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
  27. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
  28. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
  29. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
  30. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
  31. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
  32. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
  33. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
  34. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
  35. package/dist/components/new-trace-viewer/components/minimap.d.ts +14 -0
  36. package/dist/components/new-trace-viewer/components/minimap.d.ts.map +1 -0
  37. package/dist/components/new-trace-viewer/components/minimap.js +337 -0
  38. package/dist/components/new-trace-viewer/components/pane-constants.d.ts +14 -0
  39. package/dist/components/new-trace-viewer/components/pane-constants.d.ts.map +1 -0
  40. package/dist/components/new-trace-viewer/components/pane-constants.js +16 -0
  41. package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
  42. package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
  43. package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
  44. package/dist/components/new-trace-viewer/components/split-pane.d.ts +3 -7
  45. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -1
  46. package/dist/components/new-trace-viewer/components/split-pane.js +25 -84
  47. package/dist/components/new-trace-viewer/components/timeline.d.ts +19 -15
  48. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
  49. package/dist/components/new-trace-viewer/components/timeline.js +229 -111
  50. package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
  51. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts +5 -0
  52. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.d.ts.map +1 -0
  53. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.js +55 -0
  54. package/dist/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  55. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
  56. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
  57. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +26 -0
  58. package/dist/components/new-trace-viewer/components/use-element-width.d.ts +8 -0
  59. package/dist/components/new-trace-viewer/components/use-element-width.d.ts.map +1 -0
  60. package/dist/components/new-trace-viewer/components/use-element-width.js +25 -0
  61. package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
  62. package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
  63. package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
  64. package/dist/components/new-trace-viewer/context.d.ts +3 -1
  65. package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
  66. package/dist/components/new-trace-viewer/context.js +9 -10
  67. package/dist/components/new-trace-viewer/icons.js +3 -3
  68. package/dist/components/new-trace-viewer/search.d.ts +19 -0
  69. package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
  70. package/dist/components/new-trace-viewer/search.js +134 -0
  71. package/dist/components/new-trace-viewer/trace-viewer.d.ts +6 -3
  72. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
  73. package/dist/components/new-trace-viewer/trace-viewer.js +167 -162
  74. package/dist/components/new-trace-viewer/types.d.ts +2 -0
  75. package/dist/components/new-trace-viewer/types.d.ts.map +1 -1
  76. package/dist/components/new-trace-viewer/types.js +2 -2
  77. package/dist/components/new-trace-viewer/utils.d.ts +48 -13
  78. package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
  79. package/dist/components/new-trace-viewer/utils.js +135 -107
  80. package/dist/components/run-trace-view.d.ts +5 -7
  81. package/dist/components/run-trace-view.d.ts.map +1 -1
  82. package/dist/components/run-trace-view.js +3 -3
  83. package/dist/components/sidebar/attribute-panel.d.ts +4 -1
  84. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  85. package/dist/components/sidebar/attribute-panel.js +133 -113
  86. package/dist/components/sidebar/attributes-block.d.ts +40 -0
  87. package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
  88. package/dist/components/sidebar/attributes-block.js +140 -0
  89. package/dist/components/sidebar/conversation-view.js +1 -1
  90. package/dist/components/sidebar/copyable-data-block.d.ts +2 -0
  91. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  92. package/dist/components/sidebar/copyable-data-block.js +17 -16
  93. package/dist/components/sidebar/entity-detail-panel.d.ts +11 -11
  94. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  95. package/dist/components/sidebar/entity-detail-panel.js +35 -69
  96. package/dist/components/sidebar/events-list.d.ts +6 -2
  97. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  98. package/dist/components/sidebar/events-list.js +76 -62
  99. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  100. package/dist/components/sidebar/sidebar-data-context.d.ts +10 -7
  101. package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -1
  102. package/dist/components/sidebar/sidebar-data-context.js +1 -1
  103. package/dist/components/sidebar/span-detail-merge.d.ts +31 -0
  104. package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
  105. package/dist/components/sidebar/span-detail-merge.js +92 -0
  106. package/dist/components/sidebar/use-selected-span-detail.d.ts +16 -0
  107. package/dist/components/sidebar/use-selected-span-detail.d.ts.map +1 -0
  108. package/dist/components/sidebar/use-selected-span-detail.js +93 -0
  109. package/dist/components/stream-viewer.js +1 -1
  110. package/dist/components/trace-viewer/components/map.d.ts +2 -2
  111. package/dist/components/trace-viewer/components/map.d.ts.map +1 -1
  112. package/dist/components/trace-viewer/components/map.js +1 -1
  113. package/dist/components/trace-viewer/components/markers.js +1 -1
  114. package/dist/components/trace-viewer/components/node.d.ts +7 -7
  115. package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
  116. package/dist/components/trace-viewer/components/node.js +2 -1
  117. package/dist/components/trace-viewer/components/search-input.js +1 -1
  118. package/dist/components/trace-viewer/components/search.js +1 -1
  119. package/dist/components/trace-viewer/components/span-content.js +1 -1
  120. package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
  121. package/dist/components/trace-viewer/components/span-segments.js +1 -1
  122. package/dist/components/trace-viewer/components/span-strategies.js +1 -1
  123. package/dist/components/trace-viewer/components/ui.js +1 -1
  124. package/dist/components/trace-viewer/components/zoom-button.js +1 -1
  125. package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
  126. package/dist/components/trace-viewer/context.js +1 -1
  127. package/dist/components/trace-viewer/index.js +1 -1
  128. package/dist/components/trace-viewer/trace-viewer.js +1 -1
  129. package/dist/components/trace-viewer/trace-viewer.module.css +4 -4
  130. package/dist/components/trace-viewer/types.js +1 -1
  131. package/dist/components/trace-viewer/util/constants.js +1 -1
  132. package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
  133. package/dist/components/trace-viewer/util/timing.d.ts +3 -3
  134. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
  135. package/dist/components/trace-viewer/util/timing.js +8 -11
  136. package/dist/components/trace-viewer/util/tree.js +1 -1
  137. package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
  138. package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
  139. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
  140. package/dist/components/trace-viewer/worker.js +1 -1
  141. package/dist/components/trace-viewer-new.d.ts +5 -1
  142. package/dist/components/trace-viewer-new.d.ts.map +1 -1
  143. package/dist/components/trace-viewer-new.js +8 -10
  144. package/dist/components/ui/alert.js +2 -2
  145. package/dist/components/ui/button.d.ts +10 -0
  146. package/dist/components/ui/button.d.ts.map +1 -0
  147. package/dist/components/ui/button.js +46 -0
  148. package/dist/components/ui/card.js +2 -2
  149. package/dist/components/ui/collapsible.d.ts +46 -0
  150. package/dist/components/ui/collapsible.d.ts.map +1 -0
  151. package/dist/components/ui/collapsible.js +66 -0
  152. package/dist/components/ui/context-card.d.ts +47 -0
  153. package/dist/components/ui/context-card.d.ts.map +1 -0
  154. package/dist/components/ui/context-card.js +471 -0
  155. package/dist/components/ui/data-inspector.d.ts +7 -6
  156. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  157. package/dist/components/ui/data-inspector.js +232 -99
  158. package/dist/components/ui/data-inspector.styles.d.ts +29 -0
  159. package/dist/components/ui/data-inspector.styles.d.ts.map +1 -0
  160. package/dist/components/ui/data-inspector.styles.js +95 -0
  161. package/dist/components/ui/decrypt-button.js +1 -1
  162. package/dist/components/ui/error-card.js +2 -2
  163. package/dist/components/ui/error-stack-block.d.ts +17 -10
  164. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  165. package/dist/components/ui/error-stack-block.js +49 -30
  166. package/dist/components/ui/icon-button.d.ts +19 -0
  167. package/dist/components/ui/icon-button.d.ts.map +1 -0
  168. package/dist/components/ui/icon-button.js +29 -0
  169. package/dist/components/ui/kbd.d.ts +10 -0
  170. package/dist/components/ui/kbd.d.ts.map +1 -0
  171. package/dist/components/ui/kbd.js +25 -0
  172. package/dist/components/ui/load-more-button.js +1 -1
  173. package/dist/components/ui/menu-dropdown.js +1 -1
  174. package/dist/components/ui/skeleton.js +2 -2
  175. package/dist/components/ui/spinner.js +1 -1
  176. package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
  177. package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
  178. package/dist/components/ui/timestamp-tooltip.js +80 -132
  179. package/dist/components/ui/tooltip.d.ts +10 -0
  180. package/dist/components/ui/tooltip.d.ts.map +1 -0
  181. package/dist/components/ui/tooltip.js +12 -0
  182. package/dist/components/workflow-trace-view.d.ts +7 -8
  183. package/dist/components/workflow-trace-view.d.ts.map +1 -1
  184. package/dist/components/workflow-trace-view.js +11 -16
  185. package/dist/components/workflow-traces/event-colors.d.ts +2 -1
  186. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
  187. package/dist/components/workflow-traces/event-colors.js +15 -7
  188. package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -1
  189. package/dist/components/workflow-traces/trace-colors.js +3 -4
  190. package/dist/components/workflow-traces/trace-span-construction.d.ts +7 -4
  191. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
  192. package/dist/components/workflow-traces/trace-span-construction.js +87 -33
  193. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  194. package/dist/hooks/use-dark-mode.js +1 -1
  195. package/dist/hooks/use-intersection-observer.d.ts +17 -0
  196. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  197. package/dist/hooks/use-intersection-observer.js +29 -0
  198. package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
  199. package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
  200. package/dist/hooks/use-load-more-on-scroll.js +28 -0
  201. package/dist/hooks/use-reduced-motion.d.ts +10 -0
  202. package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
  203. package/dist/hooks/use-reduced-motion.js +29 -0
  204. package/dist/index.d.ts +3 -2
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +4 -3
  207. package/dist/lib/cn.d.ts +10 -0
  208. package/dist/lib/cn.d.ts.map +1 -0
  209. package/dist/lib/cn.js +83 -0
  210. package/dist/lib/event-analysis.d.ts +1 -1
  211. package/dist/lib/event-analysis.d.ts.map +1 -1
  212. package/dist/lib/event-analysis.js +3 -2
  213. package/dist/lib/event-materialization.d.ts +1 -1
  214. package/dist/lib/event-materialization.d.ts.map +1 -1
  215. package/dist/lib/event-materialization.js +29 -21
  216. package/dist/lib/exact-event-search-id.d.ts +25 -0
  217. package/dist/lib/exact-event-search-id.d.ts.map +1 -0
  218. package/dist/lib/exact-event-search-id.js +39 -0
  219. package/dist/lib/hydration.d.ts +17 -2
  220. package/dist/lib/hydration.d.ts.map +1 -1
  221. package/dist/lib/hydration.js +185 -22
  222. package/dist/lib/stream-display.js +1 -1
  223. package/dist/lib/toast.js +1 -1
  224. package/dist/lib/trace-builder.d.ts +16 -4
  225. package/dist/lib/trace-builder.d.ts.map +1 -1
  226. package/dist/lib/trace-builder.js +34 -15
  227. package/dist/lib/utils.d.ts +23 -9
  228. package/dist/lib/utils.d.ts.map +1 -1
  229. package/dist/lib/utils.js +73 -33
  230. package/dist/lib/zstd-browser-decoder.d.ts +7 -0
  231. package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
  232. package/dist/lib/zstd-browser-decoder.js +41 -0
  233. package/dist/styles.css +14 -0
  234. package/package.json +10 -7
  235. package/src/components/event-list-view.tsx +375 -116
  236. package/src/components/index.ts +12 -5
  237. package/src/components/new-trace-viewer/components/copy-button.tsx +2 -2
  238. package/src/components/new-trace-viewer/components/detail-panel-width.test.ts +123 -0
  239. package/src/components/new-trace-viewer/components/detail-panel-width.ts +76 -0
  240. package/src/components/new-trace-viewer/components/detail-panel.tsx +273 -0
  241. package/src/components/new-trace-viewer/components/draggable-border.tsx +216 -0
  242. package/src/components/new-trace-viewer/components/event-list.tsx +57 -32
  243. package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
  244. package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
  245. package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
  246. package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
  247. package/src/components/new-trace-viewer/components/minimap.tsx +559 -0
  248. package/src/components/new-trace-viewer/components/pane-constants.ts +19 -0
  249. package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
  250. package/src/components/new-trace-viewer/components/split-pane.tsx +80 -135
  251. package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
  252. package/src/components/new-trace-viewer/components/timeline.tsx +603 -239
  253. package/src/components/new-trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  254. package/src/components/new-trace-viewer/components/trace-shortcut-helper.tsx +116 -0
  255. package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +114 -0
  256. package/src/components/new-trace-viewer/components/use-element-width.ts +29 -0
  257. package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
  258. package/src/components/new-trace-viewer/context.tsx +13 -14
  259. package/src/components/new-trace-viewer/icons.tsx +2 -2
  260. package/src/components/new-trace-viewer/search.ts +178 -0
  261. package/src/components/new-trace-viewer/trace-viewer.tsx +336 -293
  262. package/src/components/new-trace-viewer/types.ts +2 -0
  263. package/src/components/new-trace-viewer/utils.test.ts +247 -0
  264. package/src/components/new-trace-viewer/utils.ts +203 -134
  265. package/src/components/run-trace-view.tsx +10 -14
  266. package/src/components/sidebar/attribute-panel.tsx +276 -275
  267. package/src/components/sidebar/attributes-block.tsx +326 -0
  268. package/src/components/sidebar/copyable-data-block.tsx +50 -28
  269. package/src/components/sidebar/entity-detail-panel.tsx +89 -123
  270. package/src/components/sidebar/events-list.tsx +196 -178
  271. package/src/components/sidebar/sidebar-data-context.tsx +11 -11
  272. package/src/components/sidebar/span-detail-merge.ts +134 -0
  273. package/src/components/sidebar/use-selected-span-detail.ts +146 -0
  274. package/src/components/trace-viewer/components/node.tsx +3 -2
  275. package/src/components/trace-viewer/trace-viewer.module.css +4 -4
  276. package/src/components/trace-viewer/util/timing.ts +7 -11
  277. package/src/components/trace-viewer-new.tsx +21 -15
  278. package/src/components/ui/alert.tsx +1 -1
  279. package/src/components/ui/button.tsx +68 -0
  280. package/src/components/ui/card.tsx +1 -1
  281. package/src/components/ui/collapsible.tsx +219 -0
  282. package/src/components/ui/context-card.tsx +784 -0
  283. package/src/components/ui/data-inspector.styles.ts +96 -0
  284. package/src/components/ui/data-inspector.tsx +501 -204
  285. package/src/components/ui/error-card.tsx +1 -1
  286. package/src/components/ui/error-stack-block.tsx +84 -55
  287. package/src/components/ui/icon-button.tsx +53 -0
  288. package/src/components/ui/kbd.tsx +43 -0
  289. package/src/components/ui/skeleton.tsx +1 -1
  290. package/src/components/ui/timestamp-tooltip.tsx +132 -194
  291. package/src/components/ui/tooltip.tsx +47 -0
  292. package/src/components/workflow-trace-view.tsx +31 -36
  293. package/src/components/workflow-traces/event-colors.ts +15 -11
  294. package/src/components/workflow-traces/trace-colors.ts +6 -6
  295. package/src/components/workflow-traces/trace-span-construction.test.ts +85 -0
  296. package/src/components/workflow-traces/trace-span-construction.ts +118 -35
  297. package/src/hooks/use-intersection-observer.ts +57 -0
  298. package/src/hooks/use-load-more-on-scroll.ts +49 -0
  299. package/src/hooks/use-reduced-motion.ts +34 -0
  300. package/src/index.ts +9 -0
  301. package/src/lib/cn.ts +93 -0
  302. package/src/lib/event-analysis.ts +6 -4
  303. package/src/lib/event-materialization.ts +35 -21
  304. package/src/lib/exact-event-search-id.ts +67 -0
  305. package/src/lib/hydration.ts +203 -29
  306. package/src/lib/trace-builder.ts +44 -19
  307. package/src/lib/utils.test.ts +33 -0
  308. package/src/lib/utils.ts +82 -35
  309. package/src/lib/zstd-browser-decoder.ts +42 -0
  310. package/src/styles.css +14 -0
  311. package/dist/components/error-boundary.js.map +0 -1
  312. package/dist/components/event-list-view.js.map +0 -1
  313. package/dist/components/hook-actions.js.map +0 -1
  314. package/dist/components/index.js.map +0 -1
  315. package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
  316. package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
  317. package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
  318. package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
  319. package/dist/components/new-trace-viewer/context.js.map +0 -1
  320. package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
  321. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
  322. package/dist/components/new-trace-viewer/detail-panel.js +0 -11
  323. package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
  324. package/dist/components/new-trace-viewer/icons.js.map +0 -1
  325. package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
  326. package/dist/components/new-trace-viewer/types.js.map +0 -1
  327. package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
  328. package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
  329. package/dist/components/new-trace-viewer/util/constants.js +0 -2
  330. package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
  331. package/dist/components/new-trace-viewer/utils.js.map +0 -1
  332. package/dist/components/run-trace-view.js.map +0 -1
  333. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  334. package/dist/components/sidebar/conversation-view.js.map +0 -1
  335. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  336. package/dist/components/sidebar/detail-card.d.ts +0 -14
  337. package/dist/components/sidebar/detail-card.d.ts.map +0 -1
  338. package/dist/components/sidebar/detail-card.js +0 -20
  339. package/dist/components/sidebar/detail-card.js.map +0 -1
  340. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  341. package/dist/components/sidebar/events-list.js.map +0 -1
  342. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  343. package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
  344. package/dist/components/stream-viewer.js.map +0 -1
  345. package/dist/components/trace-viewer/components/map.js.map +0 -1
  346. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  347. package/dist/components/trace-viewer/components/node.js.map +0 -1
  348. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  349. package/dist/components/trace-viewer/components/search.js.map +0 -1
  350. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  351. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  352. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  353. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  354. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  355. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  356. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  357. package/dist/components/trace-viewer/context.js.map +0 -1
  358. package/dist/components/trace-viewer/index.js.map +0 -1
  359. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  360. package/dist/components/trace-viewer/types.js.map +0 -1
  361. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  362. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  363. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  364. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  365. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  366. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  367. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  368. package/dist/components/trace-viewer/worker.js.map +0 -1
  369. package/dist/components/trace-viewer-new.js.map +0 -1
  370. package/dist/components/ui/alert.js.map +0 -1
  371. package/dist/components/ui/card.js.map +0 -1
  372. package/dist/components/ui/data-inspector.js.map +0 -1
  373. package/dist/components/ui/decrypt-button.js.map +0 -1
  374. package/dist/components/ui/error-card.js.map +0 -1
  375. package/dist/components/ui/error-stack-block.js.map +0 -1
  376. package/dist/components/ui/inspector-theme.d.ts +0 -95
  377. package/dist/components/ui/inspector-theme.d.ts.map +0 -1
  378. package/dist/components/ui/inspector-theme.js +0 -82
  379. package/dist/components/ui/inspector-theme.js.map +0 -1
  380. package/dist/components/ui/load-more-button.js.map +0 -1
  381. package/dist/components/ui/menu-dropdown.js.map +0 -1
  382. package/dist/components/ui/skeleton.js.map +0 -1
  383. package/dist/components/ui/spinner.js.map +0 -1
  384. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  385. package/dist/components/workflow-trace-view.js.map +0 -1
  386. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  387. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  388. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  389. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  390. package/dist/hooks/use-dark-mode.js.map +0 -1
  391. package/dist/index.js.map +0 -1
  392. package/dist/lib/event-analysis.js.map +0 -1
  393. package/dist/lib/event-materialization.js.map +0 -1
  394. package/dist/lib/hydration.js.map +0 -1
  395. package/dist/lib/stream-display.js.map +0 -1
  396. package/dist/lib/toast.js.map +0 -1
  397. package/dist/lib/trace-builder.js.map +0 -1
  398. package/dist/lib/utils.js.map +0 -1
  399. package/src/components/new-trace-viewer/detail-panel.tsx +0 -57
  400. package/src/components/new-trace-viewer/util/constants.ts +0 -0
  401. package/src/components/sidebar/detail-card.tsx +0 -65
  402. package/src/components/ui/inspector-theme.ts +0 -110
@@ -2,7 +2,11 @@
2
2
  * Color utilities for workflow traces
3
3
  */
4
4
 
5
- import type { Step, WorkflowRun } from '@workflow/world';
5
+ import {
6
+ isHookLifecycleEventType,
7
+ type Step,
8
+ type WorkflowRun,
9
+ } from '@workflow/world';
6
10
  import styles from '../trace-viewer/trace-viewer.module.css';
7
11
  import type { SpanNode, SpanNodeEvent } from '../trace-viewer/types';
8
12
 
@@ -99,11 +103,7 @@ export const getCustomSpanEventClassName = (
99
103
  }
100
104
 
101
105
  // Webhook-related events - Purple
102
- if (
103
- eventName === 'hook_created' ||
104
- eventName === 'hook_received' ||
105
- eventName === 'hook_disposed'
106
- ) {
106
+ if (isHookLifecycleEventType(eventName)) {
107
107
  return styles.eventHook;
108
108
  }
109
109
 
@@ -0,0 +1,85 @@
1
+ import type { Event, WorkflowRun } from '@workflow/world';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { runToSpan } from './trace-span-construction';
4
+ import { otelTimeToMs } from './trace-time-utils';
5
+
6
+ const date = (ms: number) => new Date(ms);
7
+
8
+ function run(overrides: Partial<WorkflowRun> = {}): WorkflowRun {
9
+ return {
10
+ runId: 'run_1',
11
+ status: 'completed',
12
+ deploymentId: 'dpl_1',
13
+ workflowName: 'workflow//./workflow//testWorkflow',
14
+ specVersion: 2,
15
+ attributes: {},
16
+ createdAt: date(1_000),
17
+ updatedAt: date(6_000),
18
+ startedAt: date(2_000),
19
+ completedAt: date(6_000),
20
+ output: null,
21
+ ...overrides,
22
+ } as WorkflowRun;
23
+ }
24
+
25
+ function event(overrides: Partial<Event>): Event {
26
+ return {
27
+ runId: 'run_1',
28
+ eventId: `evt_${overrides.eventType ?? 'unknown'}`,
29
+ eventType: 'run_created',
30
+ createdAt: date(1_000),
31
+ specVersion: 2,
32
+ eventData: {
33
+ deploymentId: 'dpl_1',
34
+ workflowName: 'workflow//./workflow//testWorkflow',
35
+ input: null,
36
+ },
37
+ ...overrides,
38
+ } as Event;
39
+ }
40
+
41
+ describe('runToSpan', () => {
42
+ it('prefers occurredAt for run span timing when available', () => {
43
+ const span = runToSpan(
44
+ run(),
45
+ [
46
+ event({
47
+ eventType: 'run_created',
48
+ createdAt: date(1_000),
49
+ occurredAt: date(100),
50
+ }),
51
+ event({
52
+ eventType: 'run_started',
53
+ createdAt: date(2_000),
54
+ occurredAt: date(200),
55
+ }),
56
+ event({
57
+ eventType: 'run_completed',
58
+ createdAt: date(6_000),
59
+ occurredAt: date(500),
60
+ }),
61
+ ],
62
+ date(10_000)
63
+ );
64
+
65
+ expect(otelTimeToMs(span.startTime)).toBe(100);
66
+ expect(
67
+ span.activeStartTime ? otelTimeToMs(span.activeStartTime) : undefined
68
+ ).toBe(200);
69
+ expect(otelTimeToMs(span.endTime)).toBe(500);
70
+ expect(
71
+ span.events.find((e) => e.name === 'run_created')?.timestamp
72
+ ).toEqual([0, 100_000_000]);
73
+
74
+ const data = span.attributes.data as {
75
+ createdAt: Date;
76
+ startedAt?: Date;
77
+ completedAt?: Date;
78
+ occurredAt?: Date;
79
+ };
80
+ expect(data.createdAt).toEqual(date(100));
81
+ expect(data.startedAt).toEqual(date(200));
82
+ expect(data.completedAt).toEqual(date(500));
83
+ expect(data).not.toHaveProperty('occurredAt');
84
+ });
85
+ });
@@ -3,7 +3,11 @@
3
3
  */
4
4
 
5
5
  import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
6
- import type { Event, WorkflowRun } from '@workflow/world';
6
+ import {
7
+ type Event,
8
+ isTerminalStepEventType,
9
+ type WorkflowRun,
10
+ } from '@workflow/world';
7
11
  import type { Span, SpanEvent } from '../trace-viewer/types';
8
12
  import { shouldShowVerticalLine } from './event-colors';
9
13
  import { calculateDuration, dateToOtelTime } from './trace-time-utils';
@@ -26,15 +30,27 @@ const MARKER_EVENT_TYPES: Set<Event['eventType']> = new Set([
26
30
  'run_failed',
27
31
  'wait_created',
28
32
  'wait_completed',
33
+ 'attr_set',
29
34
  ]);
30
35
 
36
+ export const getEventTimestamp = (
37
+ event: Event | undefined
38
+ ): Date | undefined => {
39
+ const value = event?.occurredAt ?? event?.createdAt;
40
+ if (!value) return undefined;
41
+
42
+ const date = value instanceof Date ? value : new Date(value);
43
+ return Number.isNaN(date.getTime()) ? undefined : date;
44
+ };
45
+
31
46
  /**
32
47
  * Convert workflow events to span events
33
48
  * Only includes events that should be displayed as markers
34
49
  */
35
50
  export function convertEventsToSpanEvents(
36
51
  events: Event[],
37
- filterTypes = true
52
+ filterTypes = true,
53
+ options: { preferOccurredAt?: boolean } = {}
38
54
  ): SpanEvent[] {
39
55
  return events
40
56
  .filter((event) =>
@@ -42,7 +58,11 @@ export function convertEventsToSpanEvents(
42
58
  )
43
59
  .map((event) => ({
44
60
  name: event.eventType,
45
- timestamp: dateToOtelTime(event.createdAt),
61
+ timestamp: dateToOtelTime(
62
+ options.preferOccurredAt
63
+ ? (getEventTimestamp(event) ?? event.createdAt)
64
+ : event.createdAt
65
+ ),
46
66
  attributes: {
47
67
  eventId: event.eventId,
48
68
  correlationId: event.correlationId,
@@ -59,7 +79,7 @@ export const waitEventsToWaitEntity = (
59
79
  waitId: string;
60
80
  runId: string;
61
81
  createdAt: Date;
62
- resumeAt: Date;
82
+ resumeAt?: Date;
63
83
  completedAt?: Date;
64
84
  } | null => {
65
85
  const startEvent = events.find((event) => event.eventType === 'wait_created');
@@ -72,22 +92,40 @@ export const waitEventsToWaitEntity = (
72
92
  return {
73
93
  waitId: startEvent.correlationId,
74
94
  runId: startEvent.runId,
75
- createdAt: startEvent.createdAt,
76
- resumeAt: startEvent.eventData?.resumeAt,
77
- completedAt: completedEvent?.createdAt,
95
+ createdAt: getEventTimestamp(startEvent) ?? startEvent.createdAt,
96
+ resumeAt: startEvent.eventData?.resumeAt
97
+ ? new Date(startEvent.eventData.resumeAt)
98
+ : undefined,
99
+ completedAt: getEventTimestamp(completedEvent),
78
100
  };
79
101
  };
80
102
 
81
103
  /**
82
104
  * Converts a workflow Wait to an OpenTelemetry Span
83
105
  */
84
- export function waitToSpan(events: Event[], maxEndTime: Date): Span | null {
106
+ export function waitToSpan(
107
+ events: Event[],
108
+ maxEndTime: Date,
109
+ fallbackEndTime = maxEndTime
110
+ ): Span | null {
85
111
  const wait = waitEventsToWaitEntity(events);
86
112
  if (!wait) {
87
113
  return null;
88
114
  }
89
115
  const startTime = wait.createdAt;
90
- const endTime = wait.completedAt ?? maxEndTime;
116
+ const startMs = startTime.getTime();
117
+ let endTime = wait.completedAt;
118
+ if (!endTime) {
119
+ const fallbackCap =
120
+ wait.resumeAt && wait.resumeAt.getTime() < fallbackEndTime.getTime()
121
+ ? wait.resumeAt
122
+ : fallbackEndTime;
123
+ endTime =
124
+ maxEndTime.getTime() > startMs &&
125
+ maxEndTime.getTime() < fallbackCap.getTime()
126
+ ? maxEndTime
127
+ : fallbackCap;
128
+ }
91
129
  const start = dateToOtelTime(startTime);
92
130
  const end = dateToOtelTime(endTime);
93
131
  const duration = calculateDuration(startTime, endTime);
@@ -150,16 +188,16 @@ export const stepEventsToStepEntity = (
150
188
  case 'step_started':
151
189
  status = 'running';
152
190
  attempt += 1;
153
- if (!startedAt) startedAt = e.createdAt;
191
+ if (!startedAt) startedAt = getEventTimestamp(e) ?? e.createdAt;
154
192
  completedAt = undefined;
155
193
  break;
156
194
  case 'step_completed':
157
195
  status = 'completed';
158
- completedAt = e.createdAt;
196
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
159
197
  break;
160
198
  case 'step_failed':
161
199
  status = 'failed';
162
- completedAt = e.createdAt;
200
+ completedAt = getEventTimestamp(e) ?? e.createdAt;
163
201
  break;
164
202
  case 'step_retrying':
165
203
  status = 'pending';
@@ -172,14 +210,18 @@ export const stepEventsToStepEntity = (
172
210
  if (attempt === 0) attempt = 1;
173
211
 
174
212
  const lastEvent = events[events.length - 1];
213
+
175
214
  return {
176
215
  stepId: anchorEvent.correlationId ?? '',
177
216
  runId: anchorEvent.runId,
178
217
  stepName: createdEvent?.eventData?.stepName ?? '',
179
218
  status,
180
219
  attempt,
181
- createdAt: anchorEvent.createdAt,
182
- updatedAt: lastEvent?.createdAt ?? anchorEvent.createdAt,
220
+ createdAt: getEventTimestamp(anchorEvent) ?? anchorEvent.createdAt,
221
+ updatedAt:
222
+ getEventTimestamp(lastEvent) ??
223
+ lastEvent?.createdAt ??
224
+ anchorEvent.createdAt,
183
225
  startedAt,
184
226
  completedAt,
185
227
  specVersion: anchorEvent.specVersion,
@@ -202,25 +244,37 @@ export function stepToSpan(stepEvents: Event[], maxEndTime: Date): Span | null {
202
244
  };
203
245
 
204
246
  const resource = 'step';
205
- const endTime = new Date(step.completedAt ?? maxEndTime);
206
247
 
207
248
  // Include ALL correlated events on the span so the sidebar detail view
208
249
  // can display them. The timeline uses the `showVerticalLine` flag to
209
250
  // determine which events appear as markers.
210
- const events = convertEventsToSpanEvents(stepEvents, false);
251
+ const events = convertEventsToSpanEvents(stepEvents, false, {
252
+ preferOccurredAt: true,
253
+ });
211
254
 
212
- // Use createdAt as span start time, with activeStartTime for when execution began
213
- // This allows visualization of the "queued" period before execution
214
- const spanStartTime = new Date(step.createdAt);
255
+ // Use the event occurrence timestamp for step spans when it is available,
256
+ // falling back to the ingest timestamp used by older event streams.
257
+ const spanStartEvent =
258
+ stepEvents.find((event) => event.eventType === 'step_created') ??
259
+ stepEvents[0];
260
+ const spanStartTime =
261
+ getEventTimestamp(spanStartEvent) ?? new Date(step.createdAt);
215
262
  let activeStartTime = step.startedAt ? new Date(step.startedAt) : undefined;
216
263
  const firstStartEvent = stepEvents.find(
217
264
  (event) => event.eventType === 'step_started'
218
265
  );
219
266
  if (firstStartEvent) {
220
- // `step.startedAt` is the server-side creation timestamp, and `event.createdAt` is
221
- // the client-side creation timestamp. For now, to align the event marker with the
222
- // line we show for step.startedAt, we overwrite here to always use client-side time.
223
- activeStartTime = new Date(firstStartEvent.createdAt);
267
+ activeStartTime =
268
+ getEventTimestamp(firstStartEvent) ?? new Date(firstStartEvent.createdAt);
269
+ }
270
+
271
+ let endTime = new Date(maxEndTime);
272
+ if (step.completedAt) {
273
+ const completedEvent = stepEvents
274
+ .slice()
275
+ .reverse()
276
+ .find((event) => isTerminalStepEventType(event.eventType));
277
+ endTime = getEventTimestamp(completedEvent) ?? new Date(step.completedAt);
224
278
  }
225
279
 
226
280
  return {
@@ -273,10 +327,10 @@ export const hookEventsToHookEntity = (
273
327
  hookId: createdEvent.correlationId,
274
328
  runId: createdEvent.runId,
275
329
  token: createdEvent.eventData?.token,
276
- createdAt: createdEvent.createdAt,
330
+ createdAt: getEventTimestamp(createdEvent) ?? createdEvent.createdAt,
277
331
  receivedCount: receivedEvents.length,
278
- lastReceivedAt: lastReceivedEvent?.createdAt || undefined,
279
- disposedAt: disposedEvents.at(-1)?.createdAt || undefined,
332
+ lastReceivedAt: getEventTimestamp(lastReceivedEvent),
333
+ disposedAt: getEventTimestamp(disposedEvents.at(-1)),
280
334
  };
281
335
  };
282
336
 
@@ -296,7 +350,7 @@ export function hookToSpan(hookEvents: Event[], maxEndTime: Date): Span | null {
296
350
 
297
351
  return {
298
352
  spanId: String(hook.hookId),
299
- name: String(hook.hookId),
353
+ name: hook.token ?? String(hook.hookId),
300
354
  kind: 1, // INTERNAL span kind
301
355
  resource: 'hook',
302
356
  library: WORKFLOW_LIBRARY,
@@ -324,21 +378,50 @@ export function runToSpan(
324
378
  ): Span {
325
379
  const now = nowTime ?? new Date();
326
380
 
381
+ // Prefer the event occurrence timestamp when available so the root span
382
+ // lines up with child spans that already use event occurrence time.
383
+ const runCreatedEvent = runEvents.find(
384
+ (event) => event.eventType === 'run_created'
385
+ );
386
+ const runStartedEvent = runEvents.find(
387
+ (event) => event.eventType === 'run_started'
388
+ );
389
+ const terminalEvent = runEvents
390
+ .slice()
391
+ .reverse()
392
+ .find(
393
+ (event) =>
394
+ event.eventType === 'run_completed' ||
395
+ event.eventType === 'run_failed' ||
396
+ event.eventType === 'run_cancelled'
397
+ );
398
+ const spanStartTime =
399
+ getEventTimestamp(runCreatedEvent) ?? new Date(run.createdAt);
400
+ const activeStartTime =
401
+ getEventTimestamp(runStartedEvent) ??
402
+ (run.startedAt ? new Date(run.startedAt) : undefined);
403
+ const completedAt =
404
+ getEventTimestamp(terminalEvent) ?? run.completedAt ?? undefined;
405
+ const endTime = completedAt ?? now;
406
+
327
407
  // Only embed identification fields — not the full object with
328
- // input/output/error which may contain non-cloneable types.
408
+ // input/output/error which may contain non-cloneable types. Lifecycle
409
+ // timestamps are event-derived so detail rows align with the span timeline.
329
410
  const { input: _i, output: _o, error: _e, ...runIdentity } = run;
330
411
  const attributes = {
331
412
  resource: 'run' as const,
332
- data: runIdentity,
413
+ data: {
414
+ ...runIdentity,
415
+ createdAt: spanStartTime,
416
+ startedAt: activeStartTime,
417
+ completedAt,
418
+ },
333
419
  };
334
420
 
335
- // Use createdAt as span start time, with activeStartTime for when execution began
336
- const spanStartTime = new Date(run.createdAt);
337
- const activeStartTime = run.startedAt ? new Date(run.startedAt) : undefined;
338
- const endTime = run.completedAt ?? now;
339
-
340
421
  // Convert run-level events to span events
341
- const events = convertEventsToSpanEvents(runEvents, false);
422
+ const events = convertEventsToSpanEvents(runEvents, false, {
423
+ preferOccurredAt: true,
424
+ });
342
425
 
343
426
  return {
344
427
  spanId: String(run.runId),
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+
3
+ import type { RefObject } from 'react';
4
+ import { useEffect, useState } from 'react';
5
+
6
+ interface UseIntersectionObserverArgs
7
+ extends Omit<IntersectionObserverInit, 'root'> {
8
+ /**
9
+ * Scroll container the target is observed within. Defaults to the viewport.
10
+ * Passed as a ref so it resolves after commit (when the node exists).
11
+ */
12
+ rootRef?: RefObject<Element | null>;
13
+ freezeOnceVisible?: boolean;
14
+ }
15
+
16
+ /**
17
+ * Returns the latest IntersectionObserverEntry for `elementRef`.
18
+ * Ported from vercel/front's `@vercel/hooks` `useIntersectionObserver`, with
19
+ * `root` threaded as a ref so we can observe inside a custom scroll container.
20
+ */
21
+ export function useIntersectionObserver(
22
+ elementRef: RefObject<Element | null>,
23
+ {
24
+ threshold = 0,
25
+ rootRef,
26
+ rootMargin = '0%',
27
+ freezeOnceVisible = false,
28
+ }: UseIntersectionObserverArgs = {}
29
+ ): IntersectionObserverEntry | undefined {
30
+ const [entry, setEntry] = useState<IntersectionObserverEntry>();
31
+
32
+ const frozen = entry?.isIntersecting && freezeOnceVisible;
33
+
34
+ useEffect(() => {
35
+ const node = elementRef?.current;
36
+
37
+ const hasIOSupport = !!window.IntersectionObserver;
38
+
39
+ if (!hasIOSupport || frozen || !node) return;
40
+
41
+ const updateEntry = ([entry]: IntersectionObserverEntry[]): void => {
42
+ setEntry(entry);
43
+ };
44
+
45
+ const observer = new IntersectionObserver(updateEntry, {
46
+ threshold,
47
+ root: rootRef?.current ?? null,
48
+ rootMargin,
49
+ });
50
+
51
+ observer.observe(node);
52
+
53
+ return () => observer.disconnect();
54
+ }, [elementRef, threshold, rootRef, rootMargin, frozen]);
55
+
56
+ return entry;
57
+ }
@@ -0,0 +1,49 @@
1
+ 'use client';
2
+
3
+ import type { RefObject } from 'react';
4
+ import { useEffect, useRef } from 'react';
5
+ import { useIntersectionObserver } from './use-intersection-observer';
6
+
7
+ interface UseLoadMoreOnScrollOptions {
8
+ hasMore: boolean;
9
+ isLoadingMore: boolean;
10
+ /** Scroll container the sentinel lives in. Defaults to the viewport. */
11
+ rootRef?: RefObject<Element | null>;
12
+ rootMargin?: string;
13
+ }
14
+
15
+ /**
16
+ * Triggers `loadMore` when a sentinel element scrolls into view.
17
+ * Returns a ref to attach to an invisible sentinel `<div>` placed after the
18
+ * list content. Ported from vercel/front's `@vercel/hooks`
19
+ * `useLoadMoreOnScroll`.
20
+ *
21
+ * Because it keys off `isIntersecting`/`isLoadingMore`, it self-continues:
22
+ * if the sentinel is still in view once a page finishes loading, the next
23
+ * page is requested automatically.
24
+ */
25
+ export function useLoadMoreOnScroll(
26
+ loadMore: () => void,
27
+ {
28
+ hasMore,
29
+ isLoadingMore,
30
+ rootRef,
31
+ rootMargin = '400px',
32
+ }: UseLoadMoreOnScrollOptions
33
+ ) {
34
+ const sentinelRef = useRef<HTMLDivElement>(null);
35
+ const entry = useIntersectionObserver(sentinelRef, { rootRef, rootMargin });
36
+
37
+ const loadMoreRef = useRef(loadMore);
38
+ useEffect(() => {
39
+ loadMoreRef.current = loadMore;
40
+ }, [loadMore]);
41
+
42
+ useEffect(() => {
43
+ if (entry?.isIntersecting && hasMore && !isLoadingMore) {
44
+ loadMoreRef.current();
45
+ }
46
+ }, [entry?.isIntersecting, hasMore, isLoadingMore]);
47
+
48
+ return sentinelRef;
49
+ }
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+
5
+ const QUERY = '(prefers-reduced-motion: reduce)';
6
+
7
+ /**
8
+ * Hook that detects whether the user has requested reduced motion and reacts
9
+ * to changes. Mirrors the `prefers-reduced-motion: reduce` media query so
10
+ * components can skip or shorten animations for users with motion
11
+ * sensitivities (e.g. vestibular disorders).
12
+ *
13
+ * @returns `true` if the user prefers reduced motion, `false` otherwise
14
+ */
15
+ export const useReducedMotion = (): boolean => {
16
+ const [reduced, setReduced] = useState(() => {
17
+ if (typeof window === 'undefined' || !window.matchMedia) return false;
18
+ return window.matchMedia(QUERY).matches;
19
+ });
20
+
21
+ useEffect(() => {
22
+ if (typeof window === 'undefined' || !window.matchMedia) return;
23
+
24
+ const media = window.matchMedia(QUERY);
25
+ const onChange = (): void => setReduced(media.matches);
26
+
27
+ media.addEventListener('change', onChange);
28
+ onChange();
29
+
30
+ return () => media.removeEventListener('change', onChange);
31
+ }, []);
32
+
33
+ return reduced;
34
+ };
package/src/index.ts CHANGED
@@ -33,6 +33,13 @@ export {
33
33
  materializeSteps,
34
34
  materializeWaits,
35
35
  } from './lib/event-materialization';
36
+ export {
37
+ type ExactIdSearchResult,
38
+ type ExactWorkflowSearchId,
39
+ type ExactWorkflowSearchIdKind,
40
+ looksLikeWorkflowIdSearchInput,
41
+ parseExactWorkflowSearchId,
42
+ } from './lib/exact-event-search-id';
36
43
  export type { Revivers, StreamRef } from './lib/hydration';
37
44
  export {
38
45
  CLASS_INSTANCE_REF_TYPE,
@@ -42,6 +49,7 @@ export {
42
49
  getWebRevivers,
43
50
  hasEncryptedFields,
44
51
  hydrateResourceIO,
52
+ hydrateResourceIOAsync,
45
53
  hydrateResourceIOWithKey,
46
54
  isClassInstanceRef,
47
55
  isEncryptedMarker,
@@ -57,6 +65,7 @@ export type { StreamStep } from './lib/utils';
57
65
  export {
58
66
  extractConversation,
59
67
  formatDuration,
68
+ formatDurationPrecise,
60
69
  identifyStreamSteps,
61
70
  isDoStreamStep,
62
71
  } from './lib/utils';
package/src/lib/cn.ts ADDED
@@ -0,0 +1,93 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { extendTailwindMerge } from 'tailwind-merge';
3
+
4
+ const twMergeConfig = {
5
+ extend: {
6
+ classGroups: {
7
+ 'text-heading': [
8
+ {
9
+ 'text-heading': [
10
+ '72',
11
+ '64',
12
+ '56',
13
+ '48',
14
+ '40',
15
+ '32',
16
+ '24',
17
+ '20',
18
+ '16',
19
+ '14',
20
+ ],
21
+ },
22
+ ],
23
+ 'text-button': [
24
+ {
25
+ 'text-button': ['16', '14', '12'],
26
+ },
27
+ ],
28
+ 'text-label': [
29
+ {
30
+ 'text-label': [
31
+ '20',
32
+ '18',
33
+ '16',
34
+ '14',
35
+ '14-mono',
36
+ '13',
37
+ '13-mono',
38
+ '12',
39
+ '12-mono',
40
+ ],
41
+ },
42
+ ],
43
+ 'text-copy': [
44
+ {
45
+ 'text-copy': ['24', '20', '18', '16', '14', '13', '13-mono'],
46
+ },
47
+ ],
48
+ material: [
49
+ {
50
+ material: [
51
+ 'base',
52
+ 'small',
53
+ 'medium',
54
+ 'large',
55
+ 'tooltip',
56
+ 'menu',
57
+ 'modal',
58
+ 'fullscreen',
59
+ ],
60
+ },
61
+ ],
62
+ },
63
+ // Make each category conflict with itself, so e.g. text-heading-32 overrides text-heading-24
64
+ conflictingClassGroups: {
65
+ 'text-heading': ['text-heading'],
66
+ 'text-button': ['text-button'],
67
+ 'text-label': ['text-label'],
68
+ 'text-copy': ['text-copy'],
69
+ material: ['material'],
70
+ },
71
+ },
72
+ } as const;
73
+
74
+ type CustomClassGroupIds =
75
+ | 'text-heading'
76
+ | 'text-button'
77
+ | 'text-label'
78
+ | 'text-copy'
79
+ | 'material';
80
+
81
+ const customTwMerge = extendTailwindMerge<CustomClassGroupIds>(twMergeConfig);
82
+
83
+ /**
84
+ * Merges Tailwind class names and resolves any conflicts using `clsx` with `tailwind-merge`.
85
+ *
86
+ * @param inputs - An array of class names to merge.
87
+ * @returns A string of merged and optimized class names.
88
+ */
89
+ function cn(...classes: ClassValue[]) {
90
+ return customTwMerge(clsx(...classes));
91
+ }
92
+
93
+ export { cn };
@@ -3,7 +3,11 @@
3
3
  * Used by run-actions and trace viewer components.
4
4
  */
5
5
 
6
- import type { Event, WorkflowRunStatus } from '@workflow/world';
6
+ import {
7
+ type Event,
8
+ isTerminalWorkflowRunStatus,
9
+ type WorkflowRunStatus,
10
+ } from '@workflow/world';
7
11
 
8
12
  // Time thresholds for Re-enqueue button visibility
9
13
  const STEP_ACTIVITY_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
@@ -140,9 +144,7 @@ export function analyzeEvents(events: Event[] | undefined): EventAnalysis {
140
144
  export function isTerminalStatus(
141
145
  status: WorkflowRunStatus | undefined
142
146
  ): boolean {
143
- return (
144
- status === 'completed' || status === 'failed' || status === 'cancelled'
145
- );
147
+ return status ? isTerminalWorkflowRunStatus(status) : false;
146
148
  }
147
149
 
148
150
  /**