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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/README.md +5 -13
  2. package/dist/components/error-boundary.js +1 -1
  3. package/dist/components/event-list-view.d.ts +46 -1
  4. package/dist/components/event-list-view.d.ts.map +1 -1
  5. package/dist/components/event-list-view.js +235 -97
  6. package/dist/components/hook-actions.js +1 -1
  7. package/dist/components/index.d.ts +8 -5
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/components/index.js +6 -4
  10. package/dist/components/sidebar/attribute-panel.d.ts +4 -1
  11. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  12. package/dist/components/sidebar/attribute-panel.js +173 -119
  13. package/dist/components/sidebar/attributes-block.d.ts +40 -0
  14. package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
  15. package/dist/components/sidebar/attributes-block.js +140 -0
  16. package/dist/components/sidebar/conversation-view.js +1 -1
  17. package/dist/components/sidebar/copyable-data-block.d.ts +2 -0
  18. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  19. package/dist/components/sidebar/copyable-data-block.js +17 -16
  20. package/dist/components/sidebar/entity-detail-panel.d.ts +11 -11
  21. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  22. package/dist/components/sidebar/entity-detail-panel.js +37 -71
  23. package/dist/components/sidebar/events-list.d.ts +6 -2
  24. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  25. package/dist/components/sidebar/events-list.js +77 -63
  26. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  27. package/dist/components/sidebar/sidebar-data-context.d.ts +10 -7
  28. package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -1
  29. package/dist/components/sidebar/sidebar-data-context.js +1 -1
  30. package/dist/components/sidebar/span-detail-merge.d.ts +31 -0
  31. package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
  32. package/dist/components/sidebar/span-detail-merge.js +92 -0
  33. package/dist/components/sidebar/use-selected-span-detail.d.ts +16 -0
  34. package/dist/components/sidebar/use-selected-span-detail.d.ts.map +1 -0
  35. package/dist/components/sidebar/use-selected-span-detail.js +93 -0
  36. package/dist/components/stream-viewer-skeleton.d.ts +2 -0
  37. package/dist/components/stream-viewer-skeleton.d.ts.map +1 -0
  38. package/dist/components/stream-viewer-skeleton.js +12 -0
  39. package/dist/components/stream-viewer.d.ts +1 -1
  40. package/dist/components/stream-viewer.d.ts.map +1 -1
  41. package/dist/components/stream-viewer.js +9 -26
  42. package/dist/components/trace-viewer/components/copy-button.d.ts.map +1 -0
  43. package/dist/components/trace-viewer/components/copy-button.js +27 -0
  44. package/dist/components/trace-viewer/components/detail-panel-width.d.ts +34 -0
  45. package/dist/components/trace-viewer/components/detail-panel-width.d.ts.map +1 -0
  46. package/dist/components/trace-viewer/components/detail-panel-width.js +67 -0
  47. package/dist/components/trace-viewer/components/detail-panel.d.ts +14 -0
  48. package/dist/components/trace-viewer/components/detail-panel.d.ts.map +1 -0
  49. package/dist/components/trace-viewer/components/detail-panel.js +122 -0
  50. package/dist/components/trace-viewer/components/draggable-border.d.ts +31 -0
  51. package/dist/components/trace-viewer/components/draggable-border.d.ts.map +1 -0
  52. package/dist/components/trace-viewer/components/draggable-border.js +140 -0
  53. package/dist/components/trace-viewer/components/event-list.d.ts +10 -0
  54. package/dist/components/trace-viewer/components/event-list.d.ts.map +1 -0
  55. package/dist/components/trace-viewer/components/event-list.js +47 -0
  56. package/dist/components/trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
  57. package/dist/components/trace-viewer/components/middle-truncate/copy-selection.js +54 -0
  58. package/dist/components/trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
  59. package/dist/components/trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
  60. package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/truncate.d.ts +1 -1
  61. package/dist/components/trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
  62. package/dist/components/trace-viewer/components/middle-truncate/truncate.js +101 -0
  63. package/dist/components/trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
  64. package/dist/components/trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
  65. package/dist/components/trace-viewer/components/minimap.d.ts +14 -0
  66. package/dist/components/trace-viewer/components/minimap.d.ts.map +1 -0
  67. package/dist/components/trace-viewer/components/minimap.js +337 -0
  68. package/dist/components/trace-viewer/components/pane-constants.d.ts +14 -0
  69. package/dist/components/trace-viewer/components/pane-constants.d.ts.map +1 -0
  70. package/dist/components/trace-viewer/components/pane-constants.js +16 -0
  71. package/dist/components/trace-viewer/components/span-markers.d.ts +46 -0
  72. package/dist/components/trace-viewer/components/span-markers.d.ts.map +1 -0
  73. package/dist/components/trace-viewer/components/span-markers.js +85 -0
  74. package/dist/components/trace-viewer/components/split-pane.d.ts +10 -0
  75. package/dist/components/trace-viewer/components/split-pane.d.ts.map +1 -0
  76. package/dist/components/trace-viewer/components/split-pane.js +41 -0
  77. package/dist/components/trace-viewer/components/timeline.d.ts +42 -0
  78. package/dist/components/trace-viewer/components/timeline.d.ts.map +1 -0
  79. package/dist/components/trace-viewer/components/timeline.js +321 -0
  80. package/dist/components/trace-viewer/components/timeline.module.css +46 -0
  81. package/dist/components/trace-viewer/components/trace-shortcut-helper.d.ts +5 -0
  82. package/dist/components/trace-viewer/components/trace-shortcut-helper.d.ts.map +1 -0
  83. package/dist/components/trace-viewer/components/trace-shortcut-helper.js +55 -0
  84. package/dist/components/trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  85. package/dist/components/trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
  86. package/dist/components/trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
  87. package/dist/components/trace-viewer/components/trace-viewer-skeleton.js +26 -0
  88. package/dist/components/trace-viewer/components/use-element-width.d.ts +8 -0
  89. package/dist/components/trace-viewer/components/use-element-width.d.ts.map +1 -0
  90. package/dist/components/trace-viewer/components/use-element-width.js +25 -0
  91. package/dist/components/trace-viewer/components/use-row-window.d.ts +34 -0
  92. package/dist/components/trace-viewer/components/use-row-window.d.ts.map +1 -0
  93. package/dist/components/trace-viewer/components/use-row-window.js +107 -0
  94. package/dist/components/trace-viewer/context.d.ts +14 -182
  95. package/dist/components/trace-viewer/context.d.ts.map +1 -1
  96. package/dist/components/trace-viewer/context.js +44 -351
  97. package/dist/components/trace-viewer/icons.d.ts.map +1 -0
  98. package/dist/components/trace-viewer/icons.js +15 -0
  99. package/dist/components/trace-viewer/search.d.ts +19 -0
  100. package/dist/components/trace-viewer/search.d.ts.map +1 -0
  101. package/dist/components/trace-viewer/search.js +134 -0
  102. package/dist/components/trace-viewer/trace-viewer.d.ts +7 -28
  103. package/dist/components/trace-viewer/trace-viewer.d.ts.map +1 -1
  104. package/dist/components/trace-viewer/trace-viewer.js +306 -356
  105. package/dist/components/trace-viewer/types.d.ts +2 -211
  106. package/dist/components/trace-viewer/types.d.ts.map +1 -1
  107. package/dist/components/trace-viewer/types.js +1 -1
  108. package/dist/components/trace-viewer/util/timing.d.ts +2 -2
  109. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
  110. package/dist/components/trace-viewer/util/timing.js +3 -3
  111. package/dist/components/trace-viewer/utils.d.ts +111 -0
  112. package/dist/components/trace-viewer/utils.d.ts.map +1 -0
  113. package/dist/components/trace-viewer/utils.js +430 -0
  114. package/dist/components/{trace-viewer-new.d.ts → trace-viewer.d.ts} +7 -3
  115. package/dist/components/trace-viewer.d.ts.map +1 -0
  116. package/dist/components/trace-viewer.js +21 -0
  117. package/dist/components/ui/alert.js +3 -3
  118. package/dist/components/ui/button.d.ts +10 -0
  119. package/dist/components/ui/button.d.ts.map +1 -0
  120. package/dist/components/ui/button.js +46 -0
  121. package/dist/components/ui/card.d.ts.map +1 -1
  122. package/dist/components/ui/card.js +4 -4
  123. package/dist/components/ui/collapsible.d.ts +46 -0
  124. package/dist/components/ui/collapsible.d.ts.map +1 -0
  125. package/dist/components/ui/collapsible.js +66 -0
  126. package/dist/components/ui/context-card.d.ts +47 -0
  127. package/dist/components/ui/context-card.d.ts.map +1 -0
  128. package/dist/components/ui/context-card.js +471 -0
  129. package/dist/components/ui/data-inspector.d.ts +7 -6
  130. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  131. package/dist/components/ui/data-inspector.js +232 -99
  132. package/dist/components/ui/data-inspector.styles.d.ts +29 -0
  133. package/dist/components/ui/data-inspector.styles.d.ts.map +1 -0
  134. package/dist/components/ui/data-inspector.styles.js +95 -0
  135. package/dist/components/ui/decrypt-button.js +1 -1
  136. package/dist/components/ui/error-card.js +3 -3
  137. package/dist/components/ui/error-stack-block.d.ts +17 -10
  138. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  139. package/dist/components/ui/error-stack-block.js +49 -30
  140. package/dist/components/ui/icon-button.d.ts +19 -0
  141. package/dist/components/ui/icon-button.d.ts.map +1 -0
  142. package/dist/components/ui/icon-button.js +29 -0
  143. package/dist/components/ui/kbd.d.ts +10 -0
  144. package/dist/components/ui/kbd.d.ts.map +1 -0
  145. package/dist/components/ui/kbd.js +25 -0
  146. package/dist/components/ui/load-more-button.js +1 -1
  147. package/dist/components/ui/menu-dropdown.js +1 -1
  148. package/dist/components/ui/skeleton.js +2 -2
  149. package/dist/components/ui/spinner.js +1 -1
  150. package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
  151. package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
  152. package/dist/components/ui/timestamp-tooltip.js +80 -132
  153. package/dist/components/ui/tooltip.d.ts +10 -0
  154. package/dist/components/ui/tooltip.d.ts.map +1 -0
  155. package/dist/components/ui/tooltip.js +12 -0
  156. package/dist/components/workflow-traces/event-colors.d.ts +2 -1
  157. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
  158. package/dist/components/workflow-traces/event-colors.js +15 -7
  159. package/dist/components/workflow-traces/trace-span-construction.d.ts +6 -3
  160. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
  161. package/dist/components/workflow-traces/trace-span-construction.js +71 -30
  162. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  163. package/dist/hooks/use-dark-mode.js +1 -1
  164. package/dist/hooks/use-intersection-observer.d.ts +17 -0
  165. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  166. package/dist/hooks/use-intersection-observer.js +29 -0
  167. package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
  168. package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
  169. package/dist/hooks/use-load-more-on-scroll.js +28 -0
  170. package/dist/hooks/use-reduced-motion.d.ts +10 -0
  171. package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
  172. package/dist/hooks/use-reduced-motion.js +29 -0
  173. package/dist/index.d.ts +4 -3
  174. package/dist/index.d.ts.map +1 -1
  175. package/dist/index.js +4 -3
  176. package/dist/lib/cn.d.ts +10 -0
  177. package/dist/lib/cn.d.ts.map +1 -0
  178. package/dist/lib/cn.js +83 -0
  179. package/dist/lib/event-analysis.d.ts +1 -1
  180. package/dist/lib/event-analysis.d.ts.map +1 -1
  181. package/dist/lib/event-analysis.js +3 -2
  182. package/dist/lib/event-materialization.d.ts +1 -1
  183. package/dist/lib/event-materialization.d.ts.map +1 -1
  184. package/dist/lib/event-materialization.js +29 -21
  185. package/dist/lib/exact-event-search-id.d.ts +25 -0
  186. package/dist/lib/exact-event-search-id.d.ts.map +1 -0
  187. package/dist/lib/exact-event-search-id.js +39 -0
  188. package/dist/lib/hydration.d.ts +17 -2
  189. package/dist/lib/hydration.d.ts.map +1 -1
  190. package/dist/lib/hydration.js +194 -23
  191. package/dist/lib/stream-display.js +1 -1
  192. package/dist/lib/toast.js +1 -1
  193. package/dist/lib/trace-builder.d.ts +17 -5
  194. package/dist/lib/trace-builder.d.ts.map +1 -1
  195. package/dist/lib/trace-builder.js +32 -14
  196. package/dist/lib/trace-types.d.ts +54 -0
  197. package/dist/lib/trace-types.d.ts.map +1 -0
  198. package/dist/lib/trace-types.js +2 -0
  199. package/dist/lib/utils.d.ts +14 -2
  200. package/dist/lib/utils.d.ts.map +1 -1
  201. package/dist/lib/utils.js +46 -6
  202. package/dist/lib/zstd-browser-decoder.d.ts +7 -0
  203. package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
  204. package/dist/lib/zstd-browser-decoder.js +41 -0
  205. package/dist/styles.css +210 -139
  206. package/package.json +11 -8
  207. package/src/components/event-list-view.tsx +385 -123
  208. package/src/components/index.ts +14 -8
  209. package/src/components/sidebar/attribute-panel.tsx +331 -282
  210. package/src/components/sidebar/attributes-block.tsx +326 -0
  211. package/src/components/sidebar/copyable-data-block.tsx +50 -28
  212. package/src/components/sidebar/entity-detail-panel.tsx +92 -126
  213. package/src/components/sidebar/events-list.tsx +197 -179
  214. package/src/components/sidebar/sidebar-data-context.tsx +11 -11
  215. package/src/components/sidebar/span-detail-merge.ts +134 -0
  216. package/src/components/sidebar/use-selected-span-detail.ts +146 -0
  217. package/src/components/stream-viewer-skeleton.tsx +34 -0
  218. package/src/components/stream-viewer.tsx +34 -106
  219. package/src/components/{new-trace-viewer → trace-viewer}/components/copy-button.tsx +2 -2
  220. package/src/components/trace-viewer/components/detail-panel-width.test.ts +123 -0
  221. package/src/components/trace-viewer/components/detail-panel-width.ts +76 -0
  222. package/src/components/trace-viewer/components/detail-panel.tsx +273 -0
  223. package/src/components/trace-viewer/components/draggable-border.tsx +216 -0
  224. package/src/components/trace-viewer/components/event-list.tsx +144 -0
  225. package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/middle-truncate.tsx +8 -8
  226. package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/truncate.ts +1 -1
  227. package/src/components/trace-viewer/components/minimap.tsx +556 -0
  228. package/src/components/trace-viewer/components/pane-constants.ts +19 -0
  229. package/src/components/trace-viewer/components/span-markers.tsx +173 -0
  230. package/src/components/trace-viewer/components/split-pane.tsx +141 -0
  231. package/src/components/trace-viewer/components/timeline.module.css +46 -0
  232. package/src/components/trace-viewer/components/timeline.tsx +850 -0
  233. package/src/components/trace-viewer/components/trace-shortcut-helper.module.css +20 -0
  234. package/src/components/trace-viewer/components/trace-shortcut-helper.tsx +116 -0
  235. package/src/components/trace-viewer/components/trace-viewer-skeleton.tsx +114 -0
  236. package/src/components/trace-viewer/components/use-element-width.ts +29 -0
  237. package/src/components/trace-viewer/components/use-row-window.ts +140 -0
  238. package/src/components/trace-viewer/context.tsx +63 -656
  239. package/src/components/{new-trace-viewer → trace-viewer}/icons.tsx +2 -2
  240. package/src/components/trace-viewer/search.ts +178 -0
  241. package/src/components/trace-viewer/trace-viewer.tsx +563 -531
  242. package/src/components/trace-viewer/types.ts +2 -234
  243. package/src/components/trace-viewer/util/timing.ts +2 -2
  244. package/src/components/trace-viewer/utils.test.ts +458 -0
  245. package/src/components/{new-trace-viewer → trace-viewer}/utils.ts +271 -50
  246. package/src/components/{trace-viewer-new.tsx → trace-viewer.tsx} +24 -18
  247. package/src/components/ui/alert.tsx +2 -2
  248. package/src/components/ui/button.tsx +68 -0
  249. package/src/components/ui/card.tsx +3 -10
  250. package/src/components/ui/collapsible.tsx +219 -0
  251. package/src/components/ui/context-card.tsx +784 -0
  252. package/src/components/ui/data-inspector.styles.ts +96 -0
  253. package/src/components/ui/data-inspector.tsx +501 -204
  254. package/src/components/ui/error-card.tsx +4 -4
  255. package/src/components/ui/error-stack-block.tsx +84 -55
  256. package/src/components/ui/icon-button.tsx +53 -0
  257. package/src/components/ui/kbd.tsx +43 -0
  258. package/src/components/ui/skeleton.tsx +1 -1
  259. package/src/components/ui/timestamp-tooltip.tsx +132 -194
  260. package/src/components/ui/tooltip.tsx +47 -0
  261. package/src/components/workflow-traces/event-colors.ts +15 -11
  262. package/src/components/workflow-traces/trace-span-construction.test.ts +85 -0
  263. package/src/components/workflow-traces/trace-span-construction.ts +97 -32
  264. package/src/hooks/use-intersection-observer.ts +57 -0
  265. package/src/hooks/use-load-more-on-scroll.ts +49 -0
  266. package/src/hooks/use-reduced-motion.ts +34 -0
  267. package/src/index.ts +10 -4
  268. package/src/lib/cn.ts +93 -0
  269. package/src/lib/event-analysis.ts +6 -4
  270. package/src/lib/event-materialization.ts +35 -21
  271. package/src/lib/exact-event-search-id.ts +67 -0
  272. package/src/lib/hydration.ts +210 -30
  273. package/src/lib/trace-builder.ts +43 -19
  274. package/src/lib/trace-types.ts +56 -0
  275. package/src/lib/utils.test.ts +33 -0
  276. package/src/lib/utils.ts +53 -6
  277. package/src/lib/zstd-browser-decoder.ts +42 -0
  278. package/src/styles.css +210 -139
  279. package/dist/components/error-boundary.js.map +0 -1
  280. package/dist/components/event-list-view.js.map +0 -1
  281. package/dist/components/hook-actions.js.map +0 -1
  282. package/dist/components/index.js.map +0 -1
  283. package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +0 -1
  284. package/dist/components/new-trace-viewer/components/copy-button.js +0 -27
  285. package/dist/components/new-trace-viewer/components/copy-button.js.map +0 -1
  286. package/dist/components/new-trace-viewer/components/event-list.d.ts +0 -8
  287. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +0 -1
  288. package/dist/components/new-trace-viewer/components/event-list.js +0 -38
  289. package/dist/components/new-trace-viewer/components/event-list.js.map +0 -1
  290. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +0 -1
  291. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +0 -54
  292. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js.map +0 -1
  293. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +0 -1
  294. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +0 -81
  295. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js.map +0 -1
  296. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +0 -1
  297. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +0 -101
  298. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js.map +0 -1
  299. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +0 -1
  300. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +0 -114
  301. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js.map +0 -1
  302. package/dist/components/new-trace-viewer/components/split-pane.d.ts +0 -14
  303. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +0 -1
  304. package/dist/components/new-trace-viewer/components/split-pane.js +0 -99
  305. package/dist/components/new-trace-viewer/components/split-pane.js.map +0 -1
  306. package/dist/components/new-trace-viewer/components/timeline.d.ts +0 -31
  307. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +0 -1
  308. package/dist/components/new-trace-viewer/components/timeline.js +0 -138
  309. package/dist/components/new-trace-viewer/components/timeline.js.map +0 -1
  310. package/dist/components/new-trace-viewer/context.d.ts +0 -15
  311. package/dist/components/new-trace-viewer/context.d.ts.map +0 -1
  312. package/dist/components/new-trace-viewer/context.js +0 -47
  313. package/dist/components/new-trace-viewer/context.js.map +0 -1
  314. package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
  315. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
  316. package/dist/components/new-trace-viewer/detail-panel.js +0 -12
  317. package/dist/components/new-trace-viewer/detail-panel.js.map +0 -1
  318. package/dist/components/new-trace-viewer/icons.d.ts.map +0 -1
  319. package/dist/components/new-trace-viewer/icons.js +0 -15
  320. package/dist/components/new-trace-viewer/icons.js.map +0 -1
  321. package/dist/components/new-trace-viewer/trace-viewer.d.ts +0 -8
  322. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +0 -1
  323. package/dist/components/new-trace-viewer/trace-viewer.js +0 -349
  324. package/dist/components/new-trace-viewer/trace-viewer.js.map +0 -1
  325. package/dist/components/new-trace-viewer/types.d.ts +0 -1
  326. package/dist/components/new-trace-viewer/types.d.ts.map +0 -1
  327. package/dist/components/new-trace-viewer/types.js +0 -2
  328. package/dist/components/new-trace-viewer/types.js.map +0 -1
  329. package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
  330. package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
  331. package/dist/components/new-trace-viewer/util/constants.js +0 -2
  332. package/dist/components/new-trace-viewer/util/constants.js.map +0 -1
  333. package/dist/components/new-trace-viewer/utils.d.ts +0 -42
  334. package/dist/components/new-trace-viewer/utils.d.ts.map +0 -1
  335. package/dist/components/new-trace-viewer/utils.js +0 -305
  336. package/dist/components/new-trace-viewer/utils.js.map +0 -1
  337. package/dist/components/run-trace-view.d.ts +0 -25
  338. package/dist/components/run-trace-view.d.ts.map +0 -1
  339. package/dist/components/run-trace-view.js +0 -11
  340. package/dist/components/run-trace-view.js.map +0 -1
  341. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  342. package/dist/components/sidebar/conversation-view.js.map +0 -1
  343. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  344. package/dist/components/sidebar/detail-card.d.ts +0 -14
  345. package/dist/components/sidebar/detail-card.d.ts.map +0 -1
  346. package/dist/components/sidebar/detail-card.js +0 -20
  347. package/dist/components/sidebar/detail-card.js.map +0 -1
  348. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  349. package/dist/components/sidebar/events-list.js.map +0 -1
  350. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  351. package/dist/components/sidebar/sidebar-data-context.js.map +0 -1
  352. package/dist/components/stream-viewer.js.map +0 -1
  353. package/dist/components/trace-viewer/components/map.d.ts +0 -8
  354. package/dist/components/trace-viewer/components/map.d.ts.map +0 -1
  355. package/dist/components/trace-viewer/components/map.js +0 -162
  356. package/dist/components/trace-viewer/components/map.js.map +0 -1
  357. package/dist/components/trace-viewer/components/markers.d.ts +0 -23
  358. package/dist/components/trace-viewer/components/markers.d.ts.map +0 -1
  359. package/dist/components/trace-viewer/components/markers.js +0 -416
  360. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  361. package/dist/components/trace-viewer/components/node.d.ts +0 -35
  362. package/dist/components/trace-viewer/components/node.d.ts.map +0 -1
  363. package/dist/components/trace-viewer/components/node.js +0 -285
  364. package/dist/components/trace-viewer/components/node.js.map +0 -1
  365. package/dist/components/trace-viewer/components/search-input.d.ts +0 -9
  366. package/dist/components/trace-viewer/components/search-input.d.ts.map +0 -1
  367. package/dist/components/trace-viewer/components/search-input.js +0 -9
  368. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  369. package/dist/components/trace-viewer/components/search.d.ts +0 -3
  370. package/dist/components/trace-viewer/components/search.d.ts.map +0 -1
  371. package/dist/components/trace-viewer/components/search.js +0 -25
  372. package/dist/components/trace-viewer/components/search.js.map +0 -1
  373. package/dist/components/trace-viewer/components/span-content.d.ts +0 -19
  374. package/dist/components/trace-viewer/components/span-content.d.ts.map +0 -1
  375. package/dist/components/trace-viewer/components/span-content.js +0 -137
  376. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  377. package/dist/components/trace-viewer/components/span-detail-panel.d.ts +0 -10
  378. package/dist/components/trace-viewer/components/span-detail-panel.d.ts.map +0 -1
  379. package/dist/components/trace-viewer/components/span-detail-panel.js +0 -285
  380. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  381. package/dist/components/trace-viewer/components/span-segments.d.ts +0 -50
  382. package/dist/components/trace-viewer/components/span-segments.d.ts.map +0 -1
  383. package/dist/components/trace-viewer/components/span-segments.js +0 -445
  384. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  385. package/dist/components/trace-viewer/components/span-strategies.d.ts +0 -46
  386. package/dist/components/trace-viewer/components/span-strategies.d.ts.map +0 -1
  387. package/dist/components/trace-viewer/components/span-strategies.js +0 -108
  388. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  389. package/dist/components/trace-viewer/components/ui.d.ts +0 -28
  390. package/dist/components/trace-viewer/components/ui.d.ts.map +0 -1
  391. package/dist/components/trace-viewer/components/ui.js +0 -39
  392. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  393. package/dist/components/trace-viewer/components/zoom-button.d.ts +0 -3
  394. package/dist/components/trace-viewer/components/zoom-button.d.ts.map +0 -1
  395. package/dist/components/trace-viewer/components/zoom-button.js +0 -29
  396. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  397. package/dist/components/trace-viewer/components/zoom-icons.d.ts +0 -11
  398. package/dist/components/trace-viewer/components/zoom-icons.d.ts.map +0 -1
  399. package/dist/components/trace-viewer/components/zoom-icons.js +0 -11
  400. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  401. package/dist/components/trace-viewer/context.js.map +0 -1
  402. package/dist/components/trace-viewer/index.d.ts +0 -5
  403. package/dist/components/trace-viewer/index.d.ts.map +0 -1
  404. package/dist/components/trace-viewer/index.js +0 -4
  405. package/dist/components/trace-viewer/index.js.map +0 -1
  406. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  407. package/dist/components/trace-viewer/trace-viewer.module.css +0 -1465
  408. package/dist/components/trace-viewer/types.js.map +0 -1
  409. package/dist/components/trace-viewer/util/constants.d.ts +0 -9
  410. package/dist/components/trace-viewer/util/constants.d.ts.map +0 -1
  411. package/dist/components/trace-viewer/util/constants.js +0 -9
  412. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  413. package/dist/components/trace-viewer/util/scrollbar-width.d.ts +0 -2
  414. package/dist/components/trace-viewer/util/scrollbar-width.d.ts.map +0 -1
  415. package/dist/components/trace-viewer/util/scrollbar-width.js +0 -14
  416. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  417. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  418. package/dist/components/trace-viewer/util/tree.d.ts +0 -13
  419. package/dist/components/trace-viewer/util/tree.d.ts.map +0 -1
  420. package/dist/components/trace-viewer/util/tree.js +0 -227
  421. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  422. package/dist/components/trace-viewer/util/use-immediate-style.d.ts +0 -15
  423. package/dist/components/trace-viewer/util/use-immediate-style.d.ts.map +0 -1
  424. package/dist/components/trace-viewer/util/use-immediate-style.js +0 -23
  425. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  426. package/dist/components/trace-viewer/util/use-streaming-spans.d.ts +0 -8
  427. package/dist/components/trace-viewer/util/use-streaming-spans.d.ts.map +0 -1
  428. package/dist/components/trace-viewer/util/use-streaming-spans.js +0 -345
  429. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  430. package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts +0 -6
  431. package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts.map +0 -1
  432. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +0 -39
  433. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  434. package/dist/components/trace-viewer/worker.d.ts +0 -2
  435. package/dist/components/trace-viewer/worker.d.ts.map +0 -1
  436. package/dist/components/trace-viewer/worker.js +0 -109
  437. package/dist/components/trace-viewer/worker.js.map +0 -1
  438. package/dist/components/trace-viewer-new.d.ts.map +0 -1
  439. package/dist/components/trace-viewer-new.js +0 -23
  440. package/dist/components/trace-viewer-new.js.map +0 -1
  441. package/dist/components/ui/alert.js.map +0 -1
  442. package/dist/components/ui/card.js.map +0 -1
  443. package/dist/components/ui/data-inspector.js.map +0 -1
  444. package/dist/components/ui/decrypt-button.js.map +0 -1
  445. package/dist/components/ui/error-card.js.map +0 -1
  446. package/dist/components/ui/error-stack-block.js.map +0 -1
  447. package/dist/components/ui/inspector-theme.d.ts +0 -95
  448. package/dist/components/ui/inspector-theme.d.ts.map +0 -1
  449. package/dist/components/ui/inspector-theme.js +0 -82
  450. package/dist/components/ui/inspector-theme.js.map +0 -1
  451. package/dist/components/ui/load-more-button.js.map +0 -1
  452. package/dist/components/ui/menu-dropdown.js.map +0 -1
  453. package/dist/components/ui/skeleton.js.map +0 -1
  454. package/dist/components/ui/spinner.js.map +0 -1
  455. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  456. package/dist/components/workflow-trace-view.d.ts +0 -40
  457. package/dist/components/workflow-trace-view.d.ts.map +0 -1
  458. package/dist/components/workflow-trace-view.js +0 -695
  459. package/dist/components/workflow-trace-view.js.map +0 -1
  460. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  461. package/dist/components/workflow-traces/trace-colors.d.ts +0 -15
  462. package/dist/components/workflow-traces/trace-colors.d.ts.map +0 -1
  463. package/dist/components/workflow-traces/trace-colors.js +0 -87
  464. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  465. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  466. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  467. package/dist/hooks/use-dark-mode.js.map +0 -1
  468. package/dist/index.js.map +0 -1
  469. package/dist/lib/event-analysis.js.map +0 -1
  470. package/dist/lib/event-materialization.js.map +0 -1
  471. package/dist/lib/hydration.js.map +0 -1
  472. package/dist/lib/stream-display.js.map +0 -1
  473. package/dist/lib/toast.js.map +0 -1
  474. package/dist/lib/trace-builder.js.map +0 -1
  475. package/dist/lib/utils.js.map +0 -1
  476. package/src/components/new-trace-viewer/components/event-list.tsx +0 -116
  477. package/src/components/new-trace-viewer/components/split-pane.tsx +0 -185
  478. package/src/components/new-trace-viewer/components/timeline.tsx +0 -382
  479. package/src/components/new-trace-viewer/context.tsx +0 -92
  480. package/src/components/new-trace-viewer/detail-panel.tsx +0 -58
  481. package/src/components/new-trace-viewer/trace-viewer.tsx +0 -645
  482. package/src/components/new-trace-viewer/types.ts +0 -0
  483. package/src/components/new-trace-viewer/util/constants.ts +0 -0
  484. package/src/components/run-trace-view.tsx +0 -84
  485. package/src/components/sidebar/detail-card.tsx +0 -65
  486. package/src/components/trace-viewer/components/map.tsx +0 -226
  487. package/src/components/trace-viewer/components/markers.tsx +0 -612
  488. package/src/components/trace-viewer/components/node.tsx +0 -505
  489. package/src/components/trace-viewer/components/search-input.tsx +0 -52
  490. package/src/components/trace-viewer/components/search.tsx +0 -47
  491. package/src/components/trace-viewer/components/span-content.tsx +0 -247
  492. package/src/components/trace-viewer/components/span-detail-panel.tsx +0 -655
  493. package/src/components/trace-viewer/components/span-segments.ts +0 -585
  494. package/src/components/trace-viewer/components/span-strategies.ts +0 -205
  495. package/src/components/trace-viewer/components/ui.tsx +0 -156
  496. package/src/components/trace-viewer/components/zoom-button.tsx +0 -61
  497. package/src/components/trace-viewer/components/zoom-icons.tsx +0 -65
  498. package/src/components/trace-viewer/index.tsx +0 -4
  499. package/src/components/trace-viewer/trace-viewer.module.css +0 -1465
  500. package/src/components/trace-viewer/util/constants.ts +0 -8
  501. package/src/components/trace-viewer/util/scrollbar-width.ts +0 -13
  502. package/src/components/trace-viewer/util/tree.ts +0 -277
  503. package/src/components/trace-viewer/util/use-immediate-style.ts +0 -38
  504. package/src/components/trace-viewer/util/use-streaming-spans.ts +0 -426
  505. package/src/components/trace-viewer/util/use-trackpad-zoom.tsx +0 -51
  506. package/src/components/trace-viewer/worker.ts +0 -131
  507. package/src/components/ui/inspector-theme.ts +0 -110
  508. package/src/components/workflow-trace-view.tsx +0 -1171
  509. package/src/components/workflow-traces/trace-colors.ts +0 -112
  510. /package/dist/components/{new-trace-viewer → trace-viewer}/components/copy-button.d.ts +0 -0
  511. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/copy-selection.d.ts +0 -0
  512. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/middle-truncate.d.ts +0 -0
  513. /package/dist/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/use-middle-truncate.d.ts +0 -0
  514. /package/dist/components/{new-trace-viewer → trace-viewer}/icons.d.ts +0 -0
  515. /package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/copy-selection.ts +0 -0
  516. /package/src/components/{new-trace-viewer → trace-viewer}/components/middle-truncate/use-middle-truncate.ts +0 -0
  517. /package/src/{components/trace-viewer/modules.d.ts → modules.d.ts} +0 -0
@@ -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
  /**
@@ -233,7 +204,7 @@ function EncryptedFieldBlock() {
233
204
  function ExpiredFieldBlock() {
234
205
  return (
235
206
  <div
236
- className="flex items-center gap-1.5 rounded-md border px-3 py-2 text-xs"
207
+ className="flex items-center gap-1.5 rounded-md border px-3 py-2 text-label-12"
237
208
  style={{
238
209
  borderColor: 'var(--ds-gray-300)',
239
210
  backgroundColor: 'var(--ds-gray-100)',
@@ -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,16 @@ type AttributeKey =
269
241
  | 'workflowCoreVersion'
270
242
  | 'receivedCount'
271
243
  | 'lastReceivedAt'
272
- | 'disposedAt';
244
+ | 'disposedAt'
245
+ | 'isSystem'
246
+ | 'errorCode'
247
+ // Analytics-only provenance (AnalyticsEvent / AnalyticsStep), not on Event.
248
+ | 'computeInstanceId'
249
+ // Analytics-only, and event-grained: only AnalyticsEvent carries it. The key
250
+ // is `vercelId` because that is the name the backend stores the SDK's
251
+ // `requestId` under; AnalyticsEvent's sibling `requestId` column is never
252
+ // written, so reading that one would always be empty.
253
+ | 'vercelId';
273
254
 
274
255
  const attributeOrder: AttributeKey[] = [
275
256
  'workflowName',
@@ -282,38 +263,53 @@ const attributeOrder: AttributeKey[] = [
282
263
  'runId',
283
264
  'attempt',
284
265
  'token',
266
+ 'tokenRetentionUntil',
267
+ 'isWebhook',
268
+ 'isSystem',
285
269
  'receivedCount',
286
270
  'lastReceivedAt',
287
271
  'disposedAt',
288
272
  'correlationId',
289
273
  'eventType',
290
274
  'deploymentId',
275
+ 'vercelId',
276
+ 'computeInstanceId',
291
277
  'specVersion',
292
278
  'workflowCoreVersion',
293
279
  'ownerId',
294
280
  'projectId',
295
281
  'environment',
296
282
  'executionContext',
283
+ 'occurredAt',
297
284
  'createdAt',
298
285
  'startedAt',
299
286
  'updatedAt',
300
287
  'completedAt',
301
288
  'expiredAt',
302
289
  'retryAfter',
290
+ 'errorCode',
303
291
  'error',
304
292
  'metadata',
305
293
  'eventData',
306
294
  'input',
307
295
  'output',
296
+ 'attributes',
308
297
  'resumeAt',
309
298
  ];
310
299
 
311
- const sortByAttributeOrder = (a: string, b: string): number => {
312
- const aIndex = attributeOrder.indexOf(a as AttributeKey) || 0;
313
- const bIndex = attributeOrder.indexOf(b as AttributeKey) || 0;
314
- return aIndex - bIndex;
300
+ /**
301
+ * Rank of an attribute in {@link attributeOrder}. Keys absent from that list
302
+ * sort after every listed one rather than before them — `indexOf` reports a
303
+ * miss as `-1`, which is truthy, so a `|| 0` fallback never fires.
304
+ */
305
+ const attributeOrderIndex = (attribute: string): number => {
306
+ const index = attributeOrder.indexOf(attribute as AttributeKey);
307
+ return index === -1 ? attributeOrder.length : index;
315
308
  };
316
309
 
310
+ const sortByAttributeOrder = (a: string, b: string): number =>
311
+ attributeOrderIndex(a) - attributeOrderIndex(b);
312
+
317
313
  /**
318
314
  * Display names for attributes that should render differently from their key.
319
315
  */
@@ -326,11 +322,17 @@ const attributeDisplayNames: Partial<Record<AttributeKey, string>> = {
326
322
  attempt: 'Attempts',
327
323
  eventId: 'Event ID',
328
324
  runId: 'Run ID',
325
+ token: 'Token',
326
+ tokenRetentionUntil: 'Minimum Retention Until',
329
327
  eventType: 'Event Type',
328
+ errorCode: 'Error Code',
330
329
  correlationId: 'Correlation ID',
331
330
  deploymentId: 'Deployment ID',
331
+ vercelId: 'Request ID',
332
+ computeInstanceId: 'Compute Instance ID',
332
333
  specVersion: 'Spec Version',
333
334
  workflowCoreVersion: '@workflow/core version',
335
+ occurredAt: 'Occurred',
334
336
  createdAt: 'Created',
335
337
  startedAt: 'Started',
336
338
  updatedAt: 'Updated',
@@ -380,15 +382,7 @@ const parseDateValue = (value: unknown): Date | null => {
380
382
  };
381
383
 
382
384
  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
- });
385
+ format(date, 'MMM dd HH:mm:ss.SS OO').toUpperCase();
392
386
 
393
387
  export const localMillisecondTime = (value: unknown): string => {
394
388
  const date = parseDateValue(value);
@@ -396,7 +390,6 @@ export const localMillisecondTime = (value: unknown): string => {
396
390
  return '-';
397
391
  }
398
392
 
399
- // e.g. 12/17/2025, 9:08:55.182 AM
400
393
  return formatLocalMillisecondTime(date);
401
394
  };
402
395
 
@@ -418,8 +411,18 @@ const timestampWithTooltipOrNull = (value: unknown): ReactNode | null => {
418
411
  );
419
412
  };
420
413
 
414
+ /**
415
+ * Renders an opaque provenance id. The analytics read contract types these as
416
+ * nullable, and only a `null` return is filtered out of the panel, so a bare
417
+ * `String()` would surface the literal text "null" as the value.
418
+ */
419
+ const opaqueIdOrNull = (value: unknown): string | null =>
420
+ hasDisplayContent(value) ? String(value) : null;
421
+
421
422
  interface DisplayContext {
422
423
  stepName?: string;
424
+ sectionOpen?: boolean;
425
+ onSectionOpenChange?: (open: boolean) => void;
423
426
  }
424
427
 
425
428
  const attributeToDisplayFn: Record<
@@ -432,7 +435,7 @@ const attributeToDisplayFn: Record<
432
435
  stepName: (_value: unknown) => null,
433
436
  // IDs
434
437
  runId: (_value: unknown) => null,
435
- stepId: (_value: unknown) => null,
438
+ stepId: (value: unknown) => String(value),
436
439
  hookId: (value: unknown) => String(value),
437
440
  eventId: (value: unknown) => String(value),
438
441
  // Run/step details
@@ -440,15 +443,23 @@ const attributeToDisplayFn: Record<
440
443
  attempt: (value: unknown) => String(value),
441
444
  // Hook details
442
445
  token: (value: unknown) => String(value),
446
+ tokenRetentionUntil: timestampWithTooltipOrNull,
443
447
  isWebhook: (value: unknown) => String(value),
448
+ isSystem: (value: unknown) => String(value),
444
449
  receivedCount: (value: unknown) => String(value),
445
450
  lastReceivedAt: localMillisecondTimeOrNull,
446
451
  disposedAt: localMillisecondTimeOrNull,
452
+ // Internal resume plumbing — not surfaced in the UI
453
+ resumeContext: (_value: unknown) => null,
454
+ resumeId: (_value: unknown) => null,
455
+ resumeCapabilities: (_value: unknown) => null,
447
456
  // Event details
448
457
  eventType: (value: unknown) => String(value),
449
458
  correlationId: (value: unknown) => String(value),
450
459
  // Project details
451
460
  deploymentId: (value: unknown) => String(value),
461
+ vercelId: opaqueIdOrNull,
462
+ computeInstanceId: opaqueIdOrNull,
452
463
  specVersion: (value: unknown) => String(value),
453
464
  workflowCoreVersion: (value: unknown) => String(value),
454
465
  // Tenancy (we don't show these)
@@ -456,7 +467,15 @@ const attributeToDisplayFn: Record<
456
467
  projectId: (_value: unknown) => null,
457
468
  environment: (_value: unknown) => null,
458
469
  executionContext: (_value: unknown) => null,
470
+ // Attributes — string-string metadata attached to the run.
471
+ // Rendered as key-value rows in its own collapsible section;
472
+ // if empty/missing, hidden by the hasDisplayContent gate.
473
+ attributes: (value: unknown) => {
474
+ if (!hasDisplayContent(value)) return null;
475
+ return <RunAttributesCard attributes={value as Record<string, string>} />;
476
+ },
459
477
  // Dates — wrapped with TimestampTooltip showing UTC/local + relative time
478
+ occurredAt: timestampWithTooltipOrNull,
460
479
  createdAt: timestampWithTooltipOrNull,
461
480
  startedAt: timestampWithTooltipOrNull,
462
481
  updatedAt: (_value: unknown) => null,
@@ -467,12 +486,34 @@ const attributeToDisplayFn: Record<
467
486
  // Resolved attributes, won't actually use this function
468
487
  metadata: (value: unknown) => {
469
488
  if (!hasDisplayContent(value)) return null;
470
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
471
- if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
472
- return JsonBlock(value);
489
+ if (isEncryptedMarker(value)) {
490
+ return (
491
+ <Collapsible label="Metadata">
492
+ <EncryptedDataBlock />
493
+ </Collapsible>
494
+ );
495
+ }
496
+ if (isExpiredMarker(value)) {
497
+ return (
498
+ <Collapsible label="Metadata">
499
+ <ExpiredFieldBlock />
500
+ </Collapsible>
501
+ );
502
+ }
503
+ return <RunMetadataCard metadata={value} />;
473
504
  },
474
505
  input: (value: unknown, context?: DisplayContext) => {
475
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
506
+ if (isEncryptedMarker(value)) {
507
+ return (
508
+ <Collapsible
509
+ label="Input"
510
+ defaultOpen={context?.sectionOpen}
511
+ onOpenChange={context?.onSectionOpenChange}
512
+ >
513
+ <EncryptedFieldBlock />
514
+ </Collapsible>
515
+ );
516
+ }
476
517
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
477
518
  // Check if input has args + closure vars structure
478
519
  if (value && typeof value === 'object' && 'args' in value) {
@@ -481,8 +522,6 @@ const attributeToDisplayFn: Record<
481
522
  closureVars?: Record<string, unknown>;
482
523
  thisVal?: unknown;
483
524
  };
484
- const argCount = Array.isArray(args) ? args.length : 0;
485
- const argLabel = argCount === 1 ? 'argument' : 'arguments';
486
525
  const hasClosureVars = hasDisplayContent(closureVars);
487
526
  const hasThisVal = hasDisplayContent(thisVal);
488
527
  const hasArgs = hasDisplayContent(args);
@@ -493,16 +532,21 @@ const attributeToDisplayFn: Record<
493
532
  if (conversation && conversation.length > 0) {
494
533
  return (
495
534
  <>
496
- <ConversationWithTabs conversation={conversation} args={args} />
535
+ <ConversationWithTabs
536
+ conversation={conversation}
537
+ args={args}
538
+ defaultOpen={context?.sectionOpen}
539
+ onOpenChange={context?.onSectionOpenChange}
540
+ />
497
541
  {hasClosureVars && (
498
- <DetailCard summary="Closure Variables">
542
+ <Collapsible label="Closure Variables">
499
543
  {JsonBlock(closureVars)}
500
- </DetailCard>
544
+ </Collapsible>
501
545
  )}
502
546
  {hasThisVal && (
503
- <DetailCard summary="This Value">
547
+ <Collapsible label="This Value">
504
548
  {JsonBlock(thisVal)}
505
- </DetailCard>
549
+ </Collapsible>
506
550
  )}
507
551
  </>
508
552
  );
@@ -511,21 +555,15 @@ const attributeToDisplayFn: Record<
511
555
 
512
556
  // Don't render an empty "Input (0 arguments)" card when no input exists.
513
557
  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
- );
558
+ return <Collapsible label="Input (no data)" disabled />;
521
559
  }
522
560
 
523
561
  return (
524
562
  <>
525
- <DetailCard
526
- summary={`Input (${argCount} ${argLabel})`}
527
- summaryClassName="text-label-14 font-medium py-2"
528
- contentClassName="mt-0"
563
+ <Collapsible
564
+ label="Input"
565
+ defaultOpen={context?.sectionOpen}
566
+ onOpenChange={context?.onSectionOpenChange}
529
567
  >
530
568
  {Array.isArray(args)
531
569
  ? args.map((v, i) => (
@@ -534,36 +572,28 @@ const attributeToDisplayFn: Record<
534
572
  </div>
535
573
  ))
536
574
  : JsonBlock(args)}
537
- </DetailCard>
575
+ </Collapsible>
538
576
  {hasClosureVars && (
539
- <DetailCard summary="Closure Variables">
577
+ <Collapsible label="Closure Variables">
540
578
  {JsonBlock(closureVars)}
541
- </DetailCard>
579
+ </Collapsible>
542
580
  )}
543
581
  {hasThisVal && (
544
- <DetailCard summary="this">{JsonBlock(thisVal)}</DetailCard>
582
+ <Collapsible label="Context">{JsonBlock(thisVal)}</Collapsible>
545
583
  )}
546
584
  </>
547
585
  );
548
586
  }
549
587
 
550
588
  // Fallback: treat as plain array or object
551
- const argCount = Array.isArray(value) ? value.length : 0;
552
- const argLabel = argCount === 1 ? 'argument' : 'arguments';
553
589
  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
- );
590
+ return <Collapsible label="Input (no data)" disabled />;
561
591
  }
562
592
  return (
563
- <DetailCard
564
- summary={`Input (${argCount} ${argLabel})`}
565
- summaryClassName="text-label-14 font-medium py-2"
566
- contentClassName="mt-0"
593
+ <Collapsible
594
+ label="Input"
595
+ defaultOpen={context?.sectionOpen}
596
+ onOpenChange={context?.onSectionOpenChange}
567
597
  >
568
598
  {Array.isArray(value)
569
599
  ? value.map((v, i) => (
@@ -572,58 +602,84 @@ const attributeToDisplayFn: Record<
572
602
  </div>
573
603
  ))
574
604
  : JsonBlock(value)}
575
- </DetailCard>
605
+ </Collapsible>
576
606
  );
577
607
  },
578
- output: (value: unknown) => {
608
+ output: (value: unknown, context?: DisplayContext) => {
609
+ if (isEncryptedMarker(value)) {
610
+ return (
611
+ <Collapsible
612
+ label="Output"
613
+ defaultOpen={context?.sectionOpen}
614
+ onOpenChange={context?.onSectionOpenChange}
615
+ >
616
+ <EncryptedFieldBlock />
617
+ </Collapsible>
618
+ );
619
+ }
579
620
  if (!hasDisplayContent(value)) return null;
580
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
581
621
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
582
622
  return (
583
- <DetailCard
584
- summary="Output"
585
- summaryClassName="text-label-14 font-medium py-2"
586
- contentClassName="mt-0"
623
+ <Collapsible
624
+ label="Output"
625
+ defaultOpen={context?.sectionOpen}
626
+ onOpenChange={context?.onSectionOpenChange}
587
627
  >
588
628
  {JsonBlock(value)}
589
- </DetailCard>
629
+ </Collapsible>
590
630
  );
591
631
  },
592
632
  error: (value: unknown) => {
593
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
633
+ if (isEncryptedMarker(value)) {
634
+ return (
635
+ <Collapsible label="Error" defaultOpen>
636
+ <EncryptedFieldBlock />
637
+ </Collapsible>
638
+ );
639
+ }
594
640
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
595
641
  if (!hasDisplayContent(value)) return null;
596
642
 
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)) {
643
+ // Structured workflow errors may be persisted as either `{ message }` or
644
+ // `{ message, stack }`. Render both with the dedicated error block.
645
+ if (isStructuredError(value)) {
600
646
  return (
601
- <DetailCard
602
- summary="Error"
603
- summaryClassName="text-label-14 font-medium py-2"
604
- contentClassName="mt-0"
605
- >
647
+ <Collapsible label="Error" defaultOpen>
606
648
  <ErrorStackBlock value={value} />
607
- </DetailCard>
649
+ </Collapsible>
608
650
  );
609
651
  }
610
652
 
611
653
  return (
612
- <DetailCard
613
- summary="Error"
614
- summaryClassName="text-label-14 font-medium py-2"
615
- contentClassName="mt-0"
616
- >
654
+ <Collapsible label="Error" defaultOpen>
617
655
  {JsonBlock(value)}
618
- </DetailCard>
656
+ </Collapsible>
619
657
  );
620
658
  },
621
659
  eventData: (value: unknown) => {
622
- if (isEncryptedMarker(value)) return <EncryptedFieldBlock />;
660
+ if (isEncryptedMarker(value)) {
661
+ return (
662
+ <Collapsible label="Event Data" defaultOpen>
663
+ <EncryptedFieldBlock />
664
+ </Collapsible>
665
+ );
666
+ }
623
667
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
624
668
  if (!hasDisplayContent(value)) return null;
625
- return <DetailCard summary="Event Data">{JsonBlock(value)}</DetailCard>;
669
+ return (
670
+ <Collapsible label="Event Data" defaultOpen>
671
+ {JsonBlock(value)}
672
+ </Collapsible>
673
+ );
674
+ },
675
+ errorCode: (value: unknown) => {
676
+ if (typeof value !== 'string' || value.length === 0) return null;
677
+ return String(value);
626
678
  },
679
+ // Internal encryption plumbing: the run's X25519 public key, used by
680
+ // cross-run writers to seal payloads to this run. Not actionable for users
681
+ // and not secret — hidden rather than rendered as 44 opaque base64 chars.
682
+ encryptionPublicKey: (_value: unknown) => null,
627
683
  };
628
684
 
629
685
  const resolvableAttributes = [
@@ -631,12 +687,24 @@ const resolvableAttributes = [
631
687
  'output',
632
688
  'error',
633
689
  'metadata',
690
+ 'attributes',
634
691
  'eventData',
635
692
  ];
636
693
 
694
+ // Attributes whose displayFn renders its own section header via Collapsible,
695
+ // so the outer AttributeBlock should not duplicate the label.
696
+ const selfHeaderedAttributes = new Set([
697
+ 'input',
698
+ 'output',
699
+ 'error',
700
+ 'metadata',
701
+ 'attributes',
702
+ 'eventData',
703
+ ]);
704
+
637
705
  const ExpiredDataMessage = () => (
638
706
  <div
639
- className="text-copy-12 rounded-md border p-4 my-2"
707
+ className="text-label-12 rounded-md border p-4 my-2"
640
708
  style={{
641
709
  borderColor: 'var(--ds-gray-300)',
642
710
  backgroundColor: 'var(--ds-gray-100)',
@@ -647,6 +715,23 @@ const ExpiredDataMessage = () => (
647
715
  </div>
648
716
  );
649
717
 
718
+ const copyableBasicAttributes = new Set<AttributeKey>([
719
+ 'stepId',
720
+ 'hookId',
721
+ 'eventId',
722
+ 'deploymentId',
723
+ 'vercelId',
724
+ 'computeInstanceId',
725
+ 'moduleSpecifier',
726
+ 'token',
727
+ ]);
728
+
729
+ const loadingSectionLabels: Partial<Record<AttributeKey, string>> = {
730
+ input: 'Input',
731
+ output: 'Output',
732
+ eventData: 'Event Data',
733
+ };
734
+
650
735
  export const AttributeBlock = ({
651
736
  attribute,
652
737
  value,
@@ -660,19 +745,25 @@ export const AttributeBlock = ({
660
745
  inline?: boolean;
661
746
  context?: DisplayContext;
662
747
  }) => {
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
- );
748
+ const decryptCtx = useContext(DecryptClickContext);
749
+ const sectionOpenRef = useRef(false);
750
+ const handleSectionOpenChange = useCallback((open: boolean) => {
751
+ sectionOpenRef.current = open;
752
+ }, []);
753
+ const label = loadingSectionLabels[attribute as AttributeKey];
754
+ if (isLoading && label && !hasDisplayContent(value)) {
755
+ if (decryptCtx?.hasEncryptedData) {
756
+ return (
757
+ <Collapsible
758
+ label={label}
759
+ defaultOpen={attribute === 'eventData' || sectionOpenRef.current}
760
+ onOpenChange={handleSectionOpenChange}
761
+ >
762
+ <EncryptedFieldBlock />
763
+ </Collapsible>
764
+ );
765
+ }
766
+ return <Collapsible label={label} />;
676
767
  }
677
768
 
678
769
  const displayFn =
@@ -680,7 +771,11 @@ export const AttributeBlock = ({
680
771
  if (!displayFn) {
681
772
  return null;
682
773
  }
683
- const displayValue = displayFn(value, context);
774
+ const displayValue = displayFn(value, {
775
+ ...context,
776
+ sectionOpen: sectionOpenRef.current,
777
+ onSectionOpenChange: handleSectionOpenChange,
778
+ });
684
779
  if (!displayValue) {
685
780
  return null;
686
781
  }
@@ -701,6 +796,10 @@ export const AttributeBlock = ({
701
796
  );
702
797
  }
703
798
 
799
+ if (selfHeaderedAttributes.has(attribute)) {
800
+ return <>{displayValue}</>;
801
+ }
802
+
704
803
  return (
705
804
  <div className="relative">
706
805
  {typeof isLoading === 'boolean' && isLoading && (
@@ -711,14 +810,14 @@ export const AttributeBlock = ({
711
810
  />
712
811
  </div>
713
812
  )}
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
- >
813
+ <div key={attribute} className="my-2 flex flex-col gap-0">
718
814
  <span className="text-label-14 text-gray-1000 font-medium first-letter:uppercase">
719
815
  {attribute}
720
816
  </span>
721
- <span className="text-xs" style={{ color: 'var(--ds-gray-1000)' }}>
817
+ <span
818
+ className="text-label-12"
819
+ style={{ color: 'var(--ds-gray-1000)' }}
820
+ >
722
821
  {displayValue}
723
822
  </span>
724
823
  </div>
@@ -729,6 +828,7 @@ export const AttributeBlock = ({
729
828
  export const AttributePanel = ({
730
829
  data,
731
830
  moduleSpecifier,
831
+ moduleSourceUrl,
732
832
  isLoading,
733
833
  error,
734
834
  expiredAt,
@@ -740,6 +840,7 @@ export const AttributePanel = ({
740
840
  }: {
741
841
  data: Record<string, unknown>;
742
842
  moduleSpecifier?: string;
843
+ moduleSourceUrl?: string;
743
844
  isLoading?: boolean;
744
845
  error?: Error;
745
846
  expiredAt?: string | Date;
@@ -754,7 +855,6 @@ export const AttributePanel = ({
754
855
  /** Resource type of the selected span — used to show targeted loading skeletons. */
755
856
  resource?: string;
756
857
  }) => {
757
- const toast = useToast();
758
858
  // Extract workflowCoreVersion from executionContext for display
759
859
  const displayData = useMemo(() => {
760
860
  const result = { ...data };
@@ -784,16 +884,16 @@ export const AttributePanel = ({
784
884
 
785
885
  if (!isLoading) return present;
786
886
 
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) {
887
+ if (resource === 'sleep') return present;
888
+
889
+ const loadingPlaceholders = ['input', 'output'];
890
+ for (const key of loadingPlaceholders) {
791
891
  if (!present.includes(key)) {
792
892
  present.push(key);
793
893
  }
794
894
  }
795
895
  return present.sort(sortByAttributeOrder);
796
- }, [displayData, isLoading]);
896
+ }, [displayData, isLoading, resource]);
797
897
 
798
898
  // Filter out attributes that return null
799
899
  const visibleBasicAttributes = basicAttributes.filter((attribute) => {
@@ -838,113 +938,64 @@ export const AttributePanel = ({
838
938
  }),
839
939
  [displayData.stepName]
840
940
  );
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
- }, []);
941
+ const outerDecryptCtx = useContext(DecryptClickContext);
942
+ const decryptValue = onDecrypt
943
+ ? {
944
+ onDecrypt,
945
+ isDecrypting,
946
+ hasEncryptedData: outerDecryptCtx?.hasEncryptedData,
947
+ }
948
+ : outerDecryptCtx;
851
949
 
852
950
  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 */}
951
+ <ContextCardProvider>
952
+ <RunClickContext.Provider value={onRunClick}>
953
+ <StreamClickContext.Provider value={onStreamClick}>
954
+ <DecryptClickContext.Provider value={decryptValue}>
860
955
  {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]'
956
+ <CollapsibleRoot defaultOpen>
957
+ <CollapsibleTrigger>Metadata</CollapsibleTrigger>
958
+ <CollapsibleContent className="mt-0 mb-2">
959
+ <div className="flex flex-col">
960
+ {orderedBasicAttributes.map((attribute) => {
961
+ const displayValue = attributeToDisplayFn[
962
+ attribute as keyof typeof attributeToDisplayFn
963
+ ]?.(displayData[attribute as keyof typeof displayData]);
964
+ const isCopyableBasicAttribute =
965
+ copyableBasicAttributes.has(
966
+ attribute as AttributeKey
967
+ ) && typeof displayValue === 'string';
968
+ const label = getAttributeDisplayName(attribute);
969
+
970
+ return (
971
+ <DetailMonoKeyValueRow
972
+ key={attribute}
973
+ label={label}
974
+ value={displayValue}
975
+ copyText={
976
+ isCopyableBasicAttribute ? displayValue : undefined
977
+ }
978
+ href={
979
+ attribute === 'moduleSpecifier'
980
+ ? moduleSourceUrl
981
+ : undefined
894
982
  }
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
983
  />
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>
984
+ );
985
+ })}
986
+ {isLoading &&
987
+ resource === 'sleep' &&
988
+ !displayData.resumeAt && (
989
+ <div className="flex items-center justify-between gap-3 py-0.5">
990
+ <span className="text-label-13 text-gray-900">
991
+ Resume
992
+ </span>
993
+ <Skeleton className="h-4 w-[55%]" />
994
+ </div>
995
+ )}
945
996
  </div>
946
- )}
947
- </div>
997
+ </CollapsibleContent>
998
+ </CollapsibleRoot>
948
999
  )}
949
1000
  {error ? (
950
1001
  <ErrorCard
@@ -954,22 +1005,20 @@ export const AttributePanel = ({
954
1005
  />
955
1006
  ) : hasExpired ? (
956
1007
  <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>
1008
+ ) : resolvedAttributes.length > 0 ? (
1009
+ resolvedAttributes.map((attribute) => (
1010
+ <AttributeBlock
1011
+ isLoading={isLoading}
1012
+ key={attribute}
1013
+ attribute={attribute}
1014
+ value={displayData[attribute as keyof typeof displayData]}
1015
+ context={displayContext}
1016
+ />
1017
+ ))
1018
+ ) : null}
1019
+ </DecryptClickContext.Provider>
1020
+ </StreamClickContext.Provider>
1021
+ </RunClickContext.Provider>
1022
+ </ContextCardProvider>
974
1023
  );
975
1024
  };