@flanksource/clicky-ui 0.1.0 → 0.2.2

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 (378) hide show
  1. package/README.md +29 -2
  2. package/dist/api-explorer.d.ts +5 -0
  3. package/dist/api-explorer.d.ts.map +1 -0
  4. package/dist/api-explorer.js +25 -0
  5. package/dist/api-explorer.js.map +1 -0
  6. package/dist/clicky.d.ts +2 -0
  7. package/dist/clicky.d.ts.map +1 -0
  8. package/dist/clicky.js +5 -0
  9. package/dist/clicky.js.map +1 -0
  10. package/dist/components/DatePicker.d.ts +18 -0
  11. package/dist/components/DatePicker.d.ts.map +1 -0
  12. package/dist/components/DatePicker.js +63 -0
  13. package/dist/components/DatePicker.js.map +1 -0
  14. package/dist/components/DateTimePicker.d.ts +18 -0
  15. package/dist/components/DateTimePicker.d.ts.map +1 -0
  16. package/dist/components/DateTimePicker.js +84 -0
  17. package/dist/components/DateTimePicker.js.map +1 -0
  18. package/dist/components/FilterBar.d.ts +180 -0
  19. package/dist/components/FilterBar.d.ts.map +1 -0
  20. package/dist/components/FilterBar.js +1685 -0
  21. package/dist/components/FilterBar.js.map +1 -0
  22. package/dist/components/MultiSelect.d.ts +19 -0
  23. package/dist/components/MultiSelect.d.ts.map +1 -0
  24. package/dist/components/MultiSelect.js +143 -0
  25. package/dist/components/MultiSelect.js.map +1 -0
  26. package/dist/components/RangeSlider.d.ts +16 -0
  27. package/dist/components/RangeSlider.d.ts.map +1 -0
  28. package/dist/components/RangeSlider.js +92 -0
  29. package/dist/components/RangeSlider.js.map +1 -0
  30. package/dist/components/button.d.ts +21 -0
  31. package/dist/components/button.d.ts.map +1 -0
  32. package/dist/components/button.js +126 -0
  33. package/dist/components/button.js.map +1 -0
  34. package/dist/components/density-switcher.d.ts +7 -0
  35. package/dist/components/density-switcher.d.ts.map +1 -0
  36. package/dist/components/density-switcher.js +32 -0
  37. package/dist/components/density-switcher.js.map +1 -0
  38. package/dist/components/icon-menu-picker.d.ts +23 -0
  39. package/dist/components/icon-menu-picker.d.ts.map +1 -0
  40. package/dist/components/icon-menu-picker.js +192 -0
  41. package/dist/components/icon-menu-picker.js.map +1 -0
  42. package/dist/components/select.d.ts +15 -0
  43. package/dist/components/select.d.ts.map +1 -0
  44. package/dist/components/select.js +39 -0
  45. package/dist/components/select.js.map +1 -0
  46. package/dist/components/theme-switcher.d.ts +7 -0
  47. package/dist/components/theme-switcher.d.ts.map +1 -0
  48. package/dist/components/theme-switcher.js +42 -0
  49. package/dist/components/theme-switcher.js.map +1 -0
  50. package/dist/components.d.ts +15 -0
  51. package/dist/components.d.ts.map +1 -0
  52. package/dist/components.js +33 -0
  53. package/dist/components.js.map +1 -0
  54. package/dist/data/AnsiHtml.d.ts +7 -0
  55. package/dist/data/AnsiHtml.d.ts.map +1 -0
  56. package/dist/data/AnsiHtml.js +71 -0
  57. package/dist/data/AnsiHtml.js.map +1 -0
  58. package/dist/data/Avatar.d.ts +32 -0
  59. package/dist/data/Avatar.d.ts.map +1 -0
  60. package/dist/data/Avatar.js +201 -0
  61. package/dist/data/Avatar.js.map +1 -0
  62. package/dist/data/AvatarBadge.d.ts +26 -0
  63. package/dist/data/AvatarBadge.d.ts.map +1 -0
  64. package/dist/data/AvatarBadge.js +104 -0
  65. package/dist/data/AvatarBadge.js.map +1 -0
  66. package/dist/data/Badge.d.ts +44 -0
  67. package/dist/data/Badge.d.ts.map +1 -0
  68. package/dist/data/Badge.js +667 -0
  69. package/dist/data/Badge.js.map +1 -0
  70. package/dist/data/Clicky.d.ts +147 -0
  71. package/dist/data/Clicky.d.ts.map +1 -0
  72. package/dist/data/Clicky.fixtures.d.ts +3 -0
  73. package/dist/data/Clicky.fixtures.d.ts.map +1 -0
  74. package/dist/data/Clicky.js +1960 -0
  75. package/dist/data/Clicky.js.map +1 -0
  76. package/dist/data/DataTable.d.ts +95 -0
  77. package/dist/data/DataTable.d.ts.map +1 -0
  78. package/dist/data/DataTable.js +1464 -0
  79. package/dist/data/DataTable.js.map +1 -0
  80. package/dist/data/FilterPill.d.ts +29 -0
  81. package/dist/data/FilterPill.d.ts.map +1 -0
  82. package/dist/data/FilterPill.js +153 -0
  83. package/dist/data/FilterPill.js.map +1 -0
  84. package/dist/data/Gauge.d.ts +15 -0
  85. package/dist/data/Gauge.d.ts.map +1 -0
  86. package/dist/data/Gauge.js +63 -0
  87. package/dist/data/Gauge.js.map +1 -0
  88. package/dist/data/Icon.d.ts +53 -0
  89. package/dist/data/Icon.d.ts.map +1 -0
  90. package/dist/data/Icon.js +115 -0
  91. package/dist/data/Icon.js.map +1 -0
  92. package/dist/data/JsonView.d.ts +8 -0
  93. package/dist/data/JsonView.d.ts.map +1 -0
  94. package/dist/data/JsonView.js +74 -0
  95. package/dist/data/JsonView.js.map +1 -0
  96. package/dist/data/KeyValueList.d.ts +17 -0
  97. package/dist/data/KeyValueList.d.ts.map +1 -0
  98. package/dist/data/KeyValueList.js +33 -0
  99. package/dist/data/KeyValueList.js.map +1 -0
  100. package/dist/data/LogViewer.d.ts +10 -0
  101. package/dist/data/LogViewer.d.ts.map +1 -0
  102. package/dist/data/LogViewer.js +46 -0
  103. package/dist/data/LogViewer.js.map +1 -0
  104. package/dist/data/LogsTable.d.ts +27 -0
  105. package/dist/data/LogsTable.d.ts.map +1 -0
  106. package/dist/data/LogsTable.js +580 -0
  107. package/dist/data/LogsTable.js.map +1 -0
  108. package/dist/data/Markdown.d.ts +6 -0
  109. package/dist/data/Markdown.d.ts.map +1 -0
  110. package/dist/data/Markdown.js +59 -0
  111. package/dist/data/Markdown.js.map +1 -0
  112. package/dist/data/MatrixTable.d.ts +22 -0
  113. package/dist/data/MatrixTable.d.ts.map +1 -0
  114. package/dist/data/MatrixTable.js +164 -0
  115. package/dist/data/MatrixTable.js.map +1 -0
  116. package/dist/data/MethodBadge.d.ts +6 -0
  117. package/dist/data/MethodBadge.d.ts.map +1 -0
  118. package/dist/data/MethodBadge.js +18 -0
  119. package/dist/data/MethodBadge.js.map +1 -0
  120. package/dist/data/ProgressBar.d.ts +13 -0
  121. package/dist/data/ProgressBar.d.ts.map +1 -0
  122. package/dist/data/ProgressBar.js +34 -0
  123. package/dist/data/ProgressBar.js.map +1 -0
  124. package/dist/data/SortableHeader.d.ts +12 -0
  125. package/dist/data/SortableHeader.d.ts.map +1 -0
  126. package/dist/data/SortableHeader.js +33 -0
  127. package/dist/data/SortableHeader.js.map +1 -0
  128. package/dist/data/TabButton.d.ts +12 -0
  129. package/dist/data/TabButton.d.ts.map +1 -0
  130. package/dist/data/TabButton.js +45 -0
  131. package/dist/data/TabButton.js.map +1 -0
  132. package/dist/data/Tree.d.ts +35 -0
  133. package/dist/data/Tree.d.ts.map +1 -0
  134. package/dist/data/Tree.js +236 -0
  135. package/dist/data/Tree.js.map +1 -0
  136. package/dist/data/TreeGroupHeader.d.ts +11 -0
  137. package/dist/data/TreeGroupHeader.d.ts.map +1 -0
  138. package/dist/data/TreeGroupHeader.js +41 -0
  139. package/dist/data/TreeGroupHeader.js.map +1 -0
  140. package/dist/data/TreeNode.d.ts +43 -0
  141. package/dist/data/TreeNode.d.ts.map +1 -0
  142. package/dist/data/TreeNode.js +100 -0
  143. package/dist/data/TreeNode.js.map +1 -0
  144. package/dist/data/cells/StatusDot.d.ts +11 -0
  145. package/dist/data/cells/StatusDot.d.ts.map +1 -0
  146. package/dist/data/cells/StatusDot.js +38 -0
  147. package/dist/data/cells/StatusDot.js.map +1 -0
  148. package/dist/data/cells/TagList.d.ts +59 -0
  149. package/dist/data/cells/TagList.d.ts.map +1 -0
  150. package/dist/data/cells/TagList.js +257 -0
  151. package/dist/data/cells/TagList.js.map +1 -0
  152. package/dist/data/cells/Timestamp.d.ts +46 -0
  153. package/dist/data/cells/Timestamp.d.ts.map +1 -0
  154. package/dist/data/cells/Timestamp.js +146 -0
  155. package/dist/data/cells/Timestamp.js.map +1 -0
  156. package/dist/data/cells/status-mapping.d.ts +8 -0
  157. package/dist/data/cells/status-mapping.d.ts.map +1 -0
  158. package/dist/data/cells/status-mapping.js +44 -0
  159. package/dist/data/cells/status-mapping.js.map +1 -0
  160. package/dist/data/code-highlight.d.ts +12 -0
  161. package/dist/data/code-highlight.d.ts.map +1 -0
  162. package/dist/data/code-highlight.js +28 -0
  163. package/dist/data/code-highlight.js.map +1 -0
  164. package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts +9 -0
  165. package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts.map +1 -0
  166. package/dist/data/diagnostics/DiagnosticsDetailPanel.js +445 -0
  167. package/dist/data/diagnostics/DiagnosticsDetailPanel.js.map +1 -0
  168. package/dist/data/diagnostics/DiagnosticsTree.d.ts +9 -0
  169. package/dist/data/diagnostics/DiagnosticsTree.d.ts.map +1 -0
  170. package/dist/data/diagnostics/DiagnosticsTree.js +78 -0
  171. package/dist/data/diagnostics/DiagnosticsTree.js.map +1 -0
  172. package/dist/data/diagnostics/ErrorDetails.d.ts +20 -0
  173. package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -0
  174. package/dist/data/diagnostics/ErrorDetails.js +157 -0
  175. package/dist/data/diagnostics/ErrorDetails.js.map +1 -0
  176. package/dist/data/diagnostics/GoroutineCard.d.ts +10 -0
  177. package/dist/data/diagnostics/GoroutineCard.d.ts.map +1 -0
  178. package/dist/data/diagnostics/GoroutineCard.js +75 -0
  179. package/dist/data/diagnostics/GoroutineCard.js.map +1 -0
  180. package/dist/data/diagnostics/JvmStackTrace.d.ts +11 -0
  181. package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -0
  182. package/dist/data/diagnostics/JvmStackTrace.js +26 -0
  183. package/dist/data/diagnostics/JvmStackTrace.js.map +1 -0
  184. package/dist/data/diagnostics/RenderedStackTrace.d.ts +18 -0
  185. package/dist/data/diagnostics/RenderedStackTrace.d.ts.map +1 -0
  186. package/dist/data/diagnostics/RenderedStackTrace.js +235 -0
  187. package/dist/data/diagnostics/RenderedStackTrace.js.map +1 -0
  188. package/dist/data/diagnostics/ThreadCard.d.ts +10 -0
  189. package/dist/data/diagnostics/ThreadCard.d.ts.map +1 -0
  190. package/dist/data/diagnostics/ThreadCard.js +78 -0
  191. package/dist/data/diagnostics/ThreadCard.js.map +1 -0
  192. package/dist/data/diagnostics/error-diagnostics.d.ts +26 -0
  193. package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -0
  194. package/dist/data/diagnostics/error-diagnostics.js +108 -0
  195. package/dist/data/diagnostics/error-diagnostics.js.map +1 -0
  196. package/dist/data/diagnostics/fixtures.d.ts +3 -0
  197. package/dist/data/diagnostics/fixtures.d.ts.map +1 -0
  198. package/dist/data/diagnostics/jvm-stacktrace.d.ts +34 -0
  199. package/dist/data/diagnostics/jvm-stacktrace.d.ts.map +1 -0
  200. package/dist/data/diagnostics/jvm-stacktrace.js +190 -0
  201. package/dist/data/diagnostics/jvm-stacktrace.js.map +1 -0
  202. package/dist/data/diagnostics/stacktrace-parse.d.ts +11 -0
  203. package/dist/data/diagnostics/stacktrace-parse.d.ts.map +1 -0
  204. package/dist/data/diagnostics/stacktrace-parse.js +87 -0
  205. package/dist/data/diagnostics/stacktrace-parse.js.map +1 -0
  206. package/dist/data/diagnostics/stacktrace.d.ts +38 -0
  207. package/dist/data/diagnostics/stacktrace.d.ts.map +1 -0
  208. package/dist/data/diagnostics/stacktrace.js +119 -0
  209. package/dist/data/diagnostics/stacktrace.js.map +1 -0
  210. package/dist/data/diagnostics/types.d.ts +30 -0
  211. package/dist/data/diagnostics/types.d.ts.map +1 -0
  212. package/dist/data/diagnostics/utils.d.ts +8 -0
  213. package/dist/data/diagnostics/utils.d.ts.map +1 -0
  214. package/dist/data/diagnostics/utils.js +59 -0
  215. package/dist/data/diagnostics/utils.js.map +1 -0
  216. package/dist/data/har/HarPanel.d.ts +9 -0
  217. package/dist/data/har/HarPanel.d.ts.map +1 -0
  218. package/dist/data/har/HarPanel.js +175 -0
  219. package/dist/data/har/HarPanel.js.map +1 -0
  220. package/dist/data/har/fixtures.d.ts +3 -0
  221. package/dist/data/har/fixtures.d.ts.map +1 -0
  222. package/dist/data/har/types.d.ts +47 -0
  223. package/dist/data/har/types.d.ts.map +1 -0
  224. package/dist/data.d.ts +39 -0
  225. package/dist/data.d.ts.map +1 -0
  226. package/dist/data.js +109 -0
  227. package/dist/data.js.map +1 -0
  228. package/dist/hooks/use-density.d.ts +22 -0
  229. package/dist/hooks/use-density.d.ts.map +1 -0
  230. package/dist/hooks/use-density.js +54 -0
  231. package/dist/hooks/use-density.js.map +1 -0
  232. package/dist/hooks/use-history-route.d.ts +6 -0
  233. package/dist/hooks/use-history-route.d.ts.map +1 -0
  234. package/dist/hooks/use-history-route.js +31 -0
  235. package/dist/hooks/use-history-route.js.map +1 -0
  236. package/dist/hooks/use-sort.d.ts +17 -0
  237. package/dist/hooks/use-sort.d.ts.map +1 -0
  238. package/dist/hooks/use-sort.js +42 -0
  239. package/dist/hooks/use-sort.js.map +1 -0
  240. package/dist/hooks/use-theme.d.ts +17 -0
  241. package/dist/hooks/use-theme.d.ts.map +1 -0
  242. package/dist/hooks/use-theme.js +68 -0
  243. package/dist/hooks/use-theme.js.map +1 -0
  244. package/dist/hooks.d.ts +5 -0
  245. package/dist/hooks.d.ts.map +1 -0
  246. package/dist/hooks.js +14 -0
  247. package/dist/hooks.js.map +1 -0
  248. package/dist/index.d.ts +7 -0
  249. package/dist/index.d.ts.map +1 -0
  250. package/dist/index.js +195 -0
  251. package/dist/index.js.map +1 -0
  252. package/dist/layout/Section.d.ts +23 -0
  253. package/dist/layout/Section.d.ts.map +1 -0
  254. package/dist/layout/Section.js +73 -0
  255. package/dist/layout/Section.js.map +1 -0
  256. package/dist/layout/SplitPane.d.ts +13 -0
  257. package/dist/layout/SplitPane.d.ts.map +1 -0
  258. package/dist/layout/SplitPane.js +72 -0
  259. package/dist/layout/SplitPane.js.map +1 -0
  260. package/dist/lib/palette.d.ts +4 -0
  261. package/dist/lib/palette.d.ts.map +1 -0
  262. package/dist/lib/palette.js +35 -0
  263. package/dist/lib/palette.js.map +1 -0
  264. package/dist/lib/size.d.ts +6 -0
  265. package/dist/lib/size.d.ts.map +1 -0
  266. package/dist/lib/size.js +14 -0
  267. package/dist/lib/size.js.map +1 -0
  268. package/dist/lib/utils.d.ts +3 -0
  269. package/dist/lib/utils.d.ts.map +1 -0
  270. package/dist/lib/utils.js +9 -0
  271. package/dist/lib/utils.js.map +1 -0
  272. package/dist/overlay/HoverCard.d.ts +13 -0
  273. package/dist/overlay/HoverCard.d.ts.map +1 -0
  274. package/dist/overlay/HoverCard.js +170 -0
  275. package/dist/overlay/HoverCard.js.map +1 -0
  276. package/dist/overlay/Modal.d.ts +17 -0
  277. package/dist/overlay/Modal.d.ts.map +1 -0
  278. package/dist/overlay/Modal.js +91 -0
  279. package/dist/overlay/Modal.js.map +1 -0
  280. package/dist/rpc/AcceptPicker.d.ts +52 -0
  281. package/dist/rpc/AcceptPicker.d.ts.map +1 -0
  282. package/dist/rpc/AcceptPicker.js +126 -0
  283. package/dist/rpc/AcceptPicker.js.map +1 -0
  284. package/dist/rpc/ApiExplorer.d.ts +11 -0
  285. package/dist/rpc/ApiExplorer.d.ts.map +1 -0
  286. package/dist/rpc/ApiExplorer.js +37 -0
  287. package/dist/rpc/ApiExplorer.js.map +1 -0
  288. package/dist/rpc/CommandForm.d.ts +15 -0
  289. package/dist/rpc/CommandForm.d.ts.map +1 -0
  290. package/dist/rpc/CommandForm.js +356 -0
  291. package/dist/rpc/CommandForm.js.map +1 -0
  292. package/dist/rpc/CommandOutput.d.ts +11 -0
  293. package/dist/rpc/CommandOutput.d.ts.map +1 -0
  294. package/dist/rpc/CommandOutput.js +195 -0
  295. package/dist/rpc/CommandOutput.js.map +1 -0
  296. package/dist/rpc/EndpointList.d.ts +18 -0
  297. package/dist/rpc/EndpointList.d.ts.map +1 -0
  298. package/dist/rpc/EndpointList.js +56 -0
  299. package/dist/rpc/EndpointList.js.map +1 -0
  300. package/dist/rpc/EntityExplorerApp.d.ts +15 -0
  301. package/dist/rpc/EntityExplorerApp.d.ts.map +1 -0
  302. package/dist/rpc/EntityExplorerApp.js +282 -0
  303. package/dist/rpc/EntityExplorerApp.js.map +1 -0
  304. package/dist/rpc/ExecutionResult.d.ts +14 -0
  305. package/dist/rpc/ExecutionResult.d.ts.map +1 -0
  306. package/dist/rpc/ExecutionResult.js +51 -0
  307. package/dist/rpc/ExecutionResult.js.map +1 -0
  308. package/dist/rpc/FilterForm.d.ts +22 -0
  309. package/dist/rpc/FilterForm.d.ts.map +1 -0
  310. package/dist/rpc/FilterForm.js +392 -0
  311. package/dist/rpc/FilterForm.js.map +1 -0
  312. package/dist/rpc/InlineError.d.ts +7 -0
  313. package/dist/rpc/InlineError.d.ts.map +1 -0
  314. package/dist/rpc/InlineError.js +54 -0
  315. package/dist/rpc/InlineError.js.map +1 -0
  316. package/dist/rpc/OperationActionDialog.d.ts +12 -0
  317. package/dist/rpc/OperationActionDialog.d.ts.map +1 -0
  318. package/dist/rpc/OperationActionDialog.js +105 -0
  319. package/dist/rpc/OperationActionDialog.js.map +1 -0
  320. package/dist/rpc/OperationCatalog.d.ts +21 -0
  321. package/dist/rpc/OperationCatalog.d.ts.map +1 -0
  322. package/dist/rpc/OperationCatalog.js +339 -0
  323. package/dist/rpc/OperationCatalog.js.map +1 -0
  324. package/dist/rpc/OperationCommandPage.d.ts +22 -0
  325. package/dist/rpc/OperationCommandPage.d.ts.map +1 -0
  326. package/dist/rpc/OperationCommandPage.js +484 -0
  327. package/dist/rpc/OperationCommandPage.js.map +1 -0
  328. package/dist/rpc/OperationEntityPage.d.ts +23 -0
  329. package/dist/rpc/OperationEntityPage.d.ts.map +1 -0
  330. package/dist/rpc/OperationEntityPage.js +218 -0
  331. package/dist/rpc/OperationEntityPage.js.map +1 -0
  332. package/dist/rpc/classify.d.ts +8 -0
  333. package/dist/rpc/classify.d.ts.map +1 -0
  334. package/dist/rpc/classify.js +76 -0
  335. package/dist/rpc/classify.js.map +1 -0
  336. package/dist/rpc/clickyMetadata.d.ts +12 -0
  337. package/dist/rpc/clickyMetadata.d.ts.map +1 -0
  338. package/dist/rpc/clickyMetadata.js +71 -0
  339. package/dist/rpc/clickyMetadata.js.map +1 -0
  340. package/dist/rpc/formMetadata.d.ts +27 -0
  341. package/dist/rpc/formMetadata.d.ts.map +1 -0
  342. package/dist/rpc/formMetadata.js +250 -0
  343. package/dist/rpc/formMetadata.js.map +1 -0
  344. package/dist/rpc/types.d.ts +109 -0
  345. package/dist/rpc/types.d.ts.map +1 -0
  346. package/dist/rpc/types.js +8 -0
  347. package/dist/rpc/types.js.map +1 -0
  348. package/dist/rpc/useOperations.d.ts +346 -0
  349. package/dist/rpc/useOperations.d.ts.map +1 -0
  350. package/dist/rpc/useOperations.js +31 -0
  351. package/dist/rpc/useOperations.js.map +1 -0
  352. package/dist/rpc.d.ts +14 -0
  353. package/dist/rpc.d.ts.map +1 -0
  354. package/dist/rpc.js +37 -0
  355. package/dist/rpc.js.map +1 -0
  356. package/dist/styles.css +2 -0
  357. package/dist/styles.d.ts +1 -0
  358. package/dist/styles.d.ts.map +1 -0
  359. package/dist/styles.js +2 -0
  360. package/dist/styles.js.map +1 -0
  361. package/dist/tailwind-preset.d.ts +4 -0
  362. package/dist/tailwind-preset.d.ts.map +1 -0
  363. package/dist/tailwind-preset.js +69 -0
  364. package/dist/tailwind-preset.js.map +1 -0
  365. package/dist/utils.d.ts +4 -0
  366. package/dist/utils.d.ts.map +1 -0
  367. package/dist/utils.js +12 -0
  368. package/dist/utils.js.map +1 -0
  369. package/package.json +83 -40
  370. package/dist/index.d.mts +0 -834
  371. package/dist/index.d.mts.map +0 -1
  372. package/dist/index.mjs +0 -2918
  373. package/dist/index.mjs.map +0 -1
  374. package/dist/tailwind-preset.d.mts +0 -7
  375. package/dist/tailwind-preset.d.mts.map +0 -1
  376. package/dist/tailwind-preset.mjs +0 -64
  377. package/dist/tailwind-preset.mjs.map +0 -1
  378. package/src/styles/tokens.css +0 -78
package/dist/index.mjs DELETED
@@ -1,2918 +0,0 @@
1
- import { clsx } from "clsx";
2
- import { twMerge } from "tailwind-merge";
3
- import { Fragment, createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
4
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
5
- import { Slot } from "@radix-ui/react-slot";
6
- import { cva } from "class-variance-authority";
7
-
8
- //#region src/lib/utils.ts
9
- function cn(...inputs) {
10
- return twMerge(clsx(inputs));
11
- }
12
-
13
- //#endregion
14
- //#region src/lib/palette.ts
15
- const AVATAR_PALETTE = [
16
- "bg-rose-100 text-rose-700",
17
- "bg-pink-100 text-pink-700",
18
- "bg-fuchsia-100 text-fuchsia-700",
19
- "bg-purple-100 text-purple-700",
20
- "bg-violet-100 text-violet-700",
21
- "bg-indigo-100 text-indigo-700",
22
- "bg-blue-100 text-blue-700",
23
- "bg-sky-100 text-sky-700",
24
- "bg-cyan-100 text-cyan-700",
25
- "bg-teal-100 text-teal-700",
26
- "bg-emerald-100 text-emerald-700",
27
- "bg-green-100 text-green-700",
28
- "bg-lime-100 text-lime-800",
29
- "bg-amber-100 text-amber-800",
30
- "bg-orange-100 text-orange-700",
31
- "bg-red-100 text-red-700"
32
- ];
33
- function fnv1a32(s) {
34
- let h = 2166136261;
35
- for (let i = 0; i < s.length; i++) {
36
- h ^= s.charCodeAt(i);
37
- h = Math.imul(h, 16777619);
38
- }
39
- return h >>> 0;
40
- }
41
- function paletteClass(key) {
42
- return AVATAR_PALETTE[fnv1a32(key) % AVATAR_PALETTE.length];
43
- }
44
-
45
- //#endregion
46
- //#region src/hooks/use-theme.tsx
47
- const STORAGE_KEY$1 = "clicky-ui-theme";
48
- const DATA_ATTR$1 = "data-theme";
49
- const ThemeContext = createContext(null);
50
- function prefersDark() {
51
- if (typeof window === "undefined") return false;
52
- return window.matchMedia("(prefers-color-scheme: dark)").matches;
53
- }
54
- function readStored$1() {
55
- if (typeof window === "undefined") return "system";
56
- const raw = window.localStorage.getItem(STORAGE_KEY$1);
57
- return raw === "light" || raw === "dark" || raw === "system" ? raw : "system";
58
- }
59
- function resolve(theme) {
60
- if (theme === "system") return prefersDark() ? "dark" : "light";
61
- return theme;
62
- }
63
- function apply$1(resolved) {
64
- if (typeof document === "undefined") return;
65
- document.documentElement.setAttribute(DATA_ATTR$1, resolved);
66
- }
67
- function ThemeProvider({ children, defaultTheme = "system", storageKey = STORAGE_KEY$1 }) {
68
- const [theme, setThemeState] = useState(() => {
69
- if (typeof window === "undefined") return defaultTheme;
70
- return readStored$1() ?? defaultTheme;
71
- });
72
- const [resolvedTheme, setResolvedTheme] = useState(() => resolve(theme));
73
- useEffect(() => {
74
- const next = resolve(theme);
75
- setResolvedTheme(next);
76
- apply$1(next);
77
- if (typeof window !== "undefined") window.localStorage.setItem(storageKey, theme);
78
- }, [theme, storageKey]);
79
- useEffect(() => {
80
- if (theme !== "system" || typeof window === "undefined") return;
81
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
82
- const onChange = () => {
83
- const next = mq.matches ? "dark" : "light";
84
- setResolvedTheme(next);
85
- apply$1(next);
86
- };
87
- mq.addEventListener("change", onChange);
88
- return () => mq.removeEventListener("change", onChange);
89
- }, [theme]);
90
- const setTheme = useCallback((next) => setThemeState(next), []);
91
- const value = useMemo(() => ({
92
- theme,
93
- resolvedTheme,
94
- setTheme
95
- }), [
96
- theme,
97
- resolvedTheme,
98
- setTheme
99
- ]);
100
- return /* @__PURE__ */ jsx(ThemeContext.Provider, {
101
- value,
102
- children
103
- });
104
- }
105
- function useTheme() {
106
- const ctx = useContext(ThemeContext);
107
- if (!ctx) throw new Error("useTheme must be used inside <ThemeProvider>");
108
- return ctx;
109
- }
110
-
111
- //#endregion
112
- //#region src/hooks/use-density.tsx
113
- const STORAGE_KEY = "clicky-ui-density";
114
- const DATA_ATTR = "data-density";
115
- const DensityContext = createContext(null);
116
- function readStored() {
117
- if (typeof window === "undefined") return null;
118
- const raw = window.localStorage.getItem(STORAGE_KEY);
119
- return raw === "compact" || raw === "comfortable" || raw === "spacious" ? raw : null;
120
- }
121
- function apply(density) {
122
- if (typeof document === "undefined") return;
123
- document.documentElement.setAttribute(DATA_ATTR, density);
124
- }
125
- function DensityProvider({ children, defaultDensity = "comfortable", storageKey = STORAGE_KEY }) {
126
- const [density, setDensityState] = useState(() => {
127
- if (typeof window === "undefined") return defaultDensity;
128
- return readStored() ?? defaultDensity;
129
- });
130
- useEffect(() => {
131
- apply(density);
132
- if (typeof window !== "undefined") window.localStorage.setItem(storageKey, density);
133
- }, [density, storageKey]);
134
- const setDensity = useCallback((next) => setDensityState(next), []);
135
- const value = useMemo(() => ({
136
- density,
137
- setDensity
138
- }), [density, setDensity]);
139
- return /* @__PURE__ */ jsx(DensityContext.Provider, {
140
- value,
141
- children
142
- });
143
- }
144
- function useDensity() {
145
- const ctx = useContext(DensityContext);
146
- if (!ctx) throw new Error("useDensity must be used inside <DensityProvider>");
147
- return ctx;
148
- }
149
-
150
- //#endregion
151
- //#region src/hooks/use-sort.ts
152
- function resolvePath(obj, path) {
153
- return path.split(".").reduce((o, k) => {
154
- if (o && typeof o === "object") return o[k];
155
- }, obj);
156
- }
157
- function useSort(items, options = {}) {
158
- const { defaultKey, defaultDir = "asc", resolvers } = options;
159
- const [sort, setSort] = useState(defaultKey ? {
160
- key: defaultKey,
161
- dir: defaultDir
162
- } : null);
163
- function toggle(key) {
164
- setSort((prev) => {
165
- if (prev?.key === key) return prev.dir === "asc" ? {
166
- key,
167
- dir: "desc"
168
- } : null;
169
- return {
170
- key,
171
- dir: "asc"
172
- };
173
- });
174
- }
175
- return {
176
- sorted: useMemo(() => {
177
- if (!items) return [];
178
- if (!sort) return items;
179
- const { key, dir } = sort;
180
- const resolver = resolvers?.[key];
181
- const get = (item) => resolver ? resolver(item) : resolvePath(item, key);
182
- return [...items].sort((a, b) => {
183
- const av = get(a);
184
- const bv = get(b);
185
- if (av == null && bv == null) return 0;
186
- if (av == null) return 1;
187
- if (bv == null) return -1;
188
- const cmp = typeof av === "number" && typeof bv === "number" ? av - bv : String(av).localeCompare(String(bv));
189
- return dir === "asc" ? cmp : -cmp;
190
- });
191
- }, [
192
- items,
193
- sort,
194
- resolvers
195
- ]),
196
- sort,
197
- toggle
198
- };
199
- }
200
-
201
- //#endregion
202
- //#region src/hooks/use-history-route.ts
203
- function useHistoryRoute(options) {
204
- const { parse, build } = options;
205
- const [route, setRoute] = useState(() => typeof window === "undefined" ? parse("/", "") : parse(window.location.pathname, window.location.search));
206
- useEffect(() => {
207
- const onPop = () => setRoute(parse(window.location.pathname, window.location.search));
208
- window.addEventListener("popstate", onPop);
209
- return () => window.removeEventListener("popstate", onPop);
210
- }, [parse]);
211
- return [route, useCallback((next) => {
212
- setRoute((prev) => {
213
- const merged = typeof next === "function" ? next(prev) : {
214
- ...prev,
215
- ...next
216
- };
217
- const path = build(merged);
218
- if (typeof window !== "undefined") {
219
- if (window.location.pathname + window.location.search !== path) window.history.pushState(null, "", path);
220
- }
221
- return merged;
222
- });
223
- }, [build])];
224
- }
225
-
226
- //#endregion
227
- //#region src/components/button.tsx
228
- const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", {
229
- variants: {
230
- variant: {
231
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
232
- destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
233
- outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
234
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
235
- ghost: "hover:bg-accent hover:text-accent-foreground",
236
- link: "text-primary underline-offset-4 hover:underline"
237
- },
238
- size: {
239
- default: "h-control-h px-control-px py-2",
240
- sm: "h-8 rounded-md px-3 text-xs",
241
- lg: "h-10 rounded-md px-8",
242
- icon: "h-control-h w-control-h"
243
- }
244
- },
245
- defaultVariants: {
246
- variant: "default",
247
- size: "default"
248
- }
249
- });
250
- const Button = forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
251
- return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
252
- ref,
253
- className: cn(buttonVariants({
254
- variant,
255
- size
256
- }), className),
257
- ...props
258
- });
259
- });
260
- Button.displayName = "Button";
261
-
262
- //#endregion
263
- //#region src/data/Icon.tsx
264
- function Icon({ name, className, width, height, rotate, flip, inline, title }) {
265
- return /* @__PURE__ */ jsx("iconify-icon", {
266
- icon: name,
267
- className: cn("shrink-0", className),
268
- width,
269
- height,
270
- rotate,
271
- flip,
272
- inline,
273
- title,
274
- "aria-hidden": title ? void 0 : true
275
- });
276
- }
277
-
278
- //#endregion
279
- //#region src/components/select.tsx
280
- const Select = forwardRef(({ className, options, placeholder, children, ...props }, ref) => {
281
- return /* @__PURE__ */ jsxs("div", {
282
- className: "relative inline-flex w-full items-center",
283
- children: [/* @__PURE__ */ jsxs("select", {
284
- ref,
285
- className: cn("h-control-h w-full appearance-none rounded-md border border-input bg-background px-control-px pr-8 text-sm text-foreground", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1", "disabled:cursor-not-allowed disabled:opacity-50", className),
286
- ...props,
287
- children: [placeholder !== void 0 && /* @__PURE__ */ jsx("option", {
288
- value: "",
289
- disabled: true,
290
- children: placeholder
291
- }), options ? options.map((opt) => /* @__PURE__ */ jsx("option", {
292
- value: opt.value,
293
- disabled: opt.disabled,
294
- children: opt.label
295
- }, opt.value)) : children]
296
- }), /* @__PURE__ */ jsx(Icon, {
297
- name: "codicon:chevron-down",
298
- className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-xs text-muted-foreground"
299
- })]
300
- });
301
- });
302
- Select.displayName = "Select";
303
-
304
- //#endregion
305
- //#region src/components/theme-switcher.tsx
306
- const THEMES = [
307
- "light",
308
- "dark",
309
- "system"
310
- ];
311
- const ThemeSwitcher = forwardRef(({ className, ...props }, ref) => {
312
- const { theme, setTheme, resolvedTheme } = useTheme();
313
- return /* @__PURE__ */ jsxs("div", {
314
- ref,
315
- role: "radiogroup",
316
- "aria-label": "Theme",
317
- className: cn("inline-flex items-center gap-density-1 rounded-md border border-input bg-background p-density-1", className),
318
- ...props,
319
- children: [THEMES.map((t) => {
320
- const active = theme === t;
321
- return /* @__PURE__ */ jsx("button", {
322
- type: "button",
323
- role: "radio",
324
- "aria-checked": active,
325
- "data-active": active || void 0,
326
- onClick: () => setTheme(t),
327
- className: cn("inline-flex h-control-h items-center justify-center rounded-sm px-density-3 text-sm capitalize transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", active ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-accent hover:text-accent-foreground"),
328
- children: t
329
- }, t);
330
- }), /* @__PURE__ */ jsxs("span", {
331
- className: "ml-density-2 text-xs text-muted-foreground",
332
- children: ["resolved: ", /* @__PURE__ */ jsx("span", {
333
- "data-testid": "resolved-theme",
334
- children: resolvedTheme
335
- })]
336
- })]
337
- });
338
- });
339
- ThemeSwitcher.displayName = "ThemeSwitcher";
340
-
341
- //#endregion
342
- //#region src/components/density-switcher.tsx
343
- const DENSITIES = [
344
- "compact",
345
- "comfortable",
346
- "spacious"
347
- ];
348
- const DensitySwitcher = forwardRef(({ className, ...props }, ref) => {
349
- const { density, setDensity } = useDensity();
350
- return /* @__PURE__ */ jsx("div", {
351
- ref,
352
- role: "radiogroup",
353
- "aria-label": "Density",
354
- className: cn("inline-flex items-center gap-density-1 rounded-md border border-input bg-background p-density-1", className),
355
- ...props,
356
- children: DENSITIES.map((d) => {
357
- const active = density === d;
358
- return /* @__PURE__ */ jsx("button", {
359
- type: "button",
360
- role: "radio",
361
- "aria-checked": active,
362
- "data-active": active || void 0,
363
- onClick: () => setDensity(d),
364
- className: cn("inline-flex h-control-h items-center justify-center rounded-sm px-density-3 text-sm capitalize transition-colors", "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", active ? "bg-primary text-primary-foreground" : "text-foreground hover:bg-accent hover:text-accent-foreground"),
365
- children: d
366
- }, d);
367
- })
368
- });
369
- });
370
- DensitySwitcher.displayName = "DensitySwitcher";
371
-
372
- //#endregion
373
- //#region src/layout/SplitPane.tsx
374
- function SplitPane({ left, right, defaultSplit = 50, minLeft = 20, minRight = 20, leftClass, rightClass, className }) {
375
- const [split, setSplit] = useState(defaultSplit);
376
- const dragging = useRef(false);
377
- const container = useRef(null);
378
- const onMouseDown = useCallback((e) => {
379
- e.preventDefault();
380
- dragging.current = true;
381
- const onMove = (ev) => {
382
- if (!dragging.current || !container.current) return;
383
- const rect = container.current.getBoundingClientRect();
384
- const pct = (ev.clientX - rect.left) / rect.width * 100;
385
- setSplit(Math.max(minLeft, Math.min(100 - minRight, pct)));
386
- };
387
- const onUp = () => {
388
- dragging.current = false;
389
- document.removeEventListener("mousemove", onMove);
390
- document.removeEventListener("mouseup", onUp);
391
- document.body.style.cursor = "";
392
- document.body.style.userSelect = "";
393
- };
394
- document.addEventListener("mousemove", onMove);
395
- document.addEventListener("mouseup", onUp);
396
- document.body.style.cursor = "col-resize";
397
- document.body.style.userSelect = "none";
398
- }, [minLeft, minRight]);
399
- return /* @__PURE__ */ jsxs("div", {
400
- ref: container,
401
- className: cn("flex flex-1 overflow-hidden min-h-0", className),
402
- children: [
403
- /* @__PURE__ */ jsx("div", {
404
- style: { width: `${split}%` },
405
- className: cn("overflow-y-auto bg-background min-h-0", leftClass),
406
- children: left
407
- }),
408
- /* @__PURE__ */ jsx("div", {
409
- role: "separator",
410
- "aria-orientation": "vertical",
411
- className: "w-1 bg-border hover:bg-primary cursor-col-resize shrink-0 transition-colors",
412
- onMouseDown
413
- }),
414
- /* @__PURE__ */ jsx("div", {
415
- style: { width: `${100 - split}%` },
416
- className: cn("overflow-hidden bg-background min-h-0", rightClass),
417
- children: right
418
- })
419
- ]
420
- });
421
- }
422
-
423
- //#endregion
424
- //#region src/layout/Section.tsx
425
- const toneRing = {
426
- default: "",
427
- danger: "border-l-2 border-red-500",
428
- warning: "border-l-2 border-yellow-500",
429
- success: "border-l-2 border-green-500",
430
- info: "border-l-2 border-blue-500"
431
- };
432
- function Section({ title, summary, defaultOpen = false, open: openProp, onToggle, icon, tone = "default", className, headerClassName, bodyClassName, children }) {
433
- const isControlled = openProp !== void 0;
434
- const [innerOpen, setInnerOpen] = useState(defaultOpen);
435
- const open = isControlled ? openProp : innerOpen;
436
- function toggle() {
437
- const next = !open;
438
- if (!isControlled) setInnerOpen(next);
439
- onToggle?.(next);
440
- }
441
- return /* @__PURE__ */ jsxs("div", {
442
- className: cn("rounded-md border border-border bg-background", toneRing[tone], className),
443
- children: [/* @__PURE__ */ jsxs("button", {
444
- type: "button",
445
- onClick: toggle,
446
- "aria-expanded": open,
447
- className: cn("w-full flex items-center gap-2 px-density-3 py-density-2 text-left", "hover:bg-accent/50 transition-colors", headerClassName),
448
- children: [
449
- /* @__PURE__ */ jsx(Icon, {
450
- name: open ? "codicon:chevron-down" : "codicon:chevron-right",
451
- className: "text-muted-foreground text-xs"
452
- }),
453
- icon && /* @__PURE__ */ jsx(Icon, {
454
- name: icon,
455
- className: "text-base"
456
- }),
457
- /* @__PURE__ */ jsx("span", {
458
- className: "font-medium text-sm flex-1 truncate",
459
- children: title
460
- }),
461
- summary && /* @__PURE__ */ jsx("span", {
462
- className: "text-xs text-muted-foreground",
463
- children: summary
464
- })
465
- ]
466
- }), open && /* @__PURE__ */ jsx("div", {
467
- className: cn("px-density-3 py-density-2 border-t border-border", bodyClassName),
468
- children
469
- })]
470
- });
471
- }
472
- function DetailEmptyState({ icon, label, description, className }) {
473
- return /* @__PURE__ */ jsxs("div", {
474
- className: cn("p-density-6 text-center text-muted-foreground", className),
475
- children: [
476
- icon && /* @__PURE__ */ jsx(Icon, {
477
- name: icon,
478
- className: "text-3xl mb-density-2"
479
- }),
480
- /* @__PURE__ */ jsx("p", {
481
- className: "text-sm",
482
- children: label
483
- }),
484
- description && /* @__PURE__ */ jsx("p", {
485
- className: "text-xs mt-density-1 opacity-70",
486
- children: description
487
- })
488
- ]
489
- });
490
- }
491
-
492
- //#endregion
493
- //#region src/data/AnsiHtml.tsx
494
- const ANSI_COLORS = {
495
- "30": "color:#1e1e1e",
496
- "31": "color:#cd3131",
497
- "32": "color:#0dbc79",
498
- "33": "color:#e5e510",
499
- "34": "color:#2472c8",
500
- "35": "color:#bc3fbc",
501
- "36": "color:#11a8cd",
502
- "37": "color:#e5e5e5",
503
- "90": "color:#666",
504
- "91": "color:#f14c4c",
505
- "92": "color:#23d18b",
506
- "93": "color:#f5f543",
507
- "94": "color:#3b8eea",
508
- "95": "color:#d670d6",
509
- "96": "color:#29b8db",
510
- "97": "color:#fff",
511
- "1": "font-weight:bold",
512
- "2": "opacity:0.7",
513
- "3": "font-style:italic",
514
- "4": "text-decoration:underline"
515
- };
516
- function parseAnsi(raw) {
517
- const spans = [];
518
- const re = /\x1b\[([0-9;]*)m/g;
519
- let last = 0;
520
- let styles = [];
521
- let match;
522
- while ((match = re.exec(raw)) !== null) {
523
- if (match.index > last) spans.push({
524
- text: raw.slice(last, match.index),
525
- style: styles.join(";")
526
- });
527
- const codes = (match[1] ?? "").split(";").filter(Boolean);
528
- for (const code of codes) if (code === "0" || code === "") styles = [];
529
- else {
530
- const rule = ANSI_COLORS[code];
531
- if (rule) styles.push(rule);
532
- }
533
- last = match.index + match[0].length;
534
- }
535
- if (last < raw.length) spans.push({
536
- text: raw.slice(last),
537
- style: styles.join(";")
538
- });
539
- return spans;
540
- }
541
- function spanToStyle(style) {
542
- const out = {};
543
- for (const rule of style.split(";")) {
544
- const [k, v] = rule.split(":");
545
- if (!k || !v) continue;
546
- const key = k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
547
- out[key] = v;
548
- }
549
- return out;
550
- }
551
- function AnsiHtml({ text, className, as = "pre" }) {
552
- const children = parseAnsi(text).map((s, i) => s.style ? /* @__PURE__ */ jsx("span", {
553
- style: spanToStyle(s.style),
554
- children: s.text
555
- }, i) : /* @__PURE__ */ jsx("span", { children: s.text }, i));
556
- if (as === "span") return /* @__PURE__ */ jsx("span", {
557
- className,
558
- children
559
- });
560
- return /* @__PURE__ */ jsx("pre", {
561
- className,
562
- children
563
- });
564
- }
565
-
566
- //#endregion
567
- //#region src/data/Avatar.tsx
568
- function Avatar({ src, alt, size = 20, rounded = "full", title, href, colorKey, onError, className }) {
569
- const shape = rounded === "full" ? "rounded-full" : "rounded";
570
- const key = colorKey ?? alt;
571
- const base = cn("inline-block shrink-0", shape);
572
- const content = src ? /* @__PURE__ */ jsx("img", {
573
- src,
574
- alt,
575
- title: title ?? alt,
576
- width: size,
577
- height: size,
578
- className: cn(base, "bg-muted", className),
579
- loading: "lazy",
580
- onError
581
- }) : /* @__PURE__ */ jsx("span", {
582
- className: cn(base, paletteClass(key), "inline-flex items-center justify-center font-semibold", className),
583
- style: {
584
- width: size,
585
- height: size,
586
- fontSize: Math.max(9, Math.floor(size * .5))
587
- },
588
- title: title ?? alt,
589
- children: (alt.replace(/^@/, "").charAt(0) || "?").toUpperCase()
590
- });
591
- if (href) return /* @__PURE__ */ jsx("a", {
592
- href,
593
- target: "_blank",
594
- rel: "noopener noreferrer",
595
- className: "inline-flex shrink-0",
596
- onClick: (e) => e.stopPropagation(),
597
- children: content
598
- });
599
- return content;
600
- }
601
-
602
- //#endregion
603
- //#region src/data/Badge.tsx
604
- const badgeVariants = cva("inline-flex items-center gap-1 rounded-full font-medium whitespace-nowrap", {
605
- variants: {
606
- tone: {
607
- neutral: "",
608
- success: "",
609
- danger: "",
610
- warning: "",
611
- info: ""
612
- },
613
- variant: {
614
- soft: "",
615
- solid: "",
616
- outline: "border bg-transparent"
617
- },
618
- size: {
619
- sm: "text-[10px] px-1.5 py-0 h-4",
620
- md: "text-xs px-2 py-0.5",
621
- lg: "text-sm px-2.5 py-1"
622
- }
623
- },
624
- compoundVariants: [
625
- {
626
- tone: "neutral",
627
- variant: "soft",
628
- class: "bg-muted text-foreground"
629
- },
630
- {
631
- tone: "neutral",
632
- variant: "solid",
633
- class: "bg-foreground text-background"
634
- },
635
- {
636
- tone: "neutral",
637
- variant: "outline",
638
- class: "border-border text-foreground"
639
- },
640
- {
641
- tone: "success",
642
- variant: "soft",
643
- class: "bg-green-100 text-green-800 dark:bg-green-500/20 dark:text-green-300"
644
- },
645
- {
646
- tone: "success",
647
- variant: "solid",
648
- class: "bg-green-500 text-white"
649
- },
650
- {
651
- tone: "success",
652
- variant: "outline",
653
- class: "border-green-500 text-green-700 dark:text-green-400"
654
- },
655
- {
656
- tone: "danger",
657
- variant: "soft",
658
- class: "bg-red-100 text-red-800 dark:bg-red-500/20 dark:text-red-300"
659
- },
660
- {
661
- tone: "danger",
662
- variant: "solid",
663
- class: "bg-red-500 text-white"
664
- },
665
- {
666
- tone: "danger",
667
- variant: "outline",
668
- class: "border-red-500 text-red-700 dark:text-red-400"
669
- },
670
- {
671
- tone: "warning",
672
- variant: "soft",
673
- class: "bg-yellow-100 text-yellow-800 dark:bg-yellow-500/20 dark:text-yellow-300"
674
- },
675
- {
676
- tone: "warning",
677
- variant: "solid",
678
- class: "bg-yellow-400 text-yellow-950"
679
- },
680
- {
681
- tone: "warning",
682
- variant: "outline",
683
- class: "border-yellow-500 text-yellow-700 dark:text-yellow-400"
684
- },
685
- {
686
- tone: "info",
687
- variant: "soft",
688
- class: "bg-blue-100 text-blue-800 dark:bg-blue-500/20 dark:text-blue-300"
689
- },
690
- {
691
- tone: "info",
692
- variant: "solid",
693
- class: "bg-blue-500 text-white"
694
- },
695
- {
696
- tone: "info",
697
- variant: "outline",
698
- class: "border-blue-500 text-blue-700 dark:text-blue-400"
699
- }
700
- ],
701
- defaultVariants: {
702
- tone: "neutral",
703
- variant: "soft",
704
- size: "md"
705
- }
706
- });
707
- function Badge({ tone, variant, size, icon, count, children, className }) {
708
- return /* @__PURE__ */ jsxs("span", {
709
- className: cn(badgeVariants({
710
- tone,
711
- variant,
712
- size
713
- }), className),
714
- children: [
715
- icon && /* @__PURE__ */ jsx(Icon, {
716
- name: icon,
717
- className: "text-[1em]"
718
- }),
719
- count !== void 0 && /* @__PURE__ */ jsx("span", { children: count }),
720
- children
721
- ]
722
- });
723
- }
724
-
725
- //#endregion
726
- //#region src/data/SortableHeader.tsx
727
- function SortableHeader({ active, dir, onClick, align = "left", className, children }) {
728
- return /* @__PURE__ */ jsxs("button", {
729
- type: "button",
730
- onClick,
731
- className: cn("inline-flex items-center gap-1 cursor-pointer select-none hover:text-foreground", active ? "text-primary" : "text-muted-foreground", align === "right" ? "justify-end" : align === "center" ? "justify-center" : "justify-start", className),
732
- children: [children, active ? /* @__PURE__ */ jsx("span", {
733
- "aria-hidden": true,
734
- children: dir === "asc" ? "↑" : "↓"
735
- }) : /* @__PURE__ */ jsx("span", {
736
- "aria-hidden": true,
737
- className: "opacity-40",
738
- children: "↕"
739
- })]
740
- });
741
- }
742
-
743
- //#endregion
744
- //#region src/data/TreeNode.tsx
745
- function TreeNode({ node, depth = 0, expandAll = null, selected = null, defaultOpen, getChildren, getKey, onSelect, renderRow, rowClass, indentPx = 16, basePaddingPx = 8 }) {
746
- const children = getChildren(node);
747
- const hasChildren = (children?.length ?? 0) > 0;
748
- const [open, setOpen] = useState(defaultOpen ? defaultOpen(node, depth) : depth < 1);
749
- const prevExpandAll = useRef(expandAll);
750
- const isSelected = selected === node;
751
- useEffect(() => {
752
- if (expandAll !== null && expandAll !== prevExpandAll.current) setOpen(expandAll);
753
- prevExpandAll.current = expandAll;
754
- }, [expandAll]);
755
- function toggle() {
756
- if (hasChildren) setOpen((o) => !o);
757
- }
758
- const rowClassName = rowClass ? rowClass(node, isSelected) : isSelected ? "bg-primary/10 border-l-2 border-primary" : "hover:bg-accent";
759
- return /* @__PURE__ */ jsxs("div", {
760
- role: "treeitem",
761
- "aria-expanded": hasChildren ? open : void 0,
762
- "aria-selected": isSelected,
763
- children: [/* @__PURE__ */ jsxs("div", {
764
- className: cn("flex items-center gap-1.5 py-1 px-2 cursor-pointer text-sm", rowClassName),
765
- style: { paddingLeft: `${depth * indentPx + basePaddingPx}px` },
766
- onClick: (e) => {
767
- e.stopPropagation();
768
- onSelect?.(node);
769
- toggle();
770
- },
771
- children: [hasChildren ? /* @__PURE__ */ jsx(Icon, {
772
- name: open ? "codicon:chevron-down" : "codicon:chevron-right",
773
- className: "text-muted-foreground text-xs w-3"
774
- }) : /* @__PURE__ */ jsx("span", {
775
- className: "w-3 shrink-0",
776
- "aria-hidden": true
777
- }), renderRow({
778
- node,
779
- depth,
780
- open,
781
- selected: isSelected,
782
- hasChildren,
783
- toggle
784
- })]
785
- }), open && hasChildren && /* @__PURE__ */ jsx("div", {
786
- role: "group",
787
- children: children.map((child) => /* @__PURE__ */ jsx(TreeNode, {
788
- node: child,
789
- depth: depth + 1,
790
- expandAll,
791
- selected,
792
- defaultOpen,
793
- getChildren,
794
- getKey,
795
- onSelect,
796
- renderRow,
797
- rowClass,
798
- indentPx,
799
- basePaddingPx
800
- }, getKey(child)))
801
- })]
802
- });
803
- }
804
-
805
- //#endregion
806
- //#region src/data/Tree.tsx
807
- function Tree({ roots, empty, className, showControls = true, expandAll: controlledExpandAll, onExpandAllChange, toolbarClassName, ...nodeProps }) {
808
- const [internalExpandAll, setInternalExpandAll] = useState(null);
809
- const isControlled = onExpandAllChange !== void 0;
810
- const expandAll = isControlled ? controlledExpandAll ?? null : internalExpandAll;
811
- const setExpandAll = (next) => {
812
- if (isControlled) onExpandAllChange?.(next);
813
- else setInternalExpandAll(next);
814
- };
815
- if (roots.length === 0) return /* @__PURE__ */ jsx(Fragment$1, { children: empty ?? null });
816
- return /* @__PURE__ */ jsxs("div", {
817
- className: cn("flex flex-col min-h-0", className),
818
- children: [showControls && /* @__PURE__ */ jsxs("div", {
819
- className: cn("flex items-center gap-1 border-b border-border px-2 py-1 text-xs text-muted-foreground", toolbarClassName),
820
- children: [/* @__PURE__ */ jsxs("button", {
821
- type: "button",
822
- onClick: () => setExpandAll(true),
823
- "aria-pressed": expandAll === true,
824
- className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-accent-foreground", expandAll === true && "bg-accent text-accent-foreground"),
825
- children: [/* @__PURE__ */ jsx(Icon, {
826
- name: "codicon:expand-all",
827
- className: "text-xs"
828
- }), "Expand all"]
829
- }), /* @__PURE__ */ jsxs("button", {
830
- type: "button",
831
- onClick: () => setExpandAll(false),
832
- "aria-pressed": expandAll === false,
833
- className: cn("inline-flex items-center gap-1 rounded px-1.5 py-0.5 hover:bg-accent hover:text-accent-foreground", expandAll === false && "bg-accent text-accent-foreground"),
834
- children: [/* @__PURE__ */ jsx(Icon, {
835
- name: "codicon:collapse-all",
836
- className: "text-xs"
837
- }), "Collapse all"]
838
- })]
839
- }), /* @__PURE__ */ jsx("div", {
840
- role: "tree",
841
- className: "min-h-0 flex-1 overflow-auto",
842
- children: roots.map((root) => /* @__PURE__ */ jsx(TreeNode, {
843
- node: root,
844
- expandAll,
845
- ...nodeProps
846
- }, nodeProps.getKey(root)))
847
- })]
848
- });
849
- }
850
-
851
- //#endregion
852
- //#region src/data/Clicky.tsx
853
- function Clicky({ data, className }) {
854
- const parsed = parseClickyData(data);
855
- if (!parsed.ok) return /* @__PURE__ */ jsxs("div", {
856
- className: cn("rounded-md border border-destructive/30 bg-destructive/5 p-density-3", className),
857
- children: [/* @__PURE__ */ jsx("div", {
858
- className: "text-sm font-medium text-destructive",
859
- children: "Invalid Clicky payload"
860
- }), /* @__PURE__ */ jsxs("pre", {
861
- className: "mt-2 whitespace-pre-wrap break-all text-xs text-muted-foreground",
862
- children: [parsed.message, parsed.raw ? `\n\n${parsed.raw}` : ""]
863
- })]
864
- });
865
- return /* @__PURE__ */ jsx("div", {
866
- className,
867
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: parsed.document.node })
868
- });
869
- }
870
- function parseClickyData(data) {
871
- if (typeof data === "string") try {
872
- return normalizeClickyDocument(JSON.parse(data));
873
- } catch (error) {
874
- return {
875
- ok: false,
876
- message: error instanceof Error ? error.message : "Failed to parse JSON",
877
- raw: data
878
- };
879
- }
880
- return normalizeClickyDocument(data);
881
- }
882
- function normalizeClickyDocument(data) {
883
- if (!data || typeof data !== "object") return {
884
- ok: false,
885
- message: "Payload must be an object",
886
- raw: String(data ?? "")
887
- };
888
- const candidate = data;
889
- if ("version" in candidate && candidate.version === 1 && candidate.node && isClickyNode(candidate.node)) return {
890
- ok: true,
891
- document: candidate
892
- };
893
- if (isClickyNode(candidate)) return {
894
- ok: true,
895
- document: {
896
- version: 1,
897
- node: candidate
898
- }
899
- };
900
- return {
901
- ok: false,
902
- message: "Payload is neither a Clicky document nor a Clicky node",
903
- raw: JSON.stringify(data, null, 2)
904
- };
905
- }
906
- function isClickyNode(value) {
907
- return !!value && typeof value === "object" && typeof value.kind === "string";
908
- }
909
- function ClickyNodeRenderer({ node }) {
910
- if (!node) return null;
911
- switch (node.kind) {
912
- case "text": return /* @__PURE__ */ jsx(ClickyText, { node });
913
- case "icon": return /* @__PURE__ */ jsx(ClickyIconNode, { node });
914
- case "list": return /* @__PURE__ */ jsx(ClickyList, { node });
915
- case "map": return /* @__PURE__ */ jsx(ClickyMap, { node });
916
- case "table": return /* @__PURE__ */ jsx(ClickyTable, { node });
917
- case "tree": return /* @__PURE__ */ jsx(ClickyTreeNode, { node });
918
- case "code": return /* @__PURE__ */ jsx(ClickyCodeBlock, { node });
919
- case "collapsed": return /* @__PURE__ */ jsx(ClickyCollapsed, { node });
920
- case "button": return /* @__PURE__ */ jsx(ClickyButtonNode, { node });
921
- case "button-group": return /* @__PURE__ */ jsx(ClickyButtonGroup, { node });
922
- case "html": return /* @__PURE__ */ jsx(ClickyHtmlNode, { node });
923
- case "comment": return null;
924
- default: return /* @__PURE__ */ jsx("pre", {
925
- className: "rounded-md border border-border bg-muted p-density-3 text-xs",
926
- children: JSON.stringify(node, null, 2)
927
- });
928
- }
929
- }
930
- function ClickyText({ node }) {
931
- const inlineStyle = toInlineStyle(node.style, node.text ?? node.plain);
932
- const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [node.text, node.children?.map((child, index) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: child }) }, index))] });
933
- if (!node.style && !node.tooltip) return /* @__PURE__ */ jsx(Fragment$1, { children: content });
934
- return /* @__PURE__ */ jsx("span", {
935
- style: inlineStyle,
936
- title: node.tooltip?.plain,
937
- className: cn(node.style?.className, (node.text ?? "").includes("\n") && "whitespace-pre-wrap"),
938
- children: content
939
- });
940
- }
941
- function ClickyIconNode({ node }) {
942
- return /* @__PURE__ */ jsx("span", {
943
- style: toInlineStyle(node.style, node.plain ?? node.unicode),
944
- title: node.tooltip?.plain,
945
- className: "inline-flex items-center",
946
- children: node.iconify ? /* @__PURE__ */ jsx(Icon, { name: node.iconify }) : /* @__PURE__ */ jsx("span", { children: node.unicode ?? node.plain })
947
- });
948
- }
949
- function ClickyList({ node }) {
950
- const items = node.items ?? [];
951
- if (items.length === 0) return null;
952
- if (node.inline) return /* @__PURE__ */ jsx("span", {
953
- className: "inline-flex flex-wrap items-start gap-1",
954
- children: items.map((item, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && /* @__PURE__ */ jsx("span", {
955
- className: "text-muted-foreground",
956
- children: ","
957
- }), /* @__PURE__ */ jsxs("span", {
958
- className: "inline-flex items-center gap-1",
959
- children: [
960
- !node.ordered && node.bullet && /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: node.bullet }),
961
- node.ordered && /* @__PURE__ */ jsxs("span", {
962
- className: "text-muted-foreground",
963
- children: [index + 1, "."]
964
- }),
965
- /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: item })
966
- ]
967
- })] }, index))
968
- });
969
- if (node.unstyled) return /* @__PURE__ */ jsx("div", {
970
- className: "space-y-1",
971
- children: items.map((item, index) => /* @__PURE__ */ jsxs("div", {
972
- className: "flex items-start gap-2",
973
- children: [
974
- !node.ordered && node.bullet && /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: node.bullet }),
975
- node.ordered && /* @__PURE__ */ jsxs("span", {
976
- className: "text-muted-foreground",
977
- children: [index + 1, "."]
978
- }),
979
- /* @__PURE__ */ jsx("div", {
980
- className: "min-w-0 flex-1",
981
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: item })
982
- })
983
- ]
984
- }, index))
985
- });
986
- return /* @__PURE__ */ jsx(node.ordered ? "ol" : "ul", {
987
- className: cn("ml-5 space-y-1 text-sm", node.ordered ? "list-decimal" : "list-disc"),
988
- children: items.map((item, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: item }) }, index))
989
- });
990
- }
991
- function ClickyMap({ node }) {
992
- const fields = node.fields ?? [];
993
- if (fields.length === 0) return null;
994
- const inlineFields = fields.filter((field) => isInlineNode(field.value));
995
- const blockFields = fields.filter((field) => !isInlineNode(field.value));
996
- return /* @__PURE__ */ jsxs("div", {
997
- className: "space-y-density-4",
998
- children: [inlineFields.length > 0 && /* @__PURE__ */ jsx("dl", {
999
- className: "grid gap-density-3 md:grid-cols-2",
1000
- children: inlineFields.map((field) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", {
1001
- className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground",
1002
- children: field.label || prettifyName(field.name)
1003
- }), /* @__PURE__ */ jsx("dd", {
1004
- className: "mt-1 text-sm text-foreground",
1005
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: field.value })
1006
- })] }, field.name))
1007
- }), blockFields.map((field) => /* @__PURE__ */ jsxs("section", {
1008
- className: "space-y-2",
1009
- children: [/* @__PURE__ */ jsx("div", {
1010
- className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground",
1011
- children: field.label || prettifyName(field.name)
1012
- }), /* @__PURE__ */ jsx("div", {
1013
- className: "rounded-md border border-border bg-background p-density-3",
1014
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: field.value })
1015
- })]
1016
- }, field.name))]
1017
- });
1018
- }
1019
- function ClickyTable({ node }) {
1020
- const columns = node.columns ?? [];
1021
- const rows = node.rows ?? [];
1022
- const hasDetail = rows.some((row) => !!row.detail);
1023
- const [sortKey, setSortKey] = useState(columns[0]?.name ?? "");
1024
- const [sortDir, setSortDir] = useState("asc");
1025
- if (columns.length === 0 || rows.length === 0) return /* @__PURE__ */ jsx("div", {
1026
- className: "text-sm text-muted-foreground",
1027
- children: "No data"
1028
- });
1029
- const sortedRows = [...rows].sort((left, right) => {
1030
- if (!sortKey) return 0;
1031
- const leftValue = left.cells[sortKey]?.plain ?? left.cells[sortKey]?.text ?? "";
1032
- const rightValue = right.cells[sortKey]?.plain ?? right.cells[sortKey]?.text ?? "";
1033
- return sortDir === "asc" ? compareClickyValues(leftValue, rightValue) : compareClickyValues(rightValue, leftValue);
1034
- });
1035
- return /* @__PURE__ */ jsx("div", {
1036
- className: "overflow-auto rounded-md border border-border",
1037
- children: /* @__PURE__ */ jsxs("table", {
1038
- className: "w-full text-left text-sm table-fixed",
1039
- children: [/* @__PURE__ */ jsx("thead", {
1040
- className: "sticky top-0 bg-muted/50",
1041
- children: /* @__PURE__ */ jsxs("tr", {
1042
- className: "border-b border-border text-xs text-muted-foreground",
1043
- children: [hasDetail && /* @__PURE__ */ jsx("th", { className: "w-8 px-2 py-2" }), columns.map((column) => /* @__PURE__ */ jsx("th", {
1044
- className: "px-2 py-2 font-medium",
1045
- children: /* @__PURE__ */ jsx(SortableHeader, {
1046
- active: sortKey === column.name,
1047
- dir: sortKey === column.name ? sortDir : void 0,
1048
- align: column.align ?? "left",
1049
- onClick: () => {
1050
- if (sortKey === column.name) setSortDir((current) => current === "asc" ? "desc" : "asc");
1051
- else {
1052
- setSortKey(column.name);
1053
- setSortDir("asc");
1054
- }
1055
- },
1056
- children: column.header ? /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: column.header }) : column.label || prettifyName(column.name)
1057
- })
1058
- }, column.name))]
1059
- })
1060
- }), /* @__PURE__ */ jsx("tbody", { children: sortedRows.map((row, index) => /* @__PURE__ */ jsx(ClickyTableRow, {
1061
- row,
1062
- columns,
1063
- hasDetail
1064
- }, `${index}-${row.cells[columns[0]?.name ?? ""]?.plain ?? ""}`)) })]
1065
- })
1066
- });
1067
- }
1068
- function ClickyTableRow({ row, columns, hasDetail }) {
1069
- const [open, setOpen] = useState(false);
1070
- const expandable = !!row.detail;
1071
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("tr", {
1072
- className: cn("border-b border-border align-top", expandable && "cursor-pointer hover:bg-accent/50"),
1073
- onClick: expandable ? () => setOpen((current) => !current) : void 0,
1074
- children: [hasDetail && /* @__PURE__ */ jsx("td", {
1075
- className: "px-2 py-2 text-center text-muted-foreground",
1076
- children: expandable ? open ? "▼" : "▶" : ""
1077
- }), columns.map((column) => /* @__PURE__ */ jsx("td", {
1078
- className: cn("px-2 py-2", alignmentClass(column.align)),
1079
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: row.cells[column.name] })
1080
- }, column.name))]
1081
- }), open && row.detail && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
1082
- colSpan: columns.length + (hasDetail ? 1 : 0),
1083
- className: "bg-muted/40 p-density-3",
1084
- children: /* @__PURE__ */ jsx("div", {
1085
- className: "rounded-md border border-border bg-background p-density-3",
1086
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: row.detail })
1087
- })
1088
- }) })] });
1089
- }
1090
- function ClickyTreeNode({ node }) {
1091
- const roots = node.roots ?? [];
1092
- if (roots.length === 0) return null;
1093
- return /* @__PURE__ */ jsx(Tree, {
1094
- roots,
1095
- getChildren: (item) => item.children,
1096
- getKey: (item) => item.id,
1097
- defaultOpen: (_, depth) => depth < 1,
1098
- renderRow: ({ node: item }) => /* @__PURE__ */ jsx("div", {
1099
- className: "min-w-0 flex-1 truncate",
1100
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: item.label })
1101
- })
1102
- });
1103
- }
1104
- function ClickyCodeBlock({ node }) {
1105
- const html = node.highlightedHtml ? sanitizeHtml(node.highlightedHtml) : "";
1106
- return /* @__PURE__ */ jsxs("div", {
1107
- className: "overflow-hidden rounded-md border border-border bg-muted/40",
1108
- children: [/* @__PURE__ */ jsx("div", {
1109
- className: "border-b border-border px-3 py-1.5 text-[11px] uppercase tracking-wide text-muted-foreground",
1110
- children: node.language || "text"
1111
- }), html ? /* @__PURE__ */ jsx("div", {
1112
- className: "overflow-auto p-3 text-xs font-mono [&_.chroma]:bg-transparent [&_pre]:m-0 [&_pre]:whitespace-pre-wrap [&_pre]:bg-transparent",
1113
- dangerouslySetInnerHTML: { __html: html }
1114
- }) : /* @__PURE__ */ jsx("pre", {
1115
- className: "overflow-auto whitespace-pre-wrap break-words p-3 text-xs font-mono text-foreground",
1116
- children: node.source ?? node.plain
1117
- })]
1118
- });
1119
- }
1120
- function ClickyCollapsed({ node }) {
1121
- return /* @__PURE__ */ jsxs("details", {
1122
- className: "rounded-md border border-border bg-background",
1123
- children: [/* @__PURE__ */ jsx("summary", {
1124
- className: "cursor-pointer px-3 py-2 text-sm font-medium text-foreground",
1125
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: node.label })
1126
- }), node.content && /* @__PURE__ */ jsx("div", {
1127
- className: "border-t border-border px-3 py-3",
1128
- children: /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: node.content })
1129
- })]
1130
- });
1131
- }
1132
- function ClickyButtonNode({ node }) {
1133
- const title = [node.id, node.payload].filter(Boolean).join("\n") || void 0;
1134
- const content = node.label ? /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: node.label }) : node.text;
1135
- if (node.href) return /* @__PURE__ */ jsx("a", {
1136
- href: node.href,
1137
- target: "_blank",
1138
- rel: "noopener noreferrer",
1139
- title,
1140
- className: "inline-flex items-center rounded-md border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground hover:bg-accent",
1141
- children: content
1142
- });
1143
- return /* @__PURE__ */ jsx("button", {
1144
- type: "button",
1145
- title,
1146
- className: "inline-flex items-center rounded-md border border-border bg-muted px-3 py-1.5 text-sm font-medium text-foreground",
1147
- children: content
1148
- });
1149
- }
1150
- function ClickyButtonGroup({ node }) {
1151
- const items = node.items ?? [];
1152
- if (items.length === 0) return null;
1153
- return /* @__PURE__ */ jsx("div", {
1154
- className: "flex flex-wrap gap-2",
1155
- children: items.map((item, index) => /* @__PURE__ */ jsx(ClickyNodeRenderer, { node: item }, index))
1156
- });
1157
- }
1158
- function ClickyHtmlNode({ node }) {
1159
- const sanitized = sanitizeHtml(node.html ?? "");
1160
- if (!sanitized) return null;
1161
- return /* @__PURE__ */ jsx(isBlockHtml(sanitized) ? "div" : "span", { dangerouslySetInnerHTML: { __html: sanitized } });
1162
- }
1163
- function toInlineStyle(style, text) {
1164
- if (!style) return text?.includes("\n") ? { whiteSpace: "pre-wrap" } : void 0;
1165
- const inlineStyle = {};
1166
- if (style.color) inlineStyle.color = style.color;
1167
- if (style.backgroundColor) inlineStyle.backgroundColor = style.backgroundColor;
1168
- if (style.bold) inlineStyle.fontWeight = 700;
1169
- if (style.faint) inlineStyle.opacity = .7;
1170
- if (style.italic) inlineStyle.fontStyle = "italic";
1171
- const decorations = [];
1172
- if (style.underline) decorations.push("underline");
1173
- if (style.strikethrough) decorations.push("line-through");
1174
- if (decorations.length > 0) inlineStyle.textDecoration = decorations.join(" ");
1175
- if (style.textTransform === "uppercase" || style.textTransform === "lowercase" || style.textTransform === "capitalize") inlineStyle.textTransform = style.textTransform;
1176
- if (style.maxWidth && style.maxWidth > 0) inlineStyle.maxWidth = `${style.maxWidth}ch`;
1177
- if (style.maxLines && style.maxLines > 0) {
1178
- inlineStyle.display = "-webkit-box";
1179
- inlineStyle.overflow = "hidden";
1180
- inlineStyle.WebkitLineClamp = style.maxLines;
1181
- inlineStyle.WebkitBoxOrient = "vertical";
1182
- inlineStyle.whiteSpace = "pre-wrap";
1183
- }
1184
- if (style.truncateMode === "suffix" && style.maxWidth && (!style.maxLines || style.maxLines <= 1)) {
1185
- inlineStyle.overflow = "hidden";
1186
- inlineStyle.textOverflow = "ellipsis";
1187
- inlineStyle.whiteSpace = "nowrap";
1188
- inlineStyle.display = "inline-block";
1189
- inlineStyle.verticalAlign = "bottom";
1190
- }
1191
- if (style.monospace) inlineStyle.fontFamily = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace";
1192
- if (!inlineStyle.whiteSpace && text?.includes("\n")) inlineStyle.whiteSpace = "pre-wrap";
1193
- return Object.keys(inlineStyle).length > 0 ? inlineStyle : void 0;
1194
- }
1195
- function sanitizeHtml(raw) {
1196
- if (!raw) return "";
1197
- if (typeof DOMParser === "undefined") return raw.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/\son\w+="[^"]*"/gi, "").replace(/\son\w+='[^']*'/gi, "");
1198
- const doc = new DOMParser().parseFromString(raw, "text/html");
1199
- doc.querySelectorAll("script,iframe,object,embed,form").forEach((element) => element.remove());
1200
- doc.querySelectorAll("*").forEach((element) => {
1201
- Array.from(element.attributes).forEach((attribute) => {
1202
- const name = attribute.name.toLowerCase();
1203
- const value = attribute.value.trim().toLowerCase();
1204
- if (name.startsWith("on") || name === "srcdoc") element.removeAttribute(attribute.name);
1205
- if ((name === "href" || name === "src") && value.startsWith("javascript:")) element.removeAttribute(attribute.name);
1206
- });
1207
- });
1208
- return doc.body.innerHTML;
1209
- }
1210
- function prettifyName(name) {
1211
- return name.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").replace(/\b\w/g, (value) => value.toUpperCase());
1212
- }
1213
- function compareClickyValues(left, right) {
1214
- const leftNumber = Number(left);
1215
- const rightNumber = Number(right);
1216
- if (!Number.isNaN(leftNumber) && !Number.isNaN(rightNumber)) return leftNumber - rightNumber;
1217
- return left.localeCompare(right, void 0, {
1218
- numeric: true,
1219
- sensitivity: "base"
1220
- });
1221
- }
1222
- function isInlineNode(node) {
1223
- return node.kind === "text" || node.kind === "icon" || node.kind === "html" || node.kind === "button" || node.kind === "button-group";
1224
- }
1225
- function alignmentClass(align) {
1226
- if (align === "right") return "text-right";
1227
- if (align === "center") return "text-center";
1228
- }
1229
- function isBlockHtml(html) {
1230
- return /<(div|p|pre|table|ul|ol|li|details|blockquote|h[1-6])/i.test(html);
1231
- }
1232
-
1233
- //#endregion
1234
- //#region src/data/FilterPill.tsx
1235
- function bodyClasses(mode) {
1236
- switch (mode) {
1237
- case "active": return "bg-primary/10 border-primary/40 text-primary font-medium";
1238
- case "include": return "bg-green-500/10 border-green-500/50 text-green-700 dark:text-green-400 font-medium";
1239
- case "exclude": return "bg-red-500/10 border-red-500/50 text-red-700 dark:text-red-400 font-medium";
1240
- default: return "border-border text-muted-foreground hover:bg-accent";
1241
- }
1242
- }
1243
- const SLOT_TRANSLATE = {
1244
- exclude: "-translate-x-[21px]",
1245
- neutral: "translate-x-0",
1246
- include: "translate-x-[21px]"
1247
- };
1248
- function TristateSwitch({ mode, onChange, ariaLabel }) {
1249
- const slot = mode === "exclude" ? "exclude" : mode === "include" ? "include" : "neutral";
1250
- const bg = slot === "exclude" ? "bg-red-500" : slot === "include" ? "bg-green-500" : "bg-muted";
1251
- const fg = slot === "neutral" ? "text-muted-foreground" : "text-white";
1252
- const onSlot = (target) => {
1253
- if (target === "neutral") {
1254
- onChange("neutral");
1255
- return;
1256
- }
1257
- onChange(slot === target ? "neutral" : target);
1258
- };
1259
- return /* @__PURE__ */ jsxs("span", {
1260
- role: "radiogroup",
1261
- "aria-label": ariaLabel,
1262
- className: cn("relative inline-flex items-center justify-center w-[66px] h-6 rounded-full overflow-hidden transition-colors duration-200 shrink-0", bg),
1263
- children: [[
1264
- "exclude",
1265
- "neutral",
1266
- "include"
1267
- ].map((target) => /* @__PURE__ */ jsx("button", {
1268
- type: "button",
1269
- role: "radio",
1270
- "aria-checked": slot === target,
1271
- title: target === "exclude" ? "Exclude" : target === "include" ? "Include" : "Do not filter",
1272
- onClick: (e) => {
1273
- e.preventDefault();
1274
- e.stopPropagation();
1275
- onSlot(target);
1276
- },
1277
- className: cn("relative z-10 flex h-full flex-1 items-center justify-center transition-colors duration-100", fg),
1278
- children: /* @__PURE__ */ jsx(Icon, {
1279
- name: target === "exclude" ? "codicon:close" : target === "include" ? "codicon:check" : "codicon:primitive-dot",
1280
- className: "text-sm"
1281
- })
1282
- }, target)), /* @__PURE__ */ jsx("span", {
1283
- "aria-hidden": true,
1284
- className: cn("pointer-events-none absolute w-5 h-5 rounded-full bg-white shadow-md transition-transform duration-150", SLOT_TRANSLATE[slot])
1285
- })]
1286
- });
1287
- }
1288
- function FilterPill({ mode = "neutral", label, count, icon, badge, onModeChange, onClick, title, className }) {
1289
- const triState = !!onModeChange;
1290
- const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
1291
- count !== void 0 && /* @__PURE__ */ jsx("span", {
1292
- className: cn("inline-flex items-center justify-center min-w-[16px] h-[16px] px-1 rounded-full text-[10px] font-bold text-white", badge ?? "bg-muted-foreground"),
1293
- children: count
1294
- }),
1295
- icon && /* @__PURE__ */ jsx(Icon, {
1296
- name: icon,
1297
- className: "text-sm"
1298
- }),
1299
- /* @__PURE__ */ jsx("span", {
1300
- className: "truncate",
1301
- children: label
1302
- })
1303
- ] });
1304
- if (triState) {
1305
- const labelTone = mode === "include" ? "text-green-700 dark:text-green-400" : mode === "exclude" ? "text-red-700 dark:text-red-400" : "text-foreground";
1306
- return /* @__PURE__ */ jsxs("span", {
1307
- className: cn("inline-flex items-center gap-2 select-none", className),
1308
- title,
1309
- children: [/* @__PURE__ */ jsx(TristateSwitch, {
1310
- mode,
1311
- onChange: onModeChange,
1312
- ariaLabel: title
1313
- }), /* @__PURE__ */ jsx("span", {
1314
- className: cn("inline-flex items-center gap-1.5 text-xs", labelTone),
1315
- children: content
1316
- })]
1317
- });
1318
- }
1319
- return /* @__PURE__ */ jsxs("button", {
1320
- type: "button",
1321
- onClick,
1322
- title,
1323
- className: cn("inline-flex items-center gap-1.5 text-xs px-2 py-0.5 rounded-full border transition-colors", bodyClasses(mode), className),
1324
- children: [/* @__PURE__ */ jsx(LegacyMarker, { mode }), content]
1325
- });
1326
- }
1327
- function LegacyMarker({ mode }) {
1328
- if (mode === "include") return /* @__PURE__ */ jsx(Icon, {
1329
- name: "codicon:add",
1330
- className: "text-xs"
1331
- });
1332
- if (mode === "exclude") return /* @__PURE__ */ jsx(Icon, {
1333
- name: "codicon:remove",
1334
- className: "text-xs"
1335
- });
1336
- if (mode === "active") return /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-current" });
1337
- return /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-current opacity-30" });
1338
- }
1339
- function FilterPillGroup({ children, className }) {
1340
- return /* @__PURE__ */ jsx("div", {
1341
- className: cn("flex items-center gap-1.5 flex-wrap", className),
1342
- children
1343
- });
1344
- }
1345
- function FilterSeparator() {
1346
- return /* @__PURE__ */ jsx("span", {
1347
- "aria-hidden": true,
1348
- className: "text-border mx-0.5",
1349
- children: "|"
1350
- });
1351
- }
1352
-
1353
- //#endregion
1354
- //#region src/data/Gauge.tsx
1355
- const toneClass = {
1356
- neutral: "text-foreground",
1357
- success: "text-green-600 dark:text-green-400",
1358
- warning: "text-yellow-600 dark:text-yellow-400",
1359
- danger: "text-red-600 dark:text-red-400",
1360
- info: "text-blue-600 dark:text-blue-400"
1361
- };
1362
- function Gauge({ label, value, max = 100, tone = "neutral", suffix = "%", className }) {
1363
- const pct = max > 0 ? Math.round(value / max * 100) : 0;
1364
- return /* @__PURE__ */ jsxs("div", {
1365
- className: cn("flex flex-col items-start gap-0.5 rounded-md border border-border bg-background px-density-3 py-density-2", className),
1366
- children: [/* @__PURE__ */ jsx("span", {
1367
- className: "text-[10px] uppercase tracking-wide text-muted-foreground",
1368
- children: label
1369
- }), /* @__PURE__ */ jsxs("span", {
1370
- className: cn("text-lg font-semibold tabular-nums", toneClass[tone]),
1371
- children: [max === 100 ? value : pct, /* @__PURE__ */ jsx("span", {
1372
- className: "text-xs ml-0.5 opacity-60",
1373
- children: suffix
1374
- })]
1375
- })]
1376
- });
1377
- }
1378
-
1379
- //#endregion
1380
- //#region src/data/JsonView.tsx
1381
- function JsonView({ data, name, depth = 0, defaultOpenDepth = 2 }) {
1382
- const [open, setOpen] = useState(depth < defaultOpenDepth);
1383
- if (data === null || data === void 0) return /* @__PURE__ */ jsx("span", {
1384
- className: "text-muted-foreground italic",
1385
- children: "null"
1386
- });
1387
- if (typeof data === "string") return /* @__PURE__ */ jsxs("span", {
1388
- className: "text-green-700 dark:text-green-400",
1389
- children: [
1390
- "\"",
1391
- data,
1392
- "\""
1393
- ]
1394
- });
1395
- if (typeof data === "number" || typeof data === "boolean") return /* @__PURE__ */ jsx("span", {
1396
- className: "text-blue-700 dark:text-blue-400",
1397
- children: String(data)
1398
- });
1399
- if (typeof data !== "object") return /* @__PURE__ */ jsx("span", {
1400
- className: "text-muted-foreground",
1401
- children: String(data)
1402
- });
1403
- const isArray = Array.isArray(data);
1404
- const entries = isArray ? data.map((v, i) => [i, v]) : Object.entries(data);
1405
- const [openB, closeB] = isArray ? ["[", "]"] : ["{", "}"];
1406
- if (entries.length === 0) return /* @__PURE__ */ jsxs("span", {
1407
- className: "text-muted-foreground",
1408
- children: [openB, closeB]
1409
- });
1410
- return /* @__PURE__ */ jsxs("div", {
1411
- className: "text-sm font-mono",
1412
- style: { paddingLeft: depth > 0 ? "12px" : "0" },
1413
- children: [/* @__PURE__ */ jsxs("span", {
1414
- className: "cursor-pointer hover:bg-accent rounded px-0.5 select-none",
1415
- onClick: () => setOpen(!open),
1416
- children: [
1417
- /* @__PURE__ */ jsx("span", {
1418
- className: "text-muted-foreground text-xs mr-1",
1419
- children: open ? "▼" : "▶"
1420
- }),
1421
- name && /* @__PURE__ */ jsx("span", {
1422
- className: "text-purple-600 dark:text-purple-400",
1423
- children: name
1424
- }),
1425
- name && /* @__PURE__ */ jsx("span", {
1426
- className: "text-muted-foreground",
1427
- children: ": "
1428
- }),
1429
- !open && /* @__PURE__ */ jsxs("span", {
1430
- className: "text-muted-foreground",
1431
- children: [
1432
- openB,
1433
- " ",
1434
- entries.length,
1435
- " ",
1436
- isArray ? "items" : "keys",
1437
- " ",
1438
- closeB
1439
- ]
1440
- }),
1441
- open && /* @__PURE__ */ jsx("span", {
1442
- className: "text-muted-foreground",
1443
- children: openB
1444
- })
1445
- ]
1446
- }), open && /* @__PURE__ */ jsxs(Fragment$1, { children: [entries.map(([key, val]) => /* @__PURE__ */ jsx("div", {
1447
- className: "pl-3 border-l border-border ml-1",
1448
- children: typeof val === "object" && val !== null ? /* @__PURE__ */ jsx(JsonView, {
1449
- data: val,
1450
- name: String(key),
1451
- depth: depth + 1,
1452
- defaultOpenDepth
1453
- }) : /* @__PURE__ */ jsxs("div", { children: [
1454
- /* @__PURE__ */ jsx("span", {
1455
- className: "text-purple-600 dark:text-purple-400",
1456
- children: isArray ? "" : String(key)
1457
- }),
1458
- !isArray && /* @__PURE__ */ jsx("span", {
1459
- className: "text-muted-foreground",
1460
- children: ": "
1461
- }),
1462
- /* @__PURE__ */ jsx(JsonView, {
1463
- data: val,
1464
- depth: depth + 1,
1465
- defaultOpenDepth
1466
- })
1467
- ] })
1468
- }, key)), /* @__PURE__ */ jsx("span", {
1469
- className: "text-muted-foreground",
1470
- children: closeB
1471
- })] })]
1472
- });
1473
- }
1474
-
1475
- //#endregion
1476
- //#region src/data/LogViewer.tsx
1477
- function LogViewer({ logs, collapsedLines = 5, maxExpandedVh = 70, bgClass = "bg-muted", borderClass = "border-border", className }) {
1478
- const [expanded, setExpanded] = useState(false);
1479
- const lines = useMemo(() => logs.split("\n"), [logs]);
1480
- const hasMore = lines.length > collapsedLines;
1481
- const maxHeight = expanded ? `${maxExpandedVh}vh` : `${collapsedLines * 1.4}em`;
1482
- return /* @__PURE__ */ jsxs("div", {
1483
- className: cn("relative", className),
1484
- children: [/* @__PURE__ */ jsx("pre", {
1485
- className: cn("mt-0.5 text-[11px] text-muted-foreground rounded p-1.5 whitespace-pre-wrap overflow-y-auto border transition-all duration-200", bgClass, borderClass),
1486
- style: { maxHeight },
1487
- children: expanded ? logs : lines.slice(0, collapsedLines).join("\n")
1488
- }), hasMore && /* @__PURE__ */ jsx("button", {
1489
- type: "button",
1490
- className: cn("text-[10px] mt-0.5", expanded ? "text-muted-foreground" : "text-primary hover:opacity-80"),
1491
- onClick: () => setExpanded((e) => !e),
1492
- children: expanded ? `▲ Collapse (${lines.length} lines)` : `▼ Show more (${lines.length} lines)`
1493
- })]
1494
- });
1495
- }
1496
-
1497
- //#endregion
1498
- //#region src/data/Markdown.tsx
1499
- let loadPromise = null;
1500
- function loadMarked() {
1501
- if (loadPromise) return loadPromise;
1502
- loadPromise = import("marked").then(({ Marked, Renderer }) => {
1503
- const renderer = new Renderer();
1504
- renderer.code = ({ text, lang }) => `<pre class="bg-muted rounded p-2 text-xs overflow-x-auto border border-border my-1.5"><code${lang ? ` class="language-${lang}"` : ""}>${text}</code></pre>`;
1505
- renderer.codespan = ({ text }) => `<code class="bg-muted rounded px-1 text-xs">${text}</code>`;
1506
- renderer.heading = ({ text, depth }) => {
1507
- return `<h${depth} class="${depth <= 1 ? "font-bold text-base mt-2 mb-1" : depth === 2 ? "font-semibold text-sm mt-2 mb-1" : "font-semibold text-sm mt-2 mb-1"}">${text}</h${depth}>`;
1508
- };
1509
- renderer.link = ({ href, text }) => `<a href="${href}" target="_blank" rel="noopener noreferrer" class="text-primary hover:underline">${text}</a>`;
1510
- renderer.blockquote = ({ text }) => `<blockquote class="border-l-2 border-border pl-2 text-muted-foreground italic my-1">${text}</blockquote>`;
1511
- renderer.tablerow = ({ text }) => `<tr class="border-b border-border">${text}</tr>`;
1512
- renderer.list = function(token) {
1513
- const tag = token.ordered ? "ol" : "ul";
1514
- return `<${tag} class="${token.ordered ? "list-decimal ml-4 my-1" : "list-disc ml-4 my-1"}">${token.items.map((item) => this.listitem(item)).join("")}</${tag}>`;
1515
- };
1516
- renderer.listitem = ({ text }) => `<li class="my-0.5">${text}</li>`;
1517
- renderer.image = ({ href, text }) => `<img src="${href}" alt="${text}" class="max-w-full rounded my-1" />`;
1518
- renderer.hr = () => "<hr class=\"border-border my-2\" />";
1519
- renderer.paragraph = ({ text }) => `<p class="mt-1.5">${text}</p>`;
1520
- return new Marked({
1521
- renderer,
1522
- gfm: true,
1523
- breaks: true
1524
- });
1525
- });
1526
- return loadPromise;
1527
- }
1528
- function Markdown({ text, className }) {
1529
- const [html, setHtml] = useState(null);
1530
- useEffect(() => {
1531
- let cancelled = false;
1532
- loadMarked().then((m) => Promise.resolve(m.parse(text))).then((out) => {
1533
- if (!cancelled) setHtml(out);
1534
- }).catch(() => {
1535
- if (!cancelled) setHtml(text);
1536
- });
1537
- return () => {
1538
- cancelled = true;
1539
- };
1540
- }, [text]);
1541
- if (html === null) return /* @__PURE__ */ jsx("pre", {
1542
- className: cn("text-sm whitespace-pre-wrap", className),
1543
- children: text
1544
- });
1545
- return /* @__PURE__ */ jsx("div", {
1546
- className: cn("prose prose-sm max-w-none dark:prose-invert", className),
1547
- dangerouslySetInnerHTML: { __html: html }
1548
- });
1549
- }
1550
-
1551
- //#endregion
1552
- //#region src/data/ProgressBar.tsx
1553
- function ProgressBar({ segments, total, height = "h-2", className }) {
1554
- if (total === 0) return null;
1555
- const tooltip = segments.filter((s) => s.count > 0).map((s) => `${s.count} ${s.label}`).join(", ");
1556
- return /* @__PURE__ */ jsx("div", {
1557
- className: cn("w-full bg-muted rounded-full flex overflow-hidden", height, className),
1558
- title: tooltip,
1559
- role: "progressbar",
1560
- "aria-valuemin": 0,
1561
- "aria-valuemax": total,
1562
- "aria-valuenow": segments.reduce((acc, s) => acc + s.count, 0),
1563
- children: segments.map((seg, i) => {
1564
- if (seg.count === 0) return null;
1565
- const pct = seg.count / total * 100;
1566
- return /* @__PURE__ */ jsx("div", {
1567
- className: cn(seg.color, height, "transition-all duration-300"),
1568
- style: { width: `${pct}%` },
1569
- title: `${seg.count} ${seg.label}`
1570
- }, i);
1571
- })
1572
- });
1573
- }
1574
-
1575
- //#endregion
1576
- //#region src/data/TabButton.tsx
1577
- function TabButton({ active, onClick, label, icon, count, countColor = "bg-muted-foreground", className }) {
1578
- return /* @__PURE__ */ jsxs("button", {
1579
- type: "button",
1580
- role: "tab",
1581
- "aria-selected": active,
1582
- onClick,
1583
- className: cn("inline-flex items-center gap-1.5 px-density-3 py-density-1.5 text-sm rounded-md transition-colors", active ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-accent hover:text-foreground", className),
1584
- children: [
1585
- icon && /* @__PURE__ */ jsx(Icon, { name: icon }),
1586
- /* @__PURE__ */ jsx("span", { children: label }),
1587
- count !== void 0 && count > 0 && /* @__PURE__ */ jsx("span", {
1588
- className: cn("inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold text-white", countColor),
1589
- children: count
1590
- })
1591
- ]
1592
- });
1593
- }
1594
-
1595
- //#endregion
1596
- //#region src/data/TreeGroupHeader.tsx
1597
- function TreeGroupHeader({ title, open, onToggle, icon, count, className }) {
1598
- return /* @__PURE__ */ jsxs("button", {
1599
- type: "button",
1600
- onClick: onToggle,
1601
- "aria-expanded": open,
1602
- className: cn("w-full flex items-center gap-2 px-3 py-2 border-b border-border select-none", "hover:bg-accent transition-colors text-left", className),
1603
- children: [
1604
- /* @__PURE__ */ jsx(Icon, {
1605
- name: open ? "codicon:chevron-down" : "codicon:chevron-right",
1606
- className: "text-muted-foreground text-xs"
1607
- }),
1608
- icon && /* @__PURE__ */ jsx(Icon, {
1609
- name: icon,
1610
- className: "text-base"
1611
- }),
1612
- /* @__PURE__ */ jsx("span", {
1613
- className: "font-medium text-sm flex-1 truncate",
1614
- children: title
1615
- }),
1616
- count !== void 0 && /* @__PURE__ */ jsx("span", {
1617
- className: "text-xs text-muted-foreground",
1618
- children: count
1619
- })
1620
- ]
1621
- });
1622
- }
1623
-
1624
- //#endregion
1625
- //#region src/data/diagnostics/utils.ts
1626
- function countProcesses(node) {
1627
- if (!node) return 0;
1628
- return 1 + (node.children || []).reduce((sum, child) => sum + countProcesses(child), 0);
1629
- }
1630
- function findProcessByPID(node, pid) {
1631
- if (!node) return null;
1632
- if (node.pid === pid) return node;
1633
- for (const child of node.children || []) {
1634
- const found = findProcessByPID(child, pid);
1635
- if (found) return found;
1636
- }
1637
- return null;
1638
- }
1639
- function processStateIcon(status) {
1640
- const value = (status || "").toLowerCase();
1641
- if (value.includes("run")) return "codicon:play-circle";
1642
- if (value.includes("sleep") || value.includes("idle")) return "codicon:clock";
1643
- if (value.includes("stop") || value.includes("halt")) return "codicon:debug-pause";
1644
- if (value.includes("zombie") || value.includes("dead")) return "codicon:error";
1645
- if (value.includes("wait") || value.includes("block")) return "codicon:debug-step-over";
1646
- return "codicon:circle-filled";
1647
- }
1648
- function processStateColor(status) {
1649
- const value = (status || "").toLowerCase();
1650
- if (value.includes("run")) return "text-green-600";
1651
- if (value.includes("sleep") || value.includes("idle")) return "text-amber-500";
1652
- if (value.includes("stop") || value.includes("halt")) return "text-orange-600";
1653
- if (value.includes("zombie") || value.includes("dead")) return "text-red-600";
1654
- if (value.includes("wait") || value.includes("block")) return "text-blue-600";
1655
- return "text-muted-foreground";
1656
- }
1657
- function formatBytes$1(value) {
1658
- if (!value || value <= 0) return "0 B";
1659
- const units = [
1660
- "B",
1661
- "KB",
1662
- "MB",
1663
- "GB",
1664
- "TB"
1665
- ];
1666
- let size = value;
1667
- let unit = 0;
1668
- while (size >= 1024 && unit < units.length - 1) {
1669
- size /= 1024;
1670
- unit++;
1671
- }
1672
- return `${size >= 10 || unit === 0 ? size.toFixed(0) : size.toFixed(1)} ${units[unit]}`;
1673
- }
1674
- function processLabel(node) {
1675
- if (node.name) return node.name;
1676
- if (node.command) {
1677
- const [first] = node.command.split(/\s+/, 1);
1678
- return first || `pid ${node.pid}`;
1679
- }
1680
- return `pid ${node.pid}`;
1681
- }
1682
-
1683
- //#endregion
1684
- //#region src/data/diagnostics/DiagnosticsTree.tsx
1685
- function DiagnosticsTree({ root, selectedPid, expandAll = null, onSelect }) {
1686
- if (!root) return /* @__PURE__ */ jsxs("div", {
1687
- className: "p-density-6 text-center text-muted-foreground",
1688
- children: [/* @__PURE__ */ jsx(Icon, {
1689
- name: "svg-spinners:ring-resize",
1690
- className: "text-3xl text-blue-500"
1691
- }), /* @__PURE__ */ jsx("p", {
1692
- className: "mt-density-2",
1693
- children: "Waiting for process diagnostics..."
1694
- })]
1695
- });
1696
- if (countProcesses(root) === 0) return /* @__PURE__ */ jsx("div", {
1697
- className: "p-density-6 text-center text-muted-foreground text-sm",
1698
- children: "No processes available"
1699
- });
1700
- return /* @__PURE__ */ jsx(Tree, {
1701
- roots: [root],
1702
- getChildren: (n) => n.children,
1703
- getKey: (n) => n.pid,
1704
- expandAll,
1705
- defaultOpen: (n, depth) => !!n.is_root || depth < 1,
1706
- onSelect: (n) => onSelect(n.pid),
1707
- renderRow: ({ node }) => {
1708
- const selected = node.pid === selectedPid;
1709
- const cpu = node.cpu_percent || 0;
1710
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1711
- /* @__PURE__ */ jsx(Icon, {
1712
- name: node.is_root ? "codicon:server-process" : "codicon:debug-alt",
1713
- className: node.is_root ? "text-base text-blue-600" : "text-base text-muted-foreground"
1714
- }),
1715
- /* @__PURE__ */ jsx("span", {
1716
- className: `truncate ${selected ? "font-semibold text-primary" : "font-medium text-foreground"}`,
1717
- children: processLabel(node)
1718
- }),
1719
- /* @__PURE__ */ jsxs("span", {
1720
- className: "text-xs text-muted-foreground shrink-0",
1721
- children: ["pid ", node.pid]
1722
- }),
1723
- /* @__PURE__ */ jsx("span", { className: "flex-1" }),
1724
- node.status && /* @__PURE__ */ jsxs("span", {
1725
- className: `inline-flex items-center gap-1 text-xs shrink-0 ${processStateColor(node.status)}`,
1726
- children: [/* @__PURE__ */ jsx(Icon, { name: processStateIcon(node.status) }), node.status]
1727
- }),
1728
- /* @__PURE__ */ jsxs("span", {
1729
- className: "text-xs text-muted-foreground shrink-0 tabular-nums",
1730
- children: [cpu.toFixed(1), "%"]
1731
- }),
1732
- /* @__PURE__ */ jsx("span", {
1733
- className: "text-xs text-muted-foreground shrink-0 tabular-nums",
1734
- children: formatBytes$1(node.rss)
1735
- })
1736
- ] });
1737
- },
1738
- rowClass: (node) => node.pid === selectedPid ? "bg-primary/10 border-l-2 border-primary" : "hover:bg-accent"
1739
- });
1740
- }
1741
-
1742
- //#endregion
1743
- //#region src/data/diagnostics/jvm-stacktrace.ts
1744
- const headerRe$1 = /^"(?<name>[^"]*)"(?<rest>.*)$/;
1745
- const stateRe = /^\s*java\.lang\.Thread\.State:\s+(?<state>[A-Z_]+)(?:\s+\((?<sub>[^)]+)\))?/;
1746
- const frameRe = /^\s*at\s+(?<fn>[^\s(]+)\((?<src>[^)]+)\)\s*$/;
1747
- const srcLineRe = /^(?<file>[^:]+):(?<line>\d+)$/;
1748
- const annotationRe = /^\s*-\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\b(?<rest>.*)$/;
1749
- function parseJvmThreadDump(text) {
1750
- const trimmed = text.trim();
1751
- if (!trimmed) return [];
1752
- const blocks = splitIntoThreadBlocks(trimmed);
1753
- const threads = [];
1754
- for (const block of blocks) {
1755
- const parsed = parseThreadBlock(block);
1756
- if (parsed) threads.push(parsed);
1757
- }
1758
- return threads;
1759
- }
1760
- function splitIntoThreadBlocks(text) {
1761
- const out = [];
1762
- let current = [];
1763
- const lines = text.split("\n");
1764
- for (const raw of lines) {
1765
- const line = raw.replace(/\r$/, "");
1766
- if (line.startsWith("\"") && current.length > 0) {
1767
- out.push(current.join("\n"));
1768
- current = [line];
1769
- } else current.push(line);
1770
- }
1771
- if (current.length > 0) out.push(current.join("\n"));
1772
- return out;
1773
- }
1774
- function parseThreadBlock(block) {
1775
- const lines = block.split("\n");
1776
- const header = lines[0]?.trim() ?? "";
1777
- const headerMatch = headerRe$1.exec(header);
1778
- if (!headerMatch?.groups) return null;
1779
- const name = headerMatch.groups.name;
1780
- const rest = headerMatch.groups.rest ?? "";
1781
- const idMatch = /#(\d+)\b/.exec(rest);
1782
- const prioMatch = /\bprio=(\d+)/.exec(rest);
1783
- const nidMatch = /\bnid=(0x[0-9a-f]+)/i.exec(rest);
1784
- const daemon = /\bdaemon\b/.test(rest);
1785
- let rawState = extractHeaderStateTrail(rest) ?? "";
1786
- let state = normalizeJvmState(rawState);
1787
- const frames = [];
1788
- for (let i = 1; i < lines.length; i++) {
1789
- const line = lines[i];
1790
- if (!line.trim()) continue;
1791
- const stateMatch = stateRe.exec(line);
1792
- if (stateMatch?.groups) {
1793
- const primary = stateMatch.groups.state;
1794
- const sub = stateMatch.groups.sub;
1795
- rawState = sub ? `${primary} (${sub})` : primary;
1796
- state = normalizeJvmState(primary);
1797
- continue;
1798
- }
1799
- const frameMatch = frameRe.exec(line);
1800
- if (frameMatch?.groups) {
1801
- const functionName = frameMatch.groups.fn;
1802
- const src = frameMatch.groups.src;
1803
- const frame = {
1804
- functionName,
1805
- displayName: sanitizeJvmFunctionName(functionName),
1806
- kind: "frame",
1807
- runtime: isJvmRuntimeFrame(functionName),
1808
- nativeMethod: src === "Native Method"
1809
- };
1810
- const srcMatch = srcLineRe.exec(src);
1811
- if (srcMatch?.groups) {
1812
- frame.file = srcMatch.groups.file;
1813
- frame.line = Number(srcMatch.groups.line);
1814
- frame.location = `${frame.file}:${frame.line}`;
1815
- } else if (src === "Native Method") frame.location = "Native Method";
1816
- else frame.location = src;
1817
- frames.push(frame);
1818
- continue;
1819
- }
1820
- const annoMatch = annotationRe.exec(line);
1821
- if (annoMatch?.groups) {
1822
- const kind = mapAnnotationKind(annoMatch.groups.kind);
1823
- frames.push({
1824
- functionName: annoMatch.groups.kind,
1825
- displayName: annoMatch.groups.kind,
1826
- kind,
1827
- runtime: false,
1828
- nativeMethod: false,
1829
- annotationText: (annoMatch.groups.rest ?? "").trim()
1830
- });
1831
- continue;
1832
- }
1833
- }
1834
- const userFrameCount = frames.filter((f) => f.kind === "frame" && !f.runtime).length;
1835
- const topFunction = frames.find((f) => f.kind === "frame")?.functionName;
1836
- const searchText = [header, ...frames.map((f) => `${f.functionName} ${f.location ?? ""} ${f.annotationText ?? ""}`)].join("\n").toLowerCase();
1837
- return {
1838
- id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest),
1839
- nid: nidMatch ? nidMatch[1] : void 0,
1840
- name,
1841
- state: state || "unknown",
1842
- rawState: rawState || "",
1843
- priority: prioMatch ? Number(prioMatch[1]) : void 0,
1844
- daemon,
1845
- frames,
1846
- raw: block,
1847
- userFrameCount,
1848
- topFunction,
1849
- searchText
1850
- };
1851
- }
1852
- function extractHeaderStateTrail(rest) {
1853
- return rest.match(/nid=0x[0-9a-f]+\s+(?<desc>[^\[]+?)(?:\s+\[0x[0-9a-f]+\])?\s*$/i)?.groups?.desc?.trim();
1854
- }
1855
- function deriveSyntheticId(name, rest) {
1856
- const tid = /\btid=(0x[0-9a-f]+)/i.exec(rest);
1857
- if (tid) {
1858
- const hex = tid[1].slice(2);
1859
- const n = Number.parseInt(hex.slice(-8), 16);
1860
- if (Number.isFinite(n)) return n;
1861
- }
1862
- let h = 0;
1863
- for (let i = 0; i < name.length; i++) h = h * 31 + name.charCodeAt(i) | 0;
1864
- return Math.abs(h);
1865
- }
1866
- function mapAnnotationKind(kind) {
1867
- switch (kind) {
1868
- case "locked": return "locked";
1869
- case "waiting on": return "waiting_on";
1870
- case "waiting to lock": return "waiting_to_lock";
1871
- case "parking to wait for": return "parking";
1872
- default: return "frame";
1873
- }
1874
- }
1875
- function countThreadsByState(threads) {
1876
- const counts = /* @__PURE__ */ new Map();
1877
- for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1);
1878
- return counts;
1879
- }
1880
- function normalizeJvmState(value) {
1881
- if (!value) return "";
1882
- const upper = value.trim().toUpperCase();
1883
- if (upper.startsWith("RUNNABLE")) return "runnable";
1884
- if (upper.startsWith("TIMED_WAITING")) return "timed_waiting";
1885
- if (upper.startsWith("WAITING")) return "waiting";
1886
- if (upper.startsWith("BLOCKED")) return "blocked";
1887
- if (upper.startsWith("NEW")) return "new";
1888
- if (upper.startsWith("TERMINATED")) return "terminated";
1889
- const lower = value.trim().toLowerCase();
1890
- if (lower.includes("runnable")) return "runnable";
1891
- if (lower.includes("waiting on condition") || lower.includes("sleeping")) return "timed_waiting";
1892
- if (lower.includes("waiting")) return "waiting";
1893
- if (lower.includes("blocked")) return "blocked";
1894
- return lower.split(/\s+/)[0];
1895
- }
1896
- const runtimePrefixes = [
1897
- "java.",
1898
- "javax.",
1899
- "sun.",
1900
- "jdk.",
1901
- "com.sun.",
1902
- "oracle.jrockit."
1903
- ];
1904
- function isJvmRuntimeFrame(functionName) {
1905
- return runtimePrefixes.some((p) => functionName.startsWith(p));
1906
- }
1907
- function sanitizeJvmFunctionName(functionName) {
1908
- const parts = functionName.split(".");
1909
- if (parts.length < 2) return functionName;
1910
- const method = parts[parts.length - 1];
1911
- return `${parts[parts.length - 2]}.${method}`;
1912
- }
1913
-
1914
- //#endregion
1915
- //#region src/data/diagnostics/stacktrace.ts
1916
- function detectDumpFormat(text) {
1917
- const trimmed = text.trim();
1918
- if (!trimmed) return "unknown";
1919
- if (/^"[^"]*"[^\n]*\b(prio=|tid=|nid=)/m.test(trimmed)) return "jvm";
1920
- if (/^goroutine\s+\d+\s+\[[^\]]+\]:/m.test(trimmed)) return "go";
1921
- return "unknown";
1922
- }
1923
- function parseStackDump(text) {
1924
- const format = detectDumpFormat(text);
1925
- if (format === "jvm") return {
1926
- format: "jvm",
1927
- threads: parseJvmThreadDump(text)
1928
- };
1929
- if (format === "go") return {
1930
- format: "go",
1931
- goroutines: parseGoroutineDump(text)
1932
- };
1933
- return {
1934
- format: "unknown",
1935
- goroutines: [],
1936
- threads: []
1937
- };
1938
- }
1939
- function countStackByState(stack) {
1940
- if (stack.format === "jvm") return countThreadsByState(stack.threads);
1941
- if (stack.format === "go") return countGoroutinesByState(stack.goroutines);
1942
- return /* @__PURE__ */ new Map();
1943
- }
1944
- const headerRe = /^goroutine\s+(\d+)\s+\[(.+?)\]:$/;
1945
- const fileRe = /^\s*(.+?):(\d+)(?:\s+\+0x[0-9a-f]+)?$/i;
1946
- const goSrcPrefixRe = /^\/usr\/local\/go[\d.]+\/src\//;
1947
- const goWorkspacePrefixRe = /^.*?\/go\/src\//;
1948
- const goPkgModPrefixRe = /^.*?\/go\/pkg\/mod\//;
1949
- function parseGoroutineDump(text) {
1950
- const trimmed = text.trim();
1951
- if (!trimmed) return [];
1952
- const blocks = trimmed.split(/\n\s*\n+/);
1953
- const goroutines = [];
1954
- for (const block of blocks) {
1955
- const lines = block.split("\n").map((line) => line.replace(/\r$/, ""));
1956
- const header = lines[0]?.trim();
1957
- const match = headerRe.exec(header || "");
1958
- if (!match) continue;
1959
- const id = Number(match[1]);
1960
- const rawState = match[2];
1961
- const state = normalizeState(rawState);
1962
- const frames = [];
1963
- for (let i = 1; i < lines.length; i++) {
1964
- const trimmedLine = lines[i].trim();
1965
- if (!trimmedLine) continue;
1966
- const fileMatch = fileRe.exec(trimmedLine);
1967
- if (fileMatch && frames.length > 0 && !frames[frames.length - 1].file) {
1968
- frames[frames.length - 1].file = fileMatch[1];
1969
- frames[frames.length - 1].line = Number(fileMatch[2]);
1970
- continue;
1971
- }
1972
- const kind = trimmedLine.startsWith("created by ") ? "created_by" : "frame";
1973
- const functionName = kind === "created_by" ? trimmedLine.slice(11) : trimmedLine;
1974
- frames.push({
1975
- functionName,
1976
- displayName: sanitizeFunctionName(functionName),
1977
- kind,
1978
- runtime: isRuntimeFrame(functionName)
1979
- });
1980
- }
1981
- for (const frame of frames) if (frame.file) {
1982
- frame.file = normalizeFilePath(frame.file);
1983
- frame.location = `${frame.file}${frame.line ? `:${frame.line}` : ""}`;
1984
- }
1985
- goroutines.push({
1986
- id,
1987
- state,
1988
- rawState,
1989
- frames,
1990
- raw: block,
1991
- userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === "frame").length,
1992
- topFunction: frames.find((frame) => frame.kind === "frame")?.functionName,
1993
- searchText: `${header}\n${frames.map((frame) => `${frame.functionName} ${frame.file || ""}`).join("\n")}`.toLowerCase()
1994
- });
1995
- }
1996
- return goroutines;
1997
- }
1998
- function countGoroutinesByState(goroutines) {
1999
- const counts = /* @__PURE__ */ new Map();
2000
- for (const goroutine of goroutines) counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);
2001
- return counts;
2002
- }
2003
- function normalizeState(value) {
2004
- return value.split(",")[0].trim().toLowerCase();
2005
- }
2006
- function isRuntimeFrame(functionName) {
2007
- return functionName.startsWith("runtime.") || functionName.startsWith("runtime/") || functionName.startsWith("internal/") || functionName.startsWith("runtime/internal/") || functionName.startsWith("syscall.") || functionName.startsWith("reflect.");
2008
- }
2009
- function sanitizeFunctionName(functionName) {
2010
- let name = functionName.trim();
2011
- const paren = name.indexOf("(");
2012
- if (paren !== -1) name = name.slice(0, paren);
2013
- name = name.replace(/\.\(\*([^)]+)\)\./g, ".$1.");
2014
- return stripPackageQualifier(name);
2015
- }
2016
- function stripPackageQualifier(name) {
2017
- return name.replace(/^((?:[^./\s]+\/)+)([^./\s]+)\./, "$2.");
2018
- }
2019
- function normalizeFilePath(path) {
2020
- return path.replace(goSrcPrefixRe, "").replace(goWorkspacePrefixRe, "").replace(goPkgModPrefixRe, "");
2021
- }
2022
-
2023
- //#endregion
2024
- //#region src/data/diagnostics/GoroutineCard.tsx
2025
- function goroutineStateBadge(state) {
2026
- if (state.includes("running")) return "bg-green-50 text-green-700 dark:bg-green-500/20 dark:text-green-300";
2027
- if (state.includes("chan") || state.includes("wait")) return "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300";
2028
- if (state.includes("sleep")) return "bg-amber-50 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300";
2029
- if (state.includes("select")) return "bg-violet-50 text-violet-700 dark:bg-violet-500/20 dark:text-violet-300";
2030
- return "bg-muted text-muted-foreground";
2031
- }
2032
- function goroutineStateDot(state) {
2033
- if (state.includes("running")) return "bg-green-500";
2034
- if (state.includes("chan") || state.includes("wait")) return "bg-blue-500";
2035
- if (state.includes("sleep")) return "bg-amber-500";
2036
- if (state.includes("select")) return "bg-violet-500";
2037
- return "bg-muted-foreground/40";
2038
- }
2039
- function GoroutineCard({ goroutine, search, hideRuntimeOnly }) {
2040
- const frames = hideRuntimeOnly ? goroutine.frames.filter((frame) => !frame.runtime || frame.kind === "created_by") : goroutine.frames;
2041
- return /* @__PURE__ */ jsxs("details", {
2042
- className: "border-0 bg-transparent",
2043
- open: goroutine.state === "running" || !!search,
2044
- children: [/* @__PURE__ */ jsx("summary", {
2045
- className: "cursor-pointer list-none px-0 py-1",
2046
- children: /* @__PURE__ */ jsxs("div", {
2047
- className: "flex items-center gap-2 flex-wrap",
2048
- children: [
2049
- /* @__PURE__ */ jsxs("span", {
2050
- className: "font-mono text-xs font-semibold text-foreground",
2051
- children: ["g", goroutine.id]
2052
- }),
2053
- /* @__PURE__ */ jsxs("span", {
2054
- className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] ${goroutineStateBadge(goroutine.state)}`,
2055
- children: [/* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${goroutineStateDot(goroutine.state)}` }), goroutine.rawState]
2056
- }),
2057
- /* @__PURE__ */ jsxs("span", {
2058
- className: "text-[11px] text-muted-foreground",
2059
- children: [frames.length, "f"]
2060
- }),
2061
- goroutine.userFrameCount > 0 && /* @__PURE__ */ jsxs("span", {
2062
- className: "text-[11px] text-muted-foreground",
2063
- children: [goroutine.userFrameCount, "u"]
2064
- }),
2065
- goroutine.topFunction && /* @__PURE__ */ jsx("span", {
2066
- className: "truncate text-[11px] text-muted-foreground",
2067
- children: goroutine.topFunction
2068
- })
2069
- ]
2070
- })
2071
- }), /* @__PURE__ */ jsx("div", {
2072
- className: "pl-3 py-1 space-y-0.5",
2073
- children: frames.map((frame, index) => /* @__PURE__ */ jsx(FrameRow, { frame }, `${goroutine.id}-${index}`))
2074
- })]
2075
- });
2076
- }
2077
- function FrameRow({ frame }) {
2078
- return /* @__PURE__ */ jsx("div", {
2079
- className: frame.runtime ? "text-muted-foreground" : "text-foreground",
2080
- children: /* @__PURE__ */ jsxs("div", {
2081
- className: "flex items-start gap-1.5",
2082
- children: [/* @__PURE__ */ jsx(Icon, {
2083
- name: frame.kind === "created_by" ? "codicon:debug-restart" : frame.runtime ? "codicon:debug-step-over" : "codicon:symbol-method",
2084
- className: "shrink-0 mt-0.5 text-[11px]"
2085
- }), /* @__PURE__ */ jsx("div", {
2086
- className: "min-w-0",
2087
- children: /* @__PURE__ */ jsxs("div", {
2088
- className: "break-all font-mono text-[11px] font-semibold leading-4",
2089
- children: [frame.displayName, frame.location && /* @__PURE__ */ jsx("span", {
2090
- className: "ml-2 text-[10px] font-normal opacity-80",
2091
- children: frame.location
2092
- })]
2093
- })
2094
- })]
2095
- })
2096
- });
2097
- }
2098
-
2099
- //#endregion
2100
- //#region src/data/diagnostics/ThreadCard.tsx
2101
- function threadStateBadge(state) {
2102
- switch (state) {
2103
- case "runnable": return "bg-green-50 text-green-700 dark:bg-green-500/20 dark:text-green-300";
2104
- case "blocked": return "bg-red-50 text-red-700 dark:bg-red-500/20 dark:text-red-300";
2105
- case "waiting":
2106
- case "timed_waiting": return "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300";
2107
- case "new": return "bg-amber-50 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300";
2108
- case "terminated": return "bg-muted text-muted-foreground";
2109
- default: return "bg-muted text-muted-foreground";
2110
- }
2111
- }
2112
- function threadStateDot(state) {
2113
- switch (state) {
2114
- case "runnable": return "bg-green-500";
2115
- case "blocked": return "bg-red-500";
2116
- case "waiting":
2117
- case "timed_waiting": return "bg-blue-500";
2118
- case "new": return "bg-amber-500";
2119
- case "terminated": return "bg-muted-foreground/40";
2120
- default: return "bg-muted-foreground/40";
2121
- }
2122
- }
2123
- function ThreadCard({ thread, search, hideRuntimeOnly }) {
2124
- const frames = hideRuntimeOnly ? thread.frames.filter((f) => f.kind !== "frame" || !f.runtime) : thread.frames;
2125
- return /* @__PURE__ */ jsxs("details", {
2126
- className: "border-0 bg-transparent",
2127
- open: thread.state === "runnable" || thread.state === "blocked" || !!search,
2128
- children: [/* @__PURE__ */ jsx("summary", {
2129
- className: "cursor-pointer list-none px-0 py-1",
2130
- children: /* @__PURE__ */ jsxs("div", {
2131
- className: "flex items-center gap-2 flex-wrap",
2132
- children: [
2133
- /* @__PURE__ */ jsxs("span", {
2134
- className: "font-mono text-xs font-semibold text-foreground",
2135
- children: ["#", thread.id]
2136
- }),
2137
- /* @__PURE__ */ jsx("span", {
2138
- className: "truncate font-mono text-xs text-foreground",
2139
- children: thread.name
2140
- }),
2141
- /* @__PURE__ */ jsxs("span", {
2142
- className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] ${threadStateBadge(thread.state)}`,
2143
- children: [/* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${threadStateDot(thread.state)}` }), thread.rawState || thread.state]
2144
- }),
2145
- thread.daemon && /* @__PURE__ */ jsx("span", {
2146
- className: "rounded-full bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground",
2147
- children: "daemon"
2148
- }),
2149
- /* @__PURE__ */ jsxs("span", {
2150
- className: "text-[11px] text-muted-foreground",
2151
- children: [frames.length, "f"]
2152
- }),
2153
- thread.userFrameCount > 0 && /* @__PURE__ */ jsxs("span", {
2154
- className: "text-[11px] text-muted-foreground",
2155
- children: [thread.userFrameCount, "u"]
2156
- }),
2157
- thread.topFunction && /* @__PURE__ */ jsx("span", {
2158
- className: "truncate text-[11px] text-muted-foreground",
2159
- children: thread.topFunction
2160
- })
2161
- ]
2162
- })
2163
- }), /* @__PURE__ */ jsx("div", {
2164
- className: "pl-3 py-1 space-y-0.5",
2165
- children: frames.map((frame, index) => /* @__PURE__ */ jsx(ThreadFrameRow, { frame }, `${thread.id}-${index}`))
2166
- })]
2167
- });
2168
- }
2169
- function ThreadFrameRow({ frame }) {
2170
- const isAnno = frame.kind !== "frame";
2171
- const iconName = isAnno ? frame.kind === "locked" ? "codicon:lock" : frame.kind === "waiting_to_lock" ? "codicon:sync" : "codicon:watch" : frame.nativeMethod ? "codicon:chip" : frame.runtime ? "codicon:debug-step-over" : "codicon:symbol-method";
2172
- return /* @__PURE__ */ jsx("div", {
2173
- className: frame.runtime ? "text-muted-foreground" : "text-foreground",
2174
- children: /* @__PURE__ */ jsxs("div", {
2175
- className: "flex items-start gap-1.5",
2176
- children: [/* @__PURE__ */ jsx(Icon, {
2177
- name: iconName,
2178
- className: "shrink-0 mt-0.5 text-[11px]"
2179
- }), /* @__PURE__ */ jsx("div", {
2180
- className: "min-w-0",
2181
- children: /* @__PURE__ */ jsx("div", {
2182
- className: "break-all font-mono text-[11px] font-semibold leading-4",
2183
- children: isAnno ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
2184
- className: "opacity-70",
2185
- children: frame.functionName
2186
- }), frame.annotationText && /* @__PURE__ */ jsx("span", {
2187
- className: "ml-2 font-normal opacity-80",
2188
- children: frame.annotationText
2189
- })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [frame.displayName, frame.location && /* @__PURE__ */ jsx("span", {
2190
- className: "ml-2 text-[10px] font-normal opacity-80",
2191
- children: frame.location
2192
- })] })
2193
- })
2194
- })]
2195
- })
2196
- });
2197
- }
2198
-
2199
- //#endregion
2200
- //#region src/data/diagnostics/DiagnosticsDetailPanel.tsx
2201
- const STACK_MIN_HEIGHT = `10rem`;
2202
- function cpuTone(pct) {
2203
- if (pct >= 90) return "danger";
2204
- if (pct >= 60) return "warning";
2205
- if (pct > 0) return "success";
2206
- return "neutral";
2207
- }
2208
- function memoryTone(rss, vms) {
2209
- if (!rss || !vms) return "neutral";
2210
- const ratio = rss / vms;
2211
- if (ratio >= .9) return "danger";
2212
- if (ratio >= .6) return "warning";
2213
- return "info";
2214
- }
2215
- function DiagnosticsDetailPanel({ process, collectBusy, onCollectStack, runMeta }) {
2216
- const [search, setSearch] = useState("");
2217
- const [selectedStates, setSelectedStates] = useState(/* @__PURE__ */ new Set());
2218
- const [hideRuntimeOnly, setHideRuntimeOnly] = useState(true);
2219
- const stack = process?.stack_capture;
2220
- const parsed = useMemo(() => parseStackDump(stack?.text || ""), [stack?.text]);
2221
- const stateCounts = useMemo(() => countStackByState(parsed), [parsed]);
2222
- const filtered = useMemo(() => {
2223
- const needle = search.trim().toLowerCase();
2224
- return (parsed.format === "jvm" ? parsed.threads : parsed.format === "go" ? parsed.goroutines : []).filter((item) => {
2225
- if (selectedStates.size > 0 && !selectedStates.has(item.state)) return false;
2226
- if (hideRuntimeOnly && item.userFrameCount === 0) return false;
2227
- if (needle && !item.searchText.includes(needle)) return false;
2228
- return true;
2229
- });
2230
- }, [
2231
- parsed,
2232
- search,
2233
- selectedStates,
2234
- hideRuntimeOnly
2235
- ]);
2236
- useEffect(() => {
2237
- setSearch("");
2238
- setSelectedStates(/* @__PURE__ */ new Set());
2239
- setHideRuntimeOnly(true);
2240
- }, [stack?.text, process?.pid]);
2241
- if (!process) return /* @__PURE__ */ jsx("div", {
2242
- className: "flex items-center justify-center h-full text-muted-foreground text-sm",
2243
- children: /* @__PURE__ */ jsxs("div", {
2244
- className: "text-center",
2245
- children: [/* @__PURE__ */ jsx(Icon, {
2246
- name: "codicon:server-process",
2247
- className: "text-4xl mb-density-2"
2248
- }), /* @__PURE__ */ jsx("div", { children: "Select a process to view diagnostics" })]
2249
- })
2250
- });
2251
- return /* @__PURE__ */ jsxs("div", {
2252
- className: "h-full min-h-0 flex flex-col gap-density-3 p-density-4",
2253
- children: [
2254
- /* @__PURE__ */ jsx(Header, { process }),
2255
- runMeta && /* @__PURE__ */ jsx(RunSection, { runMeta }),
2256
- process.command && /* @__PURE__ */ jsx(PanelSection, {
2257
- title: "Command",
2258
- children: /* @__PURE__ */ jsx("pre", {
2259
- className: "text-xs text-foreground whitespace-pre-wrap font-mono bg-blue-50 dark:bg-blue-500/10 rounded p-2 break-all",
2260
- children: process.command
2261
- })
2262
- }),
2263
- /* @__PURE__ */ jsx(PanelSection, {
2264
- title: "Metrics",
2265
- children: /* @__PURE__ */ jsx(ProcessMetrics, { process })
2266
- }),
2267
- /* @__PURE__ */ jsx(PanelSection, {
2268
- title: "Stack",
2269
- grow: true,
2270
- children: /* @__PURE__ */ jsx(StackBlock, {
2271
- process,
2272
- parsed,
2273
- stateCounts,
2274
- filtered,
2275
- search,
2276
- setSearch,
2277
- selectedStates,
2278
- setSelectedStates,
2279
- hideRuntimeOnly,
2280
- setHideRuntimeOnly,
2281
- collectBusy,
2282
- onCollectStack
2283
- })
2284
- })
2285
- ]
2286
- });
2287
- }
2288
- function Header({ process }) {
2289
- return /* @__PURE__ */ jsx("div", {
2290
- className: "flex items-start justify-between gap-density-3",
2291
- children: /* @__PURE__ */ jsxs("div", {
2292
- className: "min-w-0 flex-1",
2293
- children: [/* @__PURE__ */ jsxs("div", {
2294
- className: "flex items-center gap-density-2",
2295
- children: [/* @__PURE__ */ jsx(Icon, {
2296
- name: process.is_root ? "codicon:server-process" : "codicon:debug-alt",
2297
- className: "text-2xl text-blue-600"
2298
- }), /* @__PURE__ */ jsx("h2", {
2299
- className: "text-lg font-bold text-foreground break-words",
2300
- children: processLabel(process)
2301
- })]
2302
- }), /* @__PURE__ */ jsxs("div", {
2303
- className: "mt-1 flex items-center gap-density-2 flex-wrap text-xs text-muted-foreground",
2304
- children: [
2305
- /* @__PURE__ */ jsxs("span", {
2306
- className: "font-mono",
2307
- children: ["pid ", process.pid]
2308
- }),
2309
- process.ppid ? /* @__PURE__ */ jsxs("span", {
2310
- className: "font-mono",
2311
- children: ["ppid ", process.ppid]
2312
- }) : null,
2313
- process.status ? /* @__PURE__ */ jsxs("span", {
2314
- className: `inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 ${processStateColor(process.status)}`,
2315
- children: [/* @__PURE__ */ jsx(Icon, { name: processStateIcon(process.status) }), process.status]
2316
- }) : null
2317
- ]
2318
- })]
2319
- })
2320
- });
2321
- }
2322
- function RunSection({ runMeta }) {
2323
- return /* @__PURE__ */ jsx(PanelSection, {
2324
- title: "Run",
2325
- children: /* @__PURE__ */ jsxs("div", {
2326
- className: "grid grid-cols-2 gap-density-2 text-sm",
2327
- children: [/* @__PURE__ */ jsx(InfoTile, {
2328
- label: runMeta.kind === "rerun" ? `Rerun #${runMeta.sequence}` : "Initial run",
2329
- value: runMeta.started ? new Date(runMeta.started).toLocaleString() : "Unavailable"
2330
- }), /* @__PURE__ */ jsx(InfoTile, {
2331
- label: "Finished",
2332
- value: runMeta.ended ? new Date(runMeta.ended).toLocaleString() : "In progress"
2333
- })]
2334
- })
2335
- });
2336
- }
2337
- function stackItemCount(parsed) {
2338
- if (parsed.format === "jvm") return parsed.threads.length;
2339
- if (parsed.format === "go") return parsed.goroutines.length;
2340
- return 0;
2341
- }
2342
- function stackItemLabel(parsed) {
2343
- if (parsed.format === "jvm") return "threads";
2344
- if (parsed.format === "go") return "goroutines";
2345
- return "frames";
2346
- }
2347
- function stackStateDot(parsed, state) {
2348
- return parsed.format === "jvm" ? threadStateDot(state) : goroutineStateDot(state);
2349
- }
2350
- function StackBlock(props) {
2351
- const { process, parsed, stateCounts, filtered, search, setSearch, selectedStates, setSelectedStates, hideRuntimeOnly, setHideRuntimeOnly, collectBusy, onCollectStack } = props;
2352
- const stack = process.stack_capture;
2353
- if (!stack?.text) return /* @__PURE__ */ jsxs("div", {
2354
- className: "h-full min-h-[14rem] flex flex-col justify-center gap-density-3 p-density-3",
2355
- children: [/* @__PURE__ */ jsxs("div", {
2356
- className: "space-y-1.5",
2357
- children: [
2358
- /* @__PURE__ */ jsx("div", { className: `h-3 w-40 rounded ${collectBusy ? "animate-pulse bg-muted" : "bg-muted/70"}` }),
2359
- /* @__PURE__ */ jsx("div", { className: `h-3 w-full rounded ${collectBusy ? "animate-pulse bg-muted" : "bg-muted/70"}` }),
2360
- /* @__PURE__ */ jsx("div", { className: `h-3 w-5/6 rounded ${collectBusy ? "animate-pulse bg-muted" : "bg-muted/70"}` })
2361
- ]
2362
- }), /* @__PURE__ */ jsxs("div", {
2363
- className: "flex items-center justify-between gap-density-3",
2364
- children: [/* @__PURE__ */ jsx("div", {
2365
- className: "text-sm text-muted-foreground",
2366
- children: stack?.error ? stack.error : collectBusy ? "Collecting stack trace..." : "No stack trace collected yet."
2367
- }), onCollectStack && /* @__PURE__ */ jsx(CollectButton, {
2368
- pid: process.pid,
2369
- busy: collectBusy,
2370
- onClick: onCollectStack,
2371
- primary: true
2372
- })]
2373
- })]
2374
- });
2375
- return /* @__PURE__ */ jsxs("div", {
2376
- className: "h-full min-h-0 flex flex-col",
2377
- children: [
2378
- /* @__PURE__ */ jsxs("div", {
2379
- className: "px-1 py-1.5 space-y-density-2",
2380
- children: [/* @__PURE__ */ jsxs("div", {
2381
- className: "flex items-center justify-between gap-density-2 text-[11px] text-muted-foreground flex-wrap",
2382
- children: [/* @__PURE__ */ jsxs("div", {
2383
- className: "flex items-center gap-density-2 flex-wrap",
2384
- children: [
2385
- /* @__PURE__ */ jsx(StackStatusBadge, { status: stack.status }),
2386
- stack.collected_at && /* @__PURE__ */ jsx("span", { children: new Date(stack.collected_at).toLocaleString() }),
2387
- stackItemCount(parsed) > 0 && /* @__PURE__ */ jsxs("span", { children: [
2388
- filtered.length,
2389
- " / ",
2390
- stackItemCount(parsed),
2391
- " ",
2392
- stackItemLabel(parsed)
2393
- ] })
2394
- ]
2395
- }), onCollectStack && /* @__PURE__ */ jsx(CollectButton, {
2396
- pid: process.pid,
2397
- busy: collectBusy,
2398
- onClick: onCollectStack
2399
- })]
2400
- }), stackItemCount(parsed) > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
2401
- className: "flex items-center gap-1.5 flex-wrap",
2402
- children: [
2403
- /* @__PURE__ */ jsxs("div", {
2404
- className: "relative min-w-[14rem] flex-1",
2405
- children: [/* @__PURE__ */ jsx(Icon, {
2406
- name: "codicon:search",
2407
- className: "absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground text-xs"
2408
- }), /* @__PURE__ */ jsx("input", {
2409
- className: "w-full rounded-md border border-border bg-muted/50 py-1 pl-7 pr-2 text-xs outline-none focus:border-primary focus:bg-background",
2410
- placeholder: parsed.format === "jvm" ? "Filter by thread name, function, or file" : "Filter by goroutine id, function, or file",
2411
- value: search,
2412
- onChange: (e) => setSearch(e.target.value)
2413
- })]
2414
- }),
2415
- /* @__PURE__ */ jsxs("label", {
2416
- className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-muted/50 px-2 py-1 text-[11px] text-muted-foreground",
2417
- children: [/* @__PURE__ */ jsx("input", {
2418
- type: "checkbox",
2419
- checked: hideRuntimeOnly,
2420
- onChange: (e) => setHideRuntimeOnly(e.target.checked)
2421
- }), "Hide runtime-only"]
2422
- }),
2423
- (search || selectedStates.size > 0 || !hideRuntimeOnly) && /* @__PURE__ */ jsx("button", {
2424
- className: "text-[11px] text-muted-foreground hover:text-foreground",
2425
- onClick: () => {
2426
- setSearch("");
2427
- setSelectedStates(() => /* @__PURE__ */ new Set());
2428
- setHideRuntimeOnly(true);
2429
- },
2430
- children: "Clear"
2431
- })
2432
- ]
2433
- }), /* @__PURE__ */ jsx("div", {
2434
- className: "flex items-center gap-1 flex-wrap",
2435
- children: Array.from(stateCounts.entries()).sort((a, b) => b[1] - a[1]).map(([state, count]) => {
2436
- return /* @__PURE__ */ jsxs("button", {
2437
- className: `inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] transition-colors ${selectedStates.has(state) ? "border-primary bg-primary/10 text-primary" : "border-border bg-muted/50 text-muted-foreground hover:bg-background"}`,
2438
- onClick: () => {
2439
- setSelectedStates((prev) => {
2440
- const next = new Set(prev);
2441
- if (next.has(state)) next.delete(state);
2442
- else next.add(state);
2443
- return next;
2444
- });
2445
- },
2446
- children: [
2447
- /* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${stackStateDot(parsed, state)}` }),
2448
- state,
2449
- /* @__PURE__ */ jsx("span", {
2450
- className: "text-[10px] opacity-70",
2451
- children: count
2452
- })
2453
- ]
2454
- }, state);
2455
- })
2456
- })] })]
2457
- }),
2458
- stack.error && /* @__PURE__ */ jsx("div", {
2459
- className: "mt-density-2 text-xs text-red-600 whitespace-pre-wrap",
2460
- children: stack.error
2461
- }),
2462
- stackItemCount(parsed) === 0 ? /* @__PURE__ */ jsx("pre", {
2463
- className: "flex-1 min-h-0 overflow-auto py-1 text-[11px] text-foreground whitespace-pre-wrap font-mono leading-4",
2464
- style: { minHeight: STACK_MIN_HEIGHT },
2465
- children: stack.text
2466
- }) : /* @__PURE__ */ jsxs("div", {
2467
- className: "flex-1 min-h-0 overflow-auto py-1 space-y-1",
2468
- style: { minHeight: STACK_MIN_HEIGHT },
2469
- children: [
2470
- filtered.length === 0 && /* @__PURE__ */ jsxs("div", {
2471
- className: "py-density-3 text-center text-xs text-muted-foreground",
2472
- children: [
2473
- "No ",
2474
- stackItemLabel(parsed),
2475
- " match the current filters."
2476
- ]
2477
- }),
2478
- parsed.format === "jvm" && parsed.threads.filter((t) => filtered.includes(t)).map((t) => /* @__PURE__ */ jsx(ThreadCard, {
2479
- thread: t,
2480
- search,
2481
- hideRuntimeOnly
2482
- }, t.id)),
2483
- parsed.format === "go" && parsed.goroutines.filter((g) => filtered.includes(g)).map((goroutine) => /* @__PURE__ */ jsx(GoroutineCard, {
2484
- goroutine,
2485
- search,
2486
- hideRuntimeOnly
2487
- }, goroutine.id))
2488
- ]
2489
- })
2490
- ]
2491
- });
2492
- }
2493
- function StackStatusBadge({ status }) {
2494
- return /* @__PURE__ */ jsx("span", {
2495
- className: `px-2 py-0.5 rounded-full ${status === "ready" ? "bg-green-100 text-green-700 dark:bg-green-500/20 dark:text-green-300" : status === "unsupported" ? "bg-yellow-100 text-yellow-700 dark:bg-yellow-500/20 dark:text-yellow-300" : "bg-red-100 text-red-700 dark:bg-red-500/20 dark:text-red-300"}`,
2496
- children: status
2497
- });
2498
- }
2499
- function CollectButton({ pid, busy, onClick, primary }) {
2500
- return /* @__PURE__ */ jsxs("button", {
2501
- className: `shrink-0 text-[11px] px-2 py-1 rounded disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-1 ${primary ? "bg-primary text-primary-foreground hover:bg-primary/90" : "border border-border text-muted-foreground hover:bg-accent"}`,
2502
- onClick: () => onClick(pid),
2503
- disabled: busy,
2504
- title: primary ? "Collect the latest stack trace" : "Refresh stack trace",
2505
- children: [/* @__PURE__ */ jsx(Icon, { name: busy ? "svg-spinners:ring-resize" : primary ? "codicon:debug-alt-small" : "codicon:refresh" }), busy ? "Collecting..." : primary ? "Collect stack trace" : "Refresh"]
2506
- });
2507
- }
2508
- function PanelSection({ title, grow, children }) {
2509
- return /* @__PURE__ */ jsxs("section", {
2510
- className: grow ? "flex min-h-0 flex-1 flex-col" : "",
2511
- children: [/* @__PURE__ */ jsx("div", {
2512
- className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground mb-1.5",
2513
- children: title
2514
- }), grow ? /* @__PURE__ */ jsx("div", {
2515
- className: "flex-1 min-h-0 overflow-hidden",
2516
- children
2517
- }) : children]
2518
- });
2519
- }
2520
- function InfoTile({ label, value }) {
2521
- return /* @__PURE__ */ jsxs("div", {
2522
- className: "border border-border rounded-lg bg-muted/50 px-2.5 py-density-2",
2523
- children: [/* @__PURE__ */ jsx("div", {
2524
- className: "text-[10px] uppercase tracking-wide text-muted-foreground",
2525
- children: label
2526
- }), /* @__PURE__ */ jsx("div", {
2527
- className: "text-xs font-medium text-foreground mt-0.5",
2528
- children: value
2529
- })]
2530
- });
2531
- }
2532
- function ProcessMetrics({ process }) {
2533
- const cpu = process.cpu_percent || 0;
2534
- const rss = process.rss;
2535
- const vms = process.vms;
2536
- const memRatioPct = rss && vms && vms > 0 ? Math.min(100, Math.round(rss / vms * 100)) : 0;
2537
- return /* @__PURE__ */ jsxs("div", {
2538
- className: "grid grid-cols-4 gap-density-1",
2539
- children: [
2540
- /* @__PURE__ */ jsx(MetricTile, {
2541
- label: "CPU",
2542
- value: `${cpu.toFixed(1)}%`,
2543
- barPct: Math.min(100, cpu),
2544
- tone: cpuTone(cpu)
2545
- }),
2546
- /* @__PURE__ */ jsx(MetricTile, {
2547
- label: "RSS",
2548
- value: rss !== void 0 ? formatBytes$1(rss) : "n/a",
2549
- barPct: memRatioPct,
2550
- tone: memoryTone(rss, vms)
2551
- }),
2552
- /* @__PURE__ */ jsx(MetricTile, {
2553
- label: "VMS",
2554
- value: vms !== void 0 ? formatBytes$1(vms) : "n/a",
2555
- tone: "neutral"
2556
- }),
2557
- /* @__PURE__ */ jsx(MetricTile, {
2558
- label: "Files",
2559
- value: process.open_files !== void 0 ? String(process.open_files) : "n/a",
2560
- barPct: process.open_files ? Math.min(100, process.open_files / 1024 * 100) : 0,
2561
- tone: "info"
2562
- })
2563
- ]
2564
- });
2565
- }
2566
- function MetricTile({ label, value, barPct, tone = "neutral" }) {
2567
- return /* @__PURE__ */ jsxs("div", {
2568
- className: "flex flex-col gap-0.5 rounded-md border border-border bg-background px-density-2 py-1 min-w-0",
2569
- children: [
2570
- /* @__PURE__ */ jsx("span", {
2571
- className: "text-[9px] uppercase tracking-wide text-muted-foreground leading-none",
2572
- children: label
2573
- }),
2574
- /* @__PURE__ */ jsx("span", {
2575
- className: `text-xs font-semibold tabular-nums truncate ${{
2576
- neutral: "text-foreground",
2577
- success: "text-green-600 dark:text-green-400",
2578
- warning: "text-yellow-600 dark:text-yellow-400",
2579
- danger: "text-red-600 dark:text-red-400",
2580
- info: "text-blue-600 dark:text-blue-400"
2581
- }[tone]}`,
2582
- children: value
2583
- }),
2584
- barPct !== void 0 && /* @__PURE__ */ jsx("div", {
2585
- className: "h-0.5 w-full rounded-full bg-muted overflow-hidden",
2586
- children: /* @__PURE__ */ jsx("div", {
2587
- className: `h-full ${{
2588
- neutral: "bg-muted-foreground/40",
2589
- success: "bg-green-500",
2590
- warning: "bg-yellow-500",
2591
- danger: "bg-red-500",
2592
- info: "bg-blue-500"
2593
- }[tone]} transition-all duration-300`,
2594
- style: { width: `${barPct}%` }
2595
- })
2596
- })
2597
- ]
2598
- });
2599
- }
2600
-
2601
- //#endregion
2602
- //#region src/data/har/HarPanel.tsx
2603
- const COLS = [
2604
- {
2605
- key: "request.method",
2606
- label: "Method",
2607
- cls: "px-2 py-2 w-16"
2608
- },
2609
- {
2610
- key: "request.url",
2611
- label: "URL",
2612
- cls: "px-2 py-2"
2613
- },
2614
- {
2615
- key: "response.status",
2616
- label: "Status",
2617
- cls: "px-2 py-2 w-20"
2618
- },
2619
- {
2620
- key: "time",
2621
- label: "Time",
2622
- cls: "px-2 py-2 w-16 text-right",
2623
- align: "right"
2624
- },
2625
- {
2626
- key: "response.bodySize",
2627
- label: "Size",
2628
- cls: "px-2 py-2 w-16 text-right",
2629
- align: "right"
2630
- },
2631
- {
2632
- key: "response.content.mimeType",
2633
- label: "Type",
2634
- cls: "px-2 py-2 w-40"
2635
- }
2636
- ];
2637
- function HarPanel({ entries, search, emptyLabel = "No HTTP traffic captured", className }) {
2638
- const { sorted, sort, toggle } = useSort(useMemo(() => {
2639
- if (!search) return entries;
2640
- const needle = search.toLowerCase();
2641
- return entries.filter((e) => matchesSearch(needle, e));
2642
- }, [entries, search]), { defaultKey: "time" });
2643
- if (!entries || entries.length === 0) return /* @__PURE__ */ jsx("div", {
2644
- className: "p-density-6 text-center text-muted-foreground text-sm",
2645
- children: emptyLabel
2646
- });
2647
- return /* @__PURE__ */ jsx("div", {
2648
- className: `overflow-auto h-full ${className ?? ""}`,
2649
- children: /* @__PURE__ */ jsxs("table", {
2650
- className: "w-full text-left table-fixed",
2651
- children: [/* @__PURE__ */ jsx("thead", {
2652
- className: "bg-muted/50 sticky top-0",
2653
- children: /* @__PURE__ */ jsx("tr", {
2654
- className: "text-xs text-muted-foreground border-b border-border",
2655
- children: COLS.map((c) => /* @__PURE__ */ jsx("th", {
2656
- className: `${c.cls} cursor-pointer select-none whitespace-nowrap font-medium`,
2657
- children: /* @__PURE__ */ jsx(SortableHeader, {
2658
- active: sort?.key === c.key,
2659
- dir: sort?.dir,
2660
- onClick: () => toggle(c.key),
2661
- align: c.align,
2662
- children: c.label
2663
- })
2664
- }, c.key))
2665
- })
2666
- }), /* @__PURE__ */ jsx("tbody", { children: sorted.map((entry, i) => /* @__PURE__ */ jsx(HarRow, { entry }, i)) })]
2667
- })
2668
- });
2669
- }
2670
- function HarRow({ entry }) {
2671
- const [open, setOpen] = useState(false);
2672
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("tr", {
2673
- className: "hover:bg-accent cursor-pointer text-xs border-b border-border",
2674
- onClick: () => setOpen(!open),
2675
- children: [
2676
- /* @__PURE__ */ jsx("td", {
2677
- className: "px-2 py-1.5 font-mono font-medium whitespace-nowrap",
2678
- children: entry.request.method
2679
- }),
2680
- /* @__PURE__ */ jsx("td", {
2681
- className: "px-2 py-1.5 font-mono truncate max-w-0",
2682
- title: entry.request.url,
2683
- children: entry.request.url
2684
- }),
2685
- /* @__PURE__ */ jsx("td", {
2686
- className: `px-2 py-1.5 font-medium whitespace-nowrap ${statusColor(entry.response.status)}`,
2687
- children: entry.response.status
2688
- }),
2689
- /* @__PURE__ */ jsxs("td", {
2690
- className: "px-2 py-1.5 text-right text-muted-foreground whitespace-nowrap tabular-nums",
2691
- children: [entry.time.toFixed(0), "ms"]
2692
- }),
2693
- /* @__PURE__ */ jsx("td", {
2694
- className: "px-2 py-1.5 text-right text-muted-foreground whitespace-nowrap tabular-nums",
2695
- children: formatBytes(entry.response.bodySize)
2696
- }),
2697
- /* @__PURE__ */ jsx("td", {
2698
- className: "px-2 py-1.5 text-muted-foreground whitespace-nowrap",
2699
- children: entry.response.content?.mimeType || ""
2700
- })
2701
- ]
2702
- }), open && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", {
2703
- colSpan: COLS.length,
2704
- className: "bg-muted/50 p-density-3 text-xs",
2705
- children: /* @__PURE__ */ jsx(HarRowDetails, { entry })
2706
- }) })] });
2707
- }
2708
- function HarRowDetails({ entry }) {
2709
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
2710
- className: "grid grid-cols-2 gap-density-4",
2711
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(HeaderList, {
2712
- title: "Request Headers",
2713
- headers: entry.request.headers
2714
- }), entry.request.postData?.text && /* @__PURE__ */ jsxs("div", {
2715
- className: "mt-density-2",
2716
- children: [/* @__PURE__ */ jsx("div", {
2717
- className: "font-semibold text-foreground mb-1",
2718
- children: "Request Body"
2719
- }), /* @__PURE__ */ jsx("div", {
2720
- className: "bg-background p-density-2 rounded border border-border overflow-auto max-h-48",
2721
- children: /* @__PURE__ */ jsx(BodyView, {
2722
- text: entry.request.postData.text,
2723
- mimeType: entry.request.postData.mimeType
2724
- })
2725
- })]
2726
- })] }), /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(HeaderList, {
2727
- title: "Response Headers",
2728
- headers: entry.response.headers
2729
- }) })]
2730
- }), entry.response.content?.text && /* @__PURE__ */ jsxs("div", {
2731
- className: "mt-density-3",
2732
- children: [/* @__PURE__ */ jsx("div", {
2733
- className: "font-semibold text-foreground mb-1",
2734
- children: "Response Body"
2735
- }), /* @__PURE__ */ jsx("div", {
2736
- className: "bg-background p-density-2 rounded border border-border overflow-auto max-h-64",
2737
- children: /* @__PURE__ */ jsx(BodyView, {
2738
- text: entry.response.content.text,
2739
- mimeType: entry.response.content.mimeType
2740
- })
2741
- })]
2742
- })] });
2743
- }
2744
- function HeaderList({ title, headers }) {
2745
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
2746
- className: "font-semibold text-foreground mb-1",
2747
- children: title
2748
- }), /* @__PURE__ */ jsx("div", {
2749
- className: "space-y-0.5",
2750
- children: headers?.map((h, i) => /* @__PURE__ */ jsxs("div", {
2751
- className: "whitespace-nowrap",
2752
- children: [
2753
- /* @__PURE__ */ jsxs("span", {
2754
- className: "text-purple-600 dark:text-purple-400",
2755
- children: [h.name, ":"]
2756
- }),
2757
- " ",
2758
- h.value
2759
- ]
2760
- }, i))
2761
- })] });
2762
- }
2763
- function BodyView({ text, mimeType }) {
2764
- if (isJsonType(mimeType)) {
2765
- const parsed = tryParseJson(text);
2766
- if (parsed !== null) return /* @__PURE__ */ jsx(JsonView, { data: parsed });
2767
- }
2768
- return /* @__PURE__ */ jsx("pre", {
2769
- className: "whitespace-pre-wrap break-all",
2770
- children: text
2771
- });
2772
- }
2773
- function tryParseJson(text) {
2774
- try {
2775
- return JSON.parse(text);
2776
- } catch {
2777
- return null;
2778
- }
2779
- }
2780
- function isJsonType(mime) {
2781
- return !!mime && (mime.includes("json") || mime.includes("javascript"));
2782
- }
2783
- function matchesSearch(needle, e) {
2784
- return [
2785
- e.request.url,
2786
- e.request.method,
2787
- e.request.postData?.text,
2788
- e.response.content?.text
2789
- ].some((h) => !!h && h.toLowerCase().includes(needle));
2790
- }
2791
- function formatBytes(bytes) {
2792
- if (bytes < 0) return "";
2793
- if (bytes < 1024) return `${bytes}B`;
2794
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
2795
- return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
2796
- }
2797
- function statusColor(status) {
2798
- if (status >= 500) return "text-red-600";
2799
- if (status >= 400) return "text-amber-600";
2800
- if (status >= 300) return "text-blue-600";
2801
- if (status >= 200) return "text-green-600";
2802
- return "text-muted-foreground";
2803
- }
2804
-
2805
- //#endregion
2806
- //#region src/overlay/HoverCard.tsx
2807
- const placementPos = {
2808
- top: "bottom-full left-1/2 -translate-x-1/2 mb-1.5",
2809
- bottom: "top-full left-1/2 -translate-x-1/2 mt-1.5",
2810
- left: "right-full top-1/2 -translate-y-1/2 mr-1.5",
2811
- right: "left-full top-1/2 -translate-y-1/2 ml-1.5"
2812
- };
2813
- function HoverCard({ trigger, children, placement = "top", delay = 0, arrow = true, className, cardClassName }) {
2814
- const [open, setOpen] = useState(false);
2815
- const timer = useState(null);
2816
- function onEnter() {
2817
- if (delay > 0) {
2818
- const id = window.setTimeout(() => setOpen(true), delay);
2819
- timer[1](id);
2820
- } else setOpen(true);
2821
- }
2822
- function onLeave() {
2823
- if (timer[0] !== null) window.clearTimeout(timer[0]);
2824
- setOpen(false);
2825
- }
2826
- return /* @__PURE__ */ jsxs("span", {
2827
- className: cn("relative inline-flex items-center", className),
2828
- onMouseEnter: onEnter,
2829
- onMouseLeave: onLeave,
2830
- onFocus: onEnter,
2831
- onBlur: onLeave,
2832
- children: [trigger, open && /* @__PURE__ */ jsxs("div", {
2833
- role: "tooltip",
2834
- className: cn("absolute z-20 bg-background border border-border rounded-md shadow-lg px-2.5 py-1.5 whitespace-nowrap text-[11px]", placementPos[placement], cardClassName),
2835
- children: [children, arrow && placement === "top" && /* @__PURE__ */ jsx("div", {
2836
- className: "absolute top-full left-1/2 -translate-x-1/2 -mt-px",
2837
- children: /* @__PURE__ */ jsx("div", { className: "w-1.5 h-1.5 bg-background border-b border-r border-border rotate-45 -translate-y-1" })
2838
- })]
2839
- })]
2840
- });
2841
- }
2842
-
2843
- //#endregion
2844
- //#region src/overlay/Modal.tsx
2845
- const sizeClass = {
2846
- sm: "max-w-sm",
2847
- md: "max-w-md",
2848
- lg: "max-w-2xl",
2849
- xl: "max-w-4xl",
2850
- full: "max-w-[95vw] max-h-[95vh]"
2851
- };
2852
- function Modal({ open, onClose, title, size = "md", closeOnBackdrop = true, closeOnEsc = true, hideClose = false, className, headerSlot, footer, children }) {
2853
- const dialogRef = useRef(null);
2854
- useEffect(() => {
2855
- if (!open || !closeOnEsc) return;
2856
- const onKey = (e) => {
2857
- if (e.key === "Escape") onClose();
2858
- };
2859
- document.addEventListener("keydown", onKey);
2860
- return () => document.removeEventListener("keydown", onKey);
2861
- }, [
2862
- open,
2863
- closeOnEsc,
2864
- onClose
2865
- ]);
2866
- useEffect(() => {
2867
- if (!open) return;
2868
- const prev = document.activeElement;
2869
- dialogRef.current?.focus();
2870
- return () => prev?.focus?.();
2871
- }, [open]);
2872
- if (!open) return null;
2873
- return /* @__PURE__ */ jsx("div", {
2874
- className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40",
2875
- onClick: closeOnBackdrop ? onClose : void 0,
2876
- role: "presentation",
2877
- children: /* @__PURE__ */ jsxs("div", {
2878
- ref: dialogRef,
2879
- tabIndex: -1,
2880
- role: "dialog",
2881
- "aria-modal": "true",
2882
- "aria-label": typeof title === "string" ? title : void 0,
2883
- className: cn("relative bg-background border border-border rounded-lg shadow-xl w-full flex flex-col", sizeClass[size], className),
2884
- onClick: (e) => e.stopPropagation(),
2885
- children: [
2886
- (title || headerSlot || !hideClose) && /* @__PURE__ */ jsxs("div", {
2887
- className: "flex items-center gap-density-2 px-density-4 py-density-3 border-b border-border",
2888
- children: [
2889
- title && /* @__PURE__ */ jsx("h2", {
2890
- className: "text-sm font-semibold flex-1",
2891
- children: title
2892
- }),
2893
- headerSlot,
2894
- !hideClose && /* @__PURE__ */ jsx("button", {
2895
- type: "button",
2896
- onClick: onClose,
2897
- "aria-label": "Close",
2898
- className: "text-muted-foreground hover:text-foreground",
2899
- children: /* @__PURE__ */ jsx(Icon, { name: "codicon:close" })
2900
- })
2901
- ]
2902
- }),
2903
- /* @__PURE__ */ jsx("div", {
2904
- className: "flex-1 overflow-auto px-density-4 py-density-3",
2905
- children
2906
- }),
2907
- footer && /* @__PURE__ */ jsx("div", {
2908
- className: "px-density-4 py-density-3 border-t border-border",
2909
- children: footer
2910
- })
2911
- ]
2912
- })
2913
- });
2914
- }
2915
-
2916
- //#endregion
2917
- export { AVATAR_PALETTE, AnsiHtml, Avatar, Badge, Button, Clicky, DensityProvider, DensitySwitcher, DetailEmptyState, DiagnosticsDetailPanel, DiagnosticsTree, FilterPill, FilterPillGroup, FilterSeparator, Gauge, HarPanel, HoverCard, Icon, JsonView, LogViewer, Markdown, Modal, ProgressBar, Section, Select, SortableHeader, SplitPane, TabButton, ThemeProvider, ThemeSwitcher, Tree, TreeGroupHeader, TreeNode, badgeVariants, buttonVariants, cn, countGoroutinesByState, countProcesses, countStackByState, countThreadsByState, detectDumpFormat, findProcessByPID, fnv1a32, paletteClass, parseGoroutineDump, parseJvmThreadDump, parseStackDump, processLabel, processStateColor, processStateIcon, useDensity, useHistoryRoute, useSort, useTheme };
2918
- //# sourceMappingURL=index.mjs.map