@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
@@ -5,6 +5,7 @@ const react = require("react");
5
5
  const Icon = require("../Icon.cjs");
6
6
  const SplitPane = require("../../layout/SplitPane.cjs");
7
7
  const utils = require("../../lib/utils.cjs");
8
+ const useContainerWidth = require("../../hooks/use-container-width.cjs");
8
9
  const status = require("./status.cjs");
9
10
  const adapter = require("./adapter.cjs");
10
11
  const context = require("./context.cjs");
@@ -13,10 +14,12 @@ const TestDetailPanel = require("./TestDetailPanel.cjs");
13
14
  const TestRunSummary = require("./TestRunSummary.cjs");
14
15
  const TestFilterBar = require("./TestFilterBar.cjs");
15
16
  const UiBeaker = require("../../icons/components/UiBeaker.cjs");
17
+ const UiArrowLeft = require("../../icons/components/UiArrowLeft.cjs");
16
18
  function toRegistry(adapters) {
17
19
  if (adapters instanceof adapter.TestNodeAdapterRegistry) return adapters;
18
20
  return adapter.createTestRunnerRegistry(adapters ?? []);
19
21
  }
22
+ const SPLIT_MIN_WIDTH = 640;
20
23
  function TestRunner({
21
24
  tests,
22
25
  allTests,
@@ -31,6 +34,8 @@ function TestRunner({
31
34
  busy,
32
35
  activeTab,
33
36
  onTabChange,
37
+ activeAttempt,
38
+ onAttemptChange,
34
39
  onSelect,
35
40
  onFiltersChange,
36
41
  onExpandAllChange,
@@ -60,6 +65,8 @@ function TestRunner({
60
65
  busy: busy ?? {},
61
66
  activeTab,
62
67
  onTabChange,
68
+ activeAttempt,
69
+ onAttemptChange,
63
70
  onSelect,
64
71
  onFiltersChange,
65
72
  onExpandAllChange,
@@ -79,6 +86,8 @@ function TestRunner({
79
86
  busy,
80
87
  activeTab,
81
88
  onTabChange,
89
+ activeAttempt,
90
+ onAttemptChange,
82
91
  onSelect,
83
92
  onFiltersChange,
84
93
  onExpandAllChange,
@@ -90,19 +99,30 @@ function TestRunner({
90
99
  const summaryTests = allTests ?? tests;
91
100
  const frameworks = react.useMemo(() => status.collectFrameworks(summaryTests), [summaryTests]);
92
101
  const filterCounts = react.useMemo(() => status.aggregateStatusCounts(summaryTests), [summaryTests]);
93
- const hasContent = summaryTests.length > 0;
94
- return /* @__PURE__ */ jsxRuntime.jsx(context.TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex h-full min-h-0 flex-col bg-background", className), children: [
95
- !hideHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border bg-card px-density-4 py-density-3", children: [
96
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3", children: [
97
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
98
- title === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "inline-flex items-center gap-1.5 text-lg font-bold", children: [
99
- /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiBeaker.UiBeaker, className: "text-primary" }),
100
- "Test Results"
101
- ] }) : title,
102
- statusText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: statusText })
103
- ] }),
104
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
105
- headerSlot,
102
+ const filterBar = !hideHeader && summaryTests.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
103
+ TestFilterBar.TestFilterBar,
104
+ {
105
+ filters,
106
+ onChange: onFiltersChange,
107
+ counts: filterCounts,
108
+ frameworks
109
+ }
110
+ ) : null;
111
+ const { ref, wider: roomy } = useContainerWidth.useContainerWiderThan(SPLIT_MIN_WIDTH);
112
+ return /* @__PURE__ */ jsxRuntime.jsx(context.TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: utils.cn("flex h-full min-h-0 flex-col bg-background", className), children: [
113
+ !hideHeader && /* @__PURE__ */ jsxRuntime.jsxs(
114
+ "div",
115
+ {
116
+ className: "flex min-w-0 items-center gap-3 border-b border-border bg-card px-density-4 py-density-2",
117
+ "data-runner-header": "",
118
+ children: [
119
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
120
+ title === void 0 ? /* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "inline-flex shrink-0 items-center gap-1.5 text-base font-bold", children: [
121
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiBeaker.UiBeaker, className: "text-primary" }),
122
+ "Test Results"
123
+ ] }) : title,
124
+ statusText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm text-muted-foreground", children: statusText })
125
+ ] }),
106
126
  showSummary && /* @__PURE__ */ jsxRuntime.jsx(
107
127
  TestRunSummary.TestRunSummary,
108
128
  {
@@ -111,22 +131,16 @@ function TestRunner({
111
131
  endTime,
112
132
  done,
113
133
  now,
114
- runMeta
134
+ runMeta,
135
+ compact: true,
136
+ className: "ml-auto flex-nowrap"
115
137
  }
116
- )
117
- ] })
118
- ] }),
119
- hasContent && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
120
- TestFilterBar.TestFilterBar,
121
- {
122
- filters,
123
- onChange: onFiltersChange,
124
- counts: filterCounts,
125
- frameworks
126
- }
127
- ) })
128
- ] }),
129
- /* @__PURE__ */ jsxRuntime.jsx(
138
+ ),
139
+ headerSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn("flex shrink-0 items-center gap-1", !showSummary && "ml-auto"), children: headerSlot })
140
+ ]
141
+ }
142
+ ),
143
+ roomy ? /* @__PURE__ */ jsxRuntime.jsx(
130
144
  SplitPane.SplitPane,
131
145
  {
132
146
  className: "min-h-0 flex-1",
@@ -134,10 +148,24 @@ function TestRunner({
134
148
  minLeft: 25,
135
149
  minRight: 30,
136
150
  leftClass: "border-r-2 border-border bg-muted/30",
137
- left: /* @__PURE__ */ jsxRuntime.jsx(TestTree.TestTree, {}),
151
+ left: /* @__PURE__ */ jsxRuntime.jsx(TestTree.TestTree, { actions: filterBar }),
138
152
  right: /* @__PURE__ */ jsxRuntime.jsx(TestDetailPanel.TestDetailPanel, {})
139
153
  }
140
- )
154
+ ) : selected ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
155
+ /* @__PURE__ */ jsxRuntime.jsxs(
156
+ "button",
157
+ {
158
+ type: "button",
159
+ onClick: () => onSelect(null),
160
+ className: "inline-flex items-center gap-1.5 border-b border-border px-density-3 py-density-2 text-left text-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
161
+ children: [
162
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiArrowLeft.UiArrowLeft }),
163
+ "Back to results"
164
+ ]
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(TestDetailPanel.TestDetailPanel, {}) })
168
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx(TestTree.TestTree, { actions: filterBar }) })
141
169
  ] }) });
142
170
  }
143
171
  exports.TestRunner = TestRunner;
@@ -1 +1 @@
1
- {"version":3,"file":"TestRunner.cjs","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiBeaker } from \"../../icons\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { aggregateStatusCounts, collectFrameworks } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n /**\n * The full, unfiltered forest driving the filter bar's pills/counts and the\n * header summary — falls back to `tests` when omitted (every existing\n * caller pre-filters `tests` itself). Pass this explicitly when `tests` is a\n * filtered subset of a larger report, so toggling a status filter (e.g.\n * excluding the only failed node) can't make its own pill — or the whole\n * filter bar, once every pill's count reads zero — disappear.\n */\n allTests?: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n /** Controlled active detail-tab id; omit to let the detail pane own tab state. */\n activeTab?: string;\n /** Called with the picked tab id when `activeTab` is controlled. */\n onTabChange?: (tabId: string) => void;\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /**\n * Header title. Defaults (when omitted) to the \"Test Results\" beaker heading.\n * Pass `null` to render no title — e.g. a host that owns the title in its own\n * dialog/page header and embeds the runner below it.\n */\n title?: ReactNode;\n /**\n * Render the built-in run summary (counts + progress) in the header. Defaults\n * to true; pass false when the host shows the summary itself (e.g. in a dialog\n * header) to avoid duplicating it.\n */\n showSummary?: boolean;\n /** Extra header content (e.g. export/download controls owned by the host). */\n headerSlot?: ReactNode;\n /**\n * Suppresses the entire built-in header bar (title, summary, filter row).\n * Defaults to false; pass true when a host renders its own combined header\n * (e.g. a dialog header that already embeds `TestRunSummary` and filters) so\n * the runner doesn't render a second bordered bar underneath it.\n */\n hideHeader?: boolean;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n allTests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n title,\n showSummary = true,\n headerSlot,\n hideHeader = false,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const summaryTests = allTests ?? tests;\n const frameworks = useMemo(() => collectFrameworks(summaryTests), [summaryTests]);\n const filterCounts = useMemo(() => aggregateStatusCounts(summaryTests), [summaryTests]);\n const hasContent = summaryTests.length > 0;\n\n return (\n <TestRunnerProvider value={ctx}>\n <div className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n {!hideHeader && (\n <div className=\"border-b border-border bg-card px-density-4 py-density-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n {title === undefined ? (\n <h1 className=\"inline-flex items-center gap-1.5 text-lg font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n ) : (\n title\n )}\n {statusText && <span className=\"text-sm text-muted-foreground\">{statusText}</span>}\n </div>\n <div className=\"flex items-center gap-3\">\n {headerSlot}\n {showSummary && (\n <TestRunSummary\n tests={summaryTests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n />\n )}\n </div>\n </div>\n {hasContent && (\n <div className=\"mt-2\">\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n </div>\n )}\n </div>\n )}\n\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree />}\n right={<TestDetailPanel />}\n />\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":["TestNodeAdapterRegistry","createTestRunnerRegistry","status","useMemo","collectFrameworks","aggregateStatusCounts","jsx","TestRunnerProvider","jsxs","cn","Icon","UiBeaker","TestRunSummary","TestFilterBar","SplitPane","TestTree","TestDetailPanel"],"mappings":"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"}
1
+ {"version":3,"file":"TestRunner.cjs","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiArrowLeft, UiBeaker } from \"../../icons\";\nimport { useContainerWiderThan } from \"../../hooks/use-container-width\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { aggregateStatusCounts, collectFrameworks } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n /**\n * The full, unfiltered forest driving the filter bar's pills/counts and the\n * header summary — falls back to `tests` when omitted (every existing\n * caller pre-filters `tests` itself). Pass this explicitly when `tests` is a\n * filtered subset of a larger report, so toggling a status filter (e.g.\n * excluding the only failed node) can't make its own pill — or the whole\n * filter bar, once every pill's count reads zero — disappear.\n */\n allTests?: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n /** Controlled active detail-tab id; omit to let the detail pane own tab state. */\n activeTab?: string;\n /** Called with the picked tab id when `activeTab` is controlled. */\n onTabChange?: (tabId: string) => void;\n activeAttempt?: number;\n onAttemptChange?: (attempt: number) => void;\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /**\n * Header title. Defaults (when omitted) to the \"Test Results\" beaker heading.\n * Pass `null` to render no title — e.g. a host that owns the title in its own\n * dialog/page header and embeds the runner below it.\n */\n title?: ReactNode;\n /**\n * Render the built-in run summary (counts + progress) in the header. Defaults\n * to true; pass false when the host shows the summary itself (e.g. in a dialog\n * header) to avoid duplicating it.\n */\n showSummary?: boolean;\n /** Run actions at the right end of the one-line header (e.g. re-run, export, copy). */\n headerSlot?: ReactNode;\n /**\n * Suppresses the built-in header bar (title, summary) and the status/tool\n * facets in the tree toolbar.\n * Defaults to false; pass true when a host renders its own combined header\n * (e.g. a dialog header that already embeds `TestRunSummary` and filters) so\n * the runner doesn't render a second bordered bar underneath it.\n */\n hideHeader?: boolean;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\nconst SPLIT_MIN_WIDTH = 640;\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n allTests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n title,\n showSummary = true,\n headerSlot,\n hideHeader = false,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const summaryTests = allTests ?? tests;\n const frameworks = useMemo(() => collectFrameworks(summaryTests), [summaryTests]);\n const filterCounts = useMemo(() => aggregateStatusCounts(summaryTests), [summaryTests]);\n // A host that hides the header renders its own filters (see hideHeader).\n const filterBar =\n !hideHeader && summaryTests.length > 0 ? (\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n ) : null;\n // Below this the split leaves both panes too narrow to read, so the runner\n // goes master/detail: the tree, then the selected test with a way back.\n const { ref, wider: roomy } = useContainerWiderThan(SPLIT_MIN_WIDTH);\n\n return (\n <TestRunnerProvider value={ctx}>\n <div ref={ref} className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n {!hideHeader && (\n <div\n className=\"flex min-w-0 items-center gap-3 border-b border-border bg-card px-density-4 py-density-2\"\n data-runner-header=\"\"\n >\n <div className=\"flex min-w-0 items-center gap-3\">\n {title === undefined ? (\n <h1 className=\"inline-flex shrink-0 items-center gap-1.5 text-base font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n ) : (\n title\n )}\n {statusText && (\n <span className=\"truncate text-sm text-muted-foreground\">{statusText}</span>\n )}\n </div>\n {showSummary && (\n <TestRunSummary\n tests={summaryTests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n compact\n className=\"ml-auto flex-nowrap\"\n />\n )}\n {headerSlot && (\n <div className={cn(\"flex shrink-0 items-center gap-1\", !showSummary && \"ml-auto\")}>\n {headerSlot}\n </div>\n )}\n </div>\n )}\n\n {roomy ? (\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree actions={filterBar} />}\n right={<TestDetailPanel />}\n />\n ) : selected ? (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <button\n type=\"button\"\n onClick={() => onSelect(null)}\n className=\"inline-flex items-center gap-1.5 border-b border-border px-density-3 py-density-2 text-left text-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiArrowLeft} />\n Back to results\n </button>\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <TestDetailPanel />\n </div>\n </div>\n ) : (\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n <TestTree actions={filterBar} />\n </div>\n )}\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":["TestNodeAdapterRegistry","createTestRunnerRegistry","status","useMemo","collectFrameworks","aggregateStatusCounts","jsx","TestFilterBar","useContainerWiderThan","TestRunnerProvider","jsxs","cn","Icon","UiBeaker","TestRunSummary","SplitPane","TestTree","TestDetailPanel","UiArrowLeft"],"mappings":"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"}
@@ -30,6 +30,8 @@ export type TestRunnerProps = {
30
30
  activeTab?: string;
31
31
  /** Called with the picked tab id when `activeTab` is controlled. */
32
32
  onTabChange?: (tabId: string) => void;
33
+ activeAttempt?: number;
34
+ onAttemptChange?: (attempt: number) => void;
33
35
  onSelect: (node: Test | null) => void;
34
36
  onFiltersChange: (next: TestFilters) => void;
35
37
  onExpandAllChange: (next: boolean | null) => void;
@@ -49,10 +51,11 @@ export type TestRunnerProps = {
49
51
  * header) to avoid duplicating it.
50
52
  */
51
53
  showSummary?: boolean;
52
- /** Extra header content (e.g. export/download controls owned by the host). */
54
+ /** Run actions at the right end of the one-line header (e.g. re-run, export, copy). */
53
55
  headerSlot?: ReactNode;
54
56
  /**
55
- * Suppresses the entire built-in header bar (title, summary, filter row).
57
+ * Suppresses the built-in header bar (title, summary) and the status/tool
58
+ * facets in the tree toolbar.
56
59
  * Defaults to false; pass true when a host renders its own combined header
57
60
  * (e.g. a dialog header that already embeds `TestRunSummary` and filters) so
58
61
  * the runner doesn't render a second bordered bar underneath it.
@@ -70,5 +73,5 @@ export type TestRunnerProps = {
70
73
  * are exposed to sub-components through a single `TestRunnerContext`. Domain
71
74
  * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.
72
75
  */
73
- export declare function TestRunner({ tests, allTests, selected, filters, expandAll, done, runMeta, status, statusText, now, busy, activeTab, onTabChange, onSelect, onFiltersChange, onExpandAllChange, onRerun, onStop, adapters, title, showSummary, headerSlot, hideHeader, defaultSplit, startTime, endTime, className, }: TestRunnerProps): import("react").JSX.Element;
76
+ export declare function TestRunner({ tests, allTests, selected, filters, expandAll, done, runMeta, status, statusText, now, busy, activeTab, onTabChange, activeAttempt, onAttemptChange, onSelect, onFiltersChange, onExpandAllChange, onRerun, onStop, adapters, title, showSummary, headerSlot, hideHeader, defaultSplit, startTime, endTime, className, }: TestRunnerProps): import("react").JSX.Element;
74
77
  //# sourceMappingURL=TestRunner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TestRunner.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestRunner.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKhD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAEL,KAAK,eAAe,EACpB,uBAAuB,EACxB,MAAM,WAAW,CAAC;AAOnB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAE3C,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEtC,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IACtC,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAE9B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,eAAe,EAAE,GAAG,uBAAuB,CAAC;IACvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AASF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,SAAS,EACT,IAAI,EACJ,OAAO,EACP,MAAM,EACN,UAAU,EACV,GAAG,EACH,IAAI,EACJ,SAAS,EACT,WAAW,EACX,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAkB,EAClB,UAAU,EACV,UAAkB,EAClB,YAAiB,EACjB,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE,eAAe,+BAyGjB"}
1
+ {"version":3,"file":"TestRunner.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestRunner.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMhD,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAEL,KAAK,eAAe,EACpB,uBAAuB,EACxB,MAAM,WAAW,CAAC;AAOnB,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,SAAS,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAE3C,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5C,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;IACtC,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAE9B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,eAAe,EAAE,GAAG,uBAAuB,CAAC;IACvD;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAWF;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,SAAS,EACT,IAAI,EACJ,OAAO,EACP,MAAM,EACN,UAAU,EACV,GAAG,EACH,IAAI,EACJ,SAAS,EACT,WAAW,EACX,aAAa,EACb,eAAe,EACf,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAkB,EAClB,UAAU,EACV,UAAkB,EAClB,YAAiB,EACjB,SAAS,EACT,OAAO,EACP,SAAS,GACV,EAAE,eAAe,+BA0IjB"}
@@ -3,6 +3,7 @@ import { useMemo } from "react";
3
3
  import { Icon } from "../Icon.js";
4
4
  import { SplitPane } from "../../layout/SplitPane.js";
5
5
  import { cn } from "../../lib/utils.js";
6
+ import { useContainerWiderThan } from "../../hooks/use-container-width.js";
6
7
  import { collectFrameworks, aggregateStatusCounts } from "./status.js";
7
8
  import { TestNodeAdapterRegistry, createTestRunnerRegistry } from "./adapter.js";
8
9
  import { TestRunnerProvider } from "./context.js";
@@ -11,10 +12,12 @@ import { TestDetailPanel } from "./TestDetailPanel.js";
11
12
  import { TestRunSummary } from "./TestRunSummary.js";
12
13
  import { TestFilterBar } from "./TestFilterBar.js";
13
14
  import { UiBeaker } from "../../icons/components/UiBeaker.js";
15
+ import { UiArrowLeft } from "../../icons/components/UiArrowLeft.js";
14
16
  function toRegistry(adapters) {
15
17
  if (adapters instanceof TestNodeAdapterRegistry) return adapters;
16
18
  return createTestRunnerRegistry(adapters ?? []);
17
19
  }
20
+ const SPLIT_MIN_WIDTH = 640;
18
21
  function TestRunner({
19
22
  tests,
20
23
  allTests,
@@ -29,6 +32,8 @@ function TestRunner({
29
32
  busy,
30
33
  activeTab,
31
34
  onTabChange,
35
+ activeAttempt,
36
+ onAttemptChange,
32
37
  onSelect,
33
38
  onFiltersChange,
34
39
  onExpandAllChange,
@@ -58,6 +63,8 @@ function TestRunner({
58
63
  busy: busy ?? {},
59
64
  activeTab,
60
65
  onTabChange,
66
+ activeAttempt,
67
+ onAttemptChange,
61
68
  onSelect,
62
69
  onFiltersChange,
63
70
  onExpandAllChange,
@@ -77,6 +84,8 @@ function TestRunner({
77
84
  busy,
78
85
  activeTab,
79
86
  onTabChange,
87
+ activeAttempt,
88
+ onAttemptChange,
80
89
  onSelect,
81
90
  onFiltersChange,
82
91
  onExpandAllChange,
@@ -88,19 +97,30 @@ function TestRunner({
88
97
  const summaryTests = allTests ?? tests;
89
98
  const frameworks = useMemo(() => collectFrameworks(summaryTests), [summaryTests]);
90
99
  const filterCounts = useMemo(() => aggregateStatusCounts(summaryTests), [summaryTests]);
91
- const hasContent = summaryTests.length > 0;
92
- return /* @__PURE__ */ jsx(TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-full min-h-0 flex-col bg-background", className), children: [
93
- !hideHeader && /* @__PURE__ */ jsxs("div", { className: "border-b border-border bg-card px-density-4 py-density-3", children: [
94
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
95
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
96
- title === void 0 ? /* @__PURE__ */ jsxs("h1", { className: "inline-flex items-center gap-1.5 text-lg font-bold", children: [
97
- /* @__PURE__ */ jsx(Icon, { icon: UiBeaker, className: "text-primary" }),
98
- "Test Results"
99
- ] }) : title,
100
- statusText && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: statusText })
101
- ] }),
102
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
103
- headerSlot,
100
+ const filterBar = !hideHeader && summaryTests.length > 0 ? /* @__PURE__ */ jsx(
101
+ TestFilterBar,
102
+ {
103
+ filters,
104
+ onChange: onFiltersChange,
105
+ counts: filterCounts,
106
+ frameworks
107
+ }
108
+ ) : null;
109
+ const { ref, wider: roomy } = useContainerWiderThan(SPLIT_MIN_WIDTH);
110
+ return /* @__PURE__ */ jsx(TestRunnerProvider, { value: ctx, children: /* @__PURE__ */ jsxs("div", { ref, className: cn("flex h-full min-h-0 flex-col bg-background", className), children: [
111
+ !hideHeader && /* @__PURE__ */ jsxs(
112
+ "div",
113
+ {
114
+ className: "flex min-w-0 items-center gap-3 border-b border-border bg-card px-density-4 py-density-2",
115
+ "data-runner-header": "",
116
+ children: [
117
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
118
+ title === void 0 ? /* @__PURE__ */ jsxs("h1", { className: "inline-flex shrink-0 items-center gap-1.5 text-base font-bold", children: [
119
+ /* @__PURE__ */ jsx(Icon, { icon: UiBeaker, className: "text-primary" }),
120
+ "Test Results"
121
+ ] }) : title,
122
+ statusText && /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-muted-foreground", children: statusText })
123
+ ] }),
104
124
  showSummary && /* @__PURE__ */ jsx(
105
125
  TestRunSummary,
106
126
  {
@@ -109,22 +129,16 @@ function TestRunner({
109
129
  endTime,
110
130
  done,
111
131
  now,
112
- runMeta
132
+ runMeta,
133
+ compact: true,
134
+ className: "ml-auto flex-nowrap"
113
135
  }
114
- )
115
- ] })
116
- ] }),
117
- hasContent && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
118
- TestFilterBar,
119
- {
120
- filters,
121
- onChange: onFiltersChange,
122
- counts: filterCounts,
123
- frameworks
124
- }
125
- ) })
126
- ] }),
127
- /* @__PURE__ */ jsx(
136
+ ),
137
+ headerSlot && /* @__PURE__ */ jsx("div", { className: cn("flex shrink-0 items-center gap-1", !showSummary && "ml-auto"), children: headerSlot })
138
+ ]
139
+ }
140
+ ),
141
+ roomy ? /* @__PURE__ */ jsx(
128
142
  SplitPane,
129
143
  {
130
144
  className: "min-h-0 flex-1",
@@ -132,10 +146,24 @@ function TestRunner({
132
146
  minLeft: 25,
133
147
  minRight: 30,
134
148
  leftClass: "border-r-2 border-border bg-muted/30",
135
- left: /* @__PURE__ */ jsx(TestTree, {}),
149
+ left: /* @__PURE__ */ jsx(TestTree, { actions: filterBar }),
136
150
  right: /* @__PURE__ */ jsx(TestDetailPanel, {})
137
151
  }
138
- )
152
+ ) : selected ? /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [
153
+ /* @__PURE__ */ jsxs(
154
+ "button",
155
+ {
156
+ type: "button",
157
+ onClick: () => onSelect(null),
158
+ className: "inline-flex items-center gap-1.5 border-b border-border px-density-3 py-density-2 text-left text-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
159
+ children: [
160
+ /* @__PURE__ */ jsx(Icon, { icon: UiArrowLeft }),
161
+ "Back to results"
162
+ ]
163
+ }
164
+ ),
165
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(TestDetailPanel, {}) })
166
+ ] }) : /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx(TestTree, { actions: filterBar }) })
139
167
  ] }) });
140
168
  }
141
169
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"TestRunner.js","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiBeaker } from \"../../icons\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { aggregateStatusCounts, collectFrameworks } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n /**\n * The full, unfiltered forest driving the filter bar's pills/counts and the\n * header summary — falls back to `tests` when omitted (every existing\n * caller pre-filters `tests` itself). Pass this explicitly when `tests` is a\n * filtered subset of a larger report, so toggling a status filter (e.g.\n * excluding the only failed node) can't make its own pill — or the whole\n * filter bar, once every pill's count reads zero — disappear.\n */\n allTests?: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n /** Controlled active detail-tab id; omit to let the detail pane own tab state. */\n activeTab?: string;\n /** Called with the picked tab id when `activeTab` is controlled. */\n onTabChange?: (tabId: string) => void;\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /**\n * Header title. Defaults (when omitted) to the \"Test Results\" beaker heading.\n * Pass `null` to render no title — e.g. a host that owns the title in its own\n * dialog/page header and embeds the runner below it.\n */\n title?: ReactNode;\n /**\n * Render the built-in run summary (counts + progress) in the header. Defaults\n * to true; pass false when the host shows the summary itself (e.g. in a dialog\n * header) to avoid duplicating it.\n */\n showSummary?: boolean;\n /** Extra header content (e.g. export/download controls owned by the host). */\n headerSlot?: ReactNode;\n /**\n * Suppresses the entire built-in header bar (title, summary, filter row).\n * Defaults to false; pass true when a host renders its own combined header\n * (e.g. a dialog header that already embeds `TestRunSummary` and filters) so\n * the runner doesn't render a second bordered bar underneath it.\n */\n hideHeader?: boolean;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n allTests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n title,\n showSummary = true,\n headerSlot,\n hideHeader = false,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n activeTab,\n onTabChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const summaryTests = allTests ?? tests;\n const frameworks = useMemo(() => collectFrameworks(summaryTests), [summaryTests]);\n const filterCounts = useMemo(() => aggregateStatusCounts(summaryTests), [summaryTests]);\n const hasContent = summaryTests.length > 0;\n\n return (\n <TestRunnerProvider value={ctx}>\n <div className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n {!hideHeader && (\n <div className=\"border-b border-border bg-card px-density-4 py-density-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-center gap-3\">\n {title === undefined ? (\n <h1 className=\"inline-flex items-center gap-1.5 text-lg font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n ) : (\n title\n )}\n {statusText && <span className=\"text-sm text-muted-foreground\">{statusText}</span>}\n </div>\n <div className=\"flex items-center gap-3\">\n {headerSlot}\n {showSummary && (\n <TestRunSummary\n tests={summaryTests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n />\n )}\n </div>\n </div>\n {hasContent && (\n <div className=\"mt-2\">\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n </div>\n )}\n </div>\n )}\n\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree />}\n right={<TestDetailPanel />}\n />\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TestRunner.js","sources":["../../../src/data/test-runner/TestRunner.tsx"],"sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { Icon } from \"../Icon\";\nimport { SplitPane } from \"../../layout/SplitPane\";\nimport { cn } from \"../../lib/utils\";\nimport { UiArrowLeft, UiBeaker } from \"../../icons\";\nimport { useContainerWiderThan } from \"../../hooks/use-container-width\";\nimport type { RunMeta, SnapshotStatus, Test } from \"./types\";\nimport { aggregateStatusCounts, collectFrameworks } from \"./status\";\nimport { type TestFilters } from \"./filterState\";\nimport {\n createTestRunnerRegistry,\n type TestNodeAdapter,\n TestNodeAdapterRegistry,\n} from \"./adapter\";\nimport { TestRunnerProvider, type TestRunnerContext } from \"./context\";\nimport { TestTree } from \"./TestTree\";\nimport { TestDetailPanel } from \"./TestDetailPanel\";\nimport { TestRunSummary } from \"./TestRunSummary\";\nimport { TestFilterBar } from \"./TestFilterBar\";\n\nexport type TestRunnerProps = {\n tests: Test[];\n /**\n * The full, unfiltered forest driving the filter bar's pills/counts and the\n * header summary — falls back to `tests` when omitted (every existing\n * caller pre-filters `tests` itself). Pass this explicitly when `tests` is a\n * filtered subset of a larger report, so toggling a status filter (e.g.\n * excluding the only failed node) can't make its own pill — or the whole\n * filter bar, once every pill's count reads zero — disappear.\n */\n allTests?: Test[];\n selected: Test | null;\n filters: TestFilters;\n expandAll: boolean | null;\n done: boolean;\n runMeta?: RunMeta;\n status?: SnapshotStatus;\n /** Free-form status line shown next to the title (e.g. \"Running tests...\"). */\n statusText?: string;\n now?: number;\n busy?: { rerun?: boolean; stop?: boolean };\n\n /** Controlled active detail-tab id; omit to let the detail pane own tab state. */\n activeTab?: string;\n /** Called with the picked tab id when `activeTab` is controlled. */\n onTabChange?: (tabId: string) => void;\n activeAttempt?: number;\n onAttemptChange?: (attempt: number) => void;\n\n onSelect: (node: Test | null) => void;\n onFiltersChange: (next: TestFilters) => void;\n onExpandAllChange: (next: boolean | null) => void;\n onRerun?: (node: Test) => void;\n onStop?: (node: Test) => void;\n\n /** Domain node adapters, or a pre-built registry. Defaults to default-only. */\n adapters?: TestNodeAdapter[] | TestNodeAdapterRegistry;\n /**\n * Header title. Defaults (when omitted) to the \"Test Results\" beaker heading.\n * Pass `null` to render no title — e.g. a host that owns the title in its own\n * dialog/page header and embeds the runner below it.\n */\n title?: ReactNode;\n /**\n * Render the built-in run summary (counts + progress) in the header. Defaults\n * to true; pass false when the host shows the summary itself (e.g. in a dialog\n * header) to avoid duplicating it.\n */\n showSummary?: boolean;\n /** Run actions at the right end of the one-line header (e.g. re-run, export, copy). */\n headerSlot?: ReactNode;\n /**\n * Suppresses the built-in header bar (title, summary) and the status/tool\n * facets in the tree toolbar.\n * Defaults to false; pass true when a host renders its own combined header\n * (e.g. a dialog header that already embeds `TestRunSummary` and filters) so\n * the runner doesn't render a second bordered bar underneath it.\n */\n hideHeader?: boolean;\n /** Initial left-pane width percentage. */\n defaultSplit?: number;\n startTime?: number | null;\n endTime?: number | null;\n className?: string;\n};\n\nfunction toRegistry(\n adapters: TestNodeAdapter[] | TestNodeAdapterRegistry | undefined,\n): TestNodeAdapterRegistry {\n if (adapters instanceof TestNodeAdapterRegistry) return adapters;\n return createTestRunnerRegistry(adapters ?? []);\n}\n\nconst SPLIT_MIN_WIDTH = 640;\n\n/**\n * Top-level, pure-presentational test runner: a summary/filter header over a\n * resizable tree + detail split. All data and handlers flow in via props and\n * are exposed to sub-components through a single `TestRunnerContext`. Domain\n * rendering is pluggable via node adapters; no fetch/SSE/routing lives here.\n */\nexport function TestRunner({\n tests,\n allTests,\n selected,\n filters,\n expandAll,\n done,\n runMeta,\n status,\n statusText,\n now,\n busy,\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters,\n title,\n showSummary = true,\n headerSlot,\n hideHeader = false,\n defaultSplit = 45,\n startTime,\n endTime,\n className,\n}: TestRunnerProps) {\n const registry = useMemo(() => toRegistry(adapters), [adapters]);\n\n const ctx: TestRunnerContext = useMemo(\n () => ({\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy: busy ?? {},\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n adapters: registry,\n }),\n [\n tests,\n selected,\n runMeta,\n status,\n done,\n now,\n filters,\n expandAll,\n busy,\n activeTab,\n onTabChange,\n activeAttempt,\n onAttemptChange,\n onSelect,\n onFiltersChange,\n onExpandAllChange,\n onRerun,\n onStop,\n registry,\n ],\n );\n\n const summaryTests = allTests ?? tests;\n const frameworks = useMemo(() => collectFrameworks(summaryTests), [summaryTests]);\n const filterCounts = useMemo(() => aggregateStatusCounts(summaryTests), [summaryTests]);\n // A host that hides the header renders its own filters (see hideHeader).\n const filterBar =\n !hideHeader && summaryTests.length > 0 ? (\n <TestFilterBar\n filters={filters}\n onChange={onFiltersChange}\n counts={filterCounts}\n frameworks={frameworks}\n />\n ) : null;\n // Below this the split leaves both panes too narrow to read, so the runner\n // goes master/detail: the tree, then the selected test with a way back.\n const { ref, wider: roomy } = useContainerWiderThan(SPLIT_MIN_WIDTH);\n\n return (\n <TestRunnerProvider value={ctx}>\n <div ref={ref} className={cn(\"flex h-full min-h-0 flex-col bg-background\", className)}>\n {!hideHeader && (\n <div\n className=\"flex min-w-0 items-center gap-3 border-b border-border bg-card px-density-4 py-density-2\"\n data-runner-header=\"\"\n >\n <div className=\"flex min-w-0 items-center gap-3\">\n {title === undefined ? (\n <h1 className=\"inline-flex shrink-0 items-center gap-1.5 text-base font-bold\">\n <Icon icon={UiBeaker} className=\"text-primary\" />\n Test Results\n </h1>\n ) : (\n title\n )}\n {statusText && (\n <span className=\"truncate text-sm text-muted-foreground\">{statusText}</span>\n )}\n </div>\n {showSummary && (\n <TestRunSummary\n tests={summaryTests}\n startTime={startTime}\n endTime={endTime}\n done={done}\n now={now}\n runMeta={runMeta}\n compact\n className=\"ml-auto flex-nowrap\"\n />\n )}\n {headerSlot && (\n <div className={cn(\"flex shrink-0 items-center gap-1\", !showSummary && \"ml-auto\")}>\n {headerSlot}\n </div>\n )}\n </div>\n )}\n\n {roomy ? (\n <SplitPane\n className=\"min-h-0 flex-1\"\n defaultSplit={defaultSplit}\n minLeft={25}\n minRight={30}\n leftClass=\"border-r-2 border-border bg-muted/30\"\n left={<TestTree actions={filterBar} />}\n right={<TestDetailPanel />}\n />\n ) : selected ? (\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <button\n type=\"button\"\n onClick={() => onSelect(null)}\n className=\"inline-flex items-center gap-1.5 border-b border-border px-density-3 py-density-2 text-left text-sm text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Icon icon={UiArrowLeft} />\n Back to results\n </button>\n <div className=\"min-h-0 flex-1 overflow-hidden\">\n <TestDetailPanel />\n </div>\n </div>\n ) : (\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n <TestTree actions={filterBar} />\n </div>\n )}\n </div>\n </TestRunnerProvider>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -19,7 +19,7 @@ const nodeKey = /* @__PURE__ */ (() => {
19
19
  return key;
20
20
  };
21
21
  })();
22
- function TestTree({ className }) {
22
+ function TestTree({ className, actions }) {
23
23
  const runner = context.useTestRunner();
24
24
  return /* @__PURE__ */ jsxRuntime.jsx(
25
25
  Tree.Tree,
@@ -33,8 +33,11 @@ function TestTree({ className }) {
33
33
  expandAll: runner.expandAll,
34
34
  onExpandAllChange: runner.onExpandAllChange,
35
35
  defaultOpen: (node, depth) => depth < 1 || status.hasFailed(node),
36
+ showSearch: true,
37
+ searchLabel: "Filter tests",
36
38
  getSearchText: (node) => `${node.name} ${node.framework ?? ""}`,
37
- renderRow: ({ node, selected }) => /* @__PURE__ */ jsxRuntime.jsx(TestTreeNode.TestTreeNode, { node, selected })
39
+ renderRow: ({ node, selected }) => /* @__PURE__ */ jsxRuntime.jsx(TestTreeNode.TestTreeNode, { node, selected }),
40
+ actions
38
41
  }
39
42
  );
40
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TestTree.cjs","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default.\n */\nexport function TestTree({ className }: { className?: string }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n />\n );\n}\n"],"names":["useTestRunner","jsx","Tree","cn","hasFailed","TestTreeNode"],"mappings":";;;;;;;;AAOA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAOO,SAAS,SAAS,EAAE,aAAqC;AAC9D,QAAM,SAASA,QAAAA,cAAA;AACf,SACEC,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAWC,MAAAA,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAKC,OAAAA,UAAU,IAAI;AAAA,MACzD,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAeH,2BAAAA,IAACI,aAAAA,cAAA,EAAa,MAAY,SAAA,CAAoB;AAAA,IAAA;AAAA,EAAA;AAGvF;;"}
1
+ {"version":3,"file":"TestTree.cjs","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default. A name filter is always shown, and `actions`\n * sit in the tree toolbar beside it and Expand all / Collapse all.\n */\nexport function TestTree({ className, actions }: { className?: string; actions?: ReactNode }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n showSearch\n searchLabel=\"Filter tests\"\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n actions={actions}\n />\n );\n}\n"],"names":["useTestRunner","jsx","Tree","cn","hasFailed","TestTreeNode"],"mappings":";;;;;;;;AAQA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAQO,SAAS,SAAS,EAAE,WAAW,WAAwD;AAC5F,QAAM,SAASA,QAAAA,cAAA;AACf,SACEC,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAWC,MAAAA,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAKC,OAAAA,UAAU,IAAI;AAAA,MACzD,YAAU;AAAA,MACV,aAAY;AAAA,MACZ,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAeH,2BAAAA,IAACI,2BAAA,EAAa,MAAY,UAAoB;AAAA,MACjF;AAAA,IAAA;AAAA,EAAA;AAGN;;"}
@@ -1,9 +1,12 @@
1
+ import { ReactNode } from 'react';
1
2
  /**
2
3
  * The left pane: the test forest rendered through the clicky `Tree`. Selection,
3
4
  * handlers and adapters all come from the runner context; failing branches and
4
- * the top level open by default.
5
+ * the top level open by default. A name filter is always shown, and `actions`
6
+ * sit in the tree toolbar beside it and Expand all / Collapse all.
5
7
  */
6
- export declare function TestTree({ className }: {
8
+ export declare function TestTree({ className, actions }: {
7
9
  className?: string;
10
+ actions?: ReactNode;
8
11
  }): import("react").JSX.Element;
9
12
  //# sourceMappingURL=TestTree.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TestTree.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestTree.tsx"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAiB7D"}
1
+ {"version":3,"file":"TestTree.d.ts","sourceRoot":"","sources":["../../../src/data/test-runner/TestTree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAyBvC;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,+BAoB3F"}
@@ -17,7 +17,7 @@ const nodeKey = /* @__PURE__ */ (() => {
17
17
  return key;
18
18
  };
19
19
  })();
20
- function TestTree({ className }) {
20
+ function TestTree({ className, actions }) {
21
21
  const runner = useTestRunner();
22
22
  return /* @__PURE__ */ jsx(
23
23
  Tree,
@@ -31,8 +31,11 @@ function TestTree({ className }) {
31
31
  expandAll: runner.expandAll,
32
32
  onExpandAllChange: runner.onExpandAllChange,
33
33
  defaultOpen: (node, depth) => depth < 1 || hasFailed(node),
34
+ showSearch: true,
35
+ searchLabel: "Filter tests",
34
36
  getSearchText: (node) => `${node.name} ${node.framework ?? ""}`,
35
- renderRow: ({ node, selected }) => /* @__PURE__ */ jsx(TestTreeNode, { node, selected })
37
+ renderRow: ({ node, selected }) => /* @__PURE__ */ jsx(TestTreeNode, { node, selected }),
38
+ actions
36
39
  }
37
40
  );
38
41
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TestTree.js","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default.\n */\nexport function TestTree({ className }: { className?: string }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;AAOA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAOO,SAAS,SAAS,EAAE,aAAqC;AAC9D,QAAM,SAAS,cAAA;AACf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAK,UAAU,IAAI;AAAA,MACzD,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAe,oBAAC,cAAA,EAAa,MAAY,SAAA,CAAoB;AAAA,IAAA;AAAA,EAAA;AAGvF;"}
1
+ {"version":3,"file":"TestTree.js","sources":["../../../src/data/test-runner/TestTree.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Tree } from \"../Tree\";\nimport { cn } from \"../../lib/utils\";\nimport type { Test } from \"./types\";\nimport { useTestRunner } from \"./context\";\nimport { hasFailed } from \"./status\";\nimport { TestTreeNode } from \"./TestTreeNode\";\n\nconst nodeKey = (() => {\n // Tests carry no guaranteed id; derive a stable per-render key from route_path\n // when present, else the node's name path. A WeakMap keeps keys stable across\n // re-renders for the same object identity.\n const cache = new WeakMap<Test, string>();\n let counter = 0;\n return (node: Test): string => {\n if (node.route_path) return node.route_path;\n let key = cache.get(node);\n if (!key) {\n key = `tn-${counter++}-${node.name}`;\n cache.set(node, key);\n }\n return key;\n };\n})();\n\n/**\n * The left pane: the test forest rendered through the clicky `Tree`. Selection,\n * handlers and adapters all come from the runner context; failing branches and\n * the top level open by default. A name filter is always shown, and `actions`\n * sit in the tree toolbar beside it and Expand all / Collapse all.\n */\nexport function TestTree({ className, actions }: { className?: string; actions?: ReactNode }) {\n const runner = useTestRunner();\n return (\n <Tree<Test>\n className={cn(\"min-h-0\", className)}\n roots={runner.tests}\n getKey={nodeKey}\n getChildren={(node) => node.children}\n selected={runner.selected}\n onSelect={(node) => runner.onSelect(node === runner.selected ? null : node)}\n expandAll={runner.expandAll}\n onExpandAllChange={runner.onExpandAllChange}\n defaultOpen={(node, depth) => depth < 1 || hasFailed(node)}\n showSearch\n searchLabel=\"Filter tests\"\n getSearchText={(node) => `${node.name} ${node.framework ?? \"\"}`}\n renderRow={({ node, selected }) => <TestTreeNode node={node} selected={selected} />}\n actions={actions}\n />\n );\n}\n"],"names":[],"mappings":";;;;;;AAQA,MAAM,UAAW,uBAAM;AAIrB,QAAM,4BAAY,QAAA;AAClB,MAAI,UAAU;AACd,SAAO,CAAC,SAAuB;AAC7B,QAAI,KAAK,WAAY,QAAO,KAAK;AACjC,QAAI,MAAM,MAAM,IAAI,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,MAAM,SAAS,IAAI,KAAK,IAAI;AAClC,YAAM,IAAI,MAAM,GAAG;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AACF,GAAA;AAQO,SAAS,SAAS,EAAE,WAAW,WAAwD;AAC5F,QAAM,SAAS,cAAA;AACf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,GAAG,WAAW,SAAS;AAAA,MAClC,OAAO,OAAO;AAAA,MACd,QAAQ;AAAA,MACR,aAAa,CAAC,SAAS,KAAK;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,UAAU,CAAC,SAAS,OAAO,SAAS,SAAS,OAAO,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAW,OAAO;AAAA,MAClB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,CAAC,MAAM,UAAU,QAAQ,KAAK,UAAU,IAAI;AAAA,MACzD,YAAU;AAAA,MACV,aAAY;AAAA,MACZ,eAAe,CAAC,SAAS,GAAG,KAAK,IAAI,IAAI,KAAK,aAAa,EAAE;AAAA,MAC7D,WAAW,CAAC,EAAE,MAAM,eAAe,oBAAC,cAAA,EAAa,MAAY,UAAoB;AAAA,MACjF;AAAA,IAAA;AAAA,EAAA;AAGN;"}