@flanksource/clicky-ui 0.3.46 → 0.3.48

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 (474) hide show
  1. package/NOTICE.md +11 -0
  2. package/README.md +49 -0
  3. package/dist/ai.cjs +13 -8
  4. package/dist/ai.cjs.map +1 -1
  5. package/dist/ai.js +7 -2
  6. package/dist/ai.js.map +1 -1
  7. package/dist/comments/CommentSidePanel.cjs +10 -4
  8. package/dist/comments/CommentSidePanel.cjs.map +1 -1
  9. package/dist/comments/CommentSidePanel.d.ts +2 -0
  10. package/dist/comments/CommentSidePanel.d.ts.map +1 -1
  11. package/dist/comments/CommentSidePanel.js +10 -4
  12. package/dist/comments/CommentSidePanel.js.map +1 -1
  13. package/dist/comments/CommentThread.cjs +2 -0
  14. package/dist/comments/CommentThread.cjs.map +1 -1
  15. package/dist/comments/CommentThread.d.ts +2 -1
  16. package/dist/comments/CommentThread.d.ts.map +1 -1
  17. package/dist/comments/CommentThread.js +2 -0
  18. package/dist/comments/CommentThread.js.map +1 -1
  19. package/dist/comments/CommentThreadList.cjs +3 -0
  20. package/dist/comments/CommentThreadList.cjs.map +1 -1
  21. package/dist/comments/CommentThreadList.d.ts +3 -1
  22. package/dist/comments/CommentThreadList.d.ts.map +1 -1
  23. package/dist/comments/CommentThreadList.js +3 -0
  24. package/dist/comments/CommentThreadList.js.map +1 -1
  25. package/dist/components/ErrorWrapper.cjs +2 -3
  26. package/dist/components/ErrorWrapper.cjs.map +1 -1
  27. package/dist/components/ErrorWrapper.d.ts.map +1 -1
  28. package/dist/components/ErrorWrapper.js +3 -4
  29. package/dist/components/ErrorWrapper.js.map +1 -1
  30. package/dist/data/Clicky.cjs +3 -0
  31. package/dist/data/Clicky.cjs.map +1 -1
  32. package/dist/data/Clicky.js +3 -0
  33. package/dist/data/Clicky.js.map +1 -1
  34. package/dist/data/CodeLine.cjs +4 -2
  35. package/dist/data/CodeLine.cjs.map +1 -1
  36. package/dist/data/CodeLine.d.ts.map +1 -1
  37. package/dist/data/CodeLine.js +4 -2
  38. package/dist/data/CodeLine.js.map +1 -1
  39. package/dist/data/FilterPill.cjs +15 -2
  40. package/dist/data/FilterPill.cjs.map +1 -1
  41. package/dist/data/FilterPill.d.ts +1 -1
  42. package/dist/data/FilterPill.d.ts.map +1 -1
  43. package/dist/data/FilterPill.js +15 -2
  44. package/dist/data/FilterPill.js.map +1 -1
  45. package/dist/data/LogViewer.cjs +27 -8
  46. package/dist/data/LogViewer.cjs.map +1 -1
  47. package/dist/data/LogViewer.d.ts +11 -3
  48. package/dist/data/LogViewer.d.ts.map +1 -1
  49. package/dist/data/LogViewer.js +27 -8
  50. package/dist/data/LogViewer.js.map +1 -1
  51. package/dist/data/Properties.cjs +2 -15
  52. package/dist/data/Properties.cjs.map +1 -1
  53. package/dist/data/Properties.d.ts +4 -0
  54. package/dist/data/Properties.d.ts.map +1 -1
  55. package/dist/data/Properties.js +2 -15
  56. package/dist/data/Properties.js.map +1 -1
  57. package/dist/data/PropertyValue.cjs +37 -0
  58. package/dist/data/PropertyValue.cjs.map +1 -0
  59. package/dist/data/PropertyValue.d.ts +6 -0
  60. package/dist/data/PropertyValue.d.ts.map +1 -0
  61. package/dist/data/PropertyValue.js +37 -0
  62. package/dist/data/PropertyValue.js.map +1 -0
  63. package/dist/data/SymbolBadge.cjs +61 -0
  64. package/dist/data/SymbolBadge.cjs.map +1 -0
  65. package/dist/data/SymbolBadge.d.ts +21 -0
  66. package/dist/data/SymbolBadge.d.ts.map +1 -0
  67. package/dist/data/SymbolBadge.js +61 -0
  68. package/dist/data/SymbolBadge.js.map +1 -0
  69. package/dist/data/Tree.cjs +4 -3
  70. package/dist/data/Tree.cjs.map +1 -1
  71. package/dist/data/Tree.d.ts +3 -1
  72. package/dist/data/Tree.d.ts.map +1 -1
  73. package/dist/data/Tree.js +4 -3
  74. package/dist/data/Tree.js.map +1 -1
  75. package/dist/data/ai/ChatFab.cjs +1 -1
  76. package/dist/data/ai/ChatFab.cjs.map +1 -1
  77. package/dist/data/ai/ChatFab.js +1 -1
  78. package/dist/data/ai/ChatFab.js.map +1 -1
  79. package/dist/data/ai/ChatWindow.cjs +106 -171
  80. package/dist/data/ai/ChatWindow.cjs.map +1 -1
  81. package/dist/data/ai/ChatWindow.d.ts +6 -2
  82. package/dist/data/ai/ChatWindow.d.ts.map +1 -1
  83. package/dist/data/ai/ChatWindow.header.cjs +104 -0
  84. package/dist/data/ai/ChatWindow.header.cjs.map +1 -0
  85. package/dist/data/ai/ChatWindow.header.d.ts +29 -0
  86. package/dist/data/ai/ChatWindow.header.d.ts.map +1 -0
  87. package/dist/data/ai/ChatWindow.header.js +104 -0
  88. package/dist/data/ai/ChatWindow.header.js.map +1 -0
  89. package/dist/data/ai/ChatWindow.js +107 -172
  90. package/dist/data/ai/ChatWindow.js.map +1 -1
  91. package/dist/data/ai/ChatWindow.placement.cjs +95 -0
  92. package/dist/data/ai/ChatWindow.placement.cjs.map +1 -0
  93. package/dist/data/ai/ChatWindow.placement.d.ts +32 -0
  94. package/dist/data/ai/ChatWindow.placement.d.ts.map +1 -0
  95. package/dist/data/ai/ChatWindow.placement.js +95 -0
  96. package/dist/data/ai/ChatWindow.placement.js.map +1 -0
  97. package/dist/data/ai/SessionChatComposer.cjs +3 -1
  98. package/dist/data/ai/SessionChatComposer.cjs.map +1 -1
  99. package/dist/data/ai/SessionChatComposer.d.ts +4 -1
  100. package/dist/data/ai/SessionChatComposer.d.ts.map +1 -1
  101. package/dist/data/ai/SessionChatComposer.js +3 -1
  102. package/dist/data/ai/SessionChatComposer.js.map +1 -1
  103. package/dist/data/ai/SessionInspector.cjs +68 -72
  104. package/dist/data/ai/SessionInspector.cjs.map +1 -1
  105. package/dist/data/ai/SessionInspector.composer-slot.cjs +8 -0
  106. package/dist/data/ai/SessionInspector.composer-slot.cjs.map +1 -0
  107. package/dist/data/ai/SessionInspector.composer-slot.d.ts +9 -0
  108. package/dist/data/ai/SessionInspector.composer-slot.d.ts.map +1 -0
  109. package/dist/data/ai/SessionInspector.composer-slot.js +8 -0
  110. package/dist/data/ai/SessionInspector.composer-slot.js.map +1 -0
  111. package/dist/data/ai/SessionInspector.d.ts +6 -1
  112. package/dist/data/ai/SessionInspector.d.ts.map +1 -1
  113. package/dist/data/ai/SessionInspector.js +69 -73
  114. package/dist/data/ai/SessionInspector.js.map +1 -1
  115. package/dist/data/ai/SessionInspector.legacy.cjs +41 -42
  116. package/dist/data/ai/SessionInspector.legacy.cjs.map +1 -1
  117. package/dist/data/ai/SessionInspector.legacy.d.ts.map +1 -1
  118. package/dist/data/ai/SessionInspector.legacy.js +41 -42
  119. package/dist/data/ai/SessionInspector.legacy.js.map +1 -1
  120. package/dist/data/ai/SessionInspector.remote-view.cjs +14 -9
  121. package/dist/data/ai/SessionInspector.remote-view.cjs.map +1 -1
  122. package/dist/data/ai/SessionInspector.remote-view.d.ts +6 -2
  123. package/dist/data/ai/SessionInspector.remote-view.d.ts.map +1 -1
  124. package/dist/data/ai/SessionInspector.remote-view.js +14 -9
  125. package/dist/data/ai/SessionInspector.remote-view.js.map +1 -1
  126. package/dist/data/ai/SessionInspector.remote.cjs +84 -16
  127. package/dist/data/ai/SessionInspector.remote.cjs.map +1 -1
  128. package/dist/data/ai/SessionInspector.remote.d.ts +42 -7
  129. package/dist/data/ai/SessionInspector.remote.d.ts.map +1 -1
  130. package/dist/data/ai/SessionInspector.remote.js +86 -18
  131. package/dist/data/ai/SessionInspector.remote.js.map +1 -1
  132. package/dist/data/ai/SessionInspector.transcript.cjs +5 -0
  133. package/dist/data/ai/SessionInspector.transcript.cjs.map +1 -1
  134. package/dist/data/ai/SessionInspector.transcript.d.ts.map +1 -1
  135. package/dist/data/ai/SessionInspector.transcript.js +5 -0
  136. package/dist/data/ai/SessionInspector.transcript.js.map +1 -1
  137. package/dist/data/ai/SessionTail.cjs +63 -0
  138. package/dist/data/ai/SessionTail.cjs.map +1 -0
  139. package/dist/data/ai/SessionTail.d.ts +14 -0
  140. package/dist/data/ai/SessionTail.d.ts.map +1 -0
  141. package/dist/data/ai/SessionTail.js +63 -0
  142. package/dist/data/ai/SessionTail.js.map +1 -0
  143. package/dist/data/ai/SessionViewer.cjs +10 -3
  144. package/dist/data/ai/SessionViewer.cjs.map +1 -1
  145. package/dist/data/ai/SessionViewer.d.ts +7 -1
  146. package/dist/data/ai/SessionViewer.d.ts.map +1 -1
  147. package/dist/data/ai/SessionViewer.js +10 -3
  148. package/dist/data/ai/SessionViewer.js.map +1 -1
  149. package/dist/data/ai/SessionViewer.unified.d.ts +14 -0
  150. package/dist/data/ai/SessionViewer.unified.d.ts.map +1 -1
  151. package/dist/data/ai/index.d.ts +4 -3
  152. package/dist/data/ai/index.d.ts.map +1 -1
  153. package/dist/data/ai/use-session-scroll.cjs +30 -6
  154. package/dist/data/ai/use-session-scroll.cjs.map +1 -1
  155. package/dist/data/ai/use-session-scroll.d.ts +7 -0
  156. package/dist/data/ai/use-session-scroll.d.ts.map +1 -1
  157. package/dist/data/ai/use-session-scroll.js +30 -6
  158. package/dist/data/ai/use-session-scroll.js.map +1 -1
  159. package/dist/data/chat/Chat.cjs +1 -1
  160. package/dist/data/chat/Chat.cjs.map +1 -1
  161. package/dist/data/chat/Chat.js +1 -1
  162. package/dist/data/chat/Chat.js.map +1 -1
  163. package/dist/data/chat/ChatRuntimeToolbar.cjs +4 -4
  164. package/dist/data/chat/ChatRuntimeToolbar.cjs.map +1 -1
  165. package/dist/data/chat/ChatRuntimeToolbar.d.ts.map +1 -1
  166. package/dist/data/chat/ChatRuntimeToolbar.js +4 -4
  167. package/dist/data/chat/ChatRuntimeToolbar.js.map +1 -1
  168. package/dist/data/chat/PromptInput.cjs +4 -2
  169. package/dist/data/chat/PromptInput.cjs.map +1 -1
  170. package/dist/data/chat/PromptInput.d.ts +5 -1
  171. package/dist/data/chat/PromptInput.d.ts.map +1 -1
  172. package/dist/data/chat/PromptInput.js +4 -2
  173. package/dist/data/chat/PromptInput.js.map +1 -1
  174. package/dist/data/diagnostics/ErrorDetails.cjs +13 -2
  175. package/dist/data/diagnostics/ErrorDetails.cjs.map +1 -1
  176. package/dist/data/diagnostics/ErrorDetails.d.ts +3 -1
  177. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -1
  178. package/dist/data/diagnostics/ErrorDetails.js +14 -3
  179. package/dist/data/diagnostics/ErrorDetails.js.map +1 -1
  180. package/dist/data/diagnostics/FrameSourceWindow.cjs +3 -2
  181. package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -1
  182. package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -1
  183. package/dist/data/diagnostics/FrameSourceWindow.js +3 -2
  184. package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -1
  185. package/dist/data/diagnostics/error-diagnostics.cjs +5 -0
  186. package/dist/data/diagnostics/error-diagnostics.cjs.map +1 -1
  187. package/dist/data/diagnostics/error-diagnostics.d.ts +1 -0
  188. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -1
  189. package/dist/data/diagnostics/error-diagnostics.js +6 -1
  190. package/dist/data/diagnostics/error-diagnostics.js.map +1 -1
  191. package/dist/data/har/HarPanel.cjs +3 -1
  192. package/dist/data/har/HarPanel.cjs.map +1 -1
  193. package/dist/data/har/HarPanel.d.ts +4 -1
  194. package/dist/data/har/HarPanel.d.ts.map +1 -1
  195. package/dist/data/har/HarPanel.js +3 -1
  196. package/dist/data/har/HarPanel.js.map +1 -1
  197. package/dist/data/test-runner/Expectation.cjs +57 -0
  198. package/dist/data/test-runner/Expectation.cjs.map +1 -0
  199. package/dist/data/test-runner/Expectation.d.ts +19 -0
  200. package/dist/data/test-runner/Expectation.d.ts.map +1 -0
  201. package/dist/data/test-runner/Expectation.js +57 -0
  202. package/dist/data/test-runner/Expectation.js.map +1 -0
  203. package/dist/data/test-runner/MarkIcons.cjs +38 -0
  204. package/dist/data/test-runner/MarkIcons.cjs.map +1 -0
  205. package/dist/data/test-runner/MarkIcons.d.ts +15 -0
  206. package/dist/data/test-runner/MarkIcons.d.ts.map +1 -0
  207. package/dist/data/test-runner/MarkIcons.js +38 -0
  208. package/dist/data/test-runner/MarkIcons.js.map +1 -0
  209. package/dist/data/test-runner/TestDetailPanel.cjs +99 -53
  210. package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
  211. package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
  212. package/dist/data/test-runner/TestDetailPanel.js +101 -55
  213. package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
  214. package/dist/data/test-runner/TestFailureDetail.cjs +23 -27
  215. package/dist/data/test-runner/TestFailureDetail.cjs.map +1 -1
  216. package/dist/data/test-runner/TestFailureDetail.d.ts +2 -2
  217. package/dist/data/test-runner/TestFailureDetail.d.ts.map +1 -1
  218. package/dist/data/test-runner/TestFailureDetail.js +23 -27
  219. package/dist/data/test-runner/TestFailureDetail.js.map +1 -1
  220. package/dist/data/test-runner/TestFilterBar.cjs +87 -93
  221. package/dist/data/test-runner/TestFilterBar.cjs.map +1 -1
  222. package/dist/data/test-runner/TestFilterBar.d.ts +3 -2
  223. package/dist/data/test-runner/TestFilterBar.d.ts.map +1 -1
  224. package/dist/data/test-runner/TestFilterBar.js +89 -95
  225. package/dist/data/test-runner/TestFilterBar.js.map +1 -1
  226. package/dist/data/test-runner/TestRunSummary.cjs +35 -21
  227. package/dist/data/test-runner/TestRunSummary.cjs.map +1 -1
  228. package/dist/data/test-runner/TestRunSummary.d.ts.map +1 -1
  229. package/dist/data/test-runner/TestRunSummary.js +35 -21
  230. package/dist/data/test-runner/TestRunSummary.js.map +1 -1
  231. package/dist/data/test-runner/TestRunner.cjs +58 -30
  232. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  233. package/dist/data/test-runner/TestRunner.d.ts +6 -3
  234. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  235. package/dist/data/test-runner/TestRunner.js +58 -30
  236. package/dist/data/test-runner/TestRunner.js.map +1 -1
  237. package/dist/data/test-runner/TestTree.cjs +5 -2
  238. package/dist/data/test-runner/TestTree.cjs.map +1 -1
  239. package/dist/data/test-runner/TestTree.d.ts +5 -2
  240. package/dist/data/test-runner/TestTree.d.ts.map +1 -1
  241. package/dist/data/test-runner/TestTree.js +5 -2
  242. package/dist/data/test-runner/TestTree.js.map +1 -1
  243. package/dist/data/test-runner/TestTreeNode.cjs +28 -19
  244. package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
  245. package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
  246. package/dist/data/test-runner/TestTreeNode.js +29 -20
  247. package/dist/data/test-runner/TestTreeNode.js.map +1 -1
  248. package/dist/data/test-runner/adapter.cjs +15 -0
  249. package/dist/data/test-runner/adapter.cjs.map +1 -1
  250. package/dist/data/test-runner/adapter.d.ts +27 -7
  251. package/dist/data/test-runner/adapter.d.ts.map +1 -1
  252. package/dist/data/test-runner/adapter.js +15 -0
  253. package/dist/data/test-runner/adapter.js.map +1 -1
  254. package/dist/data/test-runner/context.cjs.map +1 -1
  255. package/dist/data/test-runner/context.d.ts +2 -0
  256. package/dist/data/test-runner/context.d.ts.map +1 -1
  257. package/dist/data/test-runner/context.js.map +1 -1
  258. package/dist/data/test-runner/copy.cjs +114 -0
  259. package/dist/data/test-runner/copy.cjs.map +1 -0
  260. package/dist/data/test-runner/copy.d.ts +47 -0
  261. package/dist/data/test-runner/copy.d.ts.map +1 -0
  262. package/dist/data/test-runner/copy.js +114 -0
  263. package/dist/data/test-runner/copy.js.map +1 -0
  264. package/dist/data/test-runner/index.d.ts +6 -3
  265. package/dist/data/test-runner/index.d.ts.map +1 -1
  266. package/dist/data/test-runner/marks.cjs +184 -0
  267. package/dist/data/test-runner/marks.cjs.map +1 -0
  268. package/dist/data/test-runner/marks.d.ts +40 -0
  269. package/dist/data/test-runner/marks.d.ts.map +1 -0
  270. package/dist/data/test-runner/marks.js +184 -0
  271. package/dist/data/test-runner/marks.js.map +1 -0
  272. package/dist/data/test-runner/status.cjs +27 -44
  273. package/dist/data/test-runner/status.cjs.map +1 -1
  274. package/dist/data/test-runner/status.d.ts +12 -3
  275. package/dist/data/test-runner/status.d.ts.map +1 -1
  276. package/dist/data/test-runner/status.js +27 -44
  277. package/dist/data/test-runner/status.js.map +1 -1
  278. package/dist/data/traces/TerminalCastPlayer.d.ts +21 -0
  279. package/dist/data/traces/TerminalCastPlayer.d.ts.map +1 -0
  280. package/dist/data/traces/TraceHarView.d.ts +13 -0
  281. package/dist/data/traces/TraceHarView.d.ts.map +1 -0
  282. package/dist/data/traces/cast.d.ts +9 -0
  283. package/dist/data/traces/cast.d.ts.map +1 -0
  284. package/dist/data/traces/fixtures.d.ts +8 -0
  285. package/dist/data/traces/fixtures.d.ts.map +1 -0
  286. package/dist/data/traces/har-adapter.d.ts +13 -0
  287. package/dist/data/traces/har-adapter.d.ts.map +1 -0
  288. package/dist/data/traces/terminal-screen.d.ts +45 -0
  289. package/dist/data/traces/terminal-screen.d.ts.map +1 -0
  290. package/dist/data/traces/terminal-timeline.d.ts +26 -0
  291. package/dist/data/traces/terminal-timeline.d.ts.map +1 -0
  292. package/dist/data/traces/types.d.ts +141 -0
  293. package/dist/data/traces/types.d.ts.map +1 -0
  294. package/dist/data/verification/VerificationResults.cjs +4 -0
  295. package/dist/data/verification/VerificationResults.cjs.map +1 -1
  296. package/dist/data/verification/VerificationResults.d.ts +3 -1
  297. package/dist/data/verification/VerificationResults.d.ts.map +1 -1
  298. package/dist/data/verification/VerificationResults.js +4 -0
  299. package/dist/data/verification/VerificationResults.js.map +1 -1
  300. package/dist/data/verification/adapterViews.cjs +28 -44
  301. package/dist/data/verification/adapterViews.cjs.map +1 -1
  302. package/dist/data/verification/adapterViews.d.ts +4 -1
  303. package/dist/data/verification/adapterViews.d.ts.map +1 -1
  304. package/dist/data/verification/adapterViews.js +28 -44
  305. package/dist/data/verification/adapterViews.js.map +1 -1
  306. package/dist/data/verification/adapters.cjs +163 -8
  307. package/dist/data/verification/adapters.cjs.map +1 -1
  308. package/dist/data/verification/adapters.d.ts +7 -1
  309. package/dist/data/verification/adapters.d.ts.map +1 -1
  310. package/dist/data/verification/adapters.js +163 -8
  311. package/dist/data/verification/adapters.js.map +1 -1
  312. package/dist/data/verification/index.d.ts +4 -2
  313. package/dist/data/verification/index.d.ts.map +1 -1
  314. package/dist/data/verification/stepKind.cjs +217 -0
  315. package/dist/data/verification/stepKind.cjs.map +1 -0
  316. package/dist/data/verification/stepKind.d.ts +87 -0
  317. package/dist/data/verification/stepKind.d.ts.map +1 -0
  318. package/dist/data/verification/stepKind.js +217 -0
  319. package/dist/data/verification/stepKind.js.map +1 -0
  320. package/dist/data/verification/stepKindViews.cjs +111 -0
  321. package/dist/data/verification/stepKindViews.cjs.map +1 -0
  322. package/dist/data/verification/stepKindViews.d.ts +18 -0
  323. package/dist/data/verification/stepKindViews.d.ts.map +1 -0
  324. package/dist/data/verification/stepKindViews.js +111 -0
  325. package/dist/data/verification/stepKindViews.js.map +1 -0
  326. package/dist/data/verification/verifyReportTests.cjs +1 -0
  327. package/dist/data/verification/verifyReportTests.cjs.map +1 -1
  328. package/dist/data/verification/verifyReportTests.d.ts +2 -1
  329. package/dist/data/verification/verifyReportTests.d.ts.map +1 -1
  330. package/dist/data/verification/verifyReportTests.js +1 -0
  331. package/dist/data/verification/verifyReportTests.js.map +1 -1
  332. package/dist/data/version-info.cjs +3 -3
  333. package/dist/data/version-info.js +3 -3
  334. package/dist/data.cjs +58 -3
  335. package/dist/data.cjs.map +1 -1
  336. package/dist/data.d.ts +3 -0
  337. package/dist/data.d.ts.map +1 -1
  338. package/dist/data.js +60 -5
  339. package/dist/data.js.map +1 -1
  340. package/dist/icons/components/UiLogoEslint.cjs +10 -0
  341. package/dist/icons/components/UiLogoEslint.cjs.map +1 -0
  342. package/dist/icons/components/UiLogoEslint.d.ts +9 -0
  343. package/dist/icons/components/UiLogoEslint.d.ts.map +1 -0
  344. package/dist/icons/components/UiLogoEslint.js +10 -0
  345. package/dist/icons/components/UiLogoEslint.js.map +1 -0
  346. package/dist/icons/components/UiLogoGo.cjs +10 -0
  347. package/dist/icons/components/UiLogoGo.cjs.map +1 -0
  348. package/dist/icons/components/UiLogoGo.d.ts +9 -0
  349. package/dist/icons/components/UiLogoGo.d.ts.map +1 -0
  350. package/dist/icons/components/UiLogoGo.js +10 -0
  351. package/dist/icons/components/UiLogoGo.js.map +1 -0
  352. package/dist/icons/components/UiLogoJest.cjs +10 -0
  353. package/dist/icons/components/UiLogoJest.cjs.map +1 -0
  354. package/dist/icons/components/UiLogoJest.d.ts +9 -0
  355. package/dist/icons/components/UiLogoJest.d.ts.map +1 -0
  356. package/dist/icons/components/UiLogoJest.js +10 -0
  357. package/dist/icons/components/UiLogoJest.js.map +1 -0
  358. package/dist/icons/components/UiLogoMarkdown.cjs +10 -0
  359. package/dist/icons/components/UiLogoMarkdown.cjs.map +1 -0
  360. package/dist/icons/components/UiLogoMarkdown.d.ts +9 -0
  361. package/dist/icons/components/UiLogoMarkdown.d.ts.map +1 -0
  362. package/dist/icons/components/UiLogoMarkdown.js +10 -0
  363. package/dist/icons/components/UiLogoMarkdown.js.map +1 -0
  364. package/dist/icons/components/UiLogoOxc.cjs +10 -0
  365. package/dist/icons/components/UiLogoOxc.cjs.map +1 -0
  366. package/dist/icons/components/UiLogoOxc.d.ts +9 -0
  367. package/dist/icons/components/UiLogoOxc.d.ts.map +1 -0
  368. package/dist/icons/components/UiLogoOxc.js +10 -0
  369. package/dist/icons/components/UiLogoOxc.js.map +1 -0
  370. package/dist/icons/components/UiLogoPlaywright.cjs +10 -0
  371. package/dist/icons/components/UiLogoPlaywright.cjs.map +1 -0
  372. package/dist/icons/components/UiLogoPlaywright.d.ts +9 -0
  373. package/dist/icons/components/UiLogoPlaywright.d.ts.map +1 -0
  374. package/dist/icons/components/UiLogoPlaywright.js +10 -0
  375. package/dist/icons/components/UiLogoPlaywright.js.map +1 -0
  376. package/dist/icons/components/UiLogoPython.cjs +10 -0
  377. package/dist/icons/components/UiLogoPython.cjs.map +1 -0
  378. package/dist/icons/components/UiLogoPython.d.ts +9 -0
  379. package/dist/icons/components/UiLogoPython.d.ts.map +1 -0
  380. package/dist/icons/components/UiLogoPython.js +10 -0
  381. package/dist/icons/components/UiLogoPython.js.map +1 -0
  382. package/dist/icons/components/UiLogoReact.cjs +10 -0
  383. package/dist/icons/components/UiLogoReact.cjs.map +1 -0
  384. package/dist/icons/components/UiLogoReact.d.ts +9 -0
  385. package/dist/icons/components/UiLogoReact.d.ts.map +1 -0
  386. package/dist/icons/components/UiLogoReact.js +10 -0
  387. package/dist/icons/components/UiLogoReact.js.map +1 -0
  388. package/dist/icons/components/UiLogoRuff.cjs +10 -0
  389. package/dist/icons/components/UiLogoRuff.cjs.map +1 -0
  390. package/dist/icons/components/UiLogoRuff.d.ts +9 -0
  391. package/dist/icons/components/UiLogoRuff.d.ts.map +1 -0
  392. package/dist/icons/components/UiLogoRuff.js +10 -0
  393. package/dist/icons/components/UiLogoRuff.js.map +1 -0
  394. package/dist/icons/components/UiLogoTypescript.cjs +10 -0
  395. package/dist/icons/components/UiLogoTypescript.cjs.map +1 -0
  396. package/dist/icons/components/UiLogoTypescript.d.ts +9 -0
  397. package/dist/icons/components/UiLogoTypescript.d.ts.map +1 -0
  398. package/dist/icons/components/UiLogoTypescript.js +10 -0
  399. package/dist/icons/components/UiLogoTypescript.js.map +1 -0
  400. package/dist/icons/components/UiLogoVitest.cjs +10 -0
  401. package/dist/icons/components/UiLogoVitest.cjs.map +1 -0
  402. package/dist/icons/components/UiLogoVitest.d.ts +9 -0
  403. package/dist/icons/components/UiLogoVitest.d.ts.map +1 -0
  404. package/dist/icons/components/UiLogoVitest.js +10 -0
  405. package/dist/icons/components/UiLogoVitest.js.map +1 -0
  406. package/dist/icons/index.d.ts +11 -0
  407. package/dist/icons/index.d.ts.map +1 -1
  408. package/dist/icons/registry.cjs +22 -0
  409. package/dist/icons/registry.cjs.map +1 -1
  410. package/dist/icons/registry.d.ts.map +1 -1
  411. package/dist/icons/registry.js +22 -0
  412. package/dist/icons/registry.js.map +1 -1
  413. package/dist/icons.cjs +22 -0
  414. package/dist/icons.cjs.map +1 -1
  415. package/dist/icons.js +22 -0
  416. package/dist/icons.js.map +1 -1
  417. package/dist/index.cjs +60 -3
  418. package/dist/index.cjs.map +1 -1
  419. package/dist/index.js +62 -5
  420. package/dist/index.js.map +1 -1
  421. package/dist/overlay/DropdownMenuSubmenu.cjs +4 -4
  422. package/dist/overlay/DropdownMenuSubmenu.cjs.map +1 -1
  423. package/dist/overlay/DropdownMenuSubmenu.js +4 -4
  424. package/dist/overlay/DropdownMenuSubmenu.js.map +1 -1
  425. package/dist/rpc/FilterForm.cjs +9 -0
  426. package/dist/rpc/FilterForm.cjs.map +1 -1
  427. package/dist/rpc/FilterForm.d.ts +5 -1
  428. package/dist/rpc/FilterForm.d.ts.map +1 -1
  429. package/dist/rpc/FilterForm.js +9 -0
  430. package/dist/rpc/FilterForm.js.map +1 -1
  431. package/dist/rpc/InlineError.cjs +12 -43
  432. package/dist/rpc/InlineError.cjs.map +1 -1
  433. package/dist/rpc/InlineError.d.ts.map +1 -1
  434. package/dist/rpc/InlineError.js +13 -44
  435. package/dist/rpc/InlineError.js.map +1 -1
  436. package/dist/rpc/OperationArgsForm.cjs +153 -0
  437. package/dist/rpc/OperationArgsForm.cjs.map +1 -0
  438. package/dist/rpc/OperationArgsForm.d.ts +16 -0
  439. package/dist/rpc/OperationArgsForm.d.ts.map +1 -0
  440. package/dist/rpc/OperationArgsForm.js +153 -0
  441. package/dist/rpc/OperationArgsForm.js.map +1 -0
  442. package/dist/rpc/OperationScheduleDialog.cjs +119 -22
  443. package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
  444. package/dist/rpc/OperationScheduleDialog.d.ts +7 -0
  445. package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
  446. package/dist/rpc/OperationScheduleDialog.js +120 -23
  447. package/dist/rpc/OperationScheduleDialog.js.map +1 -1
  448. package/dist/rpc/OperationSchedules.cjs +17 -2
  449. package/dist/rpc/OperationSchedules.cjs.map +1 -1
  450. package/dist/rpc/OperationSchedules.d.ts.map +1 -1
  451. package/dist/rpc/OperationSchedules.js +17 -2
  452. package/dist/rpc/OperationSchedules.js.map +1 -1
  453. package/dist/rpc/operation-schedule-model.cjs +2 -7
  454. package/dist/rpc/operation-schedule-model.cjs.map +1 -1
  455. package/dist/rpc/operation-schedule-model.d.ts +0 -2
  456. package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
  457. package/dist/rpc/operation-schedule-model.js +2 -7
  458. package/dist/rpc/operation-schedule-model.js.map +1 -1
  459. package/dist/rpc/operation-schedule-types.d.ts +12 -1
  460. package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
  461. package/dist/rpc.cjs +2 -0
  462. package/dist/rpc.cjs.map +1 -1
  463. package/dist/rpc.d.ts +1 -0
  464. package/dist/rpc.d.ts.map +1 -1
  465. package/dist/rpc.js +2 -0
  466. package/dist/rpc.js.map +1 -1
  467. package/dist/styles.css +1 -1
  468. package/package.json +1 -1
  469. package/dist/data/test-runner/frameworkIcon.cjs +0 -27
  470. package/dist/data/test-runner/frameworkIcon.cjs.map +0 -1
  471. package/dist/data/test-runner/frameworkIcon.d.ts +0 -3
  472. package/dist/data/test-runner/frameworkIcon.d.ts.map +0 -1
  473. package/dist/data/test-runner/frameworkIcon.js +0 -27
  474. package/dist/data/test-runner/frameworkIcon.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"error-diagnostics.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAIjC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,gBAAgB,GAAG,IAAI,CAwCzB;AAiBD,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CA4BpF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,UAM5C;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,WAKnD"}
1
+ {"version":3,"file":"error-diagnostics.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAIjC,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,gBAAgB,GAAG,IAAI,CAwCzB;AAqBD,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAGnD;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CA4BpF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,UAM5C;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,WAKnD"}
@@ -45,6 +45,10 @@ function detailBlocks(value) {
45
45
  return label && detail ? [{ label, value: detail }] : [];
46
46
  });
47
47
  }
48
+ function reportPageLine() {
49
+ if (typeof window === "undefined") return void 0;
50
+ return `Page: ${window.location.origin}${window.location.pathname}`;
51
+ }
48
52
  function parseDiagnosticsStackTrace(stacktrace) {
49
53
  const lines = stacktrace.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
50
54
  const frames = [];
@@ -156,6 +160,7 @@ export {
156
160
  isApplicationStackFrame,
157
161
  normalizeErrorDiagnostics,
158
162
  parseDiagnosticsStackTrace,
159
- parseInlineJsonContextValue
163
+ parseInlineJsonContextValue,
164
+ reportPageLine
160
165
  };
161
166
  //# sourceMappingURL=error-diagnostics.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-diagnostics.js","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n // details carries values too long for a context badge — a failing SQL\n // statement, a response body. They render as labeled preformatted blocks and\n // are part of the copied report.\n details?: ErrorDetailBlock[];\n raw?: unknown;\n};\n\nexport type ErrorDetailBlock = {\n label: string;\n value: string;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nestedError = objectRecord(record.error);\n if (nestedError && nestedError !== record) {\n return normalizeErrorDiagnostics(nestedError, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const hint = firstString(record, [\"hint\"]);\n // The hint leads the context badges: of everything the server attaches it is\n // the one field that says what to do next.\n const context: Array<[string, string]> = [\n ...(hint ? ([[\"Hint\", hint]] as Array<[string, string]>) : []),\n ...contextEntries(record.context),\n ];\n const details = detailBlocks(record.details);\n if (!message && !trace && !stacktrace && !time && context.length === 0) {\n const nestedDiagnostics = objectRecord(record.diagnostics);\n if (nestedDiagnostics && nestedDiagnostics !== record) {\n return normalizeErrorDiagnostics(nestedDiagnostics, fallback);\n }\n }\n if (!message && !trace && !stacktrace && !time && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n ...(details.length > 0 ? { details } : {}),\n };\n}\n\n// `details` is overloaded on the wire: our own envelope sends an array of\n// {label, value} blocks (entity.ErrorResponse), while third-party bodies use a\n// bare string that firstString already reads as the message. Only the array\n// form produces blocks; content_type is dropped because every block renders as\n// preformatted text either way.\nfunction detailBlocks(value: unknown): ErrorDetailBlock[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((entry) => {\n const record = objectRecord(entry);\n const label = firstString(record ?? {}, [\"label\"]);\n const detail = firstString(record ?? {}, [\"value\"]);\n return label && detail ? [{ label, value: detail }] : [];\n });\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const prefix = \"--- at \";\n if (!line.startsWith(prefix)) return null;\n\n const value = line.slice(prefix.length);\n let fileEnd = -1;\n let lineStart = -1;\n let lineEnd = -1;\n let functionStart = -1;\n\n for (let index = 0; index < value.length; index++) {\n if (value[index] !== \":\" || !isDecimalDigit(value[index + 1])) continue;\n\n let end = index + 1;\n while (isDecimalDigit(value[end])) end++;\n if (end === value.length) {\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = -1;\n continue;\n }\n if (!isWhitespace(value[end])) continue;\n\n let start = end;\n while (isWhitespace(value[start])) start++;\n if (start === value.length && start - end < 2) continue;\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = start;\n }\n\n if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;\n const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : \"\";\n return {\n raw: line,\n file: value.slice(0, fileEnd),\n line: Number(value.slice(lineStart, lineEnd)),\n ...(functionName ? { functionName } : {}),\n };\n}\n\nfunction isDecimalDigit(value: string | undefined): boolean {\n return value !== undefined && value >= \"0\" && value <= \"9\";\n}\n\nfunction isWhitespace(value: string | undefined): boolean {\n return value !== undefined && value.trim() === \"\";\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"error-diagnostics.js","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n // details carries values too long for a context badge — a failing SQL\n // statement, a response body. They render as labeled preformatted blocks and\n // are part of the copied report.\n details?: ErrorDetailBlock[];\n raw?: unknown;\n};\n\nexport type ErrorDetailBlock = {\n label: string;\n value: string;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nestedError = objectRecord(record.error);\n if (nestedError && nestedError !== record) {\n return normalizeErrorDiagnostics(nestedError, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const hint = firstString(record, [\"hint\"]);\n // The hint leads the context badges: of everything the server attaches it is\n // the one field that says what to do next.\n const context: Array<[string, string]> = [\n ...(hint ? ([[\"Hint\", hint]] as Array<[string, string]>) : []),\n ...contextEntries(record.context),\n ];\n const details = detailBlocks(record.details);\n if (!message && !trace && !stacktrace && !time && context.length === 0) {\n const nestedDiagnostics = objectRecord(record.diagnostics);\n if (nestedDiagnostics && nestedDiagnostics !== record) {\n return normalizeErrorDiagnostics(nestedDiagnostics, fallback);\n }\n }\n if (!message && !trace && !stacktrace && !time && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n ...(details.length > 0 ? { details } : {}),\n };\n}\n\n// `details` is overloaded on the wire: our own envelope sends an array of\n// {label, value} blocks (entity.ErrorResponse), while third-party bodies use a\n// bare string that firstString already reads as the message. Only the array\n// form produces blocks; content_type is dropped because every block renders as\n// preformatted text either way.\nfunction detailBlocks(value: unknown): ErrorDetailBlock[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((entry) => {\n const record = objectRecord(entry);\n const label = firstString(record ?? {}, [\"label\"]);\n const detail = firstString(record ?? {}, [\"value\"]);\n return label && detail ? [{ label, value: detail }] : [];\n });\n}\n\n// reportPageLine names the page an error report came from. Origin and path\n// only: a report is pasted into issues and chats, and a query string or\n// fragment routinely carries a session token, a signed URL or a search term\n// the reporter did not mean to publish.\nexport function reportPageLine(): string | undefined {\n if (typeof window === \"undefined\") return undefined;\n return `Page: ${window.location.origin}${window.location.pathname}`;\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const prefix = \"--- at \";\n if (!line.startsWith(prefix)) return null;\n\n const value = line.slice(prefix.length);\n let fileEnd = -1;\n let lineStart = -1;\n let lineEnd = -1;\n let functionStart = -1;\n\n for (let index = 0; index < value.length; index++) {\n if (value[index] !== \":\" || !isDecimalDigit(value[index + 1])) continue;\n\n let end = index + 1;\n while (isDecimalDigit(value[end])) end++;\n if (end === value.length) {\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = -1;\n continue;\n }\n if (!isWhitespace(value[end])) continue;\n\n let start = end;\n while (isWhitespace(value[start])) start++;\n if (start === value.length && start - end < 2) continue;\n fileEnd = index;\n lineStart = index + 1;\n lineEnd = end;\n functionStart = start;\n }\n\n if (fileEnd <= 0 || lineStart < 0 || lineEnd < 0) return null;\n const functionName = functionStart >= 0 ? value.slice(functionStart).trim() : \"\";\n return {\n raw: line,\n file: value.slice(0, fileEnd),\n line: Number(value.slice(lineStart, lineEnd)),\n ...(functionName ? { functionName } : {}),\n };\n}\n\nfunction isDecimalDigit(value: string | undefined): boolean {\n return value !== undefined && value >= \"0\" && value <= \"9\";\n}\n\nfunction isWhitespace(value: string | undefined): boolean {\n return value !== undefined && value.trim() === \"\";\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
@@ -60,7 +60,8 @@ function HarPanel({
60
60
  search,
61
61
  emptyLabel = "No HTTP traffic captured",
62
62
  className,
63
- bodySource
63
+ bodySource,
64
+ menuActions
64
65
  }) {
65
66
  const filteredEntries = react.useMemo(() => {
66
67
  if (search === void 0 || search.trim() === "") return entries;
@@ -86,6 +87,7 @@ function HarPanel({
86
87
  globalFilterPlaceholder: "Filter URL, method, or body…",
87
88
  defaultSort: { key: "time", dir: "asc" },
88
89
  emptyMessage: emptyLabel,
90
+ ...menuActions ? { menuActions } : {},
89
91
  ...runningCount > 0 ? {
90
92
  footer: ({ visibleRowCount, totalRowCount }) => `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? "" : "s"} · ${runningCount} running`
91
93
  } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"HarPanel.cjs","sources":["../../../src/data/har/HarPanel.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useState } from \"react\";\nimport { useResourceClock } from \"../../hooks/use-resource-clock\";\nimport { UiLoader } from \"../../icons\";\nimport { formatDuration } from \"../../lib/format\";\nimport { DataTable, type DataTableColumn, type DataTableFooterContext } from \"../DataTable\";\nimport { Icon } from \"../Icon\";\nimport { JsonView } from \"../JsonView\";\nimport type { HAREntry } from \"./types\";\n\nconst ERROR_PREVIEW_CHARS = 80;\n\n/** Wall-clock ms shared by every in-flight row, ticking only while one exists. */\nconst HarClockContext = createContext<number | undefined>(undefined);\n\nexport type HarPanelProps = {\n /** HAR entries to render. */\n entries: HAREntry[];\n /** Optional external search term. When omitted, the internal DataTable search is shown. */\n search?: string;\n /** Empty-state label for no entries or no matches. */\n emptyLabel?: string;\n /** Classes applied to the panel root. */\n className?: string;\n /** Optional private body store used only when an expanded row needs a preview. */\n bodySource?: HarPanelBodySource;\n};\n\nexport type HarPanelBodySource = {\n hasBody: (entry: HAREntry, part: \"request\" | \"response\") => boolean;\n preview: (requestId: string, part: \"request\" | \"response\") => Promise<string>;\n downloadHref: (entry: HAREntry, part: \"request\" | \"response\") => string;\n};\n\nexport type HarEntryDetailsProps = { entry: HAREntry; bodySource?: HarPanelBodySource | undefined };\n\nconst COLS: DataTableColumn<HAREntry>[] = [\n {\n key: \"request.method\",\n label: \"Method\",\n shrink: true,\n },\n {\n key: \"request.url\",\n label: \"URL\",\n grow: true,\n render: (value, entry) => (\n <span className=\"inline-flex min-w-0 items-baseline gap-density-2\">\n <span title={String(value ?? \"\")}>{String(value ?? \"\")}</span>\n {entry._error ? (\n <span className=\"text-destructive text-xs\" title={entry._error}>\n {previewError(entry._error)}\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"response.status\",\n label: \"Status\",\n shrink: true,\n render: (value, entry) => <HarStatus status={Number(value ?? 0)} entry={entry} />,\n sortValue: (value) => Number(value ?? 0),\n filterValue: (value, entry) => harStatusLabel(Number(value ?? 0), entry),\n },\n {\n key: \"time\",\n label: \"Time\",\n align: \"right\",\n shrink: true,\n render: (value, entry) =>\n entry._pending ? <PendingElapsed entry={entry} /> : `${Number(value ?? 0).toFixed(0)}ms`,\n sortValue: (value, entry) =>\n entry._pending ? pendingElapsedMs(entry, Date.now()) : Number(value ?? 0),\n },\n {\n key: \"response.bodySize\",\n label: \"Size\",\n align: \"right\",\n shrink: true,\n render: (value) => formatBytes(Number(value ?? 0)),\n sortValue: (value) => Number(value ?? 0),\n },\n {\n key: \"response.content.mimeType\",\n label: \"Type\",\n shrink: true,\n },\n];\n\nexport function HarPanel({\n entries,\n search,\n emptyLabel = \"No HTTP traffic captured\",\n className,\n bodySource,\n}: HarPanelProps) {\n const filteredEntries = useMemo(() => {\n if (search === undefined || search.trim() === \"\") return entries;\n return entries.filter((entry) => matchesSearch(search.trim().toLowerCase(), entry));\n }, [entries, search]);\n const runningCount = useMemo(() => entries.filter((entry) => entry._pending).length, [entries]);\n const now = useResourceClock(runningCount > 0);\n\n if (!entries || entries.length === 0) {\n return (\n <div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>\n );\n }\n\n return (\n // A flex column, not a plain block: DataTable sizes itself as `flex-1\n // min-h-0` so its own scroll region can be bounded, and in a block parent\n // that resolves to content height — the table grows past the panel and\n // nothing scrolls.\n <div className={`flex h-full min-h-0 flex-col ${className ?? \"\"}`}>\n <HarClockContext.Provider value={now}>\n <DataTable\n data={filteredEntries}\n columns={COLS}\n autoFilter\n showGlobalFilter={search === undefined}\n globalFilterPlaceholder=\"Filter URL, method, or body…\"\n defaultSort={{ key: \"time\", dir: \"asc\" }}\n emptyMessage={emptyLabel}\n {...(runningCount > 0\n ? {\n footer: ({ visibleRowCount, totalRowCount }: DataTableFooterContext) =>\n `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? \"\" : \"s\"} · ${runningCount} running`,\n }\n : {})}\n getRowId={(entry, index) =>\n // `_id` is the same on a request's pending and completed snapshots,\n // so an expanded row survives the transition. Without it, leave out\n // an in-flight entry's `time`, which grows with every snapshot.\n entry._id ??\n `${entry.startedDateTime ?? index}-${entry.request.method}-${entry.request.url}${entry._pending ? \"-pending\" : `-${entry.time}`}`\n }\n renderExpandedRow={(entry) => <HarEntryDetails entry={entry} bodySource={bodySource} />}\n />\n </HarClockContext.Provider>\n </div>\n );\n}\n\nfunction HarStatus({ status, entry }: { status: number; entry: HAREntry }) {\n if (entry._pending) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Icon icon={UiLoader} className=\"animate-spin\" />\n running\n </span>\n );\n }\n if (entry._error) return <span className=\"font-semibold text-destructive\">ERR</span>;\n return <span className={statusColor(status)}>{String(status)}</span>;\n}\n\nfunction PendingElapsed({ entry }: { entry: HAREntry }) {\n const now = useContext(HarClockContext);\n if (now === undefined) throw new Error(\"PendingElapsed must render inside HarPanel's clock\");\n return <span className=\"tabular-nums\">{formatDuration(pendingElapsedMs(entry, now))}</span>;\n}\n\n/**\n * Elapsed time of an in-flight request, measured from `startedDateTime` so it\n * keeps ticking between snapshots. The snapshot's `time` is only used when the\n * start timestamp cannot be parsed.\n */\nfunction pendingElapsedMs(entry: HAREntry, now: number): number {\n const started = Date.parse(entry.startedDateTime ?? \"\");\n if (Number.isNaN(started)) return entry.time;\n // Server and browser clocks can disagree by a little; a negative elapsed is noise.\n return Math.max(0, now - started);\n}\n\nfunction harStatusLabel(status: number, entry: HAREntry): string {\n if (entry._pending) return \"running\";\n if (entry._error) return \"ERR\";\n return String(status);\n}\n\nfunction previewError(error: string): string {\n return error.length > ERROR_PREVIEW_CHARS ? `${error.slice(0, ERROR_PREVIEW_CHARS)}…` : error;\n}\n\nexport function HarEntryDetails({ entry, bodySource }: HarEntryDetailsProps) {\n const parentNow = useContext(HarClockContext);\n const ownNow = useResourceClock(Boolean(entry._pending) && parentNow === undefined);\n return <HarClockContext.Provider value={parentNow ?? ownNow}><HarRowDetails entry={entry} bodySource={bodySource} /></HarClockContext.Provider>;\n}\n\nfunction HarRowDetails({ entry, bodySource }: HarEntryDetailsProps) {\n return (\n <>\n {entry._error && (\n <div className=\"mb-density-3\">\n <div className=\"font-semibold text-foreground mb-1\">Transport Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{entry._error}</pre>\n </div>\n )}\n {entry._pending && (\n <div className=\"mb-density-3 text-muted-foreground\">\n Waiting for response — in flight for <PendingElapsed entry={entry} />\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-density-4\">\n <div>\n <HeaderList\n title=\"Request Headers\"\n {...(entry.request.headers ? { headers: entry.request.headers } : {})}\n />\n {(entry.request.postData?.text || bodySource?.hasBody(entry, \"request\")) && (\n <BodySection entry={entry} part=\"request\" text={entry.request.postData?.text}\n mimeType={entry.request.postData?.mimeType} bodySource={bodySource} />\n )}\n </div>\n <div>\n <HeaderList\n title=\"Response Headers\"\n {...(entry.response.headers ? { headers: entry.response.headers } : {})}\n />\n </div>\n </div>\n {(entry.response.content?.text || bodySource?.hasBody(entry, \"response\")) && (\n <BodySection entry={entry} part=\"response\" text={entry.response.content?.text}\n mimeType={entry.response.content?.mimeType} bodySource={bodySource} />\n )}\n </>\n );\n}\n\nfunction BodySection({ entry, part, text, mimeType, bodySource }: {\n entry: HAREntry;\n part: \"request\" | \"response\";\n text?: string | undefined;\n mimeType?: string | undefined;\n bodySource?: HarPanelBodySource | undefined;\n}) {\n const remote = !text && bodySource?.hasBody(entry, part);\n const requestId = entry._id;\n if (remote && !requestId) throw new Error(\"Private HAR body requires a request ID\");\n const [preview, setPreview] = useState<string | undefined>();\n const [error, setError] = useState<Error | undefined>();\n useEffect(() => {\n if (!remote || !bodySource || !requestId) return;\n let active = true;\n setPreview(undefined);\n setError(undefined);\n bodySource.preview(requestId, part).then(\n (value) => { if (active) setPreview(value); },\n (reason: unknown) => { if (active) setError(reason instanceof Error ? reason : new Error(String(reason))); },\n );\n return () => { active = false; };\n }, [bodySource, requestId, part, remote]);\n return (\n <div className=\"mt-density-3\">\n <div className=\"mb-1 flex items-center gap-2 font-semibold text-foreground\">\n {part === \"request\" ? \"Request Body\" : \"Response Body\"}\n {remote && bodySource && <a className=\"text-sm font-normal text-primary underline\" href={bodySource.downloadHref(entry, part)} download>Download full body</a>}\n </div>\n <div className=\"bg-background p-density-2 rounded border border-border overflow-auto max-h-64\">\n {error ? <span role=\"alert\" className=\"text-destructive\">{error.message}</span>\n : remote && preview === undefined ? <span className=\"text-muted-foreground\">Loading preview…</span>\n : <BodyView text={text || preview || \"\"} {...(mimeType ? { mimeType } : {})} />}\n </div>\n {remote && <p className=\"mt-1 text-xs text-muted-foreground\">Preview shows at most the first 64 KiB.</p>}\n </div>\n );\n}\n\nfunction HeaderList({\n title,\n headers,\n}: {\n title: string;\n headers?: { name: string; value: string }[];\n}) {\n return (\n <>\n <div className=\"font-semibold text-foreground mb-1\">{title}</div>\n <div className=\"space-y-0.5\">\n {headers?.map((h, i) => (\n <div key={i} className=\"whitespace-nowrap\">\n <span className=\"text-purple-600 dark:text-purple-400\">{h.name}:</span> {h.value}\n </div>\n ))}\n </div>\n </>\n );\n}\n\nfunction BodyView({ text, mimeType }: { text: string; mimeType?: string }) {\n if (isJsonType(mimeType)) {\n const parsed = tryParseJson(text);\n if (parsed !== null) return <JsonView data={parsed} />;\n }\n return <pre className=\"whitespace-pre-wrap break-all\">{text}</pre>;\n}\n\nfunction tryParseJson(text: string): unknown | null {\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n\nfunction isJsonType(mime?: string): boolean {\n return !!mime && (mime.includes(\"json\") || mime.includes(\"javascript\"));\n}\n\nfunction matchesSearch(needle: string, entry: HAREntry): boolean {\n return [\n entry.request.method,\n entry.request.url,\n entry.request.postData?.text,\n entry.response.content?.text,\n entry._error,\n ].some((value) => !!value && value.toLowerCase().includes(needle));\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 0) return \"\";\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n}\n\nfunction statusColor(status: number): string {\n if (status >= 500) return \"text-red-600\";\n if (status >= 400) return \"text-amber-600\";\n if (status >= 300) return \"text-blue-600\";\n if (status >= 200) return \"text-green-600\";\n return \"text-muted-foreground\";\n}\n"],"names":["createContext","jsxs","jsx","useMemo","useResourceClock","DataTable","Icon","UiLoader","useContext","Fragment","useState","useEffect","JsonView"],"mappings":"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"}
1
+ {"version":3,"file":"HarPanel.cjs","sources":["../../../src/data/har/HarPanel.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useState } from \"react\";\nimport { useResourceClock } from \"../../hooks/use-resource-clock\";\nimport { UiLoader } from \"../../icons\";\nimport { formatDuration } from \"../../lib/format\";\nimport {\n DataTable,\n type DataTableColumn,\n type DataTableFooterContext,\n type DataTableMenuAction,\n} from \"../DataTable\";\nimport { Icon } from \"../Icon\";\nimport { JsonView } from \"../JsonView\";\nimport type { HAREntry } from \"./types\";\n\nconst ERROR_PREVIEW_CHARS = 80;\n\n/** Wall-clock ms shared by every in-flight row, ticking only while one exists. */\nconst HarClockContext = createContext<number | undefined>(undefined);\n\nexport type HarPanelProps = {\n /** HAR entries to render. */\n entries: HAREntry[];\n /** Optional external search term. When omitted, the internal DataTable search is shown. */\n search?: string;\n /** Empty-state label for no entries or no matches. */\n emptyLabel?: string;\n /** Classes applied to the panel root. */\n className?: string;\n /** Optional private body store used only when an expanded row needs a preview. */\n bodySource?: HarPanelBodySource;\n /** Entries for the table's overflow menu, e.g. a `useClickyExport` action. */\n menuActions?: DataTableMenuAction[];\n};\n\nexport type HarPanelBodySource = {\n hasBody: (entry: HAREntry, part: \"request\" | \"response\") => boolean;\n preview: (requestId: string, part: \"request\" | \"response\") => Promise<string>;\n downloadHref: (entry: HAREntry, part: \"request\" | \"response\") => string;\n};\n\nexport type HarEntryDetailsProps = { entry: HAREntry; bodySource?: HarPanelBodySource | undefined };\n\nconst COLS: DataTableColumn<HAREntry>[] = [\n {\n key: \"request.method\",\n label: \"Method\",\n shrink: true,\n },\n {\n key: \"request.url\",\n label: \"URL\",\n grow: true,\n render: (value, entry) => (\n <span className=\"inline-flex min-w-0 items-baseline gap-density-2\">\n <span title={String(value ?? \"\")}>{String(value ?? \"\")}</span>\n {entry._error ? (\n <span className=\"text-destructive text-xs\" title={entry._error}>\n {previewError(entry._error)}\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"response.status\",\n label: \"Status\",\n shrink: true,\n render: (value, entry) => <HarStatus status={Number(value ?? 0)} entry={entry} />,\n sortValue: (value) => Number(value ?? 0),\n filterValue: (value, entry) => harStatusLabel(Number(value ?? 0), entry),\n },\n {\n key: \"time\",\n label: \"Time\",\n align: \"right\",\n shrink: true,\n render: (value, entry) =>\n entry._pending ? <PendingElapsed entry={entry} /> : `${Number(value ?? 0).toFixed(0)}ms`,\n sortValue: (value, entry) =>\n entry._pending ? pendingElapsedMs(entry, Date.now()) : Number(value ?? 0),\n },\n {\n key: \"response.bodySize\",\n label: \"Size\",\n align: \"right\",\n shrink: true,\n render: (value) => formatBytes(Number(value ?? 0)),\n sortValue: (value) => Number(value ?? 0),\n },\n {\n key: \"response.content.mimeType\",\n label: \"Type\",\n shrink: true,\n },\n];\n\nexport function HarPanel({\n entries,\n search,\n emptyLabel = \"No HTTP traffic captured\",\n className,\n bodySource,\n menuActions,\n}: HarPanelProps) {\n const filteredEntries = useMemo(() => {\n if (search === undefined || search.trim() === \"\") return entries;\n return entries.filter((entry) => matchesSearch(search.trim().toLowerCase(), entry));\n }, [entries, search]);\n const runningCount = useMemo(() => entries.filter((entry) => entry._pending).length, [entries]);\n const now = useResourceClock(runningCount > 0);\n\n if (!entries || entries.length === 0) {\n return (\n <div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>\n );\n }\n\n return (\n // A flex column, not a plain block: DataTable sizes itself as `flex-1\n // min-h-0` so its own scroll region can be bounded, and in a block parent\n // that resolves to content height — the table grows past the panel and\n // nothing scrolls.\n <div className={`flex h-full min-h-0 flex-col ${className ?? \"\"}`}>\n <HarClockContext.Provider value={now}>\n <DataTable\n data={filteredEntries}\n columns={COLS}\n autoFilter\n showGlobalFilter={search === undefined}\n globalFilterPlaceholder=\"Filter URL, method, or body…\"\n defaultSort={{ key: \"time\", dir: \"asc\" }}\n emptyMessage={emptyLabel}\n {...(menuActions ? { menuActions } : {})}\n {...(runningCount > 0\n ? {\n footer: ({ visibleRowCount, totalRowCount }: DataTableFooterContext) =>\n `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? \"\" : \"s\"} · ${runningCount} running`,\n }\n : {})}\n getRowId={(entry, index) =>\n // `_id` is the same on a request's pending and completed snapshots,\n // so an expanded row survives the transition. Without it, leave out\n // an in-flight entry's `time`, which grows with every snapshot.\n entry._id ??\n `${entry.startedDateTime ?? index}-${entry.request.method}-${entry.request.url}${entry._pending ? \"-pending\" : `-${entry.time}`}`\n }\n renderExpandedRow={(entry) => <HarEntryDetails entry={entry} bodySource={bodySource} />}\n />\n </HarClockContext.Provider>\n </div>\n );\n}\n\nfunction HarStatus({ status, entry }: { status: number; entry: HAREntry }) {\n if (entry._pending) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Icon icon={UiLoader} className=\"animate-spin\" />\n running\n </span>\n );\n }\n if (entry._error) return <span className=\"font-semibold text-destructive\">ERR</span>;\n return <span className={statusColor(status)}>{String(status)}</span>;\n}\n\nfunction PendingElapsed({ entry }: { entry: HAREntry }) {\n const now = useContext(HarClockContext);\n if (now === undefined) throw new Error(\"PendingElapsed must render inside HarPanel's clock\");\n return <span className=\"tabular-nums\">{formatDuration(pendingElapsedMs(entry, now))}</span>;\n}\n\n/**\n * Elapsed time of an in-flight request, measured from `startedDateTime` so it\n * keeps ticking between snapshots. The snapshot's `time` is only used when the\n * start timestamp cannot be parsed.\n */\nfunction pendingElapsedMs(entry: HAREntry, now: number): number {\n const started = Date.parse(entry.startedDateTime ?? \"\");\n if (Number.isNaN(started)) return entry.time;\n // Server and browser clocks can disagree by a little; a negative elapsed is noise.\n return Math.max(0, now - started);\n}\n\nfunction harStatusLabel(status: number, entry: HAREntry): string {\n if (entry._pending) return \"running\";\n if (entry._error) return \"ERR\";\n return String(status);\n}\n\nfunction previewError(error: string): string {\n return error.length > ERROR_PREVIEW_CHARS ? `${error.slice(0, ERROR_PREVIEW_CHARS)}…` : error;\n}\n\nexport function HarEntryDetails({ entry, bodySource }: HarEntryDetailsProps) {\n const parentNow = useContext(HarClockContext);\n const ownNow = useResourceClock(Boolean(entry._pending) && parentNow === undefined);\n return <HarClockContext.Provider value={parentNow ?? ownNow}><HarRowDetails entry={entry} bodySource={bodySource} /></HarClockContext.Provider>;\n}\n\nfunction HarRowDetails({ entry, bodySource }: HarEntryDetailsProps) {\n return (\n <>\n {entry._error && (\n <div className=\"mb-density-3\">\n <div className=\"font-semibold text-foreground mb-1\">Transport Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{entry._error}</pre>\n </div>\n )}\n {entry._pending && (\n <div className=\"mb-density-3 text-muted-foreground\">\n Waiting for response — in flight for <PendingElapsed entry={entry} />\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-density-4\">\n <div>\n <HeaderList\n title=\"Request Headers\"\n {...(entry.request.headers ? { headers: entry.request.headers } : {})}\n />\n {(entry.request.postData?.text || bodySource?.hasBody(entry, \"request\")) && (\n <BodySection entry={entry} part=\"request\" text={entry.request.postData?.text}\n mimeType={entry.request.postData?.mimeType} bodySource={bodySource} />\n )}\n </div>\n <div>\n <HeaderList\n title=\"Response Headers\"\n {...(entry.response.headers ? { headers: entry.response.headers } : {})}\n />\n </div>\n </div>\n {(entry.response.content?.text || bodySource?.hasBody(entry, \"response\")) && (\n <BodySection entry={entry} part=\"response\" text={entry.response.content?.text}\n mimeType={entry.response.content?.mimeType} bodySource={bodySource} />\n )}\n </>\n );\n}\n\nfunction BodySection({ entry, part, text, mimeType, bodySource }: {\n entry: HAREntry;\n part: \"request\" | \"response\";\n text?: string | undefined;\n mimeType?: string | undefined;\n bodySource?: HarPanelBodySource | undefined;\n}) {\n const remote = !text && bodySource?.hasBody(entry, part);\n const requestId = entry._id;\n if (remote && !requestId) throw new Error(\"Private HAR body requires a request ID\");\n const [preview, setPreview] = useState<string | undefined>();\n const [error, setError] = useState<Error | undefined>();\n useEffect(() => {\n if (!remote || !bodySource || !requestId) return;\n let active = true;\n setPreview(undefined);\n setError(undefined);\n bodySource.preview(requestId, part).then(\n (value) => { if (active) setPreview(value); },\n (reason: unknown) => { if (active) setError(reason instanceof Error ? reason : new Error(String(reason))); },\n );\n return () => { active = false; };\n }, [bodySource, requestId, part, remote]);\n return (\n <div className=\"mt-density-3\">\n <div className=\"mb-1 flex items-center gap-2 font-semibold text-foreground\">\n {part === \"request\" ? \"Request Body\" : \"Response Body\"}\n {remote && bodySource && <a className=\"text-sm font-normal text-primary underline\" href={bodySource.downloadHref(entry, part)} download>Download full body</a>}\n </div>\n <div className=\"bg-background p-density-2 rounded border border-border overflow-auto max-h-64\">\n {error ? <span role=\"alert\" className=\"text-destructive\">{error.message}</span>\n : remote && preview === undefined ? <span className=\"text-muted-foreground\">Loading preview…</span>\n : <BodyView text={text || preview || \"\"} {...(mimeType ? { mimeType } : {})} />}\n </div>\n {remote && <p className=\"mt-1 text-xs text-muted-foreground\">Preview shows at most the first 64 KiB.</p>}\n </div>\n );\n}\n\nfunction HeaderList({\n title,\n headers,\n}: {\n title: string;\n headers?: { name: string; value: string }[];\n}) {\n return (\n <>\n <div className=\"font-semibold text-foreground mb-1\">{title}</div>\n <div className=\"space-y-0.5\">\n {headers?.map((h, i) => (\n <div key={i} className=\"whitespace-nowrap\">\n <span className=\"text-purple-600 dark:text-purple-400\">{h.name}:</span> {h.value}\n </div>\n ))}\n </div>\n </>\n );\n}\n\nfunction BodyView({ text, mimeType }: { text: string; mimeType?: string }) {\n if (isJsonType(mimeType)) {\n const parsed = tryParseJson(text);\n if (parsed !== null) return <JsonView data={parsed} />;\n }\n return <pre className=\"whitespace-pre-wrap break-all\">{text}</pre>;\n}\n\nfunction tryParseJson(text: string): unknown | null {\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n\nfunction isJsonType(mime?: string): boolean {\n return !!mime && (mime.includes(\"json\") || mime.includes(\"javascript\"));\n}\n\nfunction matchesSearch(needle: string, entry: HAREntry): boolean {\n return [\n entry.request.method,\n entry.request.url,\n entry.request.postData?.text,\n entry.response.content?.text,\n entry._error,\n ].some((value) => !!value && value.toLowerCase().includes(needle));\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 0) return \"\";\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n}\n\nfunction statusColor(status: number): string {\n if (status >= 500) return \"text-red-600\";\n if (status >= 400) return \"text-amber-600\";\n if (status >= 300) return \"text-blue-600\";\n if (status >= 200) return \"text-green-600\";\n return \"text-muted-foreground\";\n}\n"],"names":["createContext","jsxs","jsx","useMemo","useResourceClock","DataTable","Icon","UiLoader","useContext","Fragment","useState","useEffect","JsonView"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { DataTableMenuAction } from '../DataTable.js';
1
2
  import { HAREntry } from './types.js';
2
3
  export type HarPanelProps = {
3
4
  /** HAR entries to render. */
@@ -10,6 +11,8 @@ export type HarPanelProps = {
10
11
  className?: string;
11
12
  /** Optional private body store used only when an expanded row needs a preview. */
12
13
  bodySource?: HarPanelBodySource;
14
+ /** Entries for the table's overflow menu, e.g. a `useClickyExport` action. */
15
+ menuActions?: DataTableMenuAction[];
13
16
  };
14
17
  export type HarPanelBodySource = {
15
18
  hasBody: (entry: HAREntry, part: "request" | "response") => boolean;
@@ -20,6 +23,6 @@ export type HarEntryDetailsProps = {
20
23
  entry: HAREntry;
21
24
  bodySource?: HarPanelBodySource | undefined;
22
25
  };
23
- export declare function HarPanel({ entries, search, emptyLabel, className, bodySource, }: HarPanelProps): import("react").JSX.Element;
26
+ export declare function HarPanel({ entries, search, emptyLabel, className, bodySource, menuActions, }: HarPanelProps): import("react").JSX.Element;
24
27
  export declare function HarEntryDetails({ entry, bodySource }: HarEntryDetailsProps): import("react").JSX.Element;
25
28
  //# sourceMappingURL=HarPanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HarPanel.d.ts","sourceRoot":"","sources":["../../../src/data/har/HarPanel.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAOxC,MAAM,MAAM,aAAa,GAAG;IAC1B,6BAA6B;IAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,UAAU,CAAC,EAAE,kBAAkB,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,OAAO,CAAC;IACpE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,YAAY,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,MAAM,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,UAAU,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAA;CAAE,CAAC;AAwDpG,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,MAAM,EACN,UAAuC,EACvC,SAAS,EACT,UAAU,GACX,EAAE,aAAa,+BA+Cf;AA2CD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,oBAAoB,+BAI1E"}
1
+ {"version":3,"file":"HarPanel.d.ts","sourceRoot":"","sources":["../../../src/data/har/HarPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAOxC,MAAM,MAAM,aAAa,GAAG;IAC1B,6BAA6B;IAC7B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,OAAO,CAAC;IACpE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,YAAY,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,KAAK,MAAM,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,UAAU,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAA;CAAE,CAAC;AAwDpG,wBAAgB,QAAQ,CAAC,EACvB,OAAO,EACP,MAAM,EACN,UAAuC,EACvC,SAAS,EACT,UAAU,EACV,WAAW,GACZ,EAAE,aAAa,+BAgDf;AA2CD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,oBAAoB,+BAI1E"}
@@ -58,7 +58,8 @@ function HarPanel({
58
58
  search,
59
59
  emptyLabel = "No HTTP traffic captured",
60
60
  className,
61
- bodySource
61
+ bodySource,
62
+ menuActions
62
63
  }) {
63
64
  const filteredEntries = useMemo(() => {
64
65
  if (search === void 0 || search.trim() === "") return entries;
@@ -84,6 +85,7 @@ function HarPanel({
84
85
  globalFilterPlaceholder: "Filter URL, method, or body…",
85
86
  defaultSort: { key: "time", dir: "asc" },
86
87
  emptyMessage: emptyLabel,
88
+ ...menuActions ? { menuActions } : {},
87
89
  ...runningCount > 0 ? {
88
90
  footer: ({ visibleRowCount, totalRowCount }) => `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? "" : "s"} · ${runningCount} running`
89
91
  } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"HarPanel.js","sources":["../../../src/data/har/HarPanel.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useState } from \"react\";\nimport { useResourceClock } from \"../../hooks/use-resource-clock\";\nimport { UiLoader } from \"../../icons\";\nimport { formatDuration } from \"../../lib/format\";\nimport { DataTable, type DataTableColumn, type DataTableFooterContext } from \"../DataTable\";\nimport { Icon } from \"../Icon\";\nimport { JsonView } from \"../JsonView\";\nimport type { HAREntry } from \"./types\";\n\nconst ERROR_PREVIEW_CHARS = 80;\n\n/** Wall-clock ms shared by every in-flight row, ticking only while one exists. */\nconst HarClockContext = createContext<number | undefined>(undefined);\n\nexport type HarPanelProps = {\n /** HAR entries to render. */\n entries: HAREntry[];\n /** Optional external search term. When omitted, the internal DataTable search is shown. */\n search?: string;\n /** Empty-state label for no entries or no matches. */\n emptyLabel?: string;\n /** Classes applied to the panel root. */\n className?: string;\n /** Optional private body store used only when an expanded row needs a preview. */\n bodySource?: HarPanelBodySource;\n};\n\nexport type HarPanelBodySource = {\n hasBody: (entry: HAREntry, part: \"request\" | \"response\") => boolean;\n preview: (requestId: string, part: \"request\" | \"response\") => Promise<string>;\n downloadHref: (entry: HAREntry, part: \"request\" | \"response\") => string;\n};\n\nexport type HarEntryDetailsProps = { entry: HAREntry; bodySource?: HarPanelBodySource | undefined };\n\nconst COLS: DataTableColumn<HAREntry>[] = [\n {\n key: \"request.method\",\n label: \"Method\",\n shrink: true,\n },\n {\n key: \"request.url\",\n label: \"URL\",\n grow: true,\n render: (value, entry) => (\n <span className=\"inline-flex min-w-0 items-baseline gap-density-2\">\n <span title={String(value ?? \"\")}>{String(value ?? \"\")}</span>\n {entry._error ? (\n <span className=\"text-destructive text-xs\" title={entry._error}>\n {previewError(entry._error)}\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"response.status\",\n label: \"Status\",\n shrink: true,\n render: (value, entry) => <HarStatus status={Number(value ?? 0)} entry={entry} />,\n sortValue: (value) => Number(value ?? 0),\n filterValue: (value, entry) => harStatusLabel(Number(value ?? 0), entry),\n },\n {\n key: \"time\",\n label: \"Time\",\n align: \"right\",\n shrink: true,\n render: (value, entry) =>\n entry._pending ? <PendingElapsed entry={entry} /> : `${Number(value ?? 0).toFixed(0)}ms`,\n sortValue: (value, entry) =>\n entry._pending ? pendingElapsedMs(entry, Date.now()) : Number(value ?? 0),\n },\n {\n key: \"response.bodySize\",\n label: \"Size\",\n align: \"right\",\n shrink: true,\n render: (value) => formatBytes(Number(value ?? 0)),\n sortValue: (value) => Number(value ?? 0),\n },\n {\n key: \"response.content.mimeType\",\n label: \"Type\",\n shrink: true,\n },\n];\n\nexport function HarPanel({\n entries,\n search,\n emptyLabel = \"No HTTP traffic captured\",\n className,\n bodySource,\n}: HarPanelProps) {\n const filteredEntries = useMemo(() => {\n if (search === undefined || search.trim() === \"\") return entries;\n return entries.filter((entry) => matchesSearch(search.trim().toLowerCase(), entry));\n }, [entries, search]);\n const runningCount = useMemo(() => entries.filter((entry) => entry._pending).length, [entries]);\n const now = useResourceClock(runningCount > 0);\n\n if (!entries || entries.length === 0) {\n return (\n <div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>\n );\n }\n\n return (\n // A flex column, not a plain block: DataTable sizes itself as `flex-1\n // min-h-0` so its own scroll region can be bounded, and in a block parent\n // that resolves to content height — the table grows past the panel and\n // nothing scrolls.\n <div className={`flex h-full min-h-0 flex-col ${className ?? \"\"}`}>\n <HarClockContext.Provider value={now}>\n <DataTable\n data={filteredEntries}\n columns={COLS}\n autoFilter\n showGlobalFilter={search === undefined}\n globalFilterPlaceholder=\"Filter URL, method, or body…\"\n defaultSort={{ key: \"time\", dir: \"asc\" }}\n emptyMessage={emptyLabel}\n {...(runningCount > 0\n ? {\n footer: ({ visibleRowCount, totalRowCount }: DataTableFooterContext) =>\n `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? \"\" : \"s\"} · ${runningCount} running`,\n }\n : {})}\n getRowId={(entry, index) =>\n // `_id` is the same on a request's pending and completed snapshots,\n // so an expanded row survives the transition. Without it, leave out\n // an in-flight entry's `time`, which grows with every snapshot.\n entry._id ??\n `${entry.startedDateTime ?? index}-${entry.request.method}-${entry.request.url}${entry._pending ? \"-pending\" : `-${entry.time}`}`\n }\n renderExpandedRow={(entry) => <HarEntryDetails entry={entry} bodySource={bodySource} />}\n />\n </HarClockContext.Provider>\n </div>\n );\n}\n\nfunction HarStatus({ status, entry }: { status: number; entry: HAREntry }) {\n if (entry._pending) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Icon icon={UiLoader} className=\"animate-spin\" />\n running\n </span>\n );\n }\n if (entry._error) return <span className=\"font-semibold text-destructive\">ERR</span>;\n return <span className={statusColor(status)}>{String(status)}</span>;\n}\n\nfunction PendingElapsed({ entry }: { entry: HAREntry }) {\n const now = useContext(HarClockContext);\n if (now === undefined) throw new Error(\"PendingElapsed must render inside HarPanel's clock\");\n return <span className=\"tabular-nums\">{formatDuration(pendingElapsedMs(entry, now))}</span>;\n}\n\n/**\n * Elapsed time of an in-flight request, measured from `startedDateTime` so it\n * keeps ticking between snapshots. The snapshot's `time` is only used when the\n * start timestamp cannot be parsed.\n */\nfunction pendingElapsedMs(entry: HAREntry, now: number): number {\n const started = Date.parse(entry.startedDateTime ?? \"\");\n if (Number.isNaN(started)) return entry.time;\n // Server and browser clocks can disagree by a little; a negative elapsed is noise.\n return Math.max(0, now - started);\n}\n\nfunction harStatusLabel(status: number, entry: HAREntry): string {\n if (entry._pending) return \"running\";\n if (entry._error) return \"ERR\";\n return String(status);\n}\n\nfunction previewError(error: string): string {\n return error.length > ERROR_PREVIEW_CHARS ? `${error.slice(0, ERROR_PREVIEW_CHARS)}…` : error;\n}\n\nexport function HarEntryDetails({ entry, bodySource }: HarEntryDetailsProps) {\n const parentNow = useContext(HarClockContext);\n const ownNow = useResourceClock(Boolean(entry._pending) && parentNow === undefined);\n return <HarClockContext.Provider value={parentNow ?? ownNow}><HarRowDetails entry={entry} bodySource={bodySource} /></HarClockContext.Provider>;\n}\n\nfunction HarRowDetails({ entry, bodySource }: HarEntryDetailsProps) {\n return (\n <>\n {entry._error && (\n <div className=\"mb-density-3\">\n <div className=\"font-semibold text-foreground mb-1\">Transport Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{entry._error}</pre>\n </div>\n )}\n {entry._pending && (\n <div className=\"mb-density-3 text-muted-foreground\">\n Waiting for response — in flight for <PendingElapsed entry={entry} />\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-density-4\">\n <div>\n <HeaderList\n title=\"Request Headers\"\n {...(entry.request.headers ? { headers: entry.request.headers } : {})}\n />\n {(entry.request.postData?.text || bodySource?.hasBody(entry, \"request\")) && (\n <BodySection entry={entry} part=\"request\" text={entry.request.postData?.text}\n mimeType={entry.request.postData?.mimeType} bodySource={bodySource} />\n )}\n </div>\n <div>\n <HeaderList\n title=\"Response Headers\"\n {...(entry.response.headers ? { headers: entry.response.headers } : {})}\n />\n </div>\n </div>\n {(entry.response.content?.text || bodySource?.hasBody(entry, \"response\")) && (\n <BodySection entry={entry} part=\"response\" text={entry.response.content?.text}\n mimeType={entry.response.content?.mimeType} bodySource={bodySource} />\n )}\n </>\n );\n}\n\nfunction BodySection({ entry, part, text, mimeType, bodySource }: {\n entry: HAREntry;\n part: \"request\" | \"response\";\n text?: string | undefined;\n mimeType?: string | undefined;\n bodySource?: HarPanelBodySource | undefined;\n}) {\n const remote = !text && bodySource?.hasBody(entry, part);\n const requestId = entry._id;\n if (remote && !requestId) throw new Error(\"Private HAR body requires a request ID\");\n const [preview, setPreview] = useState<string | undefined>();\n const [error, setError] = useState<Error | undefined>();\n useEffect(() => {\n if (!remote || !bodySource || !requestId) return;\n let active = true;\n setPreview(undefined);\n setError(undefined);\n bodySource.preview(requestId, part).then(\n (value) => { if (active) setPreview(value); },\n (reason: unknown) => { if (active) setError(reason instanceof Error ? reason : new Error(String(reason))); },\n );\n return () => { active = false; };\n }, [bodySource, requestId, part, remote]);\n return (\n <div className=\"mt-density-3\">\n <div className=\"mb-1 flex items-center gap-2 font-semibold text-foreground\">\n {part === \"request\" ? \"Request Body\" : \"Response Body\"}\n {remote && bodySource && <a className=\"text-sm font-normal text-primary underline\" href={bodySource.downloadHref(entry, part)} download>Download full body</a>}\n </div>\n <div className=\"bg-background p-density-2 rounded border border-border overflow-auto max-h-64\">\n {error ? <span role=\"alert\" className=\"text-destructive\">{error.message}</span>\n : remote && preview === undefined ? <span className=\"text-muted-foreground\">Loading preview…</span>\n : <BodyView text={text || preview || \"\"} {...(mimeType ? { mimeType } : {})} />}\n </div>\n {remote && <p className=\"mt-1 text-xs text-muted-foreground\">Preview shows at most the first 64 KiB.</p>}\n </div>\n );\n}\n\nfunction HeaderList({\n title,\n headers,\n}: {\n title: string;\n headers?: { name: string; value: string }[];\n}) {\n return (\n <>\n <div className=\"font-semibold text-foreground mb-1\">{title}</div>\n <div className=\"space-y-0.5\">\n {headers?.map((h, i) => (\n <div key={i} className=\"whitespace-nowrap\">\n <span className=\"text-purple-600 dark:text-purple-400\">{h.name}:</span> {h.value}\n </div>\n ))}\n </div>\n </>\n );\n}\n\nfunction BodyView({ text, mimeType }: { text: string; mimeType?: string }) {\n if (isJsonType(mimeType)) {\n const parsed = tryParseJson(text);\n if (parsed !== null) return <JsonView data={parsed} />;\n }\n return <pre className=\"whitespace-pre-wrap break-all\">{text}</pre>;\n}\n\nfunction tryParseJson(text: string): unknown | null {\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n\nfunction isJsonType(mime?: string): boolean {\n return !!mime && (mime.includes(\"json\") || mime.includes(\"javascript\"));\n}\n\nfunction matchesSearch(needle: string, entry: HAREntry): boolean {\n return [\n entry.request.method,\n entry.request.url,\n entry.request.postData?.text,\n entry.response.content?.text,\n entry._error,\n ].some((value) => !!value && value.toLowerCase().includes(needle));\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 0) return \"\";\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n}\n\nfunction statusColor(status: number): string {\n if (status >= 500) return \"text-red-600\";\n if (status >= 400) return \"text-amber-600\";\n if (status >= 300) return \"text-blue-600\";\n if (status >= 200) return \"text-green-600\";\n return \"text-muted-foreground\";\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"HarPanel.js","sources":["../../../src/data/har/HarPanel.tsx"],"sourcesContent":["import { createContext, useContext, useEffect, useMemo, useState } from \"react\";\nimport { useResourceClock } from \"../../hooks/use-resource-clock\";\nimport { UiLoader } from \"../../icons\";\nimport { formatDuration } from \"../../lib/format\";\nimport {\n DataTable,\n type DataTableColumn,\n type DataTableFooterContext,\n type DataTableMenuAction,\n} from \"../DataTable\";\nimport { Icon } from \"../Icon\";\nimport { JsonView } from \"../JsonView\";\nimport type { HAREntry } from \"./types\";\n\nconst ERROR_PREVIEW_CHARS = 80;\n\n/** Wall-clock ms shared by every in-flight row, ticking only while one exists. */\nconst HarClockContext = createContext<number | undefined>(undefined);\n\nexport type HarPanelProps = {\n /** HAR entries to render. */\n entries: HAREntry[];\n /** Optional external search term. When omitted, the internal DataTable search is shown. */\n search?: string;\n /** Empty-state label for no entries or no matches. */\n emptyLabel?: string;\n /** Classes applied to the panel root. */\n className?: string;\n /** Optional private body store used only when an expanded row needs a preview. */\n bodySource?: HarPanelBodySource;\n /** Entries for the table's overflow menu, e.g. a `useClickyExport` action. */\n menuActions?: DataTableMenuAction[];\n};\n\nexport type HarPanelBodySource = {\n hasBody: (entry: HAREntry, part: \"request\" | \"response\") => boolean;\n preview: (requestId: string, part: \"request\" | \"response\") => Promise<string>;\n downloadHref: (entry: HAREntry, part: \"request\" | \"response\") => string;\n};\n\nexport type HarEntryDetailsProps = { entry: HAREntry; bodySource?: HarPanelBodySource | undefined };\n\nconst COLS: DataTableColumn<HAREntry>[] = [\n {\n key: \"request.method\",\n label: \"Method\",\n shrink: true,\n },\n {\n key: \"request.url\",\n label: \"URL\",\n grow: true,\n render: (value, entry) => (\n <span className=\"inline-flex min-w-0 items-baseline gap-density-2\">\n <span title={String(value ?? \"\")}>{String(value ?? \"\")}</span>\n {entry._error ? (\n <span className=\"text-destructive text-xs\" title={entry._error}>\n {previewError(entry._error)}\n </span>\n ) : null}\n </span>\n ),\n },\n {\n key: \"response.status\",\n label: \"Status\",\n shrink: true,\n render: (value, entry) => <HarStatus status={Number(value ?? 0)} entry={entry} />,\n sortValue: (value) => Number(value ?? 0),\n filterValue: (value, entry) => harStatusLabel(Number(value ?? 0), entry),\n },\n {\n key: \"time\",\n label: \"Time\",\n align: \"right\",\n shrink: true,\n render: (value, entry) =>\n entry._pending ? <PendingElapsed entry={entry} /> : `${Number(value ?? 0).toFixed(0)}ms`,\n sortValue: (value, entry) =>\n entry._pending ? pendingElapsedMs(entry, Date.now()) : Number(value ?? 0),\n },\n {\n key: \"response.bodySize\",\n label: \"Size\",\n align: \"right\",\n shrink: true,\n render: (value) => formatBytes(Number(value ?? 0)),\n sortValue: (value) => Number(value ?? 0),\n },\n {\n key: \"response.content.mimeType\",\n label: \"Type\",\n shrink: true,\n },\n];\n\nexport function HarPanel({\n entries,\n search,\n emptyLabel = \"No HTTP traffic captured\",\n className,\n bodySource,\n menuActions,\n}: HarPanelProps) {\n const filteredEntries = useMemo(() => {\n if (search === undefined || search.trim() === \"\") return entries;\n return entries.filter((entry) => matchesSearch(search.trim().toLowerCase(), entry));\n }, [entries, search]);\n const runningCount = useMemo(() => entries.filter((entry) => entry._pending).length, [entries]);\n const now = useResourceClock(runningCount > 0);\n\n if (!entries || entries.length === 0) {\n return (\n <div className=\"p-density-6 text-center text-muted-foreground text-sm\">{emptyLabel}</div>\n );\n }\n\n return (\n // A flex column, not a plain block: DataTable sizes itself as `flex-1\n // min-h-0` so its own scroll region can be bounded, and in a block parent\n // that resolves to content height — the table grows past the panel and\n // nothing scrolls.\n <div className={`flex h-full min-h-0 flex-col ${className ?? \"\"}`}>\n <HarClockContext.Provider value={now}>\n <DataTable\n data={filteredEntries}\n columns={COLS}\n autoFilter\n showGlobalFilter={search === undefined}\n globalFilterPlaceholder=\"Filter URL, method, or body…\"\n defaultSort={{ key: \"time\", dir: \"asc\" }}\n emptyMessage={emptyLabel}\n {...(menuActions ? { menuActions } : {})}\n {...(runningCount > 0\n ? {\n footer: ({ visibleRowCount, totalRowCount }: DataTableFooterContext) =>\n `${visibleRowCount} of ${totalRowCount} row${totalRowCount === 1 ? \"\" : \"s\"} · ${runningCount} running`,\n }\n : {})}\n getRowId={(entry, index) =>\n // `_id` is the same on a request's pending and completed snapshots,\n // so an expanded row survives the transition. Without it, leave out\n // an in-flight entry's `time`, which grows with every snapshot.\n entry._id ??\n `${entry.startedDateTime ?? index}-${entry.request.method}-${entry.request.url}${entry._pending ? \"-pending\" : `-${entry.time}`}`\n }\n renderExpandedRow={(entry) => <HarEntryDetails entry={entry} bodySource={bodySource} />}\n />\n </HarClockContext.Provider>\n </div>\n );\n}\n\nfunction HarStatus({ status, entry }: { status: number; entry: HAREntry }) {\n if (entry._pending) {\n return (\n <span className=\"inline-flex items-center gap-1 text-muted-foreground\">\n <Icon icon={UiLoader} className=\"animate-spin\" />\n running\n </span>\n );\n }\n if (entry._error) return <span className=\"font-semibold text-destructive\">ERR</span>;\n return <span className={statusColor(status)}>{String(status)}</span>;\n}\n\nfunction PendingElapsed({ entry }: { entry: HAREntry }) {\n const now = useContext(HarClockContext);\n if (now === undefined) throw new Error(\"PendingElapsed must render inside HarPanel's clock\");\n return <span className=\"tabular-nums\">{formatDuration(pendingElapsedMs(entry, now))}</span>;\n}\n\n/**\n * Elapsed time of an in-flight request, measured from `startedDateTime` so it\n * keeps ticking between snapshots. The snapshot's `time` is only used when the\n * start timestamp cannot be parsed.\n */\nfunction pendingElapsedMs(entry: HAREntry, now: number): number {\n const started = Date.parse(entry.startedDateTime ?? \"\");\n if (Number.isNaN(started)) return entry.time;\n // Server and browser clocks can disagree by a little; a negative elapsed is noise.\n return Math.max(0, now - started);\n}\n\nfunction harStatusLabel(status: number, entry: HAREntry): string {\n if (entry._pending) return \"running\";\n if (entry._error) return \"ERR\";\n return String(status);\n}\n\nfunction previewError(error: string): string {\n return error.length > ERROR_PREVIEW_CHARS ? `${error.slice(0, ERROR_PREVIEW_CHARS)}…` : error;\n}\n\nexport function HarEntryDetails({ entry, bodySource }: HarEntryDetailsProps) {\n const parentNow = useContext(HarClockContext);\n const ownNow = useResourceClock(Boolean(entry._pending) && parentNow === undefined);\n return <HarClockContext.Provider value={parentNow ?? ownNow}><HarRowDetails entry={entry} bodySource={bodySource} /></HarClockContext.Provider>;\n}\n\nfunction HarRowDetails({ entry, bodySource }: HarEntryDetailsProps) {\n return (\n <>\n {entry._error && (\n <div className=\"mb-density-3\">\n <div className=\"font-semibold text-foreground mb-1\">Transport Error</div>\n <pre className=\"whitespace-pre-wrap break-all text-destructive\">{entry._error}</pre>\n </div>\n )}\n {entry._pending && (\n <div className=\"mb-density-3 text-muted-foreground\">\n Waiting for response — in flight for <PendingElapsed entry={entry} />\n </div>\n )}\n <div className=\"grid grid-cols-2 gap-density-4\">\n <div>\n <HeaderList\n title=\"Request Headers\"\n {...(entry.request.headers ? { headers: entry.request.headers } : {})}\n />\n {(entry.request.postData?.text || bodySource?.hasBody(entry, \"request\")) && (\n <BodySection entry={entry} part=\"request\" text={entry.request.postData?.text}\n mimeType={entry.request.postData?.mimeType} bodySource={bodySource} />\n )}\n </div>\n <div>\n <HeaderList\n title=\"Response Headers\"\n {...(entry.response.headers ? { headers: entry.response.headers } : {})}\n />\n </div>\n </div>\n {(entry.response.content?.text || bodySource?.hasBody(entry, \"response\")) && (\n <BodySection entry={entry} part=\"response\" text={entry.response.content?.text}\n mimeType={entry.response.content?.mimeType} bodySource={bodySource} />\n )}\n </>\n );\n}\n\nfunction BodySection({ entry, part, text, mimeType, bodySource }: {\n entry: HAREntry;\n part: \"request\" | \"response\";\n text?: string | undefined;\n mimeType?: string | undefined;\n bodySource?: HarPanelBodySource | undefined;\n}) {\n const remote = !text && bodySource?.hasBody(entry, part);\n const requestId = entry._id;\n if (remote && !requestId) throw new Error(\"Private HAR body requires a request ID\");\n const [preview, setPreview] = useState<string | undefined>();\n const [error, setError] = useState<Error | undefined>();\n useEffect(() => {\n if (!remote || !bodySource || !requestId) return;\n let active = true;\n setPreview(undefined);\n setError(undefined);\n bodySource.preview(requestId, part).then(\n (value) => { if (active) setPreview(value); },\n (reason: unknown) => { if (active) setError(reason instanceof Error ? reason : new Error(String(reason))); },\n );\n return () => { active = false; };\n }, [bodySource, requestId, part, remote]);\n return (\n <div className=\"mt-density-3\">\n <div className=\"mb-1 flex items-center gap-2 font-semibold text-foreground\">\n {part === \"request\" ? \"Request Body\" : \"Response Body\"}\n {remote && bodySource && <a className=\"text-sm font-normal text-primary underline\" href={bodySource.downloadHref(entry, part)} download>Download full body</a>}\n </div>\n <div className=\"bg-background p-density-2 rounded border border-border overflow-auto max-h-64\">\n {error ? <span role=\"alert\" className=\"text-destructive\">{error.message}</span>\n : remote && preview === undefined ? <span className=\"text-muted-foreground\">Loading preview…</span>\n : <BodyView text={text || preview || \"\"} {...(mimeType ? { mimeType } : {})} />}\n </div>\n {remote && <p className=\"mt-1 text-xs text-muted-foreground\">Preview shows at most the first 64 KiB.</p>}\n </div>\n );\n}\n\nfunction HeaderList({\n title,\n headers,\n}: {\n title: string;\n headers?: { name: string; value: string }[];\n}) {\n return (\n <>\n <div className=\"font-semibold text-foreground mb-1\">{title}</div>\n <div className=\"space-y-0.5\">\n {headers?.map((h, i) => (\n <div key={i} className=\"whitespace-nowrap\">\n <span className=\"text-purple-600 dark:text-purple-400\">{h.name}:</span> {h.value}\n </div>\n ))}\n </div>\n </>\n );\n}\n\nfunction BodyView({ text, mimeType }: { text: string; mimeType?: string }) {\n if (isJsonType(mimeType)) {\n const parsed = tryParseJson(text);\n if (parsed !== null) return <JsonView data={parsed} />;\n }\n return <pre className=\"whitespace-pre-wrap break-all\">{text}</pre>;\n}\n\nfunction tryParseJson(text: string): unknown | null {\n try {\n return JSON.parse(text);\n } catch {\n return null;\n }\n}\n\nfunction isJsonType(mime?: string): boolean {\n return !!mime && (mime.includes(\"json\") || mime.includes(\"javascript\"));\n}\n\nfunction matchesSearch(needle: string, entry: HAREntry): boolean {\n return [\n entry.request.method,\n entry.request.url,\n entry.request.postData?.text,\n entry.response.content?.text,\n entry._error,\n ].some((value) => !!value && value.toLowerCase().includes(needle));\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 0) return \"\";\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / 1024 / 1024).toFixed(1)}MB`;\n}\n\nfunction statusColor(status: number): string {\n if (status >= 500) return \"text-red-600\";\n if (status >= 400) return \"text-amber-600\";\n if (status >= 300) return \"text-blue-600\";\n if (status >= 200) return \"text-green-600\";\n return \"text-muted-foreground\";\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const JsonView = require("../JsonView.cjs");
5
+ const utils = require("../../lib/utils.cjs");
6
+ function formatValue(value) {
7
+ if (typeof value === "string") return value;
8
+ return JSON.stringify(value);
9
+ }
10
+ function isStructured(value) {
11
+ if (Array.isArray(value)) return value.some((item) => item !== null && typeof item === "object");
12
+ return value !== null && typeof value === "object";
13
+ }
14
+ function Value({
15
+ value,
16
+ tree = false,
17
+ className
18
+ }) {
19
+ if (tree && isStructured(value)) return /* @__PURE__ */ jsxRuntime.jsx(JsonView.JsonView, { data: value });
20
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: utils.cn("whitespace-pre-wrap break-words font-mono", className), children: formatValue(value) });
21
+ }
22
+ function Row({ label, children }) {
23
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
24
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { className: "text-muted-foreground", children: label }),
25
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { className: "min-w-0", children })
26
+ ] });
27
+ }
28
+ function Expectation({
29
+ check,
30
+ checkLabel = "matcher",
31
+ expected,
32
+ actual,
33
+ vars,
34
+ location,
35
+ className
36
+ }) {
37
+ const varEntries = Object.entries(vars ?? {});
38
+ return /* @__PURE__ */ jsxRuntime.jsxs(
39
+ "dl",
40
+ {
41
+ className: utils.cn(
42
+ "grid grid-cols-[auto_minmax(0,1fr)] items-baseline gap-x-3 gap-y-0.5 rounded border border-border bg-muted/30 px-2 py-1.5 text-[11px]",
43
+ className
44
+ ),
45
+ "data-expectation": "",
46
+ children: [
47
+ check && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: checkLabel, children: /* @__PURE__ */ jsxRuntime.jsx(Value, { value: check }) }),
48
+ varEntries.map(([name, value]) => /* @__PURE__ */ jsxRuntime.jsx(Row, { label: name, children: /* @__PURE__ */ jsxRuntime.jsx(Value, { value, tree: true }) }, name)),
49
+ expected !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "expected", children: /* @__PURE__ */ jsxRuntime.jsx(Value, { value: expected, className: "text-emerald-700 dark:text-emerald-400" }) }),
50
+ actual !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "actual", children: /* @__PURE__ */ jsxRuntime.jsx(Value, { value: actual, className: "text-red-700 dark:text-red-400" }) }),
51
+ location && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "at", children: /* @__PURE__ */ jsxRuntime.jsx(Value, { value: location, className: "text-muted-foreground" }) })
52
+ ]
53
+ }
54
+ );
55
+ }
56
+ exports.Expectation = Expectation;
57
+ //# sourceMappingURL=Expectation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Expectation.cjs","sources":["../../../src/data/test-runner/Expectation.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { JsonView } from \"../JsonView\";\nimport { cn } from \"../../lib/utils\";\n\nexport type ExpectationProps = {\n /** What decided the verdict: a matcher name (`Equal`) or a CEL expression. */\n check?: string | undefined;\n /** Label for `check`; defaults to \"matcher\". */\n checkLabel?: string | undefined;\n expected?: unknown;\n actual?: unknown;\n /** Variables the check saw (CEL `cel_vars`). */\n vars?: Record<string, unknown> | undefined;\n location?: string | undefined;\n className?: string | undefined;\n};\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return value;\n return JSON.stringify(value);\n}\n\n// A recorder summary or a list of rows nests too deep to read as one line.\nfunction isStructured(value: unknown): boolean {\n if (Array.isArray(value)) return value.some((item) => item !== null && typeof item === \"object\");\n return value !== null && typeof value === \"object\";\n}\n\nfunction Value({\n value,\n tree = false,\n className,\n}: {\n value: unknown;\n /** Expand a structured value as a tree instead of one JSON line. */\n tree?: boolean;\n className?: string;\n}) {\n if (tree && isStructured(value)) return <JsonView data={value} />;\n return (\n <code className={cn(\"whitespace-pre-wrap break-words font-mono\", className)}>\n {formatValue(value)}\n </code>\n );\n}\n\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <>\n <dt className=\"text-muted-foreground\">{label}</dt>\n <dd className=\"min-w-0\">{children}</dd>\n </>\n );\n}\n\n/**\n * One compact label/value grid for what a check expected and what it got —\n * shared by test failures (matcher, expected, actual, location) and CEL\n * assertions (expression, variables, expected, actual).\n */\nexport function Expectation({\n check,\n checkLabel = \"matcher\",\n expected,\n actual,\n vars,\n location,\n className,\n}: ExpectationProps) {\n const varEntries = Object.entries(vars ?? {});\n return (\n <dl\n className={cn(\n \"grid grid-cols-[auto_minmax(0,1fr)] items-baseline gap-x-3 gap-y-0.5 rounded border border-border bg-muted/30 px-2 py-1.5 text-[11px]\",\n className,\n )}\n data-expectation=\"\"\n >\n {check && (\n <Row label={checkLabel}>\n <Value value={check} />\n </Row>\n )}\n {varEntries.map(([name, value]) => (\n <Row key={name} label={name}>\n <Value value={value} tree />\n </Row>\n ))}\n {expected !== undefined && (\n <Row label=\"expected\">\n <Value value={expected} className=\"text-emerald-700 dark:text-emerald-400\" />\n </Row>\n )}\n {actual !== undefined && (\n <Row label=\"actual\">\n <Value value={actual} className=\"text-red-700 dark:text-red-400\" />\n </Row>\n )}\n {location && (\n <Row label=\"at\">\n <Value value={location} className=\"text-muted-foreground\" />\n </Row>\n )}\n </dl>\n );\n}\n"],"names":["jsx","JsonView","cn","jsxs","Fragment"],"mappings":";;;;;AAiBA,SAAS,YAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,KAAK,UAAU,KAAK;AAC7B;AAGA,SAAS,aAAa,OAAyB;AAC7C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,KAAK,CAAC,SAAS,SAAS,QAAQ,OAAO,SAAS,QAAQ;AAC/F,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;AAEA,SAAS,MAAM;AAAA,EACb;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,MAAI,QAAQ,aAAa,KAAK,UAAUA,2BAAAA,IAACC,mBAAA,EAAS,MAAM,OAAO;AAC/D,SACED,+BAAC,UAAK,WAAWE,MAAAA,GAAG,6CAA6C,SAAS,GACvE,UAAA,YAAY,KAAK,EAAA,CACpB;AAEJ;AAEA,SAAS,IAAI,EAAE,OAAO,YAAoD;AACxE,SACEC,2BAAAA,KAAAC,qBAAA,EACE,UAAA;AAAA,IAAAJ,2BAAAA,IAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IAC7CA,2BAAAA,IAAC,MAAA,EAAG,WAAU,WAAW,SAAA,CAAS;AAAA,EAAA,GACpC;AAEJ;AAOO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,aAAa,OAAO,QAAQ,QAAQ,CAAA,CAAE;AAC5C,SACEG,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWD,MAAAA;AAAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,oBAAiB;AAAA,MAEhB,UAAA;AAAA,QAAA,SACCF,2BAAAA,IAAC,OAAI,OAAO,YACV,yCAAC,OAAA,EAAM,OAAO,OAAO,EAAA,CACvB;AAAA,QAED,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,MAC3BA,2BAAAA,IAAC,KAAA,EAAe,OAAO,MACrB,yCAAC,OAAA,EAAM,OAAc,MAAI,KAAA,CAAC,KADlB,IAEV,CACD;AAAA,QACA,aAAa,UACZA,2BAAAA,IAAC,KAAA,EAAI,OAAM,YACT,UAAAA,2BAAAA,IAAC,OAAA,EAAM,OAAO,UAAU,WAAU,yCAAA,CAAyC,GAC7E;AAAA,QAED,WAAW,UACVA,2BAAAA,IAAC,KAAA,EAAI,OAAM,UACT,UAAAA,2BAAAA,IAAC,OAAA,EAAM,OAAO,QAAQ,WAAU,iCAAA,CAAiC,GACnE;AAAA,QAED,YACCA,2BAAAA,IAAC,KAAA,EAAI,OAAM,MACT,UAAAA,2BAAAA,IAAC,OAAA,EAAM,OAAO,UAAU,WAAU,wBAAA,CAAwB,EAAA,CAC5D;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;;"}
@@ -0,0 +1,19 @@
1
+ export type ExpectationProps = {
2
+ /** What decided the verdict: a matcher name (`Equal`) or a CEL expression. */
3
+ check?: string | undefined;
4
+ /** Label for `check`; defaults to "matcher". */
5
+ checkLabel?: string | undefined;
6
+ expected?: unknown;
7
+ actual?: unknown;
8
+ /** Variables the check saw (CEL `cel_vars`). */
9
+ vars?: Record<string, unknown> | undefined;
10
+ location?: string | undefined;
11
+ className?: string | undefined;
12
+ };
13
+ /**
14
+ * One compact label/value grid for what a check expected and what it got —
15
+ * shared by test failures (matcher, expected, actual, location) and CEL
16
+ * assertions (expression, variables, expected, actual).
17
+ */
18
+ export declare function Expectation({ check, checkLabel, expected, actual, vars, location, className, }: ExpectationProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=Expectation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Expectation.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/Expectation.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAwCF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,UAAsB,EACtB,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,SAAS,GACV,EAAE,gBAAgB,+BAqClB"}
@@ -0,0 +1,57 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { JsonView } from "../JsonView.js";
3
+ import { cn } from "../../lib/utils.js";
4
+ function formatValue(value) {
5
+ if (typeof value === "string") return value;
6
+ return JSON.stringify(value);
7
+ }
8
+ function isStructured(value) {
9
+ if (Array.isArray(value)) return value.some((item) => item !== null && typeof item === "object");
10
+ return value !== null && typeof value === "object";
11
+ }
12
+ function Value({
13
+ value,
14
+ tree = false,
15
+ className
16
+ }) {
17
+ if (tree && isStructured(value)) return /* @__PURE__ */ jsx(JsonView, { data: value });
18
+ return /* @__PURE__ */ jsx("code", { className: cn("whitespace-pre-wrap break-words font-mono", className), children: formatValue(value) });
19
+ }
20
+ function Row({ label, children }) {
21
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
22
+ /* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: label }),
23
+ /* @__PURE__ */ jsx("dd", { className: "min-w-0", children })
24
+ ] });
25
+ }
26
+ function Expectation({
27
+ check,
28
+ checkLabel = "matcher",
29
+ expected,
30
+ actual,
31
+ vars,
32
+ location,
33
+ className
34
+ }) {
35
+ const varEntries = Object.entries(vars ?? {});
36
+ return /* @__PURE__ */ jsxs(
37
+ "dl",
38
+ {
39
+ className: cn(
40
+ "grid grid-cols-[auto_minmax(0,1fr)] items-baseline gap-x-3 gap-y-0.5 rounded border border-border bg-muted/30 px-2 py-1.5 text-[11px]",
41
+ className
42
+ ),
43
+ "data-expectation": "",
44
+ children: [
45
+ check && /* @__PURE__ */ jsx(Row, { label: checkLabel, children: /* @__PURE__ */ jsx(Value, { value: check }) }),
46
+ varEntries.map(([name, value]) => /* @__PURE__ */ jsx(Row, { label: name, children: /* @__PURE__ */ jsx(Value, { value, tree: true }) }, name)),
47
+ expected !== void 0 && /* @__PURE__ */ jsx(Row, { label: "expected", children: /* @__PURE__ */ jsx(Value, { value: expected, className: "text-emerald-700 dark:text-emerald-400" }) }),
48
+ actual !== void 0 && /* @__PURE__ */ jsx(Row, { label: "actual", children: /* @__PURE__ */ jsx(Value, { value: actual, className: "text-red-700 dark:text-red-400" }) }),
49
+ location && /* @__PURE__ */ jsx(Row, { label: "at", children: /* @__PURE__ */ jsx(Value, { value: location, className: "text-muted-foreground" }) })
50
+ ]
51
+ }
52
+ );
53
+ }
54
+ export {
55
+ Expectation
56
+ };
57
+ //# sourceMappingURL=Expectation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Expectation.js","sources":["../../../src/data/test-runner/Expectation.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { JsonView } from \"../JsonView\";\nimport { cn } from \"../../lib/utils\";\n\nexport type ExpectationProps = {\n /** What decided the verdict: a matcher name (`Equal`) or a CEL expression. */\n check?: string | undefined;\n /** Label for `check`; defaults to \"matcher\". */\n checkLabel?: string | undefined;\n expected?: unknown;\n actual?: unknown;\n /** Variables the check saw (CEL `cel_vars`). */\n vars?: Record<string, unknown> | undefined;\n location?: string | undefined;\n className?: string | undefined;\n};\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return value;\n return JSON.stringify(value);\n}\n\n// A recorder summary or a list of rows nests too deep to read as one line.\nfunction isStructured(value: unknown): boolean {\n if (Array.isArray(value)) return value.some((item) => item !== null && typeof item === \"object\");\n return value !== null && typeof value === \"object\";\n}\n\nfunction Value({\n value,\n tree = false,\n className,\n}: {\n value: unknown;\n /** Expand a structured value as a tree instead of one JSON line. */\n tree?: boolean;\n className?: string;\n}) {\n if (tree && isStructured(value)) return <JsonView data={value} />;\n return (\n <code className={cn(\"whitespace-pre-wrap break-words font-mono\", className)}>\n {formatValue(value)}\n </code>\n );\n}\n\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <>\n <dt className=\"text-muted-foreground\">{label}</dt>\n <dd className=\"min-w-0\">{children}</dd>\n </>\n );\n}\n\n/**\n * One compact label/value grid for what a check expected and what it got —\n * shared by test failures (matcher, expected, actual, location) and CEL\n * assertions (expression, variables, expected, actual).\n */\nexport function Expectation({\n check,\n checkLabel = \"matcher\",\n expected,\n actual,\n vars,\n location,\n className,\n}: ExpectationProps) {\n const varEntries = Object.entries(vars ?? {});\n return (\n <dl\n className={cn(\n \"grid grid-cols-[auto_minmax(0,1fr)] items-baseline gap-x-3 gap-y-0.5 rounded border border-border bg-muted/30 px-2 py-1.5 text-[11px]\",\n className,\n )}\n data-expectation=\"\"\n >\n {check && (\n <Row label={checkLabel}>\n <Value value={check} />\n </Row>\n )}\n {varEntries.map(([name, value]) => (\n <Row key={name} label={name}>\n <Value value={value} tree />\n </Row>\n ))}\n {expected !== undefined && (\n <Row label=\"expected\">\n <Value value={expected} className=\"text-emerald-700 dark:text-emerald-400\" />\n </Row>\n )}\n {actual !== undefined && (\n <Row label=\"actual\">\n <Value value={actual} className=\"text-red-700 dark:text-red-400\" />\n </Row>\n )}\n {location && (\n <Row label=\"at\">\n <Value value={location} className=\"text-muted-foreground\" />\n </Row>\n )}\n </dl>\n );\n}\n"],"names":[],"mappings":";;;AAiBA,SAAS,YAAY,OAAwB;AAC3C,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,KAAK,UAAU,KAAK;AAC7B;AAGA,SAAS,aAAa,OAAyB;AAC7C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,KAAK,CAAC,SAAS,SAAS,QAAQ,OAAO,SAAS,QAAQ;AAC/F,SAAO,UAAU,QAAQ,OAAO,UAAU;AAC5C;AAEA,SAAS,MAAM;AAAA,EACb;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAKG;AACD,MAAI,QAAQ,aAAa,KAAK,UAAU,oBAAC,UAAA,EAAS,MAAM,OAAO;AAC/D,SACE,oBAAC,UAAK,WAAW,GAAG,6CAA6C,SAAS,GACvE,UAAA,YAAY,KAAK,EAAA,CACpB;AAEJ;AAEA,SAAS,IAAI,EAAE,OAAO,YAAoD;AACxE,SACE,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA,oBAAC,MAAA,EAAG,WAAU,yBAAyB,UAAA,OAAM;AAAA,IAC7C,oBAAC,MAAA,EAAG,WAAU,WAAW,SAAA,CAAS;AAAA,EAAA,GACpC;AAEJ;AAOO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,aAAa,OAAO,QAAQ,QAAQ,CAAA,CAAE;AAC5C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,oBAAiB;AAAA,MAEhB,UAAA;AAAA,QAAA,SACC,oBAAC,OAAI,OAAO,YACV,8BAAC,OAAA,EAAM,OAAO,OAAO,EAAA,CACvB;AAAA,QAED,WAAW,IAAI,CAAC,CAAC,MAAM,KAAK,MAC3B,oBAAC,KAAA,EAAe,OAAO,MACrB,8BAAC,OAAA,EAAM,OAAc,MAAI,KAAA,CAAC,KADlB,IAEV,CACD;AAAA,QACA,aAAa,UACZ,oBAAC,KAAA,EAAI,OAAM,YACT,UAAA,oBAAC,OAAA,EAAM,OAAO,UAAU,WAAU,yCAAA,CAAyC,GAC7E;AAAA,QAED,WAAW,UACV,oBAAC,KAAA,EAAI,OAAM,UACT,UAAA,oBAAC,OAAA,EAAM,OAAO,QAAQ,WAAU,iCAAA,CAAiC,GACnE;AAAA,QAED,YACC,oBAAC,KAAA,EAAI,OAAM,MACT,UAAA,oBAAC,OAAA,EAAM,OAAO,UAAU,WAAU,wBAAA,CAAwB,EAAA,CAC5D;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const Icon = require("../Icon.cjs");
5
+ const utils = require("../../lib/utils.cjs");
6
+ const marks = require("./marks.cjs");
7
+ function MarkIcon({ mark, className }) {
8
+ return /* @__PURE__ */ jsxRuntime.jsx(
9
+ Icon.Icon,
10
+ {
11
+ icon: mark.icon,
12
+ title: mark.label,
13
+ className: utils.cn(
14
+ "shrink-0",
15
+ mark.className,
16
+ "spin" in mark && mark.spin && "motion-safe:animate-spin",
17
+ className
18
+ )
19
+ }
20
+ );
21
+ }
22
+ function OutcomeIcon({ outcome, className }) {
23
+ return /* @__PURE__ */ jsxRuntime.jsx(MarkIcon, { mark: marks.TEST_OUTCOMES[outcome], className });
24
+ }
25
+ function LintSeverityIcon({
26
+ severity,
27
+ className
28
+ }) {
29
+ return /* @__PURE__ */ jsxRuntime.jsx(MarkIcon, { mark: marks.LINT_SEVERITIES[severity], className });
30
+ }
31
+ function ToolIcon({ tool, className }) {
32
+ const mark = marks.toolMark(tool);
33
+ return mark ? /* @__PURE__ */ jsxRuntime.jsx(MarkIcon, { mark, className }) : null;
34
+ }
35
+ exports.LintSeverityIcon = LintSeverityIcon;
36
+ exports.OutcomeIcon = OutcomeIcon;
37
+ exports.ToolIcon = ToolIcon;
38
+ //# sourceMappingURL=MarkIcons.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkIcons.cjs","sources":["../../../src/data/test-runner/MarkIcons.tsx"],"sourcesContent":["// Renders the marks.ts catalogs. Kept apart from them so this file exports\n// components only (react/only-export-components).\n\nimport { Icon } from \"../Icon\";\nimport { cn } from \"../../lib/utils\";\nimport {\n LINT_SEVERITIES,\n TEST_OUTCOMES,\n toolMark,\n type LintSeverity,\n type ResultMark,\n type TestOutcome,\n type ToolMark,\n} from \"./marks\";\n\ntype MarkIconProps = { className?: string | undefined };\n\nfunction MarkIcon({ mark, className }: MarkIconProps & { mark: ResultMark | ToolMark }) {\n return (\n <Icon\n icon={mark.icon}\n title={mark.label}\n className={cn(\n \"shrink-0\",\n mark.className,\n \"spin\" in mark && mark.spin && \"motion-safe:animate-spin\",\n className,\n )}\n />\n );\n}\n\nexport function OutcomeIcon({ outcome, className }: MarkIconProps & { outcome: TestOutcome }) {\n return <MarkIcon mark={TEST_OUTCOMES[outcome]} className={className} />;\n}\n\nexport function LintSeverityIcon({\n severity,\n className,\n}: MarkIconProps & { severity: LintSeverity }) {\n return <MarkIcon mark={LINT_SEVERITIES[severity]} className={className} />;\n}\n\nexport function ToolIcon({ tool, className }: MarkIconProps & { tool: string | undefined }) {\n const mark = toolMark(tool);\n return mark ? <MarkIcon mark={mark} className={className} /> : null;\n}\n"],"names":["jsx","Icon","cn","TEST_OUTCOMES","LINT_SEVERITIES","toolMark"],"mappings":";;;;;;AAiBA,SAAS,SAAS,EAAE,MAAM,aAA8D;AACtF,SACEA,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,WAAWC,MAAAA;AAAAA,QACT;AAAA,QACA,KAAK;AAAA,QACL,UAAU,QAAQ,KAAK,QAAQ;AAAA,QAC/B;AAAA,MAAA;AAAA,IACF;AAAA,EAAA;AAGN;AAEO,SAAS,YAAY,EAAE,SAAS,aAAuD;AAC5F,wCAAQ,UAAA,EAAS,MAAMC,MAAAA,cAAc,OAAO,GAAG,WAAsB;AACvE;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GAA+C;AAC7C,wCAAQ,UAAA,EAAS,MAAMC,MAAAA,gBAAgB,QAAQ,GAAG,WAAsB;AAC1E;AAEO,SAAS,SAAS,EAAE,MAAM,aAA2D;AAC1F,QAAM,OAAOC,MAAAA,SAAS,IAAI;AAC1B,SAAO,OAAOL,2BAAAA,IAAC,UAAA,EAAS,MAAY,WAAsB,IAAK;AACjE;;;;"}
@@ -0,0 +1,15 @@
1
+ import { LintSeverity, TestOutcome } from './marks.js';
2
+ type MarkIconProps = {
3
+ className?: string | undefined;
4
+ };
5
+ export declare function OutcomeIcon({ outcome, className }: MarkIconProps & {
6
+ outcome: TestOutcome;
7
+ }): import("react").JSX.Element;
8
+ export declare function LintSeverityIcon({ severity, className, }: MarkIconProps & {
9
+ severity: LintSeverity;
10
+ }): import("react").JSX.Element;
11
+ export declare function ToolIcon({ tool, className }: MarkIconProps & {
12
+ tool: string | undefined;
13
+ }): import("react").JSX.Element | null;
14
+ export {};
15
+ //# sourceMappingURL=MarkIcons.d.ts.map