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

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
@@ -0,0 +1,20 @@
1
+ /* Only one hint is in the DOM at a time; it is remounted on each rotation
2
+ (keyed by index in React) so this short fade-in plays as a crossfade. */
3
+ .hint {
4
+ animation: trace-shortcut-hint-fade 150ms ease-in-out;
5
+ }
6
+
7
+ @keyframes trace-shortcut-hint-fade {
8
+ from {
9
+ opacity: 0;
10
+ }
11
+ to {
12
+ opacity: 1;
13
+ }
14
+ }
15
+
16
+ @media (prefers-reduced-motion: reduce) {
17
+ .hint {
18
+ animation: none;
19
+ }
20
+ }
@@ -0,0 +1,116 @@
1
+ 'use client';
2
+
3
+ import { X } from 'lucide-react';
4
+ import { useEffect, useState } from 'react';
5
+ import { Kbd } from '../../ui/kbd';
6
+ import styles from './trace-shortcut-helper.module.css';
7
+
8
+ const DISMISSALS_KEY = 'workflow-step-shortcut-helper-dismissals';
9
+ const DISMISSAL_LIMIT = 3;
10
+ const HINT_ROTATION_MS = 8000;
11
+
12
+ function getAltKeyLabel(): 'Alt' | 'Option' {
13
+ if (typeof navigator === 'undefined') return 'Alt';
14
+ return navigator.platform.toLowerCase().includes('mac') ? 'Option' : 'Alt';
15
+ }
16
+
17
+ function readDismissals(): number {
18
+ try {
19
+ const dismissals = Number.parseInt(
20
+ window.localStorage.getItem(DISMISSALS_KEY) ?? '0',
21
+ 10
22
+ );
23
+ return Number.isNaN(dismissals) ? 0 : dismissals;
24
+ } catch {
25
+ return 0;
26
+ }
27
+ }
28
+
29
+ function AltHint() {
30
+ return (
31
+ <>
32
+ Hold
33
+ <Kbd variant="outline" size="compact" className="mx-1">
34
+ {getAltKeyLabel()}
35
+ </Kbd>
36
+ to see delta between spans
37
+ </>
38
+ );
39
+ }
40
+
41
+ function NavHint() {
42
+ return (
43
+ <>
44
+ Use
45
+ <Kbd variant="outline" size="compact" className="ml-1">
46
+ J
47
+ </Kbd>
48
+ <span className="mx-1">/</span>
49
+ <Kbd variant="outline" size="compact" className="mr-1">
50
+ K
51
+ </Kbd>
52
+ to move between spans
53
+ </>
54
+ );
55
+ }
56
+
57
+ export function TraceShortcutHelper({
58
+ hasMultipleSpans,
59
+ reducedMotion,
60
+ }: {
61
+ hasMultipleSpans: boolean;
62
+ reducedMotion: boolean;
63
+ }) {
64
+ const [visible, setVisible] = useState(false);
65
+ const [index, setIndex] = useState(0);
66
+
67
+ useEffect(() => {
68
+ setVisible(readDismissals() < DISMISSAL_LIMIT);
69
+ }, []);
70
+
71
+ useEffect(() => {
72
+ if (reducedMotion) return;
73
+ const id = setInterval(() => {
74
+ setIndex((i) => (i === 0 ? 1 : 0));
75
+ }, HINT_ROTATION_MS);
76
+ return () => clearInterval(id);
77
+ }, [reducedMotion]);
78
+
79
+ if (!visible || !hasMultipleSpans) return null;
80
+
81
+ const dismiss = () => {
82
+ try {
83
+ window.localStorage.setItem(DISMISSALS_KEY, String(readDismissals() + 1));
84
+ } catch {}
85
+ setVisible(false);
86
+ };
87
+
88
+ return (
89
+ <div className="group sticky bottom-3 z-10 ml-4 mb-3 hidden h-8 w-fit items-center gap-1 text-xs leading-none text-gray-900 @min-[480px]:flex">
90
+ <span
91
+ aria-live="polite"
92
+ aria-atomic="true"
93
+ className="inline-flex items-center whitespace-nowrap"
94
+ >
95
+ {reducedMotion ? (
96
+ <AltHint />
97
+ ) : (
98
+ <span
99
+ key={index}
100
+ className={`inline-flex items-center ${styles.hint}`}
101
+ >
102
+ {index === 0 ? <AltHint /> : <NavHint />}
103
+ </span>
104
+ )}
105
+ </span>
106
+ <button
107
+ type="button"
108
+ className="inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground group-hover:opacity-100 focus-visible:opacity-100 motion-reduce:transition-none"
109
+ onClick={dismiss}
110
+ aria-label="Dismiss trace shortcuts helper"
111
+ >
112
+ <X className="h-3 w-3" />
113
+ </button>
114
+ </div>
115
+ );
116
+ }
@@ -0,0 +1,114 @@
1
+ import { Skeleton } from '../../ui/skeleton';
2
+ import { DEFAULT_START_PX, paneColTemplate } from './pane-constants';
3
+
4
+ // Mirrors SplitPane's initial column template so the skeleton lines up with
5
+ // the real viewer's first paint.
6
+ const COL_TEMPLATE = paneColTemplate(DEFAULT_START_PX);
7
+
8
+ const ROWS: { id: string; name: number; off: number; bar: number }[] = [
9
+ { id: 'r0', name: 62, off: 0, bar: 72 },
10
+ { id: 'r1', name: 78, off: 6, bar: 48 },
11
+ { id: 'r2', name: 50, off: 10, bar: 55 },
12
+ { id: 'r3', name: 84, off: 18, bar: 30 },
13
+ { id: 'r4', name: 45, off: 18, bar: 42 },
14
+ { id: 'r5', name: 66, off: 34, bar: 38 },
15
+ { id: 'r6', name: 55, off: 41, bar: 25 },
16
+ { id: 'r7', name: 40, off: 50, bar: 30 },
17
+ ];
18
+
19
+ const HEADER_MARKERS = ['m0', 'm1', 'm2', 'm3'];
20
+
21
+ const HeaderDivider = () => (
22
+ <div className="flex justify-center">
23
+ <span aria-hidden className="h-full w-px bg-gray-alpha-400" />
24
+ </div>
25
+ );
26
+
27
+ export function TraceViewerSkeleton() {
28
+ return (
29
+ <output
30
+ aria-busy="true"
31
+ aria-label="Loading trace"
32
+ className="flex flex-col w-full h-full min-h-0 bg-background-100"
33
+ >
34
+ <span className="sr-only">Loading trace…</span>
35
+
36
+ {/* Minimap strip: thin density lines tracing the same shape as the bars */}
37
+ <div className="relative h-10 min-h-10 shrink-0 border-b border-gray-alpha-400">
38
+ <div className="absolute inset-x-4 top-[6px]">
39
+ {ROWS.map((row, index) => (
40
+ <Skeleton
41
+ key={row.id}
42
+ className="absolute h-[3px] rounded-full"
43
+ style={{
44
+ left: `${row.off}%`,
45
+ width: `${row.bar}%`,
46
+ top: index * 3.5,
47
+ }}
48
+ />
49
+ ))}
50
+ </div>
51
+ </div>
52
+
53
+ {/* Header row: search header | divider | timeline header */}
54
+ <div
55
+ className="shrink-0 grid"
56
+ style={{ gridTemplateColumns: COL_TEMPLATE }}
57
+ >
58
+ <div className="h-10 min-h-10 flex items-center border-b border-gray-alpha-400 pl-4 pr-2 gap-1.5">
59
+ <Skeleton className="w-3.5 h-3.5 shrink-0 rounded-sm" />
60
+ <Skeleton className="h-3.5 w-40" />
61
+ </div>
62
+ <HeaderDivider />
63
+ <div className="h-10 min-h-10 flex items-end border-b border-gray-alpha-400 px-4 pb-1 gap-2">
64
+ <div className="relative flex-1 flex items-end justify-between">
65
+ {HEADER_MARKERS.map((id) => (
66
+ <Skeleton key={id} className="h-3.5 w-9" />
67
+ ))}
68
+ </div>
69
+ </div>
70
+ </div>
71
+
72
+ {/* Content row: event list | gutter | timeline */}
73
+ <div
74
+ className="grid flex-1 min-h-0 overflow-hidden"
75
+ style={{ gridTemplateColumns: COL_TEMPLATE }}
76
+ >
77
+ {/* Sidebar event rows */}
78
+ <div className="block overflow-visible">
79
+ <ul className="block divide-y divide-gray-alpha-400 border-b border-gray-alpha-400">
80
+ {ROWS.map((row) => (
81
+ <li key={row.id} className="h-10 flex items-center pl-4 pr-2">
82
+ <div className="flex min-w-0 flex-1 items-center gap-2">
83
+ <Skeleton className="w-4 h-4 shrink-0 rounded-sm" />
84
+ <Skeleton
85
+ className="h-3.5"
86
+ style={{ width: `${row.name}%` }}
87
+ />
88
+ </div>
89
+ <Skeleton className="ml-2 h-3.5 w-10 shrink-0" />
90
+ </li>
91
+ ))}
92
+ </ul>
93
+ </div>
94
+
95
+ {/* Gutter */}
96
+ <span aria-hidden className="h-full w-px bg-gray-alpha-400" />
97
+
98
+ {/* Timeline bars */}
99
+ <div className="relative min-h-0">
100
+ {ROWS.map((row) => (
101
+ <div key={row.id} className="relative h-10">
102
+ <div className="absolute inset-x-4 inset-y-0">
103
+ <Skeleton
104
+ className="absolute top-1/2 -translate-y-1/2 h-6 rounded-[0.25rem]"
105
+ style={{ left: `${row.off}%`, width: `${row.bar}%` }}
106
+ />
107
+ </div>
108
+ </div>
109
+ ))}
110
+ </div>
111
+ </div>
112
+ </output>
113
+ );
114
+ }
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+
3
+ import { type RefObject, useLayoutEffect, useState } from 'react';
4
+
5
+ /**
6
+ * Observed width (px) of `ref`'s element. Measures synchronously before paint
7
+ * when (re-)enabled, then tracks resizes. While disabled it keeps the last
8
+ * measured value; re-enabling re-measures before the next paint.
9
+ */
10
+ export function useElementWidth(
11
+ ref: RefObject<HTMLElement | null>,
12
+ enabled = true
13
+ ): number {
14
+ const [width, setWidth] = useState(0);
15
+
16
+ useLayoutEffect(() => {
17
+ if (!enabled) return;
18
+ const el = ref.current;
19
+ if (!el) return;
20
+ setWidth(Math.round(el.getBoundingClientRect().width));
21
+ const observer = new ResizeObserver(([entry]) => {
22
+ setWidth(Math.round(entry?.contentRect.width ?? 0));
23
+ });
24
+ observer.observe(el);
25
+ return () => observer.disconnect();
26
+ }, [ref, enabled]);
27
+
28
+ return width;
29
+ }
@@ -0,0 +1,140 @@
1
+ 'use client';
2
+
3
+ import { type RefObject, useEffect, useState } from 'react';
4
+
5
+ /** Rows rendered on the first paint, before the container has been measured. */
6
+ const INITIAL_VISIBLE_ROWS = 60;
7
+
8
+ export interface RowWindow {
9
+ /** First visible row index (inclusive), already padded by overscan. */
10
+ start: number;
11
+ /** Last visible row index (exclusive), already padded by overscan. */
12
+ end: number;
13
+ }
14
+
15
+ /** Nearest scrollable ancestor of `el` (the shared `SplitPane` container). */
16
+ function getScrollParent(el: HTMLElement | null): HTMLElement | null {
17
+ let node = el?.parentElement ?? null;
18
+ while (node) {
19
+ const overflowY = getComputedStyle(node).overflowY;
20
+ if (overflowY === 'auto' || overflowY === 'scroll') return node;
21
+ node = node.parentElement;
22
+ }
23
+ return null;
24
+ }
25
+
26
+ /**
27
+ * Fixed-height windowing over a shared scroll container.
28
+ *
29
+ * The events list and timeline both render one `rowHeight`-tall row per span
30
+ * and scroll together inside the same `SplitPane`. Each caller passes a ref to
31
+ * its own root; the hook walks up to the shared scrollable ancestor, so the
32
+ * scroll container doesn't have to be threaded through props. Same scroll
33
+ * position + same row height means both panes window to the same range.
34
+ */
35
+ export function useRowWindow(
36
+ ref: RefObject<HTMLElement | null>,
37
+ rowCount: number,
38
+ rowHeight: number,
39
+ overscan = 12
40
+ ): RowWindow {
41
+ // Bound the pre-measurement window so the first paint of a large trace
42
+ // doesn't render every row before the effect narrows it down.
43
+ const [range, setRange] = useState<RowWindow>(() => ({
44
+ start: 0,
45
+ end: Math.min(rowCount, INITIAL_VISIBLE_ROWS),
46
+ }));
47
+
48
+ useEffect(() => {
49
+ const self = ref.current;
50
+ const el = getScrollParent(self);
51
+ if (!self || !el) return;
52
+
53
+ let raf = 0;
54
+ const measure = () => {
55
+ raf = 0;
56
+ // Offset of the list's top within the scroll container's content, so the
57
+ // window stays correct even if the list isn't flush with the top.
58
+ const offset =
59
+ self.getBoundingClientRect().top -
60
+ el.getBoundingClientRect().top +
61
+ el.scrollTop;
62
+ const top = el.scrollTop - offset;
63
+ const start = Math.max(0, Math.floor(top / rowHeight) - overscan);
64
+ const end = Math.min(
65
+ rowCount,
66
+ Math.ceil((top + el.clientHeight) / rowHeight) + overscan
67
+ );
68
+ setRange((prev) =>
69
+ prev.start === start && prev.end === end ? prev : { start, end }
70
+ );
71
+ };
72
+
73
+ const onScroll = () => {
74
+ if (!raf) raf = requestAnimationFrame(measure);
75
+ };
76
+
77
+ measure();
78
+ el.addEventListener('scroll', onScroll, { passive: true });
79
+ const ro = new ResizeObserver(measure);
80
+ ro.observe(el);
81
+
82
+ return () => {
83
+ el.removeEventListener('scroll', onScroll);
84
+ ro.disconnect();
85
+ if (raf) cancelAnimationFrame(raf);
86
+ };
87
+ }, [ref, rowCount, rowHeight, overscan]);
88
+
89
+ return range;
90
+ }
91
+
92
+ /** Row height (px) shared by the events list and timeline rows (`h-10`). */
93
+ export const ROW_HEIGHT_PX = 40;
94
+
95
+ /**
96
+ * Scroll a windowed row into view by index.
97
+ *
98
+ * The list is virtualized (fixed `rowHeight` rows), so an off-screen row has no
99
+ * DOM node to `scrollIntoView` — its target offset is computed from its index
100
+ * instead. Walks up from `listEl` to the shared scrollable ancestor (the same
101
+ * one `useRowWindow` measures against), only scrolls when the row sits outside
102
+ * the visible area, leaves a one-row `margin` of breathing room past it, and
103
+ * clamps the result to `[0, scrollHeight - clientHeight]`.
104
+ */
105
+ export function scrollRowIntoView(
106
+ listEl: HTMLElement | null,
107
+ index: number,
108
+ rowHeight: number,
109
+ opts?: { margin?: number; behavior?: ScrollBehavior }
110
+ ): void {
111
+ const scroller = listEl ? getScrollParent(listEl) : null;
112
+ if (!listEl || !scroller) return;
113
+
114
+ const margin = opts?.margin ?? rowHeight;
115
+
116
+ // Offset of the list's top within the scroll container's content.
117
+ const listOffset =
118
+ listEl.getBoundingClientRect().top -
119
+ scroller.getBoundingClientRect().top +
120
+ scroller.scrollTop;
121
+
122
+ const rowTop = listOffset + index * rowHeight;
123
+ const rowBottom = rowTop + rowHeight;
124
+ const viewTop = scroller.scrollTop;
125
+ const viewBottom = viewTop + scroller.clientHeight;
126
+
127
+ let top: number | null = null;
128
+ if (rowTop < viewTop) {
129
+ top = rowTop - margin;
130
+ } else if (rowBottom > viewBottom) {
131
+ top = rowBottom + margin - scroller.clientHeight;
132
+ }
133
+ if (top === null) return;
134
+
135
+ const max = scroller.scrollHeight - scroller.clientHeight;
136
+ scroller.scrollTo({
137
+ top: Math.max(0, Math.min(top, max)),
138
+ behavior: opts?.behavior,
139
+ });
140
+ }
@@ -9,11 +9,13 @@ import {
9
9
  useMemo,
10
10
  useState,
11
11
  } from 'react';
12
- import type { Span } from '../trace-viewer/types';
12
+ import type { Span } from './types';
13
13
 
14
14
  interface ActiveSpanContextValue {
15
15
  activeSpanId: string | null;
16
16
  activeSpan: Span | null;
17
+ /** The full span list the selection lives in (ordered as rendered). */
18
+ spans: Span[];
17
19
  setActiveSpan: (spanId: string) => void;
18
20
  clearActiveSpan: () => void;
19
21
  }
@@ -28,26 +30,22 @@ export function ActiveSpanProvider({
28
30
  spans: Span[];
29
31
  children: ReactNode;
30
32
  }) {
31
- const [activeSpanId, setActiveSpanId] = useState<string | null>(
32
- spans[0]?.spanId ?? null
33
- );
33
+ const [activeSpanId, setActiveSpanId] = useState<string | null>(null);
34
34
 
35
35
  useEffect(() => {
36
36
  setActiveSpanId((currentSpanId) => {
37
- if (spans.length === 0) {
37
+ if (!currentSpanId) {
38
38
  return null;
39
39
  }
40
40
 
41
- if (currentSpanId) {
42
- const hasCurrentSpan = spans.some(
43
- (span) => span.spanId === currentSpanId
44
- );
45
- if (hasCurrentSpan) {
46
- return currentSpanId;
47
- }
41
+ const hasCurrentSpan = spans.some(
42
+ (span) => span.spanId === currentSpanId
43
+ );
44
+ if (hasCurrentSpan) {
45
+ return currentSpanId;
48
46
  }
49
47
 
50
- return spans[0].spanId;
48
+ return null;
51
49
  });
52
50
  }, [spans]);
53
51
 
@@ -71,10 +69,11 @@ export function ActiveSpanProvider({
71
69
  () => ({
72
70
  activeSpanId,
73
71
  activeSpan,
72
+ spans,
74
73
  setActiveSpan,
75
74
  clearActiveSpan,
76
75
  }),
77
- [activeSpanId, activeSpan, setActiveSpan, clearActiveSpan]
76
+ [activeSpanId, activeSpan, spans, setActiveSpan, clearActiveSpan]
78
77
  );
79
78
 
80
79
  return (
@@ -3,7 +3,7 @@ const WorkflowIcon = () => {
3
3
  <svg
4
4
  data-testid="geist-icon"
5
5
  height="16"
6
- stroke-linejoin="round"
6
+ strokeLinejoin="round"
7
7
  style={{ color: 'currentColor' }}
8
8
  viewBox="0 0 16 16"
9
9
  width="16"
@@ -21,7 +21,7 @@ const WebhookIcon = () => {
21
21
  <svg
22
22
  data-testid="geist-icon"
23
23
  height="16"
24
- stroke-linejoin="round"
24
+ strokeLinejoin="round"
25
25
  viewBox="0 0 16 16"
26
26
  width="16"
27
27
  style={{ color: 'currentColor' }}
@@ -0,0 +1,178 @@
1
+ import type { Span } from './types';
2
+
3
+ const ATTR_FILTER_REGEX = /(?:^|\s)(?<pair>(?<key>[\w.]+):(?<value>\S*))/g;
4
+
5
+ export interface SpanAttributeFilter {
6
+ key: string;
7
+ value: string;
8
+ }
9
+
10
+ export interface ParsedSpanSearchQuery {
11
+ text: string;
12
+ attributes: SpanAttributeFilter[];
13
+ }
14
+
15
+ export interface SpanSearchResult {
16
+ isActive: boolean;
17
+ matchedSpanIds: Set<string>;
18
+ matchingSpans: Span[];
19
+ query: ParsedSpanSearchQuery;
20
+ }
21
+
22
+ export function parseSpanSearchQuery(rawQuery: string): ParsedSpanSearchQuery {
23
+ const attributes: SpanAttributeFilter[] = [];
24
+ for (const match of rawQuery.matchAll(ATTR_FILTER_REGEX)) {
25
+ const key = match.groups?.key?.trim();
26
+ if (!key) continue;
27
+ attributes.push({
28
+ key,
29
+ value: (match.groups?.value ?? '').toLocaleLowerCase(),
30
+ });
31
+ }
32
+
33
+ const text = rawQuery
34
+ .replace(ATTR_FILTER_REGEX, ' ')
35
+ .replace(/\s{2,}/g, ' ')
36
+ .trim()
37
+ .toLocaleLowerCase();
38
+
39
+ return { text, attributes };
40
+ }
41
+
42
+ export function isSpanDimmedBySearch(
43
+ spanId: string,
44
+ result: SpanSearchResult
45
+ ): boolean {
46
+ return result.isActive && !result.matchedSpanIds.has(spanId);
47
+ }
48
+
49
+ export function searchSpans(spans: Span[], rawQuery: string): SpanSearchResult {
50
+ const query = parseSpanSearchQuery(rawQuery);
51
+ const isActive = Boolean(query.text || query.attributes.length);
52
+ const matchingSpans = isActive
53
+ ? spans.filter((span) => spanMatchesQuery(span, query))
54
+ : spans;
55
+
56
+ return {
57
+ isActive,
58
+ matchedSpanIds: new Set(matchingSpans.map((span) => span.spanId)),
59
+ matchingSpans,
60
+ query,
61
+ };
62
+ }
63
+
64
+ function spanMatchesQuery(span: Span, query: ParsedSpanSearchQuery): boolean {
65
+ if (query.text && !spanMatchesText(span, query.text)) {
66
+ return false;
67
+ }
68
+
69
+ return query.attributes.every(({ key, value }) =>
70
+ spanMatchesAttribute(span, key, value)
71
+ );
72
+ }
73
+
74
+ function spanMatchesText(span: Span, text: string): boolean {
75
+ return [
76
+ span.name,
77
+ span.spanId,
78
+ span.resource,
79
+ span.library.name,
80
+ span.library.version,
81
+ ]
82
+ .filter((value): value is string => typeof value === 'string')
83
+ .some((value) => value.toLocaleLowerCase().includes(text));
84
+ }
85
+
86
+ function spanMatchesAttribute(
87
+ span: Span,
88
+ key: string,
89
+ expectedValue: string
90
+ ): boolean {
91
+ const candidates = getSearchValues(span, key);
92
+ if (!candidates.length) return false;
93
+
94
+ if (!expectedValue) {
95
+ return candidates.some((value) => value != null);
96
+ }
97
+
98
+ return candidates.some((value) =>
99
+ valueToSearchString(value).toLocaleLowerCase().includes(expectedValue)
100
+ );
101
+ }
102
+
103
+ function getSearchValues(span: Span, key: string): unknown[] {
104
+ const candidates: unknown[] = [];
105
+ const normalizedKey = key.toLocaleLowerCase();
106
+
107
+ switch (normalizedKey) {
108
+ case 'id':
109
+ case 'spanid':
110
+ case 'span.id':
111
+ candidates.push(span.spanId);
112
+ break;
113
+ case 'name':
114
+ candidates.push(span.name);
115
+ break;
116
+ case 'resource':
117
+ candidates.push(span.resource);
118
+ break;
119
+ case 'library':
120
+ case 'library.name':
121
+ candidates.push(span.library.name);
122
+ break;
123
+ case 'library.version':
124
+ candidates.push(span.library.version);
125
+ break;
126
+ case 'status':
127
+ case 'status.code':
128
+ candidates.push(span.status.code);
129
+ break;
130
+ }
131
+
132
+ candidates.push(getOwnProperty(span.attributes, key));
133
+ candidates.push(getPathValue(span.attributes, key));
134
+
135
+ if (!normalizedKey.startsWith('data.')) {
136
+ candidates.push(getPathValue(span.attributes.data, key));
137
+ }
138
+
139
+ return candidates.filter((value) => value !== undefined);
140
+ }
141
+
142
+ function getOwnProperty(source: unknown, key: string): unknown {
143
+ if (!source || typeof source !== 'object') return undefined;
144
+ if (!Object.hasOwn(source, key)) return undefined;
145
+ return (source as Record<string, unknown>)[key];
146
+ }
147
+
148
+ function getPathValue(source: unknown, path: string): unknown {
149
+ if (!source || typeof source !== 'object') return undefined;
150
+
151
+ let current: unknown = source;
152
+ for (const segment of path.split('.')) {
153
+ if (!segment) return undefined;
154
+ current = getOwnProperty(current, segment);
155
+ if (current === undefined) return undefined;
156
+ }
157
+
158
+ return current;
159
+ }
160
+
161
+ function valueToSearchString(value: unknown): string {
162
+ if (value instanceof Date) return value.toISOString();
163
+ if (typeof value === 'string') return value;
164
+ if (
165
+ value == null ||
166
+ typeof value === 'number' ||
167
+ typeof value === 'boolean' ||
168
+ typeof value === 'bigint'
169
+ ) {
170
+ return String(value);
171
+ }
172
+
173
+ try {
174
+ return JSON.stringify(value);
175
+ } catch {
176
+ return String(value);
177
+ }
178
+ }