@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,415 @@
1
+ 'use client';
2
+
3
+ import { clsx } from 'clsx';
4
+ import { useEffect, useRef, useState } from 'react';
5
+ import { getSpanClassName } from '../components/node';
6
+ import { useTraceViewer } from '../context';
7
+ import type {
8
+ VisibleSpan,
9
+ VisibleSpanEvent,
10
+ WorkerRequest,
11
+ WorkerResponse,
12
+ } from '../types';
13
+ import {
14
+ MARKER_HEIGHT,
15
+ ROW_HEIGHT,
16
+ ROW_PADDING,
17
+ TIMELINE_PADDING,
18
+ } from './constants';
19
+ import { adjustSpanVisibility } from './tree';
20
+
21
+ type UpdateFilter = (filter: string) => void;
22
+
23
+ interface QueuedSpan {
24
+ /** The distance from this span to the viewport */
25
+ d: number;
26
+ /** The span that's waiting to be rendered */
27
+ span: VisibleSpan;
28
+ }
29
+
30
+ function emptyArrayInit<T>(): T[] {
31
+ return [];
32
+ }
33
+
34
+ export const useStreamingSpans = (
35
+ highlightedSpans?: string[]
36
+ ): {
37
+ rows: VisibleSpan[][];
38
+ spans: VisibleSpan[];
39
+ events: VisibleSpanEvent[];
40
+ scale: number;
41
+ } => {
42
+ const { state, dispatch } = useTraceViewer();
43
+ const {
44
+ root,
45
+ filter: ctxFilter,
46
+ scale,
47
+ timelineRef,
48
+ timelineWidth,
49
+ spanMap,
50
+ scrollSnapshotRef,
51
+ selected,
52
+ memoCacheRef,
53
+ customSpanClassNameFunc,
54
+ } = state;
55
+ const timelineHeight = useStableValue(state.timelineHeight);
56
+ const counterRef = useRef(0);
57
+ const [rows, setRows] = useState<VisibleSpan[][]>(emptyArrayInit);
58
+ const [visibleSpans, setVisibleSpans] =
59
+ useState<VisibleSpan[]>(emptyArrayInit);
60
+ const [visibleEvents, setVisibleEvents] =
61
+ useState<VisibleSpanEvent[]>(emptyArrayInit);
62
+ const [resultScale, setResultScale] = useState(-1);
63
+
64
+ const updateFilterRef = useRef<UpdateFilter>(undefined);
65
+ useEffect(() => updateFilterRef.current?.(ctxFilter), [ctxFilter]);
66
+
67
+ useEffect(() => {
68
+ if (!highlightedSpans?.length) return;
69
+
70
+ for (const row of rows) {
71
+ for (const node of row) {
72
+ const isHighlighted = highlightedSpans.includes(node.span.spanId);
73
+ if (node.isHighlighted === isHighlighted) continue;
74
+ node.isHighlighted = isHighlighted;
75
+ memoCacheRef.current.set(node.span.spanId, {});
76
+ }
77
+ }
78
+ dispatch({
79
+ type: 'forceRender',
80
+ });
81
+ }, [rows, highlightedSpans, dispatch, memoCacheRef]);
82
+
83
+ useEffect(() => {
84
+ if (!root.startTime) return;
85
+
86
+ const worker = new Worker(new URL('../worker', import.meta.url));
87
+ let requestId = ++counterRef.current;
88
+ const onMessage = (event: MessageEvent): void => {
89
+ const data = event.data as WorkerResponse;
90
+
91
+ switch (data.type) {
92
+ case 'setRowsResult': {
93
+ if (data.isEnd) {
94
+ for (const row of data.rows) {
95
+ for (const node of row) {
96
+ // Ensure that we remap to the original span to reduce memory overhead
97
+ // and confusion down the line
98
+ node.span = spanMap[node.span.spanId]?.span ?? node.span;
99
+ }
100
+ }
101
+ }
102
+ setRows(data.rows);
103
+ break;
104
+ }
105
+ case 'updateHighlight': {
106
+ if (data?.requestId !== requestId) return;
107
+ const { matches } = data;
108
+ setRows((previous) => {
109
+ for (const row of previous) {
110
+ for (const node of row) {
111
+ const isHighlighted = matches.has(node.span.spanId);
112
+ if (node.isHighlighted === isHighlighted) continue;
113
+ node.isHighlighted = isHighlighted;
114
+ memoCacheRef.current.set(node.span.spanId, {});
115
+ }
116
+ }
117
+ return previous;
118
+ });
119
+ dispatch({
120
+ type: 'forceRender',
121
+ });
122
+ break;
123
+ }
124
+ default:
125
+ break;
126
+ }
127
+ };
128
+ worker.addEventListener('message', onMessage);
129
+
130
+ const message: WorkerRequest = {
131
+ requestId,
132
+ type: 'calculateSpanPositions',
133
+ root,
134
+ };
135
+ worker.postMessage(message);
136
+
137
+ updateFilterRef.current = (_filter) => {
138
+ const filter = _filter.trim().toLocaleLowerCase();
139
+ if (!filter) {
140
+ setRows((previous) =>
141
+ previous.map((row) =>
142
+ row.map((node) => {
143
+ node.isHighlighted = undefined;
144
+ return {
145
+ ...node,
146
+ };
147
+ })
148
+ )
149
+ );
150
+ return;
151
+ }
152
+
153
+ requestId = ++counterRef.current;
154
+ const filterMessage: WorkerRequest = {
155
+ type: 'filterSpans',
156
+ requestId,
157
+ root,
158
+ filter,
159
+ };
160
+ worker.postMessage(filterMessage);
161
+ };
162
+
163
+ return () => {
164
+ worker.terminate();
165
+ };
166
+ }, [root, spanMap, dispatch, memoCacheRef]);
167
+
168
+ useEffect(() => {
169
+ if (!rows.length) return;
170
+
171
+ const $timeline = timelineRef.current;
172
+ let snapshot = scrollSnapshotRef.current;
173
+ let hasScrolled = false;
174
+ let isDone = false;
175
+ let maxD = 0;
176
+ let currentD = 0;
177
+ const overscan = Math.max(500, timelineWidth * 0.5);
178
+ const queue = new Array<QueuedSpan[] | null>(rows.length).fill(null);
179
+
180
+ const buildQueue = (): void => {
181
+ isDone = true;
182
+
183
+ const lastRow = Math.min(
184
+ 1 + currentD + Math.ceil(snapshot?.endRow ?? Number.POSITIVE_INFINITY),
185
+ rows.length
186
+ );
187
+ for (let i = lastRow; i--; ) {
188
+ if (queue[i]) continue;
189
+ const rowDelta = getRowDelta(i);
190
+ if (Math.abs(rowDelta) > currentD) {
191
+ isDone = false;
192
+ if (rowDelta > 0) {
193
+ continue;
194
+ } else {
195
+ break;
196
+ }
197
+ }
198
+
199
+ const queueRow: QueuedSpan[] = [];
200
+ const row = rows[i];
201
+ if (!row) continue;
202
+
203
+ for (const span of row) {
204
+ if (!adjustSpanVisibility(span, scale)) continue;
205
+
206
+ const d = getDistance(span);
207
+ maxD = Math.max(d, maxD);
208
+
209
+ queueRow.push({
210
+ d,
211
+ span,
212
+ });
213
+ }
214
+
215
+ queue[i] = queueRow;
216
+ }
217
+ };
218
+
219
+ /**
220
+ * This returns the signed distance between the row and the targeted rows
221
+ */
222
+ const getRowDelta = (row: number): number => {
223
+ if (!snapshot) return 0;
224
+
225
+ if (row < snapshot.startRow) {
226
+ return row - snapshot.startRow;
227
+ } else if (row > snapshot.endRow) {
228
+ return row - snapshot.endRow;
229
+ }
230
+
231
+ return 0;
232
+ };
233
+
234
+ const getDistance = (span: VisibleSpan): number => {
235
+ if (!snapshot) return 0;
236
+
237
+ let xDistance = 0;
238
+ if (span.endTime < snapshot.startTime) {
239
+ xDistance = snapshot.startTime - span.endTime;
240
+ } else if (span.startTime > snapshot.endTime) {
241
+ xDistance = span.startTime - snapshot.endTime;
242
+ }
243
+
244
+ const yDistance = Math.abs(getRowDelta(span.row));
245
+
246
+ if (!xDistance && !yDistance) return 0;
247
+
248
+ return Math.sqrt(
249
+ (xDistance / scale) ** 2 + (yDistance * ROW_HEIGHT + ROW_PADDING) ** 2
250
+ );
251
+ };
252
+
253
+ const updateSnapshot = (): void => {
254
+ if (!$timeline) return;
255
+
256
+ const { scrollLeft, scrollTop } = $timeline;
257
+ const anchorX = 0;
258
+ const anchorT = scrollLeft / scale;
259
+ const startRow =
260
+ (scrollTop - MARKER_HEIGHT - TIMELINE_PADDING) /
261
+ (ROW_HEIGHT + ROW_PADDING);
262
+ const endRow =
263
+ startRow + Math.ceil(timelineHeight / (ROW_HEIGHT + ROW_PADDING));
264
+
265
+ snapshot = {
266
+ anchorT,
267
+ anchorX,
268
+ scrollLeft,
269
+ scrollTop,
270
+ startTime: root.startTime + scrollLeft / scale,
271
+ endTime: root.startTime + (scrollLeft + timelineWidth) / scale,
272
+ startRow,
273
+ endRow,
274
+ scale,
275
+ };
276
+ scrollSnapshotRef.current = snapshot;
277
+
278
+ for (let i = queue.length; i--; ) {
279
+ queue[i] = null;
280
+ }
281
+ };
282
+
283
+ let nextFrame = 0;
284
+ const onFrame = (): void => {
285
+ if (hasScrolled || !snapshot) {
286
+ hasScrolled = false;
287
+ updateSnapshot();
288
+ }
289
+ buildQueue();
290
+ const visible: VisibleSpan[] = [];
291
+ const events: VisibleSpanEvent[] = [];
292
+ for (const row of queue) {
293
+ if (!row) continue;
294
+
295
+ for (const { d, span } of row) {
296
+ if (d > currentD) continue;
297
+ visible.push(span);
298
+ if (span.events) {
299
+ events.push(...span.events);
300
+ }
301
+ }
302
+ }
303
+
304
+ if (currentD < overscan && (!isDone || currentD < maxD)) {
305
+ currentD = Math.min(overscan, currentD + 100);
306
+ nextFrame = requestAnimationFrame(onFrame);
307
+ }
308
+
309
+ setVisibleSpans(visible);
310
+ setVisibleEvents(events);
311
+ setResultScale(scale);
312
+ };
313
+ onFrame();
314
+
315
+ let ignoreT = Date.now();
316
+ const onWheel = (event: WheelEvent): void => {
317
+ if (event.ctrlKey || event.metaKey) {
318
+ ignoreT = Date.now();
319
+ }
320
+ };
321
+ $timeline?.addEventListener('wheel', onWheel);
322
+
323
+ const onScroll = (): void => {
324
+ if (Date.now() - ignoreT <= 50) return;
325
+
326
+ hasScrolled = true;
327
+ cancelAnimationFrame(nextFrame);
328
+ nextFrame = requestAnimationFrame(onFrame);
329
+ };
330
+ $timeline?.addEventListener('scroll', onScroll);
331
+
332
+ return () => {
333
+ cancelAnimationFrame(nextFrame);
334
+ $timeline?.removeEventListener('wheel', onWheel);
335
+ $timeline?.removeEventListener('scroll', onScroll);
336
+ };
337
+ }, [
338
+ rows,
339
+ root,
340
+ scale,
341
+ scrollSnapshotRef,
342
+ timelineRef,
343
+ timelineWidth,
344
+ timelineHeight,
345
+ ]);
346
+
347
+ useEffect(() => {
348
+ if (!selected) return;
349
+
350
+ let span: VisibleSpan | undefined;
351
+ for (const x of visibleSpans) {
352
+ if (x.span.spanId === selected.span.spanId) {
353
+ span = x;
354
+ break;
355
+ }
356
+ }
357
+
358
+ const $span = span?.ref?.current;
359
+ if (!span || !$span) return;
360
+
361
+ span.isSelected = true;
362
+ // Get both the base span className and custom class name
363
+ const baseClassName = getSpanClassName(span, scale);
364
+ const customClassName = customSpanClassNameFunc
365
+ ? customSpanClassNameFunc(span)
366
+ : '';
367
+ $span.className = clsx(baseClassName, customClassName);
368
+
369
+ return () => {
370
+ span.isSelected = false;
371
+ const baseClassName = getSpanClassName(span, scale);
372
+ const customClassName = customSpanClassNameFunc
373
+ ? customSpanClassNameFunc(span)
374
+ : '';
375
+ $span.className = clsx(baseClassName, customClassName);
376
+ };
377
+ }, [visibleSpans, scale, selected, customSpanClassNameFunc]);
378
+
379
+ return {
380
+ rows,
381
+ spans: visibleSpans,
382
+ events: visibleEvents,
383
+ scale: resultScale,
384
+ };
385
+ };
386
+
387
+ /**
388
+ * This hook keeps returning the same value until the current value
389
+ * has been stable for a few frames in a row
390
+ */
391
+ function useStableValue<T>(value: T): T {
392
+ const [cached, setCached] = useState(value);
393
+
394
+ useEffect(() => {
395
+ if (cached === value) return;
396
+
397
+ let frameCount = 0;
398
+ let nextFrame = 0;
399
+ const onFrame = (): void => {
400
+ if (++frameCount <= 3) {
401
+ nextFrame = requestAnimationFrame(onFrame);
402
+ return;
403
+ }
404
+
405
+ setCached(value);
406
+ };
407
+ onFrame();
408
+
409
+ return () => {
410
+ cancelAnimationFrame(nextFrame);
411
+ };
412
+ }, [cached, value]);
413
+
414
+ return cached;
415
+ }
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef } from 'react';
4
+
5
+ /**
6
+ * The delta is positive while zooming in, negative while zooming out
7
+ */
8
+ export type TrackpadZoomHandler = (delta: number) => void;
9
+
10
+ export function useTrackpadZoom(handler: TrackpadZoomHandler): void {
11
+ const handlerRef = useRef(handler);
12
+ handlerRef.current = handler;
13
+
14
+ useEffect(() => {
15
+ let pendingDelta = 0;
16
+ let nextFrame = 0;
17
+ const onFrame = (): void => {
18
+ handlerRef.current(pendingDelta);
19
+ pendingDelta = 0;
20
+ };
21
+
22
+ const onWheel = (event: WheelEvent): void => {
23
+ if (!event.ctrlKey && !event.metaKey) return;
24
+
25
+ event.preventDefault();
26
+ let delta = -event.deltaY;
27
+
28
+ switch (event.deltaMode) {
29
+ case WheelEvent.DOM_DELTA_PAGE:
30
+ delta *= window.innerHeight;
31
+ break;
32
+ case WheelEvent.DOM_DELTA_LINE:
33
+ delta *= 20;
34
+ break;
35
+ default:
36
+ break;
37
+ }
38
+
39
+ pendingDelta += delta;
40
+ cancelAnimationFrame(nextFrame);
41
+ nextFrame = requestAnimationFrame(onFrame);
42
+ };
43
+
44
+ window.addEventListener('wheel', onWheel, { passive: false });
45
+
46
+ return () => {
47
+ window.removeEventListener('wheel', onWheel);
48
+ cancelAnimationFrame(nextFrame);
49
+ };
50
+ }, []);
51
+ }
@@ -0,0 +1,128 @@
1
+ import type {
2
+ RootNode,
3
+ Span,
4
+ TraceNode,
5
+ VisibleSpan,
6
+ WorkerRequest,
7
+ WorkerResponse,
8
+ } from './types';
9
+ import { addToRow } from './util/tree';
10
+
11
+ // The most recent requestId
12
+ let requestId = 0;
13
+
14
+ self.addEventListener('message', (event) => {
15
+ const data = event.data as WorkerRequest;
16
+ requestId = Math.max(requestId, data?.requestId || 0);
17
+
18
+ switch (data.type) {
19
+ case 'calculateSpanPositions':
20
+ calculateSpanPositions(data.root);
21
+ break;
22
+ case 'filterSpans':
23
+ filterSpans(data.root, data.filter);
24
+ break;
25
+ default:
26
+ break;
27
+ }
28
+ });
29
+
30
+ const positionHelper = (node: TraceNode, pending: VisibleSpan[]): void => {
31
+ if ('parent' in node) {
32
+ const n = node as VisibleSpan;
33
+ n.row = -1;
34
+ n.isVisible = true;
35
+ pending.push(n);
36
+ }
37
+
38
+ const sortedChildren = node.children
39
+ .slice()
40
+ .sort((a, b) => a.startTime - b.startTime || b.duration - a.duration);
41
+ for (const child of sortedChildren) {
42
+ positionHelper(child, pending);
43
+ }
44
+ };
45
+
46
+ const calculateSpanPositions = (root: RootNode): void => {
47
+ const responseId = requestId;
48
+ const placed: VisibleSpan[][] = [];
49
+ const pending: VisibleSpan[] = [];
50
+
51
+ positionHelper(root, pending);
52
+
53
+ let lastFlushT = Date.now() - 10;
54
+ let lastFlushC = -64;
55
+ let count = 0;
56
+ const flush = (): void => {
57
+ for (const row of placed) {
58
+ row.sort((a, b) => a.startTime - b.startTime);
59
+ }
60
+ const message: WorkerResponse = {
61
+ requestId: responseId,
62
+ type: 'setRowsResult',
63
+ rows: placed,
64
+ isEnd: !pending.length,
65
+ };
66
+ postMessage(message);
67
+ lastFlushT = Date.now();
68
+ lastFlushC = count;
69
+ };
70
+
71
+ while (true) {
72
+ const node = pending.shift();
73
+ if (!node) {
74
+ flush();
75
+ return;
76
+ }
77
+ addToRow(placed, node, 0.001);
78
+ ++count;
79
+ if (Date.now() - lastFlushT >= 15 || count - lastFlushC >= 256) {
80
+ flush();
81
+ }
82
+ }
83
+ };
84
+
85
+ const ATTR_FILTER_REGEX = /(?<=^|\s)(?<pair>(?<key>[\w.]+):(?<value>\S*))/g;
86
+
87
+ const filterSpans = (root: RootNode, filter: string): void => {
88
+ const responseId = requestId;
89
+
90
+ const matches = new Set<string>();
91
+
92
+ const name = filter
93
+ .replace(ATTR_FILTER_REGEX, '')
94
+ .replace(/\s{2,}/g, ' ')
95
+ .trim();
96
+ const attrs: [string, string][] = [];
97
+ for (const m of filter.matchAll(ATTR_FILTER_REGEX)) {
98
+ const { key = '', value = '' } = m.groups || {};
99
+ attrs.push([key, value.toLocaleLowerCase()]);
100
+ }
101
+
102
+ const match = (span: Span): boolean => {
103
+ if (!span.name.toLocaleLowerCase().includes(name)) return false;
104
+ // TODO: support resource attribute filtering
105
+ return attrs.every(([key, value]) => {
106
+ const v = span.attributes[key];
107
+ if (!v) return false;
108
+ return String(v).toLocaleLowerCase().includes(value);
109
+ });
110
+ };
111
+
112
+ const helper = (node: TraceNode): void => {
113
+ for (const child of node.children) {
114
+ if (match(child.span)) {
115
+ matches.add(child.span.spanId);
116
+ }
117
+ helper(child);
118
+ }
119
+ };
120
+ helper(root);
121
+
122
+ const message: WorkerResponse = {
123
+ requestId: responseId,
124
+ type: 'updateHighlight',
125
+ matches,
126
+ };
127
+ postMessage(message);
128
+ };
@@ -0,0 +1,59 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ const alertVariants = cva(
7
+ 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'bg-background text-foreground',
12
+ destructive:
13
+ 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: 'default',
18
+ },
19
+ }
20
+ );
21
+
22
+ const Alert = React.forwardRef<
23
+ HTMLDivElement,
24
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25
+ >(({ className, variant, ...props }, ref) => (
26
+ <div
27
+ ref={ref}
28
+ role="alert"
29
+ className={cn(alertVariants({ variant }), className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ Alert.displayName = 'Alert';
34
+
35
+ const AlertTitle = React.forwardRef<
36
+ HTMLParagraphElement,
37
+ React.HTMLAttributes<HTMLHeadingElement>
38
+ >(({ className, ...props }, ref) => (
39
+ <h5
40
+ ref={ref}
41
+ className={cn('mb-1 font-medium leading-none tracking-tight', className)}
42
+ {...props}
43
+ />
44
+ ));
45
+ AlertTitle.displayName = 'AlertTitle';
46
+
47
+ const AlertDescription = React.forwardRef<
48
+ HTMLParagraphElement,
49
+ React.HTMLAttributes<HTMLParagraphElement>
50
+ >(({ className, ...props }, ref) => (
51
+ <div
52
+ ref={ref}
53
+ className={cn('text-sm [&_p]:leading-relaxed', className)}
54
+ {...props}
55
+ />
56
+ ));
57
+ AlertDescription.displayName = 'AlertDescription';
58
+
59
+ export { Alert, AlertTitle, AlertDescription };