@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
@@ -3,28 +3,34 @@
3
3
  import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
4
4
  import type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
5
5
  import type { ModelMessage } from 'ai';
6
- import { Lock } from 'lucide-react';
6
+ import { format } from 'date-fns';
7
7
  import type { KeyboardEvent, ReactNode } from 'react';
8
- import { useCallback, useContext, useMemo, useState } from 'react';
8
+ import { useCallback, useContext, useMemo, useRef, useState } from 'react';
9
9
  import { isEncryptedMarker, isExpiredMarker } from '../../lib/hydration';
10
- import { useToast } from '../../lib/toast';
11
10
  import { extractConversation, isDoStreamStep } from '../../lib/utils';
11
+ import {
12
+ Collapsible,
13
+ CollapsibleContent,
14
+ CollapsibleRoot,
15
+ CollapsibleTrigger,
16
+ } from '../ui/collapsible';
17
+ import { ContextCardProvider } from '../ui/context-card';
12
18
  import {
13
19
  DecryptClickContext,
14
20
  RunClickContext,
15
21
  StreamClickContext,
16
22
  } from '../ui/data-inspector';
17
23
  import { ErrorCard } from '../ui/error-card';
18
- import {
19
- ErrorStackBlock,
20
- isStructuredErrorWithStack,
21
- } from '../ui/error-stack-block';
24
+ import { ErrorStackBlock, isStructuredError } from '../ui/error-stack-block';
22
25
  import { Skeleton } from '../ui/skeleton';
23
- import { Spinner } from '../ui/spinner';
24
26
  import { TimestampTooltip } from '../ui/timestamp-tooltip';
27
+ import {
28
+ DetailMonoKeyValueRow,
29
+ RunAttributesCard,
30
+ RunMetadataCard,
31
+ } from './attributes-block';
25
32
  import { ConversationView } from './conversation-view';
26
- import { CopyableDataBlock } from './copyable-data-block';
27
- import { DetailCard } from './detail-card';
33
+ import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
28
34
 
29
35
  /**
30
36
  * Tab button for conversation/JSON toggle
@@ -142,16 +148,24 @@ const conversationTabs = [
142
148
  function ConversationWithTabs({
143
149
  conversation,
144
150
  args,
151
+ defaultOpen,
152
+ onOpenChange,
145
153
  }: {
146
154
  conversation: ModelMessage[];
147
155
  args: unknown[];
156
+ defaultOpen?: boolean;
157
+ onOpenChange?: (open: boolean) => void;
148
158
  }) {
149
159
  const [activeTab, setActiveTab] = useState<'conversation' | 'json'>(
150
160
  'conversation'
151
161
  );
152
162
 
153
163
  return (
154
- <DetailCard summary={`Input (${conversation.length} messages)`}>
164
+ <Collapsible
165
+ label="Input"
166
+ defaultOpen={defaultOpen}
167
+ onOpenChange={onOpenChange}
168
+ >
155
169
  <TabbedContainer
156
170
  tabs={conversationTabs}
157
171
  activeTab={activeTab}
@@ -172,7 +186,7 @@ function ConversationWithTabs({
172
186
  </div>
173
187
  )}
174
188
  </TabbedContainer>
175
- </DetailCard>
189
+ </Collapsible>
176
190
  );
177
191
  }
178
192
 
@@ -180,51 +194,8 @@ function ConversationWithTabs({
180
194
  * Render a value with the shared DataInspector (ObjectInspector with
181
195
  * custom theming, nodeRenderer for StreamRef/ClassInstanceRef, etc.)
182
196
  */
183
- /**
184
- * Inline display for an encrypted field — no expand, just a flat label
185
- * with the lucide Lock icon matching the title bar Decrypt button.
186
- */
187
197
  function EncryptedFieldBlock() {
188
- const ctx = useContext(DecryptClickContext);
189
- if (ctx) {
190
- return (
191
- <button
192
- type="button"
193
- onClick={ctx.onDecrypt}
194
- disabled={ctx.isDecrypting}
195
- className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs cursor-pointer transition-colors"
196
- style={{
197
- borderColor: 'var(--ds-gray-400)',
198
- backgroundColor: 'var(--ds-gray-100)',
199
- color: 'var(--ds-gray-700)',
200
- opacity: ctx.isDecrypting ? 0.6 : 1,
201
- }}
202
- title="Click to decrypt"
203
- >
204
- {ctx.isDecrypting ? (
205
- <Spinner size={12} />
206
- ) : (
207
- <Lock className="h-3 w-3" />
208
- )}
209
- <span className="font-medium">
210
- {ctx.isDecrypting ? 'Decrypting…' : 'Decrypt'}
211
- </span>
212
- </button>
213
- );
214
- }
215
- return (
216
- <div
217
- className="flex w-full items-center justify-center gap-1.5 rounded-md border px-3 py-2 text-xs"
218
- style={{
219
- borderColor: 'var(--ds-gray-300)',
220
- backgroundColor: 'var(--ds-gray-100)',
221
- color: 'var(--ds-gray-700)',
222
- }}
223
- >
224
- <Lock className="h-3 w-3" />
225
- <span className="font-medium">Encrypted</span>
226
- </div>
227
- );
198
+ return <EncryptedDataBlock />;
228
199
  }
229
200
 
230
201
  /**
@@ -262,6 +233,7 @@ type AttributeKey =
262
233
  | keyof WorkflowRun
263
234
  | keyof Hook
264
235
  | keyof Event
236
+ | 'occurredAt'
265
237
  | 'moduleSpecifier'
266
238
  | 'eventData'
267
239
  | 'resumeAt'
@@ -269,7 +241,9 @@ type AttributeKey =
269
241
  | 'workflowCoreVersion'
270
242
  | 'receivedCount'
271
243
  | 'lastReceivedAt'
272
- | 'disposedAt';
244
+ | 'disposedAt'
245
+ | 'isSystem'
246
+ | 'errorCode';
273
247
 
274
248
  const attributeOrder: AttributeKey[] = [
275
249
  'workflowName',
@@ -294,6 +268,7 @@ const attributeOrder: AttributeKey[] = [
294
268
  'projectId',
295
269
  'environment',
296
270
  'executionContext',
271
+ 'occurredAt',
297
272
  'createdAt',
298
273
  'startedAt',
299
274
  'updatedAt',
@@ -305,6 +280,7 @@ const attributeOrder: AttributeKey[] = [
305
280
  'eventData',
306
281
  'input',
307
282
  'output',
283
+ 'attributes',
308
284
  'resumeAt',
309
285
  ];
310
286
 
@@ -326,11 +302,14 @@ const attributeDisplayNames: Partial<Record<AttributeKey, string>> = {
326
302
  attempt: 'Attempts',
327
303
  eventId: 'Event ID',
328
304
  runId: 'Run ID',
305
+ token: 'Token',
329
306
  eventType: 'Event Type',
307
+ errorCode: 'Error Code',
330
308
  correlationId: 'Correlation ID',
331
309
  deploymentId: 'Deployment ID',
332
310
  specVersion: 'Spec Version',
333
311
  workflowCoreVersion: '@workflow/core version',
312
+ occurredAt: 'Occurred',
334
313
  createdAt: 'Created',
335
314
  startedAt: 'Started',
336
315
  updatedAt: 'Updated',
@@ -380,15 +359,7 @@ const parseDateValue = (value: unknown): Date | null => {
380
359
  };
381
360
 
382
361
  const formatLocalMillisecondTime = (date: Date): string =>
383
- date.toLocaleString(undefined, {
384
- year: 'numeric',
385
- month: 'numeric',
386
- day: 'numeric',
387
- hour: 'numeric',
388
- minute: 'numeric',
389
- second: 'numeric',
390
- fractionalSecondDigits: 3,
391
- });
362
+ format(date, 'MMM dd HH:mm:ss.SS OO').toUpperCase();
392
363
 
393
364
  export const localMillisecondTime = (value: unknown): string => {
394
365
  const date = parseDateValue(value);
@@ -396,7 +367,6 @@ export const localMillisecondTime = (value: unknown): string => {
396
367
  return '-';
397
368
  }
398
369
 
399
- // e.g. 12/17/2025, 9:08:55.182 AM
400
370
  return formatLocalMillisecondTime(date);
401
371
  };
402
372
 
@@ -420,6 +390,8 @@ const timestampWithTooltipOrNull = (value: unknown): ReactNode | null => {
420
390
 
421
391
  interface DisplayContext {
422
392
  stepName?: string;
393
+ sectionOpen?: boolean;
394
+ onSectionOpenChange?: (open: boolean) => void;
423
395
  }
424
396
 
425
397
  const attributeToDisplayFn: Record<
@@ -432,7 +404,7 @@ const attributeToDisplayFn: Record<
432
404
  stepName: (_value: unknown) => null,
433
405
  // IDs
434
406
  runId: (_value: unknown) => null,
435
- stepId: (_value: unknown) => null,
407
+ stepId: (value: unknown) => String(value),
436
408
  hookId: (value: unknown) => String(value),
437
409
  eventId: (value: unknown) => String(value),
438
410
  // Run/step details
@@ -441,6 +413,7 @@ const attributeToDisplayFn: Record<
441
413
  // Hook details
442
414
  token: (value: unknown) => String(value),
443
415
  isWebhook: (value: unknown) => String(value),
416
+ isSystem: (value: unknown) => String(value),
444
417
  receivedCount: (value: unknown) => String(value),
445
418
  lastReceivedAt: localMillisecondTimeOrNull,
446
419
  disposedAt: localMillisecondTimeOrNull,
@@ -456,7 +429,15 @@ const attributeToDisplayFn: Record<
456
429
  projectId: (_value: unknown) => null,
457
430
  environment: (_value: unknown) => null,
458
431
  executionContext: (_value: unknown) => null,
432
+ // Attributes — string-string metadata attached to the run.
433
+ // Rendered as key-value rows in its own collapsible section;
434
+ // if empty/missing, hidden by the hasDisplayContent gate.
435
+ attributes: (value: unknown) => {
436
+ if (!hasDisplayContent(value)) return null;
437
+ return <RunAttributesCard attributes={value as Record<string, string>} />;
438
+ },
459
439
  // Dates — wrapped with TimestampTooltip showing UTC/local + relative time
440
+ occurredAt: timestampWithTooltipOrNull,
460
441
  createdAt: timestampWithTooltipOrNull,
461
442
  startedAt: timestampWithTooltipOrNull,
462
443
  updatedAt: (_value: unknown) => null,
@@ -467,12 +448,34 @@ const attributeToDisplayFn: Record<
467
448
  // Resolved attributes, won't actually use this function
468
449
  metadata: (value: unknown) => {
469
450
  if (!hasDisplayContent(value)) return null;
470
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
471
- if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
472
- return JsonBlock(value);
451
+ if (isEncryptedMarker(value)) {
452
+ return (
453
+ <Collapsible label="Metadata">
454
+ <EncryptedDataBlock />
455
+ </Collapsible>
456
+ );
457
+ }
458
+ if (isExpiredMarker(value)) {
459
+ return (
460
+ <Collapsible label="Metadata">
461
+ <ExpiredFieldBlock />
462
+ </Collapsible>
463
+ );
464
+ }
465
+ return <RunMetadataCard metadata={value} />;
473
466
  },
474
467
  input: (value: unknown, context?: DisplayContext) => {
475
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
468
+ if (isEncryptedMarker(value)) {
469
+ return (
470
+ <Collapsible
471
+ label="Input"
472
+ defaultOpen={context?.sectionOpen}
473
+ onOpenChange={context?.onSectionOpenChange}
474
+ >
475
+ <EncryptedFieldBlock />
476
+ </Collapsible>
477
+ );
478
+ }
476
479
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
477
480
  // Check if input has args + closure vars structure
478
481
  if (value && typeof value === 'object' && 'args' in value) {
@@ -481,8 +484,6 @@ const attributeToDisplayFn: Record<
481
484
  closureVars?: Record<string, unknown>;
482
485
  thisVal?: unknown;
483
486
  };
484
- const argCount = Array.isArray(args) ? args.length : 0;
485
- const argLabel = argCount === 1 ? 'argument' : 'arguments';
486
487
  const hasClosureVars = hasDisplayContent(closureVars);
487
488
  const hasThisVal = hasDisplayContent(thisVal);
488
489
  const hasArgs = hasDisplayContent(args);
@@ -493,16 +494,21 @@ const attributeToDisplayFn: Record<
493
494
  if (conversation && conversation.length > 0) {
494
495
  return (
495
496
  <>
496
- <ConversationWithTabs conversation={conversation} args={args} />
497
+ <ConversationWithTabs
498
+ conversation={conversation}
499
+ args={args}
500
+ defaultOpen={context?.sectionOpen}
501
+ onOpenChange={context?.onSectionOpenChange}
502
+ />
497
503
  {hasClosureVars && (
498
- <DetailCard summary="Closure Variables">
504
+ <Collapsible label="Closure Variables">
499
505
  {JsonBlock(closureVars)}
500
- </DetailCard>
506
+ </Collapsible>
501
507
  )}
502
508
  {hasThisVal && (
503
- <DetailCard summary="This Value">
509
+ <Collapsible label="This Value">
504
510
  {JsonBlock(thisVal)}
505
- </DetailCard>
511
+ </Collapsible>
506
512
  )}
507
513
  </>
508
514
  );
@@ -511,21 +517,15 @@ const attributeToDisplayFn: Record<
511
517
 
512
518
  // Don't render an empty "Input (0 arguments)" card when no input exists.
513
519
  if (!hasArgs && !hasClosureVars && !hasThisVal) {
514
- return (
515
- <DetailCard
516
- summary="Input (no data)"
517
- disabled
518
- summaryClassName="text-label-14 font-medium py-2"
519
- />
520
- );
520
+ return <Collapsible label="Input (no data)" disabled />;
521
521
  }
522
522
 
523
523
  return (
524
524
  <>
525
- <DetailCard
526
- summary={`Input (${argCount} ${argLabel})`}
527
- summaryClassName="text-label-14 font-medium py-2"
528
- contentClassName="mt-0"
525
+ <Collapsible
526
+ label="Input"
527
+ defaultOpen={context?.sectionOpen}
528
+ onOpenChange={context?.onSectionOpenChange}
529
529
  >
530
530
  {Array.isArray(args)
531
531
  ? args.map((v, i) => (
@@ -534,36 +534,28 @@ const attributeToDisplayFn: Record<
534
534
  </div>
535
535
  ))
536
536
  : JsonBlock(args)}
537
- </DetailCard>
537
+ </Collapsible>
538
538
  {hasClosureVars && (
539
- <DetailCard summary="Closure Variables">
539
+ <Collapsible label="Closure Variables">
540
540
  {JsonBlock(closureVars)}
541
- </DetailCard>
541
+ </Collapsible>
542
542
  )}
543
543
  {hasThisVal && (
544
- <DetailCard summary="this">{JsonBlock(thisVal)}</DetailCard>
544
+ <Collapsible label="Context">{JsonBlock(thisVal)}</Collapsible>
545
545
  )}
546
546
  </>
547
547
  );
548
548
  }
549
549
 
550
550
  // Fallback: treat as plain array or object
551
- const argCount = Array.isArray(value) ? value.length : 0;
552
- const argLabel = argCount === 1 ? 'argument' : 'arguments';
553
551
  if (!hasDisplayContent(value)) {
554
- return (
555
- <DetailCard
556
- summary="Input (no data)"
557
- disabled
558
- summaryClassName="text-label-14 font-medium py-2"
559
- />
560
- );
552
+ return <Collapsible label="Input (no data)" disabled />;
561
553
  }
562
554
  return (
563
- <DetailCard
564
- summary={`Input (${argCount} ${argLabel})`}
565
- summaryClassName="text-label-14 font-medium py-2"
566
- contentClassName="mt-0"
555
+ <Collapsible
556
+ label="Input"
557
+ defaultOpen={context?.sectionOpen}
558
+ onOpenChange={context?.onSectionOpenChange}
567
559
  >
568
560
  {Array.isArray(value)
569
561
  ? value.map((v, i) => (
@@ -572,57 +564,79 @@ const attributeToDisplayFn: Record<
572
564
  </div>
573
565
  ))
574
566
  : JsonBlock(value)}
575
- </DetailCard>
567
+ </Collapsible>
576
568
  );
577
569
  },
578
- output: (value: unknown) => {
570
+ output: (value: unknown, context?: DisplayContext) => {
571
+ if (isEncryptedMarker(value)) {
572
+ return (
573
+ <Collapsible
574
+ label="Output"
575
+ defaultOpen={context?.sectionOpen}
576
+ onOpenChange={context?.onSectionOpenChange}
577
+ >
578
+ <EncryptedFieldBlock />
579
+ </Collapsible>
580
+ );
581
+ }
579
582
  if (!hasDisplayContent(value)) return null;
580
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
581
583
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
582
584
  return (
583
- <DetailCard
584
- summary="Output"
585
- summaryClassName="text-label-14 font-medium py-2"
586
- contentClassName="mt-0"
585
+ <Collapsible
586
+ label="Output"
587
+ defaultOpen={context?.sectionOpen}
588
+ onOpenChange={context?.onSectionOpenChange}
587
589
  >
588
590
  {JsonBlock(value)}
589
- </DetailCard>
591
+ </Collapsible>
590
592
  );
591
593
  },
592
594
  error: (value: unknown) => {
593
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
595
+ if (isEncryptedMarker(value)) {
596
+ return (
597
+ <Collapsible label="Error" defaultOpen>
598
+ <EncryptedFieldBlock />
599
+ </Collapsible>
600
+ );
601
+ }
594
602
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
595
603
  if (!hasDisplayContent(value)) return null;
596
604
 
597
- // If the error object has a `stack` field, render it as readable
598
- // pre-formatted text. Otherwise fall back to the raw JSON viewer.
599
- if (isStructuredErrorWithStack(value)) {
605
+ // Structured workflow errors may be persisted as either `{ message }` or
606
+ // `{ message, stack }`. Render both with the dedicated error block.
607
+ if (isStructuredError(value)) {
600
608
  return (
601
- <DetailCard
602
- summary="Error"
603
- summaryClassName="text-label-14 font-medium py-2"
604
- contentClassName="mt-0"
605
- >
609
+ <Collapsible label="Error" defaultOpen>
606
610
  <ErrorStackBlock value={value} />
607
- </DetailCard>
611
+ </Collapsible>
608
612
  );
609
613
  }
610
614
 
611
615
  return (
612
- <DetailCard
613
- summary="Error"
614
- summaryClassName="text-label-14 font-medium py-2"
615
- contentClassName="mt-0"
616
- >
616
+ <Collapsible label="Error" defaultOpen>
617
617
  {JsonBlock(value)}
618
- </DetailCard>
618
+ </Collapsible>
619
619
  );
620
620
  },
621
621
  eventData: (value: unknown) => {
622
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
622
+ if (isEncryptedMarker(value)) {
623
+ return (
624
+ <Collapsible label="Event Data" defaultOpen>
625
+ <EncryptedFieldBlock />
626
+ </Collapsible>
627
+ );
628
+ }
623
629
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
624
630
  if (!hasDisplayContent(value)) return null;
625
- return <DetailCard summary="Event Data">{JsonBlock(value)}</DetailCard>;
631
+ return (
632
+ <Collapsible label="Event Data" defaultOpen>
633
+ {JsonBlock(value)}
634
+ </Collapsible>
635
+ );
636
+ },
637
+ errorCode: (value: unknown) => {
638
+ if (typeof value !== 'string' || value.length === 0) return null;
639
+ return String(value);
626
640
  },
627
641
  };
628
642
 
@@ -631,9 +645,21 @@ const resolvableAttributes = [
631
645
  'output',
632
646
  'error',
633
647
  'metadata',
648
+ 'attributes',
634
649
  'eventData',
635
650
  ];
636
651
 
652
+ // Attributes whose displayFn renders its own section header via Collapsible,
653
+ // so the outer AttributeBlock should not duplicate the label.
654
+ const selfHeaderedAttributes = new Set([
655
+ 'input',
656
+ 'output',
657
+ 'error',
658
+ 'metadata',
659
+ 'attributes',
660
+ 'eventData',
661
+ ]);
662
+
637
663
  const ExpiredDataMessage = () => (
638
664
  <div
639
665
  className="text-copy-12 rounded-md border p-4 my-2"
@@ -647,6 +673,20 @@ const ExpiredDataMessage = () => (
647
673
  </div>
648
674
  );
649
675
 
676
+ const copyableBasicAttributes = new Set<AttributeKey>([
677
+ 'stepId',
678
+ 'hookId',
679
+ 'eventId',
680
+ 'deploymentId',
681
+ 'moduleSpecifier',
682
+ ]);
683
+
684
+ const loadingSectionLabels: Partial<Record<AttributeKey, string>> = {
685
+ input: 'Input',
686
+ output: 'Output',
687
+ eventData: 'Event Data',
688
+ };
689
+
650
690
  export const AttributeBlock = ({
651
691
  attribute,
652
692
  value,
@@ -660,19 +700,25 @@ export const AttributeBlock = ({
660
700
  inline?: boolean;
661
701
  context?: DisplayContext;
662
702
  }) => {
663
- const isExpandableLoadingTarget =
664
- attribute === 'input' || attribute === 'eventData';
665
- if (isLoading && isExpandableLoadingTarget && !hasDisplayContent(value)) {
666
- return (
667
- <div
668
- className={`my-2 flex flex-col ${attribute === 'input' ? 'gap-2 my-3.5' : 'gap-0'}`}
669
- >
670
- <span className="text-label-14 text-gray-1000 font-medium first-letter:uppercase">
671
- {attribute}
672
- </span>
673
- <Skeleton className="h-9 w-full rounded-md" />
674
- </div>
675
- );
703
+ const decryptCtx = useContext(DecryptClickContext);
704
+ const sectionOpenRef = useRef(false);
705
+ const handleSectionOpenChange = useCallback((open: boolean) => {
706
+ sectionOpenRef.current = open;
707
+ }, []);
708
+ const label = loadingSectionLabels[attribute as AttributeKey];
709
+ if (isLoading && label && !hasDisplayContent(value)) {
710
+ if (decryptCtx?.hasEncryptedData) {
711
+ return (
712
+ <Collapsible
713
+ label={label}
714
+ defaultOpen={attribute === 'eventData' || sectionOpenRef.current}
715
+ onOpenChange={handleSectionOpenChange}
716
+ >
717
+ <EncryptedFieldBlock />
718
+ </Collapsible>
719
+ );
720
+ }
721
+ return <Collapsible label={label} />;
676
722
  }
677
723
 
678
724
  const displayFn =
@@ -680,7 +726,11 @@ export const AttributeBlock = ({
680
726
  if (!displayFn) {
681
727
  return null;
682
728
  }
683
- const displayValue = displayFn(value, context);
729
+ const displayValue = displayFn(value, {
730
+ ...context,
731
+ sectionOpen: sectionOpenRef.current,
732
+ onSectionOpenChange: handleSectionOpenChange,
733
+ });
684
734
  if (!displayValue) {
685
735
  return null;
686
736
  }
@@ -701,6 +751,10 @@ export const AttributeBlock = ({
701
751
  );
702
752
  }
703
753
 
754
+ if (selfHeaderedAttributes.has(attribute)) {
755
+ return <>{displayValue}</>;
756
+ }
757
+
704
758
  return (
705
759
  <div className="relative">
706
760
  {typeof isLoading === 'boolean' && isLoading && (
@@ -711,10 +765,7 @@ export const AttributeBlock = ({
711
765
  />
712
766
  </div>
713
767
  )}
714
- <div
715
- key={attribute}
716
- className={`my-2 flex flex-col ${attribute === 'input' || attribute === 'output' || attribute === 'error' ? 'gap-2 my-3.5' : 'gap-0'}`}
717
- >
768
+ <div key={attribute} className="my-2 flex flex-col gap-0">
718
769
  <span className="text-label-14 text-gray-1000 font-medium first-letter:uppercase">
719
770
  {attribute}
720
771
  </span>
@@ -729,6 +780,7 @@ export const AttributeBlock = ({
729
780
  export const AttributePanel = ({
730
781
  data,
731
782
  moduleSpecifier,
783
+ moduleSourceUrl,
732
784
  isLoading,
733
785
  error,
734
786
  expiredAt,
@@ -740,6 +792,7 @@ export const AttributePanel = ({
740
792
  }: {
741
793
  data: Record<string, unknown>;
742
794
  moduleSpecifier?: string;
795
+ moduleSourceUrl?: string;
743
796
  isLoading?: boolean;
744
797
  error?: Error;
745
798
  expiredAt?: string | Date;
@@ -754,7 +807,6 @@ export const AttributePanel = ({
754
807
  /** Resource type of the selected span — used to show targeted loading skeletons. */
755
808
  resource?: string;
756
809
  }) => {
757
- const toast = useToast();
758
810
  // Extract workflowCoreVersion from executionContext for display
759
811
  const displayData = useMemo(() => {
760
812
  const result = { ...data };
@@ -784,16 +836,16 @@ export const AttributePanel = ({
784
836
 
785
837
  if (!isLoading) return present;
786
838
 
787
- // During loading, ensure input appears so its skeleton renders
788
- // in the correct position (above the events section).
789
- const loadingDefaults = ['input'];
790
- for (const key of loadingDefaults) {
839
+ if (resource === 'sleep') return present;
840
+
841
+ const loadingPlaceholders = ['input', 'output'];
842
+ for (const key of loadingPlaceholders) {
791
843
  if (!present.includes(key)) {
792
844
  present.push(key);
793
845
  }
794
846
  }
795
847
  return present.sort(sortByAttributeOrder);
796
- }, [displayData, isLoading]);
848
+ }, [displayData, isLoading, resource]);
797
849
 
798
850
  // Filter out attributes that return null
799
851
  const visibleBasicAttributes = basicAttributes.filter((attribute) => {
@@ -838,113 +890,64 @@ export const AttributePanel = ({
838
890
  }),
839
891
  [displayData.stepName]
840
892
  );
841
- const handleCopyModuleSpecifier = useCallback((value: string) => {
842
- navigator.clipboard
843
- .writeText(value)
844
- .then(() => {
845
- toast.success('moduleSpecifier copied');
846
- })
847
- .catch(() => {
848
- toast.error('Failed to copy moduleSpecifier');
849
- });
850
- }, []);
893
+ const outerDecryptCtx = useContext(DecryptClickContext);
894
+ const decryptValue = onDecrypt
895
+ ? {
896
+ onDecrypt,
897
+ isDecrypting,
898
+ hasEncryptedData: outerDecryptCtx?.hasEncryptedData,
899
+ }
900
+ : outerDecryptCtx;
851
901
 
852
902
  return (
853
- <RunClickContext.Provider value={onRunClick}>
854
- <StreamClickContext.Provider value={onStreamClick}>
855
- <DecryptClickContext.Provider
856
- value={onDecrypt ? { onDecrypt, isDecrypting } : undefined}
857
- >
858
- <div>
859
- {/* Basic attributes in a vertical layout with border */}
903
+ <ContextCardProvider>
904
+ <RunClickContext.Provider value={onRunClick}>
905
+ <StreamClickContext.Provider value={onStreamClick}>
906
+ <DecryptClickContext.Provider value={decryptValue}>
860
907
  {visibleBasicAttributes.length > 0 && (
861
- <div
862
- className="mb-3 flex flex-col overflow-hidden rounded-md border"
863
- style={{
864
- borderColor: 'var(--ds-gray-300)',
865
- }}
866
- >
867
- {orderedBasicAttributes.map((attribute, index) => {
868
- const displayValue = attributeToDisplayFn[
869
- attribute as keyof typeof attributeToDisplayFn
870
- ]?.(displayData[attribute as keyof typeof displayData]);
871
- const isModuleSpecifier = attribute === 'moduleSpecifier';
872
- const moduleSpecifierValue =
873
- typeof displayValue === 'string'
874
- ? displayValue
875
- : String(
876
- displayValue ?? displayData.moduleSpecifier ?? ''
877
- );
878
- const shouldCapitalizeLabel =
879
- attribute !== 'workflowCoreVersion';
880
- const showResumeAtSkeleton =
881
- isLoading && resource === 'sleep' && !displayData.resumeAt;
882
- const showDivider =
883
- index < orderedBasicAttributes.length - 1 ||
884
- showResumeAtSkeleton;
885
-
886
- return (
887
- <div key={attribute} className="py-1">
888
- <div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
889
- <span
890
- className={
891
- shouldCapitalizeLabel
892
- ? 'text-[14px] first-letter:uppercase'
893
- : 'text-[14px]'
908
+ <CollapsibleRoot defaultOpen>
909
+ <CollapsibleTrigger>Metadata</CollapsibleTrigger>
910
+ <CollapsibleContent className="mt-0 mb-2">
911
+ <div className="flex flex-col">
912
+ {orderedBasicAttributes.map((attribute) => {
913
+ const displayValue = attributeToDisplayFn[
914
+ attribute as keyof typeof attributeToDisplayFn
915
+ ]?.(displayData[attribute as keyof typeof displayData]);
916
+ const isCopyableBasicAttribute =
917
+ copyableBasicAttributes.has(
918
+ attribute as AttributeKey
919
+ ) && typeof displayValue === 'string';
920
+ const label = getAttributeDisplayName(attribute);
921
+
922
+ return (
923
+ <DetailMonoKeyValueRow
924
+ key={attribute}
925
+ label={label}
926
+ value={displayValue}
927
+ copyText={
928
+ isCopyableBasicAttribute ? displayValue : undefined
929
+ }
930
+ href={
931
+ attribute === 'moduleSpecifier'
932
+ ? moduleSourceUrl
933
+ : undefined
894
934
  }
895
- style={{ color: 'var(--ds-gray-700)' }}
896
- >
897
- {getAttributeDisplayName(attribute)}
898
- </span>
899
- {isModuleSpecifier ? (
900
- <button
901
- type="button"
902
- className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
903
- style={{
904
- color: 'var(--ds-gray-1000)',
905
- background: 'transparent',
906
- border: 'none',
907
- padding: 0,
908
- }}
909
- title={moduleSpecifierValue}
910
- onClick={() =>
911
- handleCopyModuleSpecifier(moduleSpecifierValue)
912
- }
913
- >
914
- {moduleSpecifierValue}
915
- </button>
916
- ) : (
917
- <span
918
- className="min-w-0 max-w-[70%] truncate text-right text-[13px] font-mono"
919
- style={{ color: 'var(--ds-gray-1000)' }}
920
- >
921
- {displayValue}
922
- </span>
923
- )}
924
- </div>
925
- {showDivider ? (
926
- <div
927
- className="mx-2.5 border-b"
928
- style={{ borderColor: 'var(--ds-gray-300)' }}
929
935
  />
930
- ) : null}
931
- </div>
932
- );
933
- })}
934
- {isLoading && resource === 'sleep' && !displayData.resumeAt && (
935
- <div className="py-1">
936
- <div className="flex min-h-[32px] items-center justify-between gap-4 rounded-sm px-2.5 py-1">
937
- <span
938
- className="text-[14px] first-letter:uppercase"
939
- style={{ color: 'var(--ds-gray-700)' }}
940
- >
941
- resumeAt
942
- </span>
943
- <Skeleton className="h-4 w-[55%]" />
944
- </div>
936
+ );
937
+ })}
938
+ {isLoading &&
939
+ resource === 'sleep' &&
940
+ !displayData.resumeAt && (
941
+ <div className="flex items-center justify-between gap-3 py-0.5">
942
+ <span className="text-label-13 text-gray-900">
943
+ Resume
944
+ </span>
945
+ <Skeleton className="h-4 w-[55%]" />
946
+ </div>
947
+ )}
945
948
  </div>
946
- )}
947
- </div>
949
+ </CollapsibleContent>
950
+ </CollapsibleRoot>
948
951
  )}
949
952
  {error ? (
950
953
  <ErrorCard
@@ -954,22 +957,20 @@ export const AttributePanel = ({
954
957
  />
955
958
  ) : hasExpired ? (
956
959
  <ExpiredDataMessage />
957
- ) : (
958
- <>
959
- {resolvedAttributes.map((attribute) => (
960
- <AttributeBlock
961
- isLoading={isLoading}
962
- key={attribute}
963
- attribute={attribute}
964
- value={displayData[attribute as keyof typeof displayData]}
965
- context={displayContext}
966
- />
967
- ))}
968
- </>
969
- )}
970
- </div>
971
- </DecryptClickContext.Provider>
972
- </StreamClickContext.Provider>
973
- </RunClickContext.Provider>
960
+ ) : resolvedAttributes.length > 0 ? (
961
+ resolvedAttributes.map((attribute) => (
962
+ <AttributeBlock
963
+ isLoading={isLoading}
964
+ key={attribute}
965
+ attribute={attribute}
966
+ value={displayData[attribute as keyof typeof displayData]}
967
+ context={displayContext}
968
+ />
969
+ ))
970
+ ) : null}
971
+ </DecryptClickContext.Provider>
972
+ </StreamClickContext.Provider>
973
+ </RunClickContext.Provider>
974
+ </ContextCardProvider>
974
975
  );
975
976
  };