@workflow/web-shared 4.1.0-beta.47 → 4.1.0-beta.49

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 (301) hide show
  1. package/README.md +26 -52
  2. package/dist/components/error-boundary.d.ts.map +1 -0
  3. package/dist/{error-boundary.js → components/error-boundary.js} +1 -1
  4. package/dist/components/error-boundary.js.map +1 -0
  5. package/dist/{event-list-view.d.ts → components/event-list-view.d.ts} +2 -3
  6. package/dist/components/event-list-view.d.ts.map +1 -0
  7. package/dist/{event-list-view.js → components/event-list-view.js} +9 -17
  8. package/dist/components/event-list-view.js.map +1 -0
  9. package/dist/{hook-actions.d.ts → components/hook-actions.d.ts} +2 -3
  10. package/dist/components/hook-actions.d.ts.map +1 -0
  11. package/dist/{hook-actions.js → components/hook-actions.js} +3 -4
  12. package/dist/components/hook-actions.js.map +1 -0
  13. package/dist/components/index.d.ts +10 -0
  14. package/dist/components/index.d.ts.map +1 -0
  15. package/dist/components/index.js +8 -0
  16. package/dist/components/index.js.map +1 -0
  17. package/dist/components/run-trace-view.d.ts +22 -0
  18. package/dist/components/run-trace-view.d.ts.map +1 -0
  19. package/dist/components/run-trace-view.js +11 -0
  20. package/dist/components/run-trace-view.js.map +1 -0
  21. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -0
  22. package/dist/{sidebar → components/sidebar}/attribute-panel.js +3 -3
  23. package/dist/components/sidebar/attribute-panel.js.map +1 -0
  24. package/dist/components/sidebar/conversation-view.d.ts.map +1 -0
  25. package/dist/components/sidebar/conversation-view.js.map +1 -0
  26. package/dist/components/sidebar/detail-card.d.ts.map +1 -0
  27. package/dist/components/sidebar/detail-card.js.map +1 -0
  28. package/dist/components/sidebar/entity-detail-panel.d.ts +32 -0
  29. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -0
  30. package/dist/{sidebar → components/sidebar}/entity-detail-panel.js +61 -49
  31. package/dist/components/sidebar/entity-detail-panel.js.map +1 -0
  32. package/dist/components/sidebar/events-list.d.ts +8 -0
  33. package/dist/components/sidebar/events-list.d.ts.map +1 -0
  34. package/dist/components/sidebar/events-list.js +16 -0
  35. package/dist/components/sidebar/events-list.js.map +1 -0
  36. package/dist/components/sidebar/resolve-hook-modal.d.ts.map +1 -0
  37. package/dist/components/sidebar/resolve-hook-modal.js.map +1 -0
  38. package/dist/components/stream-viewer.d.ts +18 -0
  39. package/dist/components/stream-viewer.d.ts.map +1 -0
  40. package/dist/{stream-viewer.js → components/stream-viewer.js} +1 -59
  41. package/dist/components/stream-viewer.js.map +1 -0
  42. package/dist/components/trace-viewer/components/map.d.ts.map +1 -0
  43. package/dist/components/trace-viewer/components/map.js.map +1 -0
  44. package/dist/components/trace-viewer/components/markers.d.ts.map +1 -0
  45. package/dist/components/trace-viewer/components/markers.js.map +1 -0
  46. package/dist/components/trace-viewer/components/node.d.ts.map +1 -0
  47. package/dist/components/trace-viewer/components/node.js.map +1 -0
  48. package/dist/components/trace-viewer/components/search-input.d.ts.map +1 -0
  49. package/dist/components/trace-viewer/components/search-input.js.map +1 -0
  50. package/dist/components/trace-viewer/components/search.d.ts.map +1 -0
  51. package/dist/components/trace-viewer/components/search.js.map +1 -0
  52. package/dist/components/trace-viewer/components/span-detail-panel.d.ts.map +1 -0
  53. package/dist/components/trace-viewer/components/span-detail-panel.js.map +1 -0
  54. package/dist/components/trace-viewer/components/ui.d.ts.map +1 -0
  55. package/dist/components/trace-viewer/components/ui.js.map +1 -0
  56. package/dist/components/trace-viewer/components/zoom-button.d.ts.map +1 -0
  57. package/dist/components/trace-viewer/components/zoom-button.js.map +1 -0
  58. package/dist/components/trace-viewer/components/zoom-icons.d.ts.map +1 -0
  59. package/dist/components/trace-viewer/components/zoom-icons.js.map +1 -0
  60. package/dist/components/trace-viewer/context.d.ts.map +1 -0
  61. package/dist/components/trace-viewer/context.js.map +1 -0
  62. package/dist/components/trace-viewer/index.d.ts.map +1 -0
  63. package/dist/components/trace-viewer/index.js.map +1 -0
  64. package/dist/components/trace-viewer/trace-viewer.d.ts.map +1 -0
  65. package/dist/components/trace-viewer/trace-viewer.js.map +1 -0
  66. package/dist/components/trace-viewer/types.d.ts.map +1 -0
  67. package/dist/components/trace-viewer/types.js.map +1 -0
  68. package/dist/components/trace-viewer/util/constants.d.ts.map +1 -0
  69. package/dist/components/trace-viewer/util/constants.js.map +1 -0
  70. package/dist/components/trace-viewer/util/scrollbar-width.d.ts.map +1 -0
  71. package/dist/components/trace-viewer/util/scrollbar-width.js.map +1 -0
  72. package/dist/{trace-viewer → components/trace-viewer}/util/timing.d.ts +1 -1
  73. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -0
  74. package/dist/{trace-viewer → components/trace-viewer}/util/timing.js +1 -1
  75. package/dist/components/trace-viewer/util/timing.js.map +1 -0
  76. package/dist/components/trace-viewer/util/tree.d.ts.map +1 -0
  77. package/dist/components/trace-viewer/util/tree.js.map +1 -0
  78. package/dist/components/trace-viewer/util/use-immediate-style.d.ts.map +1 -0
  79. package/dist/components/trace-viewer/util/use-immediate-style.js.map +1 -0
  80. package/dist/components/trace-viewer/util/use-streaming-spans.d.ts.map +1 -0
  81. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +1 -0
  82. package/dist/components/trace-viewer/util/use-trackpad-zoom.d.ts.map +1 -0
  83. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +1 -0
  84. package/dist/components/trace-viewer/worker.d.ts.map +1 -0
  85. package/dist/components/trace-viewer/worker.js.map +1 -0
  86. package/dist/components/workflow-trace-view.d.ts +24 -0
  87. package/dist/components/workflow-trace-view.d.ts.map +1 -0
  88. package/dist/components/workflow-trace-view.js +152 -0
  89. package/dist/components/workflow-trace-view.js.map +1 -0
  90. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -0
  91. package/dist/components/workflow-traces/event-colors.js.map +1 -0
  92. package/dist/components/workflow-traces/trace-colors.d.ts.map +1 -0
  93. package/dist/components/workflow-traces/trace-colors.js.map +1 -0
  94. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -0
  95. package/dist/components/workflow-traces/trace-span-construction.js.map +1 -0
  96. package/dist/components/workflow-traces/trace-time-utils.d.ts.map +1 -0
  97. package/dist/components/workflow-traces/trace-time-utils.js.map +1 -0
  98. package/dist/index.d.ts +3 -13
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +2 -9
  101. package/dist/index.js.map +1 -1
  102. package/package.json +15 -11
  103. package/src/components/error-boundary.tsx +79 -0
  104. package/src/components/event-list-view.tsx +429 -0
  105. package/src/components/hook-actions.tsx +167 -0
  106. package/src/components/index.d.ts +1 -0
  107. package/src/components/index.ts +23 -0
  108. package/src/components/run-trace-view.tsx +75 -0
  109. package/src/components/sidebar/attribute-panel.tsx +938 -0
  110. package/src/components/sidebar/conversation-view.tsx +235 -0
  111. package/src/components/sidebar/detail-card.tsx +43 -0
  112. package/src/components/sidebar/entity-detail-panel.tsx +338 -0
  113. package/src/components/sidebar/events-list.tsx +119 -0
  114. package/src/components/sidebar/resolve-hook-modal.tsx +219 -0
  115. package/src/components/stream-viewer.tsx +143 -0
  116. package/src/components/trace-viewer/components/map.tsx +226 -0
  117. package/src/components/trace-viewer/components/markers.tsx +564 -0
  118. package/src/components/trace-viewer/components/node.tsx +259 -0
  119. package/src/components/trace-viewer/components/search-input.tsx +52 -0
  120. package/src/components/trace-viewer/components/search.tsx +47 -0
  121. package/src/components/trace-viewer/components/span-detail-panel.tsx +650 -0
  122. package/src/components/trace-viewer/components/ui.tsx +156 -0
  123. package/src/components/trace-viewer/components/zoom-button.tsx +61 -0
  124. package/src/components/trace-viewer/components/zoom-icons.tsx +65 -0
  125. package/src/components/trace-viewer/context.tsx +633 -0
  126. package/src/components/trace-viewer/index.tsx +4 -0
  127. package/src/components/trace-viewer/modules.d.ts +16 -0
  128. package/src/components/trace-viewer/trace-viewer.module.css +1292 -0
  129. package/src/components/trace-viewer/trace-viewer.tsx +448 -0
  130. package/src/components/trace-viewer/types.ts +234 -0
  131. package/src/components/trace-viewer/util/constants.ts +8 -0
  132. package/src/components/trace-viewer/util/scrollbar-width.ts +13 -0
  133. package/src/components/trace-viewer/util/timing.ts +33 -0
  134. package/src/components/trace-viewer/util/tree.ts +277 -0
  135. package/src/components/trace-viewer/util/use-immediate-style.ts +38 -0
  136. package/src/components/trace-viewer/util/use-streaming-spans.ts +415 -0
  137. package/src/components/trace-viewer/util/use-trackpad-zoom.tsx +51 -0
  138. package/src/components/trace-viewer/worker.ts +128 -0
  139. package/src/components/ui/alert.tsx +59 -0
  140. package/src/components/ui/card.tsx +88 -0
  141. package/src/components/ui/error-card.tsx +65 -0
  142. package/src/components/ui/skeleton.tsx +15 -0
  143. package/src/components/workflow-trace-view.tsx +306 -0
  144. package/src/components/workflow-traces/event-colors.ts +94 -0
  145. package/src/components/workflow-traces/trace-colors.ts +112 -0
  146. package/src/components/workflow-traces/trace-span-construction.ts +299 -0
  147. package/src/components/workflow-traces/trace-time-utils.ts +50 -0
  148. package/src/hooks/use-dark-mode.ts +34 -0
  149. package/src/index.d.ts +1 -0
  150. package/src/index.ts +29 -0
  151. package/src/lib/event-analysis.ts +231 -0
  152. package/src/lib/utils.ts +166 -0
  153. package/dist/api/workflow-api-client.d.ts +0 -543
  154. package/dist/api/workflow-api-client.d.ts.map +0 -1
  155. package/dist/api/workflow-api-client.js +0 -953
  156. package/dist/api/workflow-api-client.js.map +0 -1
  157. package/dist/api/workflow-server-actions.d.ts +0 -230
  158. package/dist/api/workflow-server-actions.d.ts.map +0 -1
  159. package/dist/api/workflow-server-actions.js +0 -861
  160. package/dist/api/workflow-server-actions.js.map +0 -1
  161. package/dist/error-boundary.d.ts.map +0 -1
  162. package/dist/error-boundary.js.map +0 -1
  163. package/dist/event-list-view.d.ts.map +0 -1
  164. package/dist/event-list-view.js.map +0 -1
  165. package/dist/hook-actions.d.ts.map +0 -1
  166. package/dist/hook-actions.js.map +0 -1
  167. package/dist/run-trace-view.d.ts +0 -8
  168. package/dist/run-trace-view.d.ts.map +0 -1
  169. package/dist/run-trace-view.js +0 -15
  170. package/dist/run-trace-view.js.map +0 -1
  171. package/dist/sidebar/attribute-panel.d.ts.map +0 -1
  172. package/dist/sidebar/attribute-panel.js.map +0 -1
  173. package/dist/sidebar/conversation-view.d.ts.map +0 -1
  174. package/dist/sidebar/conversation-view.js.map +0 -1
  175. package/dist/sidebar/detail-card.d.ts.map +0 -1
  176. package/dist/sidebar/detail-card.js.map +0 -1
  177. package/dist/sidebar/entity-detail-panel.d.ts +0 -12
  178. package/dist/sidebar/entity-detail-panel.d.ts.map +0 -1
  179. package/dist/sidebar/entity-detail-panel.js.map +0 -1
  180. package/dist/sidebar/events-list.d.ts +0 -9
  181. package/dist/sidebar/events-list.d.ts.map +0 -1
  182. package/dist/sidebar/events-list.js +0 -36
  183. package/dist/sidebar/events-list.js.map +0 -1
  184. package/dist/sidebar/resolve-hook-modal.d.ts.map +0 -1
  185. package/dist/sidebar/resolve-hook-modal.js.map +0 -1
  186. package/dist/stream-viewer.d.ts +0 -13
  187. package/dist/stream-viewer.d.ts.map +0 -1
  188. package/dist/stream-viewer.js.map +0 -1
  189. package/dist/trace-viewer/components/map.d.ts.map +0 -1
  190. package/dist/trace-viewer/components/map.js.map +0 -1
  191. package/dist/trace-viewer/components/markers.d.ts.map +0 -1
  192. package/dist/trace-viewer/components/markers.js.map +0 -1
  193. package/dist/trace-viewer/components/node.d.ts.map +0 -1
  194. package/dist/trace-viewer/components/node.js.map +0 -1
  195. package/dist/trace-viewer/components/search-input.d.ts.map +0 -1
  196. package/dist/trace-viewer/components/search-input.js.map +0 -1
  197. package/dist/trace-viewer/components/search.d.ts.map +0 -1
  198. package/dist/trace-viewer/components/search.js.map +0 -1
  199. package/dist/trace-viewer/components/span-detail-panel.d.ts.map +0 -1
  200. package/dist/trace-viewer/components/span-detail-panel.js.map +0 -1
  201. package/dist/trace-viewer/components/ui.d.ts.map +0 -1
  202. package/dist/trace-viewer/components/ui.js.map +0 -1
  203. package/dist/trace-viewer/components/zoom-button.d.ts.map +0 -1
  204. package/dist/trace-viewer/components/zoom-button.js.map +0 -1
  205. package/dist/trace-viewer/components/zoom-icons.d.ts.map +0 -1
  206. package/dist/trace-viewer/components/zoom-icons.js.map +0 -1
  207. package/dist/trace-viewer/context.d.ts.map +0 -1
  208. package/dist/trace-viewer/context.js.map +0 -1
  209. package/dist/trace-viewer/index.d.ts.map +0 -1
  210. package/dist/trace-viewer/index.js.map +0 -1
  211. package/dist/trace-viewer/trace-viewer.d.ts.map +0 -1
  212. package/dist/trace-viewer/trace-viewer.js.map +0 -1
  213. package/dist/trace-viewer/types.d.ts.map +0 -1
  214. package/dist/trace-viewer/types.js.map +0 -1
  215. package/dist/trace-viewer/util/constants.d.ts.map +0 -1
  216. package/dist/trace-viewer/util/constants.js.map +0 -1
  217. package/dist/trace-viewer/util/scrollbar-width.d.ts.map +0 -1
  218. package/dist/trace-viewer/util/scrollbar-width.js.map +0 -1
  219. package/dist/trace-viewer/util/timing.d.ts.map +0 -1
  220. package/dist/trace-viewer/util/timing.js.map +0 -1
  221. package/dist/trace-viewer/util/tree.d.ts.map +0 -1
  222. package/dist/trace-viewer/util/tree.js.map +0 -1
  223. package/dist/trace-viewer/util/use-immediate-style.d.ts.map +0 -1
  224. package/dist/trace-viewer/util/use-immediate-style.js.map +0 -1
  225. package/dist/trace-viewer/util/use-streaming-spans.d.ts.map +0 -1
  226. package/dist/trace-viewer/util/use-streaming-spans.js.map +0 -1
  227. package/dist/trace-viewer/util/use-trackpad-zoom.d.ts.map +0 -1
  228. package/dist/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  229. package/dist/trace-viewer/worker.d.ts.map +0 -1
  230. package/dist/trace-viewer/worker.js.map +0 -1
  231. package/dist/workflow-trace-view.d.ts +0 -14
  232. package/dist/workflow-trace-view.d.ts.map +0 -1
  233. package/dist/workflow-trace-view.js +0 -135
  234. package/dist/workflow-trace-view.js.map +0 -1
  235. package/dist/workflow-traces/event-colors.d.ts.map +0 -1
  236. package/dist/workflow-traces/event-colors.js.map +0 -1
  237. package/dist/workflow-traces/trace-colors.d.ts.map +0 -1
  238. package/dist/workflow-traces/trace-colors.js.map +0 -1
  239. package/dist/workflow-traces/trace-span-construction.d.ts.map +0 -1
  240. package/dist/workflow-traces/trace-span-construction.js.map +0 -1
  241. package/dist/workflow-traces/trace-time-utils.d.ts.map +0 -1
  242. package/dist/workflow-traces/trace-time-utils.js.map +0 -1
  243. package/server/README.md +0 -1
  244. package/server/package.json +0 -4
  245. /package/dist/{error-boundary.d.ts → components/error-boundary.d.ts} +0 -0
  246. /package/dist/{sidebar → components/sidebar}/attribute-panel.d.ts +0 -0
  247. /package/dist/{sidebar → components/sidebar}/conversation-view.d.ts +0 -0
  248. /package/dist/{sidebar → components/sidebar}/conversation-view.js +0 -0
  249. /package/dist/{sidebar → components/sidebar}/detail-card.d.ts +0 -0
  250. /package/dist/{sidebar → components/sidebar}/detail-card.js +0 -0
  251. /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.d.ts +0 -0
  252. /package/dist/{sidebar → components/sidebar}/resolve-hook-modal.js +0 -0
  253. /package/dist/{trace-viewer → components/trace-viewer}/components/map.d.ts +0 -0
  254. /package/dist/{trace-viewer → components/trace-viewer}/components/map.js +0 -0
  255. /package/dist/{trace-viewer → components/trace-viewer}/components/markers.d.ts +0 -0
  256. /package/dist/{trace-viewer → components/trace-viewer}/components/markers.js +0 -0
  257. /package/dist/{trace-viewer → components/trace-viewer}/components/node.d.ts +0 -0
  258. /package/dist/{trace-viewer → components/trace-viewer}/components/node.js +0 -0
  259. /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.d.ts +0 -0
  260. /package/dist/{trace-viewer → components/trace-viewer}/components/search-input.js +0 -0
  261. /package/dist/{trace-viewer → components/trace-viewer}/components/search.d.ts +0 -0
  262. /package/dist/{trace-viewer → components/trace-viewer}/components/search.js +0 -0
  263. /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.d.ts +0 -0
  264. /package/dist/{trace-viewer → components/trace-viewer}/components/span-detail-panel.js +0 -0
  265. /package/dist/{trace-viewer → components/trace-viewer}/components/ui.d.ts +0 -0
  266. /package/dist/{trace-viewer → components/trace-viewer}/components/ui.js +0 -0
  267. /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.d.ts +0 -0
  268. /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-button.js +0 -0
  269. /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.d.ts +0 -0
  270. /package/dist/{trace-viewer → components/trace-viewer}/components/zoom-icons.js +0 -0
  271. /package/dist/{trace-viewer → components/trace-viewer}/context.d.ts +0 -0
  272. /package/dist/{trace-viewer → components/trace-viewer}/context.js +0 -0
  273. /package/dist/{trace-viewer → components/trace-viewer}/index.d.ts +0 -0
  274. /package/dist/{trace-viewer → components/trace-viewer}/index.js +0 -0
  275. /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.d.ts +0 -0
  276. /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.js +0 -0
  277. /package/dist/{trace-viewer → components/trace-viewer}/trace-viewer.module.css +0 -0
  278. /package/dist/{trace-viewer → components/trace-viewer}/types.d.ts +0 -0
  279. /package/dist/{trace-viewer → components/trace-viewer}/types.js +0 -0
  280. /package/dist/{trace-viewer → components/trace-viewer}/util/constants.d.ts +0 -0
  281. /package/dist/{trace-viewer → components/trace-viewer}/util/constants.js +0 -0
  282. /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.d.ts +0 -0
  283. /package/dist/{trace-viewer → components/trace-viewer}/util/scrollbar-width.js +0 -0
  284. /package/dist/{trace-viewer → components/trace-viewer}/util/tree.d.ts +0 -0
  285. /package/dist/{trace-viewer → components/trace-viewer}/util/tree.js +0 -0
  286. /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.d.ts +0 -0
  287. /package/dist/{trace-viewer → components/trace-viewer}/util/use-immediate-style.js +0 -0
  288. /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.d.ts +0 -0
  289. /package/dist/{trace-viewer → components/trace-viewer}/util/use-streaming-spans.js +0 -0
  290. /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.d.ts +0 -0
  291. /package/dist/{trace-viewer → components/trace-viewer}/util/use-trackpad-zoom.js +0 -0
  292. /package/dist/{trace-viewer → components/trace-viewer}/worker.d.ts +0 -0
  293. /package/dist/{trace-viewer → components/trace-viewer}/worker.js +0 -0
  294. /package/dist/{workflow-traces → components/workflow-traces}/event-colors.d.ts +0 -0
  295. /package/dist/{workflow-traces → components/workflow-traces}/event-colors.js +0 -0
  296. /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.d.ts +0 -0
  297. /package/dist/{workflow-traces → components/workflow-traces}/trace-colors.js +0 -0
  298. /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.d.ts +0 -0
  299. /package/dist/{workflow-traces → components/workflow-traces}/trace-span-construction.js +0 -0
  300. /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.d.ts +0 -0
  301. /package/dist/{workflow-traces → components/workflow-traces}/trace-time-utils.js +0 -0
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Functions for constructing OpenTelemetry spans from workflow entities
3
+ */
4
+
5
+ import { parseStepName, parseWorkflowName } from '@workflow/utils/parse-name';
6
+ import type { Event, Step, WorkflowRun } from '@workflow/world';
7
+ import type { Span, SpanEvent } from '../trace-viewer/types';
8
+ import { shouldShowVerticalLine } from './event-colors';
9
+ import { calculateDuration, dateToOtelTime } from './trace-time-utils';
10
+
11
+ export const WORKFLOW_LIBRARY = {
12
+ name: 'workflow-development-kit',
13
+ version: '4.0.0',
14
+ };
15
+
16
+ /**
17
+ * Event types that should be displayed as visual markers in the trace viewer
18
+ */
19
+ const MARKER_EVENT_TYPES: Set<Event['eventType']> = new Set([
20
+ 'hook_created',
21
+ 'hook_received',
22
+ 'hook_disposed',
23
+ 'step_started',
24
+ 'step_retrying',
25
+ 'step_failed',
26
+ 'run_failed',
27
+ 'wait_created',
28
+ 'wait_completed',
29
+ ]);
30
+
31
+ /**
32
+ * Convert workflow events to span events
33
+ * Only includes events that should be displayed as markers
34
+ */
35
+ export function convertEventsToSpanEvents(
36
+ events: Event[],
37
+ filterTypes = true
38
+ ): SpanEvent[] {
39
+ return events
40
+ .filter((event) =>
41
+ filterTypes ? MARKER_EVENT_TYPES.has(event.eventType) : true
42
+ )
43
+ .map((event) => ({
44
+ name: event.eventType,
45
+ timestamp: dateToOtelTime(event.createdAt),
46
+ attributes: {
47
+ eventId: event.eventId,
48
+ correlationId: event.correlationId,
49
+ eventData: 'eventData' in event ? event.eventData : undefined,
50
+ },
51
+ // Control whether to show vertical line in timeline
52
+ showVerticalLine: shouldShowVerticalLine(event.eventType),
53
+ }));
54
+ }
55
+
56
+ export const waitEventsToWaitEntity = (
57
+ events: Event[]
58
+ ): {
59
+ waitId: string;
60
+ runId: string;
61
+ createdAt: Date;
62
+ resumeAt: Date;
63
+ completedAt?: Date;
64
+ } | null => {
65
+ const startEvent = events.find((event) => event.eventType === 'wait_created');
66
+ if (!startEvent) {
67
+ return null;
68
+ }
69
+ const completedEvent = events.find(
70
+ (event) => event.eventType === 'wait_completed'
71
+ );
72
+ return {
73
+ waitId: startEvent.correlationId,
74
+ runId: startEvent.runId,
75
+ createdAt: startEvent.createdAt,
76
+ resumeAt: startEvent.eventData?.resumeAt,
77
+ completedAt: completedEvent?.createdAt,
78
+ };
79
+ };
80
+
81
+ /**
82
+ * Converts a workflow Wait to an OpenTelemetry Span
83
+ */
84
+ export function waitToSpan(
85
+ events: Event[],
86
+ run: WorkflowRun,
87
+ nowTime: Date
88
+ ): Span | null {
89
+ const wait = waitEventsToWaitEntity(events);
90
+ if (!wait) {
91
+ return null;
92
+ }
93
+ const viewerEndTime = new Date(run.completedAt || nowTime) ?? nowTime;
94
+ const startTime = wait?.createdAt ?? nowTime;
95
+ const endTime = wait?.completedAt ?? viewerEndTime;
96
+ const start = dateToOtelTime(startTime);
97
+ const end = dateToOtelTime(endTime);
98
+ const duration = calculateDuration(startTime, endTime);
99
+ const spanEvents = convertEventsToSpanEvents(events);
100
+ return {
101
+ spanId: wait.waitId,
102
+ name: 'sleep',
103
+ kind: 1, // INTERNAL span kind
104
+ resource: 'sleep',
105
+ library: WORKFLOW_LIBRARY,
106
+ status: { code: 0 },
107
+ traceFlags: 1,
108
+ attributes: {
109
+ resource: 'sleep' as const,
110
+ data: wait,
111
+ },
112
+ links: [],
113
+ events: spanEvents,
114
+ duration,
115
+ startTime: start,
116
+ endTime: end,
117
+ };
118
+ }
119
+
120
+ /**
121
+ * Converts a workflow Step to an OpenTelemetry Span
122
+ */
123
+ export function stepToSpan(
124
+ step: Step,
125
+ stepEvents: Event[],
126
+ nowTime?: Date
127
+ ): Span {
128
+ const now = nowTime ?? new Date();
129
+ const parsedName = parseStepName(String(step.stepName));
130
+
131
+ // Simplified attributes: only store resource type and full data
132
+ const attributes = {
133
+ resource: 'step' as const,
134
+ data: step,
135
+ };
136
+
137
+ const resource = 'step';
138
+ const endTime = new Date(step.completedAt ?? now);
139
+
140
+ // Convert step-related events to span events (for markers like hook_created, step_retrying, etc.)
141
+ // This determines which events are displayed as markers. In the detail view,
142
+ // we'll show all events that correlate with the selected resource.
143
+ const events = convertEventsToSpanEvents(stepEvents);
144
+
145
+ // Use createdAt as span start time, with activeStartTime for when execution began
146
+ // This allows visualization of the "queued" period before execution
147
+ const spanStartTime = new Date(step.createdAt);
148
+ let activeStartTime = step.startedAt ? new Date(step.startedAt) : undefined;
149
+ const firstStartEvent = stepEvents.find(
150
+ (event) => event.eventType === 'step_started'
151
+ );
152
+ if (firstStartEvent) {
153
+ // `step.startedAt` is the server-side creation timestamp, and `event.createdAt` is
154
+ // the client-side creation timestamp. For now, to align the event marker with the
155
+ // line we show for step.startedAt, we overwrite here to always use client-side time.
156
+ activeStartTime = new Date(firstStartEvent.createdAt);
157
+ }
158
+
159
+ return {
160
+ spanId: String(step.stepId),
161
+ name: parsedName?.shortName ?? '',
162
+ kind: 1, // INTERNAL span kind
163
+ resource,
164
+ library: WORKFLOW_LIBRARY,
165
+ status: { code: 0 },
166
+ traceFlags: 1,
167
+ attributes,
168
+ links: [],
169
+ events,
170
+ startTime: dateToOtelTime(spanStartTime),
171
+ endTime: dateToOtelTime(endTime),
172
+ duration: calculateDuration(spanStartTime, endTime),
173
+ // Only set activeStartTime if it differs from startTime (i.e., there was a queued period)
174
+ activeStartTime:
175
+ activeStartTime && activeStartTime.getTime() > spanStartTime.getTime()
176
+ ? dateToOtelTime(activeStartTime)
177
+ : undefined,
178
+ };
179
+ }
180
+
181
+ export const hookEventsToHookEntity = (
182
+ events: Event[]
183
+ ): {
184
+ hookId: string;
185
+ runId: string;
186
+ createdAt: Date;
187
+ receivedCount: number;
188
+ lastReceivedAt?: Date;
189
+ disposedAt?: Date;
190
+ } | null => {
191
+ const createdEvent = events.find(
192
+ (event) => event.eventType === 'hook_created'
193
+ );
194
+ if (!createdEvent) {
195
+ return null;
196
+ }
197
+ const receivedEvents = events.filter(
198
+ (event) => event.eventType === 'hook_received'
199
+ );
200
+ const disposedEvents = events.filter(
201
+ (event) => event.eventType === 'hook_disposed'
202
+ );
203
+ const lastReceivedEvent = receivedEvents.at(-1);
204
+ return {
205
+ hookId: createdEvent.correlationId,
206
+ runId: createdEvent.runId,
207
+ createdAt: createdEvent.createdAt,
208
+ receivedCount: receivedEvents.length,
209
+ lastReceivedAt: lastReceivedEvent?.createdAt || undefined,
210
+ disposedAt: disposedEvents.at(-1)?.createdAt || undefined,
211
+ };
212
+ };
213
+
214
+ /**
215
+ * Converts a workflow Hook to an OpenTelemetry Span
216
+ */
217
+ export function hookToSpan(
218
+ hookEvents: Event[],
219
+ run: WorkflowRun,
220
+ nowTime: Date
221
+ ): Span | null {
222
+ const hook = hookEventsToHookEntity(hookEvents);
223
+ if (!hook) {
224
+ return null;
225
+ }
226
+
227
+ // Convert hook-related events to span events
228
+ const events = convertEventsToSpanEvents(hookEvents);
229
+
230
+ // We display hooks as a minimum span size of 10 seconds, just to ensure
231
+ // it's clickable even if there is no
232
+ const viewerEndTime = new Date(run.completedAt || nowTime) ?? nowTime;
233
+ const endTime = hook.disposedAt || viewerEndTime;
234
+
235
+ return {
236
+ spanId: String(hook.hookId),
237
+ name: String(hook.hookId),
238
+ kind: 1, // INTERNAL span kind
239
+ resource: 'hook',
240
+ library: WORKFLOW_LIBRARY,
241
+ status: { code: 1 },
242
+ traceFlags: 1,
243
+ attributes: {
244
+ resource: 'hook' as const,
245
+ data: hook,
246
+ },
247
+ links: [],
248
+ events,
249
+ startTime: dateToOtelTime(hook.createdAt),
250
+ endTime: dateToOtelTime(endTime),
251
+ duration: calculateDuration(hook.createdAt, endTime),
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Creates a root span for the workflow run
257
+ */
258
+ export function runToSpan(
259
+ run: WorkflowRun,
260
+ runEvents: Event[],
261
+ nowTime?: Date
262
+ ): Span {
263
+ const now = nowTime ?? new Date();
264
+
265
+ // Simplified attributes: only store resource type and full data
266
+ const attributes = {
267
+ resource: 'run' as const,
268
+ data: run,
269
+ };
270
+
271
+ // Use createdAt as span start time, with activeStartTime for when execution began
272
+ const spanStartTime = new Date(run.createdAt);
273
+ const activeStartTime = run.startedAt ? new Date(run.startedAt) : undefined;
274
+ const endTime = run.completedAt ?? now;
275
+
276
+ // Convert run-level events to span events
277
+ const events = convertEventsToSpanEvents(runEvents);
278
+
279
+ return {
280
+ spanId: String(run.runId),
281
+ name: String(parseWorkflowName(run.workflowName)?.shortName ?? '?'),
282
+ kind: 1, // INTERNAL span kind
283
+ resource: 'run',
284
+ library: WORKFLOW_LIBRARY,
285
+ status: { code: 0 },
286
+ traceFlags: 1,
287
+ attributes,
288
+ links: [],
289
+ events,
290
+ startTime: dateToOtelTime(spanStartTime),
291
+ endTime: dateToOtelTime(endTime),
292
+ duration: calculateDuration(spanStartTime, endTime),
293
+ // Only set activeStartTime if it differs from startTime (i.e., there was a queued period)
294
+ activeStartTime:
295
+ activeStartTime && activeStartTime.getTime() > spanStartTime.getTime()
296
+ ? dateToOtelTime(activeStartTime)
297
+ : undefined,
298
+ };
299
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Time conversion utilities for workflow trace construction
3
+ */
4
+
5
+ /**
6
+ * Converts a Date to OpenTelemetry time format [seconds, nanoseconds]
7
+ */
8
+ export function dateToOtelTime(
9
+ date: Date | string | unknown
10
+ ): [number, number] {
11
+ if (typeof date === 'string') {
12
+ date = new Date(date);
13
+ }
14
+ if (!date || !(date instanceof Date)) {
15
+ return [0, 0];
16
+ }
17
+ const ms = date.getTime();
18
+ const seconds = Math.floor(ms / 1000);
19
+ const nanoseconds = (ms % 1000) * 1_000_000;
20
+ return [seconds, nanoseconds];
21
+ }
22
+
23
+ export function otelTimeToMs(time: [number, number]): number {
24
+ const secondsToMs = time[0] * 1_000;
25
+ const nanosecondsToMs = time[1] / 1_000_000;
26
+ return secondsToMs + nanosecondsToMs;
27
+ }
28
+
29
+ /**
30
+ * Calculates duration in [seconds, nanoseconds] format
31
+ */
32
+ export function calculateDuration(
33
+ start: Date | string | unknown,
34
+ end: Date | string | unknown
35
+ ): [number, number] {
36
+ if (typeof start === 'string') {
37
+ start = new Date(start);
38
+ }
39
+ if (typeof end === 'string') {
40
+ end = new Date(end);
41
+ }
42
+ if (!start || !(start instanceof Date)) {
43
+ return [0, 0];
44
+ }
45
+ const endTime = end && end instanceof Date ? end : new Date();
46
+ const durationMs = endTime.getTime() - start.getTime();
47
+ const seconds = Math.floor(durationMs / 1000);
48
+ const nanoseconds = (durationMs % 1000) * 1_000_000;
49
+ return [seconds, nanoseconds];
50
+ }
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+
5
+ /**
6
+ * Hook that detects if dark mode is active and reacts to theme changes.
7
+ * Observes the 'dark' class on the document element, which is how
8
+ * next-themes and similar libraries apply the theme.
9
+ *
10
+ * @returns `true` if dark mode is active, `false` otherwise
11
+ */
12
+ export const useDarkMode = (): boolean => {
13
+ const [isDark, setIsDark] = useState(() => {
14
+ if (typeof document === 'undefined') return false;
15
+ return document.documentElement.classList.contains('dark');
16
+ });
17
+
18
+ useEffect(() => {
19
+ if (typeof document === 'undefined') return;
20
+
21
+ const observer = new MutationObserver(() => {
22
+ setIsDark(document.documentElement.classList.contains('dark'));
23
+ });
24
+
25
+ observer.observe(document.documentElement, {
26
+ attributes: true,
27
+ attributeFilter: ['class'],
28
+ });
29
+
30
+ return () => observer.disconnect();
31
+ }, []);
32
+
33
+ return isDark;
34
+ };
package/src/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './index';
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ export type {
2
+ HealthCheckEndpoint,
3
+ HealthCheckResult,
4
+ } from '@workflow/core/runtime';
5
+ export {
6
+ parseStepName,
7
+ parseWorkflowName,
8
+ } from '@workflow/utils/parse-name';
9
+ export type { Event, Hook, Step, WorkflowRun } from '@workflow/world';
10
+ export * from './components';
11
+ export {
12
+ hookEventsToHookEntity,
13
+ waitEventsToWaitEntity,
14
+ } from './components/workflow-traces/trace-span-construction';
15
+ export type { EventAnalysis } from './lib/event-analysis';
16
+ export {
17
+ analyzeEvents,
18
+ hasPendingHooksFromEvents,
19
+ hasPendingStepsFromEvents,
20
+ isTerminalStatus,
21
+ shouldShowReenqueueButton,
22
+ } from './lib/event-analysis';
23
+ export type { StreamStep } from './lib/utils';
24
+ export {
25
+ extractConversation,
26
+ formatDuration,
27
+ identifyStreamSteps,
28
+ isDoStreamStep,
29
+ } from './lib/utils';
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Shared utilities for analyzing workflow events.
3
+ * Used by run-actions and trace viewer components.
4
+ */
5
+
6
+ import type { Event, WorkflowRunStatus } from '@workflow/world';
7
+
8
+ // Time thresholds for Re-enqueue button visibility
9
+ const STEP_ACTIVITY_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
10
+ const STEP_IDLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
11
+
12
+ /**
13
+ * Result of analyzing events for a workflow run
14
+ */
15
+ export interface EventAnalysis {
16
+ /** Whether there are pending sleep/wait calls */
17
+ hasPendingSleeps: boolean;
18
+ /** Whether there are pending steps (started but not completed/failed) */
19
+ hasPendingSteps: boolean;
20
+ /** Whether there are pending hooks (created but not disposed) */
21
+ hasPendingHooks: boolean;
22
+ /** Correlation IDs of pending sleeps */
23
+ pendingSleepIds: string[];
24
+ /** Correlation IDs of pending steps */
25
+ pendingStepIds: string[];
26
+ /** Correlation IDs of pending hooks */
27
+ pendingHookIds: string[];
28
+ /** Timestamp of the last step_started or step_retrying event */
29
+ lastStepActivityAt: Date | null;
30
+ /** Timestamp of the last step completion (step_completed or step_failed) */
31
+ lastStepCompletionAt: Date | null;
32
+ }
33
+
34
+ /**
35
+ * Analyze events to determine pending sleeps, steps, and hooks.
36
+ */
37
+ export function analyzeEvents(events: Event[] | undefined): EventAnalysis {
38
+ if (!events || events.length === 0) {
39
+ return {
40
+ hasPendingSleeps: false,
41
+ hasPendingSteps: false,
42
+ hasPendingHooks: false,
43
+ pendingSleepIds: [],
44
+ pendingStepIds: [],
45
+ pendingHookIds: [],
46
+ lastStepActivityAt: null,
47
+ lastStepCompletionAt: null,
48
+ };
49
+ }
50
+
51
+ // Group events by correlation ID for each type
52
+ const waitCreated = new Map<string, Event>();
53
+ const waitCompleted = new Set<string>();
54
+ const stepStarted = new Map<string, Event>();
55
+ const stepCompleted = new Set<string>();
56
+ const hookCreated = new Map<string, Event>();
57
+ const hookDisposed = new Set<string>();
58
+
59
+ let lastStepActivityAt: Date | null = null;
60
+ let lastStepCompletionAt: Date | null = null;
61
+
62
+ for (const event of events) {
63
+ const correlationId = event.correlationId;
64
+ if (!correlationId) continue;
65
+
66
+ switch (event.eventType) {
67
+ // Sleeps/Waits
68
+ case 'wait_created':
69
+ waitCreated.set(correlationId, event);
70
+ break;
71
+ case 'wait_completed':
72
+ waitCompleted.add(correlationId);
73
+ break;
74
+
75
+ // Steps
76
+ case 'step_started':
77
+ stepStarted.set(correlationId, event);
78
+ if (
79
+ !lastStepActivityAt ||
80
+ new Date(event.createdAt) > lastStepActivityAt
81
+ ) {
82
+ lastStepActivityAt = new Date(event.createdAt);
83
+ }
84
+ break;
85
+ case 'step_retrying':
86
+ if (
87
+ !lastStepActivityAt ||
88
+ new Date(event.createdAt) > lastStepActivityAt
89
+ ) {
90
+ lastStepActivityAt = new Date(event.createdAt);
91
+ }
92
+ break;
93
+ case 'step_completed':
94
+ case 'step_failed':
95
+ stepCompleted.add(correlationId);
96
+ if (
97
+ !lastStepCompletionAt ||
98
+ new Date(event.createdAt) > lastStepCompletionAt
99
+ ) {
100
+ lastStepCompletionAt = new Date(event.createdAt);
101
+ }
102
+ break;
103
+
104
+ // Hooks
105
+ case 'hook_created':
106
+ hookCreated.set(correlationId, event);
107
+ break;
108
+ case 'hook_disposed':
109
+ hookDisposed.add(correlationId);
110
+ break;
111
+ }
112
+ }
113
+
114
+ // Find pending items (created but not completed)
115
+ const pendingSleepIds = Array.from(waitCreated.keys()).filter(
116
+ (id) => !waitCompleted.has(id)
117
+ );
118
+ const pendingStepIds = Array.from(stepStarted.keys()).filter(
119
+ (id) => !stepCompleted.has(id)
120
+ );
121
+ const pendingHookIds = Array.from(hookCreated.keys()).filter(
122
+ (id) => !hookDisposed.has(id)
123
+ );
124
+
125
+ return {
126
+ hasPendingSleeps: pendingSleepIds.length > 0,
127
+ hasPendingSteps: pendingStepIds.length > 0,
128
+ hasPendingHooks: pendingHookIds.length > 0,
129
+ pendingSleepIds,
130
+ pendingStepIds,
131
+ pendingHookIds,
132
+ lastStepActivityAt,
133
+ lastStepCompletionAt,
134
+ };
135
+ }
136
+
137
+ /**
138
+ * Check if a workflow run status is terminal (completed, failed, or cancelled)
139
+ */
140
+ export function isTerminalStatus(
141
+ status: WorkflowRunStatus | undefined
142
+ ): boolean {
143
+ return (
144
+ status === 'completed' || status === 'failed' || status === 'cancelled'
145
+ );
146
+ }
147
+
148
+ /**
149
+ * Determine if the Re-enqueue button should be shown without the debug flag.
150
+ *
151
+ * The Re-enqueue button is shown when the workflow appears to be stuck:
152
+ * - The workflow is not in a terminal state
153
+ * - There are no pending sleeps (which would show the Wake up button instead)
154
+ * - There are no pending hooks (which are waiting for external input)
155
+ * - Either:
156
+ * - The last step_started or step_retrying event was >30 minutes ago, OR
157
+ * - There have been no pending steps for >5 minutes (all steps completed/failed)
158
+ */
159
+ export function shouldShowReenqueueButton(
160
+ events: Event[] | undefined,
161
+ status: WorkflowRunStatus | undefined
162
+ ): boolean {
163
+ // Never show if in terminal state
164
+ if (isTerminalStatus(status)) {
165
+ return false;
166
+ }
167
+
168
+ const analysis = analyzeEvents(events);
169
+
170
+ // Don't show if there are pending sleeps (Wake up button handles this)
171
+ if (analysis.hasPendingSleeps) {
172
+ return false;
173
+ }
174
+
175
+ // Don't show if there are pending hooks (waiting for external input)
176
+ if (analysis.hasPendingHooks) {
177
+ return false;
178
+ }
179
+
180
+ const now = Date.now();
181
+
182
+ // Check if last step activity was >30 minutes ago
183
+ if (analysis.lastStepActivityAt) {
184
+ const timeSinceLastActivity = now - analysis.lastStepActivityAt.getTime();
185
+ if (timeSinceLastActivity > STEP_ACTIVITY_TIMEOUT_MS) {
186
+ return true;
187
+ }
188
+ }
189
+
190
+ // Check if there are no pending steps and last completion was >5 minutes ago
191
+ if (!analysis.hasPendingSteps && analysis.lastStepCompletionAt) {
192
+ const timeSinceLastCompletion =
193
+ now - analysis.lastStepCompletionAt.getTime();
194
+ if (timeSinceLastCompletion > STEP_IDLE_TIMEOUT_MS) {
195
+ return true;
196
+ }
197
+ }
198
+
199
+ // If there's no step activity at all but the run is not terminal,
200
+ // and we've been waiting for a while, show the button
201
+ if (
202
+ !analysis.lastStepActivityAt &&
203
+ !analysis.hasPendingSteps &&
204
+ !analysis.hasPendingSleeps &&
205
+ !analysis.hasPendingHooks
206
+ ) {
207
+ // This case handles runs that haven't started any steps yet
208
+ // but aren't in a terminal state - they might be stuck
209
+ return true;
210
+ }
211
+
212
+ return false;
213
+ }
214
+
215
+ /**
216
+ * Check if there are pending steps from an events list.
217
+ */
218
+ export function hasPendingStepsFromEvents(
219
+ events: Event[] | undefined
220
+ ): boolean {
221
+ return analyzeEvents(events).hasPendingSteps;
222
+ }
223
+
224
+ /**
225
+ * Check if there are pending hooks from an events list.
226
+ */
227
+ export function hasPendingHooksFromEvents(
228
+ events: Event[] | undefined
229
+ ): boolean {
230
+ return analyzeEvents(events).hasPendingHooks;
231
+ }