@flanksource/clicky-ui 0.3.47 → 0.3.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/README.md +49 -0
  2. package/dist/comments/CommentSidePanel.cjs +10 -4
  3. package/dist/comments/CommentSidePanel.cjs.map +1 -1
  4. package/dist/comments/CommentSidePanel.d.ts +2 -0
  5. package/dist/comments/CommentSidePanel.d.ts.map +1 -1
  6. package/dist/comments/CommentSidePanel.js +10 -4
  7. package/dist/comments/CommentSidePanel.js.map +1 -1
  8. package/dist/comments/CommentThread.cjs +2 -0
  9. package/dist/comments/CommentThread.cjs.map +1 -1
  10. package/dist/comments/CommentThread.d.ts +2 -1
  11. package/dist/comments/CommentThread.d.ts.map +1 -1
  12. package/dist/comments/CommentThread.js +2 -0
  13. package/dist/comments/CommentThread.js.map +1 -1
  14. package/dist/comments/CommentThreadList.cjs +3 -0
  15. package/dist/comments/CommentThreadList.cjs.map +1 -1
  16. package/dist/comments/CommentThreadList.d.ts +3 -1
  17. package/dist/comments/CommentThreadList.d.ts.map +1 -1
  18. package/dist/comments/CommentThreadList.js +3 -0
  19. package/dist/comments/CommentThreadList.js.map +1 -1
  20. package/dist/data/CodeLine.cjs +4 -2
  21. package/dist/data/CodeLine.cjs.map +1 -1
  22. package/dist/data/CodeLine.d.ts.map +1 -1
  23. package/dist/data/CodeLine.js +4 -2
  24. package/dist/data/CodeLine.js.map +1 -1
  25. package/dist/data/DataTable.cjs +18 -8
  26. package/dist/data/DataTable.cjs.map +1 -1
  27. package/dist/data/DataTable.d.ts +4 -0
  28. package/dist/data/DataTable.d.ts.map +1 -1
  29. package/dist/data/DataTable.js +18 -8
  30. package/dist/data/DataTable.js.map +1 -1
  31. package/dist/data/SymbolBadge.cjs +61 -0
  32. package/dist/data/SymbolBadge.cjs.map +1 -0
  33. package/dist/data/SymbolBadge.d.ts +21 -0
  34. package/dist/data/SymbolBadge.d.ts.map +1 -0
  35. package/dist/data/SymbolBadge.js +61 -0
  36. package/dist/data/SymbolBadge.js.map +1 -0
  37. package/dist/data/TaskManager.cjs +183 -159
  38. package/dist/data/TaskManager.cjs.map +1 -1
  39. package/dist/data/TaskManager.d.ts +3 -1
  40. package/dist/data/TaskManager.d.ts.map +1 -1
  41. package/dist/data/TaskManager.js +185 -161
  42. package/dist/data/TaskManager.js.map +1 -1
  43. package/dist/data/TaskManagerButton.cjs +1 -0
  44. package/dist/data/TaskManagerButton.cjs.map +1 -1
  45. package/dist/data/TaskManagerButton.js +1 -0
  46. package/dist/data/TaskManagerButton.js.map +1 -1
  47. package/dist/data/TaskProgress.cjs +13 -7
  48. package/dist/data/TaskProgress.cjs.map +1 -1
  49. package/dist/data/TaskProgress.d.ts +3 -1
  50. package/dist/data/TaskProgress.d.ts.map +1 -1
  51. package/dist/data/TaskProgress.js +13 -7
  52. package/dist/data/TaskProgress.js.map +1 -1
  53. package/dist/data/test-runner/TestDetailPanel.cjs +26 -12
  54. package/dist/data/test-runner/TestDetailPanel.cjs.map +1 -1
  55. package/dist/data/test-runner/TestDetailPanel.d.ts.map +1 -1
  56. package/dist/data/test-runner/TestDetailPanel.js +27 -13
  57. package/dist/data/test-runner/TestDetailPanel.js.map +1 -1
  58. package/dist/data/test-runner/TestRunner.cjs +6 -0
  59. package/dist/data/test-runner/TestRunner.cjs.map +1 -1
  60. package/dist/data/test-runner/TestRunner.d.ts +3 -1
  61. package/dist/data/test-runner/TestRunner.d.ts.map +1 -1
  62. package/dist/data/test-runner/TestRunner.js +6 -0
  63. package/dist/data/test-runner/TestRunner.js.map +1 -1
  64. package/dist/data/test-runner/TestTreeNode.cjs +2 -1
  65. package/dist/data/test-runner/TestTreeNode.cjs.map +1 -1
  66. package/dist/data/test-runner/TestTreeNode.d.ts.map +1 -1
  67. package/dist/data/test-runner/TestTreeNode.js +2 -1
  68. package/dist/data/test-runner/TestTreeNode.js.map +1 -1
  69. package/dist/data/test-runner/adapter.cjs +4 -0
  70. package/dist/data/test-runner/adapter.cjs.map +1 -1
  71. package/dist/data/test-runner/adapter.d.ts +9 -0
  72. package/dist/data/test-runner/adapter.d.ts.map +1 -1
  73. package/dist/data/test-runner/adapter.js +4 -0
  74. package/dist/data/test-runner/adapter.js.map +1 -1
  75. package/dist/data/test-runner/context.cjs.map +1 -1
  76. package/dist/data/test-runner/context.d.ts +2 -0
  77. package/dist/data/test-runner/context.d.ts.map +1 -1
  78. package/dist/data/test-runner/context.js.map +1 -1
  79. package/dist/data/test-runner/index.d.ts +2 -2
  80. package/dist/data/test-runner/index.d.ts.map +1 -1
  81. package/dist/data/test-runner/marks.cjs +42 -1
  82. package/dist/data/test-runner/marks.cjs.map +1 -1
  83. package/dist/data/test-runner/marks.d.ts +10 -0
  84. package/dist/data/test-runner/marks.d.ts.map +1 -1
  85. package/dist/data/test-runner/marks.js +42 -1
  86. package/dist/data/test-runner/marks.js.map +1 -1
  87. package/dist/data/traces/ProcessTraceTree.cjs +93 -0
  88. package/dist/data/traces/ProcessTraceTree.cjs.map +1 -0
  89. package/dist/data/traces/ProcessTraceTree.d.ts +24 -0
  90. package/dist/data/traces/ProcessTraceTree.d.ts.map +1 -0
  91. package/dist/data/traces/ProcessTraceTree.js +93 -0
  92. package/dist/data/traces/ProcessTraceTree.js.map +1 -0
  93. package/dist/data/traces/Sparkline.cjs +23 -0
  94. package/dist/data/traces/Sparkline.cjs.map +1 -0
  95. package/dist/data/traces/Sparkline.d.ts +13 -0
  96. package/dist/data/traces/Sparkline.d.ts.map +1 -0
  97. package/dist/data/traces/Sparkline.js +23 -0
  98. package/dist/data/traces/Sparkline.js.map +1 -0
  99. package/dist/data/traces/SqlTraceTable.cjs +104 -0
  100. package/dist/data/traces/SqlTraceTable.cjs.map +1 -0
  101. package/dist/data/traces/SqlTraceTable.d.ts +19 -0
  102. package/dist/data/traces/SqlTraceTable.d.ts.map +1 -0
  103. package/dist/data/traces/SqlTraceTable.js +104 -0
  104. package/dist/data/traces/SqlTraceTable.js.map +1 -0
  105. package/dist/data/traces/TerminalCastPlayer.cjs +162 -0
  106. package/dist/data/traces/TerminalCastPlayer.cjs.map +1 -0
  107. package/dist/data/traces/TerminalCastPlayer.d.ts +21 -0
  108. package/dist/data/traces/TerminalCastPlayer.d.ts.map +1 -0
  109. package/dist/data/traces/TerminalCastPlayer.js +162 -0
  110. package/dist/data/traces/TerminalCastPlayer.js.map +1 -0
  111. package/dist/data/traces/TraceHarView.cjs +15 -0
  112. package/dist/data/traces/TraceHarView.cjs.map +1 -0
  113. package/dist/data/traces/TraceHarView.d.ts +13 -0
  114. package/dist/data/traces/TraceHarView.d.ts.map +1 -0
  115. package/dist/data/traces/TraceHarView.js +15 -0
  116. package/dist/data/traces/TraceHarView.js.map +1 -0
  117. package/dist/data/traces/TraceView.cjs +54 -0
  118. package/dist/data/traces/TraceView.cjs.map +1 -0
  119. package/dist/data/traces/TraceView.d.ts +18 -0
  120. package/dist/data/traces/TraceView.d.ts.map +1 -0
  121. package/dist/data/traces/TraceView.js +54 -0
  122. package/dist/data/traces/TraceView.js.map +1 -0
  123. package/dist/data/traces/cast.cjs +81 -0
  124. package/dist/data/traces/cast.cjs.map +1 -0
  125. package/dist/data/traces/cast.d.ts +9 -0
  126. package/dist/data/traces/cast.d.ts.map +1 -0
  127. package/dist/data/traces/cast.js +81 -0
  128. package/dist/data/traces/cast.js.map +1 -0
  129. package/dist/data/traces/fixtures.d.ts +8 -0
  130. package/dist/data/traces/fixtures.d.ts.map +1 -0
  131. package/dist/data/traces/har-adapter.cjs +83 -0
  132. package/dist/data/traces/har-adapter.cjs.map +1 -0
  133. package/dist/data/traces/har-adapter.d.ts +13 -0
  134. package/dist/data/traces/har-adapter.d.ts.map +1 -0
  135. package/dist/data/traces/har-adapter.js +83 -0
  136. package/dist/data/traces/har-adapter.js.map +1 -0
  137. package/dist/data/traces/index.d.ts +12 -0
  138. package/dist/data/traces/index.d.ts.map +1 -0
  139. package/dist/data/traces/process-tree.cjs +53 -0
  140. package/dist/data/traces/process-tree.cjs.map +1 -0
  141. package/dist/data/traces/process-tree.d.ts +21 -0
  142. package/dist/data/traces/process-tree.d.ts.map +1 -0
  143. package/dist/data/traces/process-tree.js +53 -0
  144. package/dist/data/traces/process-tree.js.map +1 -0
  145. package/dist/data/traces/sql-trace.cjs +39 -0
  146. package/dist/data/traces/sql-trace.cjs.map +1 -0
  147. package/dist/data/traces/sql-trace.d.ts +31 -0
  148. package/dist/data/traces/sql-trace.d.ts.map +1 -0
  149. package/dist/data/traces/sql-trace.js +39 -0
  150. package/dist/data/traces/sql-trace.js.map +1 -0
  151. package/dist/data/traces/terminal-screen.cjs +270 -0
  152. package/dist/data/traces/terminal-screen.cjs.map +1 -0
  153. package/dist/data/traces/terminal-screen.d.ts +45 -0
  154. package/dist/data/traces/terminal-screen.d.ts.map +1 -0
  155. package/dist/data/traces/terminal-screen.js +270 -0
  156. package/dist/data/traces/terminal-screen.js.map +1 -0
  157. package/dist/data/traces/terminal-timeline.cjs +48 -0
  158. package/dist/data/traces/terminal-timeline.cjs.map +1 -0
  159. package/dist/data/traces/terminal-timeline.d.ts +26 -0
  160. package/dist/data/traces/terminal-timeline.d.ts.map +1 -0
  161. package/dist/data/traces/terminal-timeline.js +48 -0
  162. package/dist/data/traces/terminal-timeline.js.map +1 -0
  163. package/dist/data/traces/types.d.ts +139 -0
  164. package/dist/data/traces/types.d.ts.map +1 -0
  165. package/dist/data/verification/VerificationResults.cjs +4 -0
  166. package/dist/data/verification/VerificationResults.cjs.map +1 -1
  167. package/dist/data/verification/VerificationResults.d.ts +3 -1
  168. package/dist/data/verification/VerificationResults.d.ts.map +1 -1
  169. package/dist/data/verification/VerificationResults.js +4 -0
  170. package/dist/data/verification/VerificationResults.js.map +1 -1
  171. package/dist/data/verification/adapterViews.cjs +12 -3
  172. package/dist/data/verification/adapterViews.cjs.map +1 -1
  173. package/dist/data/verification/adapterViews.d.ts +4 -1
  174. package/dist/data/verification/adapterViews.d.ts.map +1 -1
  175. package/dist/data/verification/adapterViews.js +12 -3
  176. package/dist/data/verification/adapterViews.js.map +1 -1
  177. package/dist/data/verification/adapters.cjs +53 -10
  178. package/dist/data/verification/adapters.cjs.map +1 -1
  179. package/dist/data/verification/adapters.d.ts +7 -1
  180. package/dist/data/verification/adapters.d.ts.map +1 -1
  181. package/dist/data/verification/adapters.js +53 -10
  182. package/dist/data/verification/adapters.js.map +1 -1
  183. package/dist/data/verification/index.d.ts +4 -2
  184. package/dist/data/verification/index.d.ts.map +1 -1
  185. package/dist/data/verification/stepKind.cjs +217 -0
  186. package/dist/data/verification/stepKind.cjs.map +1 -0
  187. package/dist/data/verification/stepKind.d.ts +87 -0
  188. package/dist/data/verification/stepKind.d.ts.map +1 -0
  189. package/dist/data/verification/stepKind.js +217 -0
  190. package/dist/data/verification/stepKind.js.map +1 -0
  191. package/dist/data/verification/stepKindViews.cjs +111 -0
  192. package/dist/data/verification/stepKindViews.cjs.map +1 -0
  193. package/dist/data/verification/stepKindViews.d.ts +18 -0
  194. package/dist/data/verification/stepKindViews.d.ts.map +1 -0
  195. package/dist/data/verification/stepKindViews.js +111 -0
  196. package/dist/data/verification/stepKindViews.js.map +1 -0
  197. package/dist/data/verification/verifyReportTests.cjs +1 -0
  198. package/dist/data/verification/verifyReportTests.cjs.map +1 -1
  199. package/dist/data/verification/verifyReportTests.d.ts +2 -1
  200. package/dist/data/verification/verifyReportTests.d.ts.map +1 -1
  201. package/dist/data/verification/verifyReportTests.js +1 -0
  202. package/dist/data/verification/verifyReportTests.js.map +1 -1
  203. package/dist/data/version-info.cjs +3 -3
  204. package/dist/data/version-info.cjs.map +1 -1
  205. package/dist/data/version-info.js +3 -3
  206. package/dist/data/version-info.js.map +1 -1
  207. package/dist/data.cjs +36 -0
  208. package/dist/data.cjs.map +1 -1
  209. package/dist/data.d.ts +2 -0
  210. package/dist/data.d.ts.map +1 -1
  211. package/dist/data.js +38 -2
  212. package/dist/data.js.map +1 -1
  213. package/dist/index.cjs +38 -0
  214. package/dist/index.cjs.map +1 -1
  215. package/dist/index.js +40 -2
  216. package/dist/index.js.map +1 -1
  217. package/dist/rpc/FilterForm.cjs +9 -0
  218. package/dist/rpc/FilterForm.cjs.map +1 -1
  219. package/dist/rpc/FilterForm.d.ts +5 -1
  220. package/dist/rpc/FilterForm.d.ts.map +1 -1
  221. package/dist/rpc/FilterForm.js +9 -0
  222. package/dist/rpc/FilterForm.js.map +1 -1
  223. package/dist/rpc/OperationArgsForm.cjs +153 -0
  224. package/dist/rpc/OperationArgsForm.cjs.map +1 -0
  225. package/dist/rpc/OperationArgsForm.d.ts +16 -0
  226. package/dist/rpc/OperationArgsForm.d.ts.map +1 -0
  227. package/dist/rpc/OperationArgsForm.js +153 -0
  228. package/dist/rpc/OperationArgsForm.js.map +1 -0
  229. package/dist/rpc/OperationScheduleDialog.cjs +61 -17
  230. package/dist/rpc/OperationScheduleDialog.cjs.map +1 -1
  231. package/dist/rpc/OperationScheduleDialog.d.ts +3 -0
  232. package/dist/rpc/OperationScheduleDialog.d.ts.map +1 -1
  233. package/dist/rpc/OperationScheduleDialog.js +62 -18
  234. package/dist/rpc/OperationScheduleDialog.js.map +1 -1
  235. package/dist/rpc/OperationSchedules.cjs +6 -1
  236. package/dist/rpc/OperationSchedules.cjs.map +1 -1
  237. package/dist/rpc/OperationSchedules.d.ts.map +1 -1
  238. package/dist/rpc/OperationSchedules.js +6 -1
  239. package/dist/rpc/OperationSchedules.js.map +1 -1
  240. package/dist/rpc/operation-schedule-model.cjs +0 -7
  241. package/dist/rpc/operation-schedule-model.cjs.map +1 -1
  242. package/dist/rpc/operation-schedule-model.d.ts +0 -2
  243. package/dist/rpc/operation-schedule-model.d.ts.map +1 -1
  244. package/dist/rpc/operation-schedule-model.js +0 -7
  245. package/dist/rpc/operation-schedule-model.js.map +1 -1
  246. package/dist/rpc/operation-schedule-types.d.ts +6 -1
  247. package/dist/rpc/operation-schedule-types.d.ts.map +1 -1
  248. package/dist/rpc.cjs +2 -0
  249. package/dist/rpc.cjs.map +1 -1
  250. package/dist/rpc.d.ts +1 -0
  251. package/dist/rpc.d.ts.map +1 -1
  252. package/dist/rpc.js +2 -0
  253. package/dist/rpc.js.map +1 -1
  254. package/dist/styles.css +1 -1
  255. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.js","sources":["../../src/data/TaskManager.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { hashKey, useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { QueryKey } from \"@tanstack/react-query\";\nimport { cn } from \"../lib/utils\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { Icon } from \"./Icon\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { Timestamp } from \"./cells/Timestamp\";\nimport { TaskProgress } from \"./TaskProgress\";\nimport { taskWorkProgress } from \"./task-work-progress\";\nimport type { TaskControlAction, TaskRunMeta, TaskSnapshot } from \"./TaskSnapshot\";\nimport type { TaskHeaderExtra } from \"./TaskHeaderExtras\";\nimport type { TaskExtraTabs } from \"./TaskStreamTabs\";\nimport { taskQueryKeys } from \"./task-query-keys\";\nimport { taskSegments, taskStatusBg, taskStatusColor, taskStatusIcon } from \"./task-status\";\n\n// TaskManager is the generic clicky-ui task-manager view: it lists every run\n// (TaskRunMeta) from GET {basePath}/tasks with kind/status filters, and expands\n// each row into a live <TaskProgress> for that run id. Runs are grouped by kind,\n// which applications use as their stable task identity.\n//\n// Requires a react-query QueryClientProvider in the host app (like\n// TimeseriesPanel and CacheBrowser): control actions run through useMutation,\n// and the listing is mirrored into the query cache so sibling views can read it.\n\nexport interface TaskManagerProps {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string;\n /** Restrict the listing to a single kind (also hides the kind filter). */\n kind?: string;\n /** Restrict the listing to runs whose labels contain every key/value pair. */\n labels?: Record<string, string>;\n pollMs?: number;\n className?: string;\n /**\n * Currently-selected (expanded) run id, e.g. driven from the URL. When set,\n * the matching run renders expanded and selection is controlled — otherwise\n * each row manages its own expand/collapse state.\n */\n selectedId?: string;\n /**\n * Called when a run row is toggled: the new selection id, or null when the\n * open row is collapsed. Pair with selectedId for URL-driven deep links.\n */\n onSelectRun?: (id: string | null) => void;\n /**\n * Contributes host-owned output panes to each task, alongside its own\n * stdout/stderr — an agent's session transcript, say.\n */\n extraTabs?: TaskExtraTabs;\n /**\n * Replaces the content beside a task's name in its header row. Returning null\n * for a task falls back to the default metadata chips.\n */\n headerExtra?: TaskHeaderExtra;\n}\n\nexport function TaskManager({\n basePath,\n kind,\n labels,\n pollMs,\n className,\n selectedId,\n onSelectRun,\n extraTabs,\n headerExtra,\n}: TaskManagerProps) {\n const [kindFilter, setKindFilter] = useState<string>(kind ?? \"\");\n const [statusFilter, setStatusFilter] = useState<string>(\"\");\n const queryClient = useQueryClient();\n const apiBase = basePath ?? \"/api/v1\";\n const activeKind = kind ?? (kindFilter || undefined);\n const { runs, runsKey, status } = useTaskRuns({\n basePath: apiBase,\n kind: activeKind,\n labels,\n status: statusFilter || undefined,\n pollMs,\n });\n const runsQueryKey = useMemo(\n () => taskQueryKeys.runs({\n basePath: apiBase,\n kind: activeKind,\n status: statusFilter || undefined,\n labels,\n }),\n [activeKind, apiBase, labels, statusFilter],\n );\n\n // Changing a filter re-subscribes the transport but leaves the previous\n // listing on screen until the next SSE/poll frame. Publishing that listing\n // under the new key would hand cache consumers rows that do not match their\n // filters, so mirror only once the delivered listing's own key agrees.\n useEffect(() => {\n if (!runsKey || hashKey(runsKey) !== hashKey(runsQueryKey)) return;\n queryClient.setQueryData(runsQueryKey, runs);\n }, [queryClient, runs, runsKey, runsQueryKey]);\n\n const kinds = useMemo(() => {\n const set = new Set<string>();\n for (const r of runs) if (r.kind) set.add(r.kind);\n return [...set].sort();\n }, [runs]);\n const applications = useMemo(() => groupRunsByApplication(runs), [runs]);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n {!kind && (\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={kindFilter}\n onChange={(e) => setKindFilter(e.target.value)}\n >\n <option value=\"\">All kinds</option>\n {kinds.map((k) => (\n <option key={k} value={k}>\n {k}\n </option>\n ))}\n </select>\n )}\n <select\n className=\"rounded-md border bg-background px-2 py-1 text-xs\"\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n >\n <option value=\"\">Any status</option>\n <option value=\"running\">Running</option>\n <option value=\"pending\">Pending</option>\n <option value=\"success\">Success</option>\n <option value=\"failed\">Failed</option>\n <option value=\"warning\">Warning</option>\n <option value=\"canceled\">Canceled</option>\n </select>\n <span className=\"text-xs text-muted-foreground\">{status}</span>\n </div>\n\n {runs.length === 0 ? (\n <div className=\"rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground\">\n No background tasks.\n </div>\n ) : (\n <div className=\"space-y-3\">\n {applications.map((application) => (\n <section key={application.kind}>\n <h3 className=\"mb-1 px-1 text-xs font-semibold text-muted-foreground\">\n {applicationLabel(application.kind)}\n </h3>\n <div className=\"overflow-hidden rounded-lg border bg-card\">\n {application.runs.map((run) => (\n <RunRow\n key={run.id}\n run={run}\n basePath={basePath}\n pollMs={pollMs}\n selectedId={selectedId}\n onSelectRun={onSelectRun}\n runsQueryKey={runsQueryKey}\n extraTabs={extraTabs}\n headerExtra={headerExtra}\n />\n ))}\n </div>\n </section>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction groupRunsByApplication(runs: TaskRunMeta[]) {\n const grouped = new Map<string, TaskRunMeta[]>();\n for (const run of runs) {\n const application = run.kind || \"other\";\n grouped.set(application, [...(grouped.get(application) ?? []), run]);\n }\n return [...grouped].map(([kind, applicationRuns]) => ({ kind, runs: applicationRuns }));\n}\n\nfunction applicationLabel(kind: string): string {\n const names: Record<string, string> = {\n makerprint: \"MakerPrint\",\n openscad: \"OpenSCAD\",\n orca: \"Orca\",\n snapmaker: \"Snapmaker\",\n other: \"Other\",\n };\n return names[kind] ?? kind;\n}\n\nfunction RunRow({\n run,\n basePath,\n pollMs,\n selectedId,\n onSelectRun,\n runsQueryKey,\n extraTabs,\n headerExtra,\n}: {\n run: TaskRunMeta;\n basePath: string | undefined;\n pollMs: number | undefined;\n selectedId: string | undefined;\n onSelectRun: ((id: string | null) => void) | undefined;\n runsQueryKey: QueryKey;\n extraTabs: TaskExtraTabs | undefined;\n headerExtra: TaskHeaderExtra | undefined;\n}) {\n const [localOpen, setLocalOpen] = useState(false);\n // Controlled by selectedId when a selection handler is wired; otherwise the\n // row owns its expand state (backward compatible for router-less consumers).\n const controlled = onSelectRun !== undefined;\n const open = controlled ? selectedId === run.id : localOpen;\n const toggle = () => {\n if (controlled) onSelectRun(open ? null : run.id);\n else setLocalOpen((v) => !v);\n };\n const isTerminal = run.status !== \"running\" && run.status !== \"pending\";\n const progress = taskWorkProgress(run);\n\n return (\n <div className=\"border-b last:border-0\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-4 px-4 py-3 text-left hover:bg-muted/50\"\n onClick={toggle}\n >\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <Icon\n icon={taskStatusIcon(run.status)}\n className={cn(taskStatusColor(run.status), run.status === \"running\" && \"animate-spin\")}\n />\n <span className=\"truncate font-medium\">{run.name}</span>\n {run.kind && (\n <span className=\"rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground\">\n {run.kind}\n </span>\n )}\n {isTerminal && (\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs\",\n taskStatusColor(run.status),\n taskStatusBg(run.status),\n )}\n >\n {run.status}\n </span>\n )}\n </div>\n <div className=\"mt-1 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground\">\n {run.startedAt && <Timestamp value={run.startedAt} format=\"relative\" />}\n <span>\n {progress.label}\n </span>\n {Object.entries(run.labels ?? {}).map(([k, v]) => (\n <span key={k} className=\"font-mono\">\n {k}={v}\n </span>\n ))}\n </div>\n </div>\n <div className=\"w-40 shrink-0\">\n <ProgressBar\n segments={taskSegments(progress.counts)}\n total={progress.total || 1}\n height=\"h-1.5\"\n />\n </div>\n </button>\n {open && (\n <ExpandedRun\n runId={run.id}\n basePath={basePath}\n pollMs={pollMs}\n runsQueryKey={runsQueryKey}\n extraTabs={extraTabs}\n headerExtra={headerExtra}\n />\n )}\n </div>\n );\n}\n\nfunction ExpandedRun({\n runId,\n basePath,\n pollMs,\n runsQueryKey,\n extraTabs,\n headerExtra,\n}: {\n runId: string;\n basePath: string | undefined;\n pollMs: number | undefined;\n runsQueryKey: QueryKey;\n extraTabs: TaskExtraTabs | undefined;\n headerExtra: TaskHeaderExtra | undefined;\n}) {\n const { snapshots, status } = useTaskRun({ id: runId, basePath, pollMs });\n const apiBase = basePath ?? \"/api/v1\";\n const queryClient = useQueryClient();\n const pendingControls = useRef(new Map<string, Promise<void>>());\n const cachedSnapshots = useRef<TaskSnapshot[] | undefined>(undefined);\n const runQueryKey = useMemo(\n () => taskQueryKeys.run({ basePath: apiBase, runId }),\n [apiBase, runId],\n );\n const controlMutation = useMutation({\n mutationKey: taskQueryKeys.control({ basePath: apiBase, runId }),\n mutationFn: postTaskControl,\n onSuccess: async () => {\n await Promise.all([\n queryClient.invalidateQueries({ queryKey: runsQueryKey, exact: true, refetchType: \"none\" }),\n queryClient.invalidateQueries({ queryKey: runQueryKey, exact: true, refetchType: \"none\" }),\n ]);\n },\n });\n\n useEffect(() => {\n const previous = cachedSnapshots.current;\n if (previous?.length === snapshots.length && previous.every((snapshot, index) => snapshot === snapshots[index])) {\n return;\n }\n cachedSnapshots.current = snapshots;\n queryClient.setQueryData(runQueryKey, snapshots);\n }, [queryClient, runQueryKey, snapshots]);\n\n const mutateControl = useCallback((request: TaskControlRequest) => {\n const key = `${request.url}:${request.action}`;\n const pending = pendingControls.current.get(key);\n if (pending) return pending;\n controlMutation.reset();\n const mutation = controlMutation.mutateAsync(request).finally(() => {\n if (pendingControls.current.get(key) === mutation) pendingControls.current.delete(key);\n });\n pendingControls.current.set(key, mutation);\n return mutation;\n }, [controlMutation.mutateAsync, controlMutation.reset]);\n const control = (action: TaskControlAction, group: TaskSnapshot) =>\n mutateControl({\n url: `${apiBase}/tasks/${encodeURIComponent(runId)}/control`,\n action,\n target: group,\n });\n const controlTask = (action: TaskControlAction, task: TaskSnapshot) =>\n mutateControl({\n url: `${apiBase}/tasks/${encodeURIComponent(runId)}/tasks/${encodeURIComponent(task.id)}/control`,\n action,\n target: task,\n });\n return (\n <div className=\"border-t bg-muted/30 px-4 py-3\">\n <TaskProgress\n snapshots={snapshots}\n connectionStatus={status}\n compact\n onControl={control}\n onTaskControl={controlTask}\n metricsBaseUrl={`${apiBase}/tasks/metrics/`}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n </div>\n );\n}\n\ninterface TaskControlRequest {\n url: string;\n action: TaskControlAction;\n target: TaskSnapshot;\n}\n\nasync function postTaskControl({ url, action, target }: TaskControlRequest) {\n const context = `Failed to ${action} ${target.type} \"${target.name}\"`;\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action }),\n });\n } catch (cause) {\n throw new Error(`${context}: ${cause instanceof Error ? cause.message : \"request failed\"}`, { cause });\n }\n if (!response.ok) {\n const detail = (await response.text()).trim() || `HTTP ${response.status}`;\n throw new Error(`${context}: ${detail}`);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskManager.js","sources":["../../src/data/TaskManager.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { hashKey, useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { QueryKey } from \"@tanstack/react-query\";\nimport { cn } from \"../lib/utils\";\nimport { formatDuration } from \"../lib/format\";\nimport { useResourceClock } from \"../hooks/use-resource-clock\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport type { FilterBarFilter } from \"../components/FilterBar\";\nimport { Icon } from \"./Icon\";\nimport { DataTable, type DataTableColumn } from \"./DataTable\";\nimport { splitTagToken } from \"./cells/tag-utils\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { TaskProgress } from \"./TaskProgress\";\nimport { taskWorkProgress } from \"./task-work-progress\";\nimport type { TaskControlAction, TaskRunMeta, TaskSnapshot } from \"./TaskSnapshot\";\nimport type { TaskHeaderExtra } from \"./TaskHeaderExtras\";\nimport type { TaskExtraTabs } from \"./TaskStreamTabs\";\nimport { taskQueryKeys } from \"./task-query-keys\";\nimport { taskSegments, taskStatusColor, taskStatusIcon } from \"./task-status\";\n\n// TaskManager is the generic clicky-ui task-manager view: it lists every run\n// (TaskRunMeta) from GET {basePath}/tasks with kind/status filters, and expands\n// each row into a live <TaskProgress> for that run id.\n//\n// Requires a react-query QueryClientProvider in the host app (like\n// TimeseriesPanel and CacheBrowser): control actions run through useMutation,\n// and the listing is mirrored into the query cache so sibling views can read it.\n\nexport interface TaskManagerProps {\n /** Base path of the clicky task API, e.g. \"/api/v1\". */\n basePath?: string;\n /** Restrict the listing to a single kind (also hides the kind filter). */\n kind?: string;\n /** Restrict the listing to runs whose labels contain every key/value pair. */\n labels?: Record<string, string>;\n pollMs?: number;\n className?: string;\n /** Keep the run columns usable in a narrow panel. */\n compact?: boolean;\n /**\n * Currently-selected (expanded) run id, e.g. driven from the URL. When set,\n * the matching run renders expanded and selection is controlled — otherwise\n * each row manages its own expand/collapse state.\n */\n selectedId?: string;\n /**\n * Called when a run row is toggled: the new selection id, or null when the\n * open row is collapsed. Pair with selectedId for URL-driven deep links.\n */\n onSelectRun?: (id: string | null) => void;\n /**\n * Contributes host-owned output panes to each task, alongside its own\n * stdout/stderr — an agent's session transcript, say.\n */\n extraTabs?: TaskExtraTabs;\n /**\n * Replaces the content beside a task's name in its header row. Returning null\n * for a task falls back to the default metadata chips.\n */\n headerExtra?: TaskHeaderExtra;\n}\n\ntype RunTableRow = Record<string, unknown> & {\n id: string;\n name: string;\n kind: string;\n status: string;\n startedAt?: string;\n finishedAt?: string;\n labels?: Record<string, string>;\n run: TaskRunMeta;\n};\n\nconst progressColumn: DataTableColumn<RunTableRow> = {\n key: \"progress\", label: \"Progress\", minWidth: 180,\n accessor: (row) => taskWorkProgress(row.run).done,\n render: (_, row) => {\n const progress = taskWorkProgress(row.run);\n return (\n <div className=\"min-w-36 space-y-1\">\n <span className=\"text-xs tabular-nums text-muted-foreground\">{progress.label}</span>\n {progress.total > 0 && <ProgressBar segments={taskSegments(progress.counts)} total={progress.total} height=\"h-1.5\" />}\n </div>\n );\n },\n};\nconst startedColumn: DataTableColumn<RunTableRow> = { key: \"startedAt\", label: \"Started\", kind: \"timestamp\", sortable: true };\nconst durationColumn: DataTableColumn<RunTableRow> = {\n key: \"duration\", label: \"Duration\", sortable: true,\n accessor: (row) => row.startedAt ? Date.parse(row.finishedAt ?? new Date().toISOString()) - Date.parse(row.startedAt) : null,\n render: (_, row) => <RunDuration startedAt={row.startedAt} finishedAt={row.finishedAt} />,\n};\nconst runColumns: DataTableColumn<RunTableRow>[] = [\n { key: \"name\", label: \"Run\", sortable: true, grow: true, minWidth: 220 },\n {\n key: \"status\", label: \"Status\", sortable: true,\n render: (_, row) => (\n <span className={cn(\"inline-flex items-center gap-1.5 capitalize\", taskStatusColor(row.status))}>\n <Icon icon={taskStatusIcon(row.status)} {...(row.status === \"running\" ? { className: \"animate-spin\" } : {})} />\n {row.status}\n </span>\n ),\n },\n durationColumn,\n progressColumn,\n { key: \"labels\", label: \"Labels\", kind: \"tags\", tags: { maxVisible: 2 }, minWidth: 160 },\n startedColumn,\n { key: \"finishedAt\", label: \"Finished\", kind: \"timestamp\", sortable: true },\n];\nconst compactRunColumns: DataTableColumn<RunTableRow>[] = [\n {\n key: \"name\", label: \"Run\", sortable: true, grow: true, minWidth: 220,\n render: (_, row) => (\n <div className=\"space-y-0.5\">\n <div className=\"font-medium\">{row.name}</div>\n <div className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <span>{applicationLabel(row.kind)}</span>\n <span className={cn(\"inline-flex items-center gap-1 capitalize\", taskStatusColor(row.status))}>\n <Icon icon={taskStatusIcon(row.status)} />{row.status}\n </span>\n </div>\n </div>\n ),\n },\n progressColumn,\n startedColumn,\n];\n\nexport function TaskManager({\n basePath,\n kind,\n labels,\n pollMs,\n className,\n compact,\n selectedId,\n onSelectRun,\n extraTabs,\n headerExtra,\n}: TaskManagerProps) {\n const [kindFilter, setKindFilter] = useState<string>(kind ?? \"\");\n const [statusFilter, setStatusFilter] = useState<string>(\"\");\n const [labelFilter, setLabelFilter] = useState(\"\");\n const [filterOptions, setFilterOptions] = useState({ kinds: [] as string[], labels: [] as string[] });\n const [localSelectedId, setLocalSelectedId] = useState<string | null>(null);\n const queryClient = useQueryClient();\n const apiBase = basePath ?? \"/api/v1\";\n const activeKind = kind ?? (kindFilter || undefined);\n const activeLabels = useMemo(() => {\n if (!labelFilter) return labels;\n const selected = splitTagToken(labelFilter);\n return { ...labels, [selected.key]: selected.value };\n }, [labels, labelFilter]);\n const { runs, runsKey, status } = useTaskRuns({\n basePath: apiBase,\n kind: activeKind,\n labels: activeLabels,\n status: statusFilter || undefined,\n pollMs,\n });\n const runsQueryKey = useMemo(\n () => taskQueryKeys.runs({\n basePath: apiBase,\n kind: activeKind,\n status: statusFilter || undefined,\n labels: activeLabels,\n }),\n [activeKind, apiBase, activeLabels, statusFilter],\n );\n\n // Changing a filter re-subscribes the transport but leaves the previous\n // listing on screen until the next SSE/poll frame. Publishing that listing\n // under the new key would hand cache consumers rows that do not match their\n // filters, so mirror only once the delivered listing's own key agrees.\n useEffect(() => {\n if (!runsKey || hashKey(runsKey) !== hashKey(runsQueryKey)) return;\n queryClient.setQueryData(runsQueryKey, runs);\n }, [queryClient, runs, runsKey, runsQueryKey]);\n\n useEffect(() => {\n setFilterOptions((previous) => {\n const kinds = [...new Set([...previous.kinds, ...runs.flatMap((run) => run.kind ? [run.kind] : [])])].sort();\n const labels = [...new Set([...previous.labels, ...runs.flatMap((run) => Object.entries(run.labels ?? {}).map(([key, value]) => `${key}=${value}`))])].sort();\n if (kinds.length === previous.kinds.length && labels.length === previous.labels.length) return previous;\n return { kinds, labels };\n });\n }, [runs]);\n const filters: FilterBarFilter[] = [\n ...(!kind ? [{ key: \"kind\", kind: \"enum\" as const, label: \"Kind\", placeholder: \"All kinds\", value: kindFilter, options: filterOptions.kinds.map((value) => ({ value, label: applicationLabel(value) })), onChange: setKindFilter }] : []),\n { key: \"status\", kind: \"enum\", label: \"Status\", placeholder: \"Any status\", value: statusFilter, options: [\n { value: \"running\", label: \"Running\" },\n { value: \"pending\", label: \"Pending\" },\n { value: \"success\", label: \"Success\" },\n { value: \"failed\", label: \"Failed\" },\n { value: \"warning\", label: \"Warning\" },\n { value: \"canceled\", label: \"Canceled\" },\n ], onChange: setStatusFilter },\n { key: \"labels\", kind: \"enum\", label: \"Labels\", placeholder: \"Any label\", value: labelFilter,\n options: filterOptions.labels.filter((token) => !(splitTagToken(token).key in (labels ?? {}))).map((value) => ({ value })),\n onChange: setLabelFilter },\n ];\n const rows = useMemo<RunTableRow[]>(() => runs.map((run) => ({\n id: run.id,\n name: run.name,\n kind: run.kind || \"other\",\n status: run.status,\n ...(run.startedAt ? { startedAt: run.startedAt } : {}),\n ...(run.finishedAt ? { finishedAt: run.finishedAt } : {}),\n ...(run.labels ? { labels: run.labels } : {}),\n run,\n })), [runs]);\n const openId = onSelectRun ? selectedId : localSelectedId;\n\n return (\n <DataTable\n {...(className ? { className } : {})}\n data={rows}\n columns={compact ? compactRunColumns : runColumns}\n emptyMessage=\"No background tasks.\"\n externalFilters={filters}\n filterBarProps={{ trailing: <span className=\"text-xs text-muted-foreground\">{status}</span> }}\n getRowId={(row) => row.id}\n defaultSort={{ key: \"startedAt\", dir: \"desc\" }}\n expandedRowIds={openId ? [openId] : []}\n onExpandedRowIdsChange={(ids) => {\n const next = ids.find((id) => id !== openId) ?? null;\n if (onSelectRun) onSelectRun(next);\n else setLocalSelectedId(next);\n }}\n renderExpandedRow={(row) => (\n <ExpandedRun\n run={row.run}\n basePath={basePath}\n pollMs={pollMs}\n runsQueryKey={runsQueryKey}\n extraTabs={extraTabs}\n headerExtra={headerExtra}\n />\n )}\n />\n );\n}\n\nfunction RunDuration({ startedAt, finishedAt }: { startedAt: string | undefined; finishedAt: string | undefined }) {\n const now = useResourceClock(!!startedAt && !finishedAt);\n if (!startedAt) return <span className=\"text-muted-foreground\">—</span>;\n return <span className=\"tabular-nums\">{formatDuration(Math.max(0, (finishedAt ? Date.parse(finishedAt) : now) - Date.parse(startedAt)))}</span>;\n}\n\nfunction applicationLabel(kind: string): string {\n const names: Record<string, string> = {\n makerprint: \"MakerPrint\",\n openscad: \"OpenSCAD\",\n orca: \"Orca\",\n snapmaker: \"Snapmaker\",\n other: \"Other\",\n };\n return names[kind] ?? kind;\n}\n\nfunction ExpandedRun({\n run,\n basePath,\n pollMs,\n runsQueryKey,\n extraTabs,\n headerExtra,\n}: {\n run: TaskRunMeta;\n basePath: string | undefined;\n pollMs: number | undefined;\n runsQueryKey: QueryKey;\n extraTabs: TaskExtraTabs | undefined;\n headerExtra: TaskHeaderExtra | undefined;\n}) {\n const runId = run.id;\n const { snapshots, status } = useTaskRun({ id: runId, basePath, pollMs });\n const apiBase = basePath ?? \"/api/v1\";\n const queryClient = useQueryClient();\n const pendingControls = useRef(new Map<string, Promise<void>>());\n const cachedSnapshots = useRef<TaskSnapshot[] | undefined>(undefined);\n const runQueryKey = useMemo(\n () => taskQueryKeys.run({ basePath: apiBase, runId }),\n [apiBase, runId],\n );\n const controlMutation = useMutation({\n mutationKey: taskQueryKeys.control({ basePath: apiBase, runId }),\n mutationFn: postTaskControl,\n onSuccess: async () => {\n await Promise.all([\n queryClient.invalidateQueries({ queryKey: runsQueryKey, exact: true, refetchType: \"none\" }),\n queryClient.invalidateQueries({ queryKey: runQueryKey, exact: true, refetchType: \"none\" }),\n ]);\n },\n });\n\n useEffect(() => {\n const previous = cachedSnapshots.current;\n if (previous?.length === snapshots.length && previous.every((snapshot, index) => snapshot === snapshots[index])) {\n return;\n }\n cachedSnapshots.current = snapshots;\n queryClient.setQueryData(runQueryKey, snapshots);\n }, [queryClient, runQueryKey, snapshots]);\n\n const mutateControl = useCallback((request: TaskControlRequest) => {\n const key = `${request.url}:${request.action}`;\n const pending = pendingControls.current.get(key);\n if (pending) return pending;\n controlMutation.reset();\n const mutation = controlMutation.mutateAsync(request).finally(() => {\n if (pendingControls.current.get(key) === mutation) pendingControls.current.delete(key);\n });\n pendingControls.current.set(key, mutation);\n return mutation;\n }, [controlMutation.mutateAsync, controlMutation.reset]);\n const control = (action: TaskControlAction, group: TaskSnapshot) =>\n mutateControl({\n url: `${apiBase}/tasks/${encodeURIComponent(runId)}/control`,\n action,\n target: group,\n });\n const controlTask = (action: TaskControlAction, task: TaskSnapshot) =>\n mutateControl({\n url: `${apiBase}/tasks/${encodeURIComponent(runId)}/tasks/${encodeURIComponent(task.id)}/control`,\n action,\n target: task,\n });\n const progress = taskWorkProgress(run);\n return (\n <div className=\"space-y-3 bg-muted/20 px-4 py-4\">\n <div className=\"flex flex-wrap gap-x-5 gap-y-1 text-xs text-muted-foreground\">\n <span>{progress.completed} completed</span>\n <span>{progress.running} running</span>\n <span>{progress.failed} failed</span>\n <span>{progress.counts.pending + progress.unstarted} waiting</span>\n {Object.entries(run.labels ?? {}).map(([key, value]) => (\n <span key={key} className=\"font-mono\">{key}={value}</span>\n ))}\n </div>\n <TaskProgress\n snapshots={snapshots}\n compact\n connectionStatus={status}\n initialShowAllTasks\n onControl={control}\n onTaskControl={controlTask}\n metricsBaseUrl={`${apiBase}/tasks/metrics/`}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n </div>\n );\n}\n\ninterface TaskControlRequest {\n url: string;\n action: TaskControlAction;\n target: TaskSnapshot;\n}\n\nasync function postTaskControl({ url, action, target }: TaskControlRequest) {\n const context = `Failed to ${action} ${target.type} \"${target.name}\"`;\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action }),\n });\n } catch (cause) {\n throw new Error(`${context}: ${cause instanceof Error ? cause.message : \"request failed\"}`, { cause });\n }\n if (!response.ok) {\n const detail = (await response.text()).trim() || `HTTP ${response.status}`;\n throw new Error(`${context}: ${detail}`);\n }\n}\n"],"names":["labels"],"mappings":"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"}
@@ -66,6 +66,7 @@ function TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, tr
66
66
  children: () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3", children: /* @__PURE__ */ jsxRuntime.jsx(
67
67
  TaskManager.TaskManager,
68
68
  {
69
+ compact: true,
69
70
  ...basePath ? { basePath } : {},
70
71
  ...kind ? { kind } : {},
71
72
  ...labels ? { labels } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManagerButton.cjs","sources":["../../src/data/TaskManagerButton.tsx"],"sourcesContent":["import { resourceSummary, taskTransportConnected, type ResourceSummary } from \"./task-resource-summary\";\nimport { useResourceClock } from \"../hooks/use-resource-clock\";\nimport { Button } from \"../components/button\";\nimport { UiActivity, UiListChecks, UiMemoryStick } from \"../icons\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { DropdownMenu, type DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { formatBytes } from \"../lib/format\";\nimport { TaskManager } from \"./TaskManager\";\nimport { taskStatusIcon } from \"./task-status\";\n\nexport interface TaskManagerButtonProps {\n basePath?: string;\n tasksHref?: string;\n latest?: number;\n onNavigate?: (href: string) => void;\n panel?: boolean;\n kind?: string;\n labels?: Record<string, string>;\n selectedId?: string;\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManagerButton({\n basePath,\n tasksHref = \"/tasks\",\n latest = 5,\n onNavigate,\n panel,\n kind,\n labels,\n selectedId,\n onSelectRun,\n}: TaskManagerButtonProps) {\n const { runs, status: runsStatus } = useTaskRuns({ basePath, kind, labels });\n const activeRuns = runs.filter((run) => run.status === \"running\" || run.status === \"pending\");\n const { snapshots, status: snapshotStatus } = useTaskRun({\n ...(basePath ? { basePath } : {}),\n ids: activeRuns.map((run) => run.id),\n enabled: activeRuns.length > 0,\n });\n const now = useResourceClock(activeRuns.length > 0);\n const resources = resourceSummary(snapshots, { now, connected: taskTransportConnected(runsStatus) && taskTransportConnected(snapshotStatus) });\n const trigger = <TaskTrigger active={activeRuns.length} {...(activeRuns.length ? { resources } : {})} />;\n\n return panel ? (\n <TaskPanelDropdown\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n trigger={trigger}\n />\n ) : (\n <RecentTasksDropdown\n latest={latest}\n {...(onNavigate ? { onNavigate } : {})}\n runs={runs}\n tasksHref={tasksHref}\n trigger={trigger}\n />\n );\n}\n\nfunction TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, trigger }: TaskManagerButtonProps & { trigger: React.ReactNode }) {\n return (\n <DropdownMenu\n align=\"right\"\n header={<span className=\"text-xs font-semibold\">Activity</span>}\n menuClassName=\"w-[min(42rem,calc(100vw-1rem))] max-w-none p-0\"\n menuLabel=\"Task activity\"\n trigger={trigger}\n >\n {() => (\n <div className=\"max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3\">\n <TaskManager\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n />\n </div>\n )}\n </DropdownMenu>\n );\n}\n\ntype TaskRuns = ReturnType<typeof useTaskRuns>[\"runs\"];\n\nfunction RecentTasksDropdown({\n latest,\n onNavigate,\n runs,\n tasksHref,\n trigger,\n}: {\n latest: number;\n onNavigate?: (href: string) => void;\n runs: TaskRuns;\n tasksHref: string;\n trigger: React.ReactNode;\n}) {\n const navigate = (href: string) => {\n if (onNavigate) onNavigate(href);\n else window.location.assign(href);\n };\n const items: DropdownMenuItem[] = runs.slice(0, latest).map((run) => ({\n label: (\n <span className=\"flex min-w-0 items-center justify-between gap-3\">\n <span className=\"truncate\">{run.name}</span>\n <span className=\"shrink-0 text-[10px] text-muted-foreground\">{run.status}</span>\n </span>\n ),\n icon: taskStatusIcon(run.status),\n onSelect: () => navigate(run.href ?? `${tasksHref}/${encodeURIComponent(run.id)}`),\n }));\n if (items.length === 0) {\n items.push({ label: \"No tasks yet\", disabled: true, onSelect: () => {} });\n }\n\n return (\n <DropdownMenu\n items={items}\n align=\"right\"\n menuLabel=\"Recent tasks\"\n trigger={trigger}\n footer={(\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"w-full justify-start\" onClick={() => navigate(tasksHref)}>\n View all tasks\n </Button>\n )}\n />\n );\n}\n\nfunction TaskTrigger({ active, resources }: { active: number; resources?: ResourceSummary }) {\n const label = `Tasks (${active} active)`;\n return (\n <Button type=\"button\" variant=\"ghost\" size={resources ? \"sm\" : \"icon\"} aria-label={label} title={label} className=\"relative gap-1.5\">\n <UiListChecks className={active > 0 ? \"animate-pulse\" : undefined} />\n {resources?.state === \"unavailable\" ? <span className=\"text-xs text-muted-foreground\">Resources unavailable</span> : resources ? (\n <span className=\"flex items-center gap-1.5 text-xs\" title={`Sampled ${new Date(resources.sampledAt).toLocaleTimeString()}; CPU 100% equals one core`}>\n <UiActivity /><span>{resources.cpu.toFixed(1)}%</span>\n <UiMemoryStick /><span>{formatBytes(resources.rss)}</span>\n {resources.state === \"stale\" && <span className=\"text-muted-foreground\">Stale</span>}\n </span>\n ) : null}\n </Button>\n );\n}\n"],"names":["useTaskRuns","useTaskRun","useResourceClock","resourceSummary","taskTransportConnected","jsx","DropdownMenu","TaskManager","jsxs","taskStatusIcon","Button","UiListChecks","UiActivity","UiMemoryStick","formatBytes"],"mappings":"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"}
1
+ {"version":3,"file":"TaskManagerButton.cjs","sources":["../../src/data/TaskManagerButton.tsx"],"sourcesContent":["import { resourceSummary, taskTransportConnected, type ResourceSummary } from \"./task-resource-summary\";\nimport { useResourceClock } from \"../hooks/use-resource-clock\";\nimport { Button } from \"../components/button\";\nimport { UiActivity, UiListChecks, UiMemoryStick } from \"../icons\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { DropdownMenu, type DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { formatBytes } from \"../lib/format\";\nimport { TaskManager } from \"./TaskManager\";\nimport { taskStatusIcon } from \"./task-status\";\n\nexport interface TaskManagerButtonProps {\n basePath?: string;\n tasksHref?: string;\n latest?: number;\n onNavigate?: (href: string) => void;\n panel?: boolean;\n kind?: string;\n labels?: Record<string, string>;\n selectedId?: string;\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManagerButton({\n basePath,\n tasksHref = \"/tasks\",\n latest = 5,\n onNavigate,\n panel,\n kind,\n labels,\n selectedId,\n onSelectRun,\n}: TaskManagerButtonProps) {\n const { runs, status: runsStatus } = useTaskRuns({ basePath, kind, labels });\n const activeRuns = runs.filter((run) => run.status === \"running\" || run.status === \"pending\");\n const { snapshots, status: snapshotStatus } = useTaskRun({\n ...(basePath ? { basePath } : {}),\n ids: activeRuns.map((run) => run.id),\n enabled: activeRuns.length > 0,\n });\n const now = useResourceClock(activeRuns.length > 0);\n const resources = resourceSummary(snapshots, { now, connected: taskTransportConnected(runsStatus) && taskTransportConnected(snapshotStatus) });\n const trigger = <TaskTrigger active={activeRuns.length} {...(activeRuns.length ? { resources } : {})} />;\n\n return panel ? (\n <TaskPanelDropdown\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n trigger={trigger}\n />\n ) : (\n <RecentTasksDropdown\n latest={latest}\n {...(onNavigate ? { onNavigate } : {})}\n runs={runs}\n tasksHref={tasksHref}\n trigger={trigger}\n />\n );\n}\n\nfunction TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, trigger }: TaskManagerButtonProps & { trigger: React.ReactNode }) {\n return (\n <DropdownMenu\n align=\"right\"\n header={<span className=\"text-xs font-semibold\">Activity</span>}\n menuClassName=\"w-[min(42rem,calc(100vw-1rem))] max-w-none p-0\"\n menuLabel=\"Task activity\"\n trigger={trigger}\n >\n {() => (\n <div className=\"max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3\">\n <TaskManager\n compact\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n />\n </div>\n )}\n </DropdownMenu>\n );\n}\n\ntype TaskRuns = ReturnType<typeof useTaskRuns>[\"runs\"];\n\nfunction RecentTasksDropdown({\n latest,\n onNavigate,\n runs,\n tasksHref,\n trigger,\n}: {\n latest: number;\n onNavigate?: (href: string) => void;\n runs: TaskRuns;\n tasksHref: string;\n trigger: React.ReactNode;\n}) {\n const navigate = (href: string) => {\n if (onNavigate) onNavigate(href);\n else window.location.assign(href);\n };\n const items: DropdownMenuItem[] = runs.slice(0, latest).map((run) => ({\n label: (\n <span className=\"flex min-w-0 items-center justify-between gap-3\">\n <span className=\"truncate\">{run.name}</span>\n <span className=\"shrink-0 text-[10px] text-muted-foreground\">{run.status}</span>\n </span>\n ),\n icon: taskStatusIcon(run.status),\n onSelect: () => navigate(run.href ?? `${tasksHref}/${encodeURIComponent(run.id)}`),\n }));\n if (items.length === 0) {\n items.push({ label: \"No tasks yet\", disabled: true, onSelect: () => {} });\n }\n\n return (\n <DropdownMenu\n items={items}\n align=\"right\"\n menuLabel=\"Recent tasks\"\n trigger={trigger}\n footer={(\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"w-full justify-start\" onClick={() => navigate(tasksHref)}>\n View all tasks\n </Button>\n )}\n />\n );\n}\n\nfunction TaskTrigger({ active, resources }: { active: number; resources?: ResourceSummary }) {\n const label = `Tasks (${active} active)`;\n return (\n <Button type=\"button\" variant=\"ghost\" size={resources ? \"sm\" : \"icon\"} aria-label={label} title={label} className=\"relative gap-1.5\">\n <UiListChecks className={active > 0 ? \"animate-pulse\" : undefined} />\n {resources?.state === \"unavailable\" ? <span className=\"text-xs text-muted-foreground\">Resources unavailable</span> : resources ? (\n <span className=\"flex items-center gap-1.5 text-xs\" title={`Sampled ${new Date(resources.sampledAt).toLocaleTimeString()}; CPU 100% equals one core`}>\n <UiActivity /><span>{resources.cpu.toFixed(1)}%</span>\n <UiMemoryStick /><span>{formatBytes(resources.rss)}</span>\n {resources.state === \"stale\" && <span className=\"text-muted-foreground\">Stale</span>}\n </span>\n ) : null}\n </Button>\n );\n}\n"],"names":["useTaskRuns","useTaskRun","useResourceClock","resourceSummary","taskTransportConnected","jsx","DropdownMenu","TaskManager","jsxs","taskStatusIcon","Button","UiListChecks","UiActivity","UiMemoryStick","formatBytes"],"mappings":"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"}
@@ -64,6 +64,7 @@ function TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, tr
64
64
  children: () => /* @__PURE__ */ jsx("div", { className: "max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3", children: /* @__PURE__ */ jsx(
65
65
  TaskManager,
66
66
  {
67
+ compact: true,
67
68
  ...basePath ? { basePath } : {},
68
69
  ...kind ? { kind } : {},
69
70
  ...labels ? { labels } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManagerButton.js","sources":["../../src/data/TaskManagerButton.tsx"],"sourcesContent":["import { resourceSummary, taskTransportConnected, type ResourceSummary } from \"./task-resource-summary\";\nimport { useResourceClock } from \"../hooks/use-resource-clock\";\nimport { Button } from \"../components/button\";\nimport { UiActivity, UiListChecks, UiMemoryStick } from \"../icons\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { DropdownMenu, type DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { formatBytes } from \"../lib/format\";\nimport { TaskManager } from \"./TaskManager\";\nimport { taskStatusIcon } from \"./task-status\";\n\nexport interface TaskManagerButtonProps {\n basePath?: string;\n tasksHref?: string;\n latest?: number;\n onNavigate?: (href: string) => void;\n panel?: boolean;\n kind?: string;\n labels?: Record<string, string>;\n selectedId?: string;\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManagerButton({\n basePath,\n tasksHref = \"/tasks\",\n latest = 5,\n onNavigate,\n panel,\n kind,\n labels,\n selectedId,\n onSelectRun,\n}: TaskManagerButtonProps) {\n const { runs, status: runsStatus } = useTaskRuns({ basePath, kind, labels });\n const activeRuns = runs.filter((run) => run.status === \"running\" || run.status === \"pending\");\n const { snapshots, status: snapshotStatus } = useTaskRun({\n ...(basePath ? { basePath } : {}),\n ids: activeRuns.map((run) => run.id),\n enabled: activeRuns.length > 0,\n });\n const now = useResourceClock(activeRuns.length > 0);\n const resources = resourceSummary(snapshots, { now, connected: taskTransportConnected(runsStatus) && taskTransportConnected(snapshotStatus) });\n const trigger = <TaskTrigger active={activeRuns.length} {...(activeRuns.length ? { resources } : {})} />;\n\n return panel ? (\n <TaskPanelDropdown\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n trigger={trigger}\n />\n ) : (\n <RecentTasksDropdown\n latest={latest}\n {...(onNavigate ? { onNavigate } : {})}\n runs={runs}\n tasksHref={tasksHref}\n trigger={trigger}\n />\n );\n}\n\nfunction TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, trigger }: TaskManagerButtonProps & { trigger: React.ReactNode }) {\n return (\n <DropdownMenu\n align=\"right\"\n header={<span className=\"text-xs font-semibold\">Activity</span>}\n menuClassName=\"w-[min(42rem,calc(100vw-1rem))] max-w-none p-0\"\n menuLabel=\"Task activity\"\n trigger={trigger}\n >\n {() => (\n <div className=\"max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3\">\n <TaskManager\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n />\n </div>\n )}\n </DropdownMenu>\n );\n}\n\ntype TaskRuns = ReturnType<typeof useTaskRuns>[\"runs\"];\n\nfunction RecentTasksDropdown({\n latest,\n onNavigate,\n runs,\n tasksHref,\n trigger,\n}: {\n latest: number;\n onNavigate?: (href: string) => void;\n runs: TaskRuns;\n tasksHref: string;\n trigger: React.ReactNode;\n}) {\n const navigate = (href: string) => {\n if (onNavigate) onNavigate(href);\n else window.location.assign(href);\n };\n const items: DropdownMenuItem[] = runs.slice(0, latest).map((run) => ({\n label: (\n <span className=\"flex min-w-0 items-center justify-between gap-3\">\n <span className=\"truncate\">{run.name}</span>\n <span className=\"shrink-0 text-[10px] text-muted-foreground\">{run.status}</span>\n </span>\n ),\n icon: taskStatusIcon(run.status),\n onSelect: () => navigate(run.href ?? `${tasksHref}/${encodeURIComponent(run.id)}`),\n }));\n if (items.length === 0) {\n items.push({ label: \"No tasks yet\", disabled: true, onSelect: () => {} });\n }\n\n return (\n <DropdownMenu\n items={items}\n align=\"right\"\n menuLabel=\"Recent tasks\"\n trigger={trigger}\n footer={(\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"w-full justify-start\" onClick={() => navigate(tasksHref)}>\n View all tasks\n </Button>\n )}\n />\n );\n}\n\nfunction TaskTrigger({ active, resources }: { active: number; resources?: ResourceSummary }) {\n const label = `Tasks (${active} active)`;\n return (\n <Button type=\"button\" variant=\"ghost\" size={resources ? \"sm\" : \"icon\"} aria-label={label} title={label} className=\"relative gap-1.5\">\n <UiListChecks className={active > 0 ? \"animate-pulse\" : undefined} />\n {resources?.state === \"unavailable\" ? <span className=\"text-xs text-muted-foreground\">Resources unavailable</span> : resources ? (\n <span className=\"flex items-center gap-1.5 text-xs\" title={`Sampled ${new Date(resources.sampledAt).toLocaleTimeString()}; CPU 100% equals one core`}>\n <UiActivity /><span>{resources.cpu.toFixed(1)}%</span>\n <UiMemoryStick /><span>{formatBytes(resources.rss)}</span>\n {resources.state === \"stale\" && <span className=\"text-muted-foreground\">Stale</span>}\n </span>\n ) : null}\n </Button>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskManagerButton.js","sources":["../../src/data/TaskManagerButton.tsx"],"sourcesContent":["import { resourceSummary, taskTransportConnected, type ResourceSummary } from \"./task-resource-summary\";\nimport { useResourceClock } from \"../hooks/use-resource-clock\";\nimport { Button } from \"../components/button\";\nimport { UiActivity, UiListChecks, UiMemoryStick } from \"../icons\";\nimport { useTaskRun, useTaskRuns } from \"../hooks/use-task-run\";\nimport { DropdownMenu, type DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { formatBytes } from \"../lib/format\";\nimport { TaskManager } from \"./TaskManager\";\nimport { taskStatusIcon } from \"./task-status\";\n\nexport interface TaskManagerButtonProps {\n basePath?: string;\n tasksHref?: string;\n latest?: number;\n onNavigate?: (href: string) => void;\n panel?: boolean;\n kind?: string;\n labels?: Record<string, string>;\n selectedId?: string;\n onSelectRun?: (id: string | null) => void;\n}\n\nexport function TaskManagerButton({\n basePath,\n tasksHref = \"/tasks\",\n latest = 5,\n onNavigate,\n panel,\n kind,\n labels,\n selectedId,\n onSelectRun,\n}: TaskManagerButtonProps) {\n const { runs, status: runsStatus } = useTaskRuns({ basePath, kind, labels });\n const activeRuns = runs.filter((run) => run.status === \"running\" || run.status === \"pending\");\n const { snapshots, status: snapshotStatus } = useTaskRun({\n ...(basePath ? { basePath } : {}),\n ids: activeRuns.map((run) => run.id),\n enabled: activeRuns.length > 0,\n });\n const now = useResourceClock(activeRuns.length > 0);\n const resources = resourceSummary(snapshots, { now, connected: taskTransportConnected(runsStatus) && taskTransportConnected(snapshotStatus) });\n const trigger = <TaskTrigger active={activeRuns.length} {...(activeRuns.length ? { resources } : {})} />;\n\n return panel ? (\n <TaskPanelDropdown\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n trigger={trigger}\n />\n ) : (\n <RecentTasksDropdown\n latest={latest}\n {...(onNavigate ? { onNavigate } : {})}\n runs={runs}\n tasksHref={tasksHref}\n trigger={trigger}\n />\n );\n}\n\nfunction TaskPanelDropdown({ basePath, kind, labels, onSelectRun, selectedId, trigger }: TaskManagerButtonProps & { trigger: React.ReactNode }) {\n return (\n <DropdownMenu\n align=\"right\"\n header={<span className=\"text-xs font-semibold\">Activity</span>}\n menuClassName=\"w-[min(42rem,calc(100vw-1rem))] max-w-none p-0\"\n menuLabel=\"Task activity\"\n trigger={trigger}\n >\n {() => (\n <div className=\"max-h-[min(42rem,calc(100vh-5rem))] overflow-auto p-3\">\n <TaskManager\n compact\n {...(basePath ? { basePath } : {})}\n {...(kind ? { kind } : {})}\n {...(labels ? { labels } : {})}\n {...(onSelectRun ? { onSelectRun } : {})}\n {...(selectedId ? { selectedId } : {})}\n />\n </div>\n )}\n </DropdownMenu>\n );\n}\n\ntype TaskRuns = ReturnType<typeof useTaskRuns>[\"runs\"];\n\nfunction RecentTasksDropdown({\n latest,\n onNavigate,\n runs,\n tasksHref,\n trigger,\n}: {\n latest: number;\n onNavigate?: (href: string) => void;\n runs: TaskRuns;\n tasksHref: string;\n trigger: React.ReactNode;\n}) {\n const navigate = (href: string) => {\n if (onNavigate) onNavigate(href);\n else window.location.assign(href);\n };\n const items: DropdownMenuItem[] = runs.slice(0, latest).map((run) => ({\n label: (\n <span className=\"flex min-w-0 items-center justify-between gap-3\">\n <span className=\"truncate\">{run.name}</span>\n <span className=\"shrink-0 text-[10px] text-muted-foreground\">{run.status}</span>\n </span>\n ),\n icon: taskStatusIcon(run.status),\n onSelect: () => navigate(run.href ?? `${tasksHref}/${encodeURIComponent(run.id)}`),\n }));\n if (items.length === 0) {\n items.push({ label: \"No tasks yet\", disabled: true, onSelect: () => {} });\n }\n\n return (\n <DropdownMenu\n items={items}\n align=\"right\"\n menuLabel=\"Recent tasks\"\n trigger={trigger}\n footer={(\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" className=\"w-full justify-start\" onClick={() => navigate(tasksHref)}>\n View all tasks\n </Button>\n )}\n />\n );\n}\n\nfunction TaskTrigger({ active, resources }: { active: number; resources?: ResourceSummary }) {\n const label = `Tasks (${active} active)`;\n return (\n <Button type=\"button\" variant=\"ghost\" size={resources ? \"sm\" : \"icon\"} aria-label={label} title={label} className=\"relative gap-1.5\">\n <UiListChecks className={active > 0 ? \"animate-pulse\" : undefined} />\n {resources?.state === \"unavailable\" ? <span className=\"text-xs text-muted-foreground\">Resources unavailable</span> : resources ? (\n <span className=\"flex items-center gap-1.5 text-xs\" title={`Sampled ${new Date(resources.sampledAt).toLocaleTimeString()}; CPU 100% equals one core`}>\n <UiActivity /><span>{resources.cpu.toFixed(1)}%</span>\n <UiMemoryStick /><span>{formatBytes(resources.rss)}</span>\n {resources.state === \"stale\" && <span className=\"text-muted-foreground\">Stale</span>}\n </span>\n ) : null}\n </Button>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAsBO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA,YAAY;AAAA,EACZ,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,EAAE,MAAM,QAAQ,WAAA,IAAe,YAAY,EAAE,UAAU,MAAM,QAAQ;AAC3E,QAAM,aAAa,KAAK,OAAO,CAAC,QAAQ,IAAI,WAAW,aAAa,IAAI,WAAW,SAAS;AAC5F,QAAM,EAAE,WAAW,QAAQ,eAAA,IAAmB,WAAW;AAAA,IACvD,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,IAC9B,KAAK,WAAW,IAAI,CAAC,QAAQ,IAAI,EAAE;AAAA,IACnC,SAAS,WAAW,SAAS;AAAA,EAAA,CAC9B;AACD,QAAM,MAAM,iBAAiB,WAAW,SAAS,CAAC;AAClD,QAAM,YAAY,gBAAgB,WAAW,EAAE,KAAK,WAAW,uBAAuB,UAAU,KAAK,uBAAuB,cAAc,EAAA,CAAG;AAC7I,QAAM,UAAU,oBAAC,aAAA,EAAY,QAAQ,WAAW,QAAS,GAAI,WAAW,SAAS,EAAE,UAAA,IAAc,CAAA,EAAC,CAAI;AAEtG,SAAO,QACL;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,MAC9B,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA;AAAA,MACtB,GAAI,SAAS,EAAE,OAAA,IAAW,CAAA;AAAA,MAC1B,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,MACpC,GAAI,aAAa,EAAE,WAAA,IAAe,CAAA;AAAA,MACnC;AAAA,IAAA;AAAA,EAAA,IAGF;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACC,GAAI,aAAa,EAAE,WAAA,IAAe,CAAA;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAAA;AAGN;AAEA,SAAS,kBAAkB,EAAE,UAAU,MAAM,QAAQ,aAAa,YAAY,WAAkE;AAC9I,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAQ,oBAAC,QAAA,EAAK,WAAU,yBAAwB,UAAA,YAAQ;AAAA,MACxD,eAAc;AAAA,MACd,WAAU;AAAA,MACV;AAAA,MAEC,UAAA,MACC,oBAAC,OAAA,EAAI,WAAU,yDACb,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAO;AAAA,UACN,GAAI,WAAW,EAAE,SAAA,IAAa,CAAA;AAAA,UAC9B,GAAI,OAAO,EAAE,KAAA,IAAS,CAAA;AAAA,UACtB,GAAI,SAAS,EAAE,OAAA,IAAW,CAAA;AAAA,UAC1B,GAAI,cAAc,EAAE,YAAA,IAAgB,CAAA;AAAA,UACpC,GAAI,aAAa,EAAE,eAAe,CAAA;AAAA,QAAC;AAAA,MAAA,EACtC,CACF;AAAA,IAAA;AAAA,EAAA;AAIR;AAIA,SAAS,oBAAoB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,WAAW,CAAC,SAAiB;AACjC,QAAI,uBAAuB,IAAI;AAAA,QAC1B,QAAO,SAAS,OAAO,IAAI;AAAA,EAClC;AACA,QAAM,QAA4B,KAAK,MAAM,GAAG,MAAM,EAAE,IAAI,CAAC,SAAS;AAAA,IACpE,OACE,qBAAC,QAAA,EAAK,WAAU,mDACd,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAU,YAAY,UAAA,IAAI,MAAK;AAAA,MACrC,oBAAC,QAAA,EAAK,WAAU,8CAA8C,cAAI,OAAA,CAAO;AAAA,IAAA,GAC3E;AAAA,IAEF,MAAM,eAAe,IAAI,MAAM;AAAA,IAC/B,UAAU,MAAM,SAAS,IAAI,QAAQ,GAAG,SAAS,IAAI,mBAAmB,IAAI,EAAE,CAAC,EAAE;AAAA,EAAA,EACjF;AACF,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,EAAE,OAAO,gBAAgB,UAAU,MAAM,UAAU,MAAM;AAAA,IAAC,GAAG;AAAA,EAC1E;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,OAAM;AAAA,MACN,WAAU;AAAA,MACV;AAAA,MACA,QACE,oBAAC,QAAA,EAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,MAAK,WAAU,wBAAuB,SAAS,MAAM,SAAS,SAAS,GAAG,UAAA,iBAAA,CAErH;AAAA,IAAA;AAAA,EAAA;AAIR;AAEA,SAAS,YAAY,EAAE,QAAQ,aAA8D;AAC3F,QAAM,QAAQ,UAAU,MAAM;AAC9B,SACE,qBAAC,QAAA,EAAO,MAAK,UAAS,SAAQ,SAAQ,MAAM,YAAY,OAAO,QAAQ,cAAY,OAAO,OAAO,OAAO,WAAU,oBAChH,UAAA;AAAA,IAAA,oBAAC,cAAA,EAAa,WAAW,SAAS,IAAI,kBAAkB,QAAW;AAAA,KAClE,uCAAW,WAAU,gBAAgB,oBAAC,UAAK,WAAU,iCAAgC,UAAA,wBAAA,CAAqB,IAAU,YACnH,qBAAC,UAAK,WAAU,qCAAoC,OAAO,WAAW,IAAI,KAAK,UAAU,SAAS,EAAE,mBAAA,CAAoB,8BACtH,UAAA;AAAA,MAAA,oBAAC,YAAA,EAAW;AAAA,2BAAG,QAAA,EAAM,UAAA;AAAA,QAAA,UAAU,IAAI,QAAQ,CAAC;AAAA,QAAE;AAAA,MAAA,GAAC;AAAA,0BAC9C,eAAA,EAAc;AAAA,MAAE,oBAAC,QAAA,EAAM,UAAA,YAAY,UAAU,GAAG,GAAE;AAAA,MAClD,UAAU,UAAU,+BAAY,QAAA,EAAK,WAAU,yBAAwB,UAAA,QAAA,CAAK;AAAA,IAAA,EAAA,CAC/E,IACE;AAAA,EAAA,GACN;AAEJ;"}
@@ -32,6 +32,7 @@ function TaskProgress({
32
32
  snapshots,
33
33
  title,
34
34
  compact,
35
+ initialShowAllTasks,
35
36
  className,
36
37
  onControl,
37
38
  onTaskControl,
@@ -56,6 +57,7 @@ function TaskProgress({
56
57
  group: g,
57
58
  tasks: tasks.filter((t) => g.groupId ? t.groupId === g.groupId : t.group === g.id),
58
59
  compact,
60
+ initialShowAllTasks,
59
61
  ...onControl ? { onControl } : {},
60
62
  ...onTaskControl ? { onTaskControl } : {},
61
63
  ...metricsBaseUrl ? { metricsBaseUrl } : {},
@@ -71,6 +73,7 @@ function TaskGroupCard({
71
73
  group: g,
72
74
  tasks,
73
75
  compact,
76
+ initialShowAllTasks,
74
77
  onControl,
75
78
  onTaskControl,
76
79
  metricsBaseUrl,
@@ -78,7 +81,7 @@ function TaskGroupCard({
78
81
  extraTabs,
79
82
  headerExtra
80
83
  }) {
81
- const [showAll, setShowAll] = react.useState(false);
84
+ const [showAll, setShowAll] = react.useState(initialShowAllTasks ?? false);
82
85
  const { state: copyState, copy } = clipboard.useCopyFlash();
83
86
  const work = taskWorkProgress.taskWorkProgress(g);
84
87
  const total = g.work ? work.total : g.total ?? tasks.length;
@@ -110,8 +113,8 @@ function TaskGroupCard({
110
113
  onSelect: () => copy(taskCopy.taskGroupErrors(g, tasks))
111
114
  }
112
115
  ];
113
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("rounded-lg border bg-card", compact ? "p-3" : "p-4"), children: [
114
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
116
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("rounded-lg border bg-card", compact ? "p-2" : "p-4"), children: [
117
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex items-center justify-between gap-3", compact ? "mb-2" : "mb-3"), children: [
115
118
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "flex min-w-0 items-center gap-1.5 text-sm font-semibold", children: [
116
119
  /* @__PURE__ */ jsxRuntime.jsx(
117
120
  Icon.Icon,
@@ -155,7 +158,7 @@ function TaskGroupCard({
155
158
  onControl && /* @__PURE__ */ jsxRuntime.jsx(TaskControls, { target: g, onControl })
156
159
  ] })
157
160
  ] }),
158
- total > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsxRuntime.jsx(ProgressBar.ProgressBar, { segments: taskStatus.taskSegments(counts), total, height: "h-1.5" }) }),
161
+ total > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: compact ? "mb-2" : "mb-3", children: /* @__PURE__ */ jsxRuntime.jsx(ProgressBar.ProgressBar, { segments: taskStatus.taskSegments(counts), total, height: "h-1.5" }) }),
159
162
  taskProcessDetails.isTaskProcessDetails(g.details) && /* @__PURE__ */ jsxRuntime.jsx(
160
163
  TaskProcessDetails.TaskProcessDetailsView,
161
164
  {
@@ -169,7 +172,7 @@ function TaskGroupCard({
169
172
  "button",
170
173
  {
171
174
  type: "button",
172
- className: "border-b py-1.5 text-xs text-muted-foreground hover:text-foreground",
175
+ className: utils.cn("border-b text-xs text-muted-foreground hover:text-foreground", compact ? "py-1" : "py-1.5"),
173
176
  onClick: () => setShowAll((v) => !v),
174
177
  children: showAll ? "▲ collapse" : `... ${(collapseCompleted ? hiddenCompleted : 0) + (collapsePending ? hiddenPending : 0)} more tasks`
175
178
  }
@@ -179,6 +182,7 @@ function TaskGroupCard({
179
182
  {
180
183
  task: t,
181
184
  group: g,
185
+ compact,
182
186
  ...onTaskControl ? { onTaskControl } : {},
183
187
  ...metricsBaseUrl ? { metricsBaseUrl } : {},
184
188
  ...connectionStatus ? { connectionStatus } : {},
@@ -192,6 +196,7 @@ function TaskGroupCard({
192
196
  function TaskRow({
193
197
  task: t,
194
198
  group,
199
+ compact,
195
200
  onTaskControl,
196
201
  metricsBaseUrl,
197
202
  connectionStatus,
@@ -215,7 +220,8 @@ function TaskRow({
215
220
  "div",
216
221
  {
217
222
  className: utils.cn(
218
- "group flex items-start gap-3 border-b py-2 last:border-0",
223
+ "group flex items-start border-b last:border-0",
224
+ compact ? "gap-2 py-1" : "gap-3 py-2",
219
225
  expandable && "-mx-1 cursor-pointer rounded px-1 hover:bg-muted/50"
220
226
  ),
221
227
  onClick: expandable ? () => setExpanded((v) => !v) : void 0,
@@ -224,7 +230,7 @@ function TaskRow({
224
230
  Icon.Icon,
225
231
  {
226
232
  icon: taskStatus.taskStatusIcon(t.status),
227
- className: utils.cn(taskStatus.taskStatusColor(t.status), "mt-0.5 text-lg", t.status === "running" && "animate-spin")
233
+ className: utils.cn(taskStatus.taskStatusColor(t.status), "mt-0.5", compact ? "text-base" : "text-lg", t.status === "running" && "animate-spin")
228
234
  }
229
235
  ),
230
236
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
@@ -1 +1 @@
1
- {"version":3,"file":"TaskProgress.cjs","sources":["../../src/data/TaskProgress.tsx"],"sourcesContent":["import { taskWorkProgress } from \"./task-work-progress\";\nimport { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { CopyButton } from \"../components/CopyButton\";\nimport { SplitButton } from \"../components/SplitButton\";\nimport { useCopyFlash } from \"../components/clipboard\";\nimport { UiCheck, UiCopy, UiJson, UiPlay, UiRefresh, UiRestart, UiStop, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport type { DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { Icon } from \"./Icon\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { TaskProcessDetailsView } from \"./TaskProcessDetails\";\nimport { TaskExecDetailsView } from \"./TaskExecDetails\";\nimport type { LogEntry, TaskControlAction, TaskSnapshot } from \"./TaskSnapshot\";\nimport { type TaskHeaderExtra, TaskMetadataChips } from \"./TaskHeaderExtras\";\nimport { type TaskExtraTabs, TaskStreamTabs } from \"./TaskStreamTabs\";\nimport {\n isFailedOrWarn,\n taskGroupErrorCount,\n taskGroupErrors,\n taskGroupJson,\n taskGroupMarkdown,\n taskMarkdown,\n} from \"./task-copy\";\nimport { isTaskExecDetails } from \"./task-exec-details\";\nimport { isTaskProcessDetails } from \"./task-process-details\";\nimport {\n bucketTasks,\n logLevelColor,\n taskSegments,\n taskStatusBg,\n taskStatusColor,\n taskStatusIcon,\n} from \"./task-status\";\n\n// TaskProgress renders one or more clicky task runs (groups) and their child\n// tasks: a segmented progress bar per group plus collapsible per-task rows with\n// status icon, duration, error, and expandable logs. Presentational only —\n// callers feed it snapshots from useTaskRun (SSE) or any other source.\n\nconst MAX_COMPLETED = 5;\nconst MAX_PENDING = 3;\n\nexport interface TaskProgressProps {\n snapshots: TaskSnapshot[];\n title?: string;\n /** Tighter spacing for embedding in a panel. */\n compact?: boolean;\n className?: string;\n onControl?: (action: TaskControlAction, group: TaskSnapshot) => void | Promise<void>;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n /**\n * Contributes host-owned output panes alongside a task's own stdout/stderr —\n * an agent's session transcript, say, which this module has no way to fetch.\n */\n extraTabs?: TaskExtraTabs;\n /**\n * Replaces the content beside a task's name in its header row. Returning null\n * for a task falls back to the default, which chips the scalar values of its\n * process metadata.\n */\n headerExtra?: TaskHeaderExtra;\n}\n\nexport function TaskProgress({\n snapshots,\n title,\n compact,\n className,\n onControl,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs,\n headerExtra,\n}: TaskProgressProps) {\n const groups = snapshots.filter((s) => s.type === \"group\");\n const tasks = snapshots.filter((s) => s.type === \"task\");\n\n if (groups.length === 0) {\n return (\n <div className={cn(\"text-sm text-muted-foreground\", className)}>\n {title ? `${title}: ` : \"\"}No tasks yet.\n </div>\n );\n }\n\n return (\n <div className={cn(compact ? \"space-y-2\" : \"space-y-3\", className)}>\n {title && <h2 className=\"text-sm font-semibold\">{title}</h2>}\n {groups.map((g) => (\n <TaskGroupCard\n key={g.groupId || g.id}\n group={g}\n tasks={tasks.filter((t) => g.groupId ? t.groupId === g.groupId : t.group === g.id)}\n compact={compact}\n {...(onControl ? { onControl } : {})}\n {...(onTaskControl ? { onTaskControl } : {})}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n ))}\n </div>\n );\n}\n\nfunction TaskGroupCard({\n group: g,\n tasks,\n compact,\n onControl,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs,\n headerExtra,\n}: {\n group: TaskSnapshot;\n tasks: TaskSnapshot[];\n compact: boolean | undefined;\n extraTabs?: TaskExtraTabs;\n headerExtra?: TaskHeaderExtra;\n onControl?: (action: TaskControlAction, group: TaskSnapshot) => void | Promise<void>;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n}) {\n const [showAll, setShowAll] = useState(false);\n const { state: copyState, copy } = useCopyFlash();\n const work = taskWorkProgress(g);\n const total = g.work ? work.total : g.total ?? tasks.length;\n const counts = g.work ? work.counts : bucketTasks(tasks);\n const done = counts.ok + counts.warn + counts.fail + counts.canceled;\n const progress = g.work ? work.label : total > 0 ? `${done}/${total}` : \"\";\n\n const running = tasks.filter((t) => t.status === \"running\");\n const pending = tasks.filter((t) => t.status === \"pending\");\n const completed = tasks.filter((t) => t.status !== \"running\" && t.status !== \"pending\");\n const alwaysShow = completed.filter(isFailedOrWarn);\n const collapsible = completed.filter((t) => !isFailedOrWarn(t));\n\n const hiddenCompleted = collapsible.length - MAX_COMPLETED;\n const collapseCompleted = !showAll && hiddenCompleted > 0;\n const visibleSuccess = collapseCompleted ? collapsible.slice(-MAX_COMPLETED) : collapsible;\n\n const hiddenPending = pending.length - MAX_PENDING;\n const collapsePending = !showAll && hiddenPending > 0;\n const visiblePending = collapsePending ? pending.slice(0, MAX_PENDING) : pending;\n\n const isTerminal = g.status !== \"running\" && g.status !== \"pending\";\n\n const copyItems: DropdownMenuItem[] = [\n {\n label: \"Copy as JSON\",\n icon: UiJson,\n onSelect: () => copy(taskGroupJson(g, tasks)),\n },\n {\n label: \"Copy errors only\",\n icon: UiWarningTriangle,\n disabled: taskGroupErrorCount(tasks) === 0,\n onSelect: () => copy(taskGroupErrors(g, tasks)),\n },\n ];\n\n return (\n <div className={cn(\"rounded-lg border bg-card\", compact ? \"p-3\" : \"p-4\")}>\n <div className=\"mb-3 flex items-center justify-between gap-3\">\n <h3 className=\"flex min-w-0 items-center gap-1.5 text-sm font-semibold\">\n <Icon\n icon={taskStatusIcon(g.status)}\n className={cn(\n \"shrink-0\",\n taskStatusColor(g.status),\n g.status === \"running\" && \"animate-spin\",\n )}\n />\n <span className=\"truncate\">{g.name}</span>\n {progress && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{progress}</span>\n )}\n {g.kind && (\n <span className=\"shrink-0 rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground\">\n {g.kind}\n </span>\n )}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n {isTerminal && (\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs\",\n taskStatusColor(g.status),\n taskStatusBg(g.status),\n )}\n >\n {g.status}\n </span>\n )}\n <SplitButton\n label={copyState === \"copied\" ? \"Copied\" : copyState === \"error\" ? \"Copy failed\" : \"Copy\"}\n icon={copyState === \"copied\" ? UiCheck : UiCopy}\n variant=\"ghost\"\n size=\"sm\"\n title=\"More copy options\"\n onClick={() => copy(taskGroupMarkdown(g, tasks))}\n items={copyItems}\n />\n {onControl && <TaskControls target={g} onControl={onControl} />}\n </div>\n </div>\n\n {total > 0 && (\n <div className=\"mb-3\">\n <ProgressBar segments={taskSegments(counts)} total={total} height=\"h-1.5\" />\n </div>\n )}\n\n {isTaskProcessDetails(g.details) && (\n <TaskProcessDetailsView\n details={g.details}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n />\n )}\n\n {!isTaskProcessDetails(g.details) && isTaskExecDetails(g.details) && (\n <TaskExecDetailsView details={g.details} />\n )}\n\n {hiddenCompleted > 0 || hiddenPending > 0 ? (\n <button\n type=\"button\"\n className=\"border-b py-1.5 text-xs text-muted-foreground hover:text-foreground\"\n onClick={() => setShowAll((v) => !v)}\n >\n {showAll\n ? \"▲ collapse\"\n : `... ${(collapseCompleted ? hiddenCompleted : 0) + (collapsePending ? hiddenPending : 0)} more tasks`}\n </button>\n ) : null}\n\n {[...visibleSuccess, ...alwaysShow, ...running, ...visiblePending].map((t) => (\n <TaskRow\n key={t.id}\n task={t}\n group={g}\n {...(onTaskControl ? { onTaskControl } : {})}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n ))}\n </div>\n );\n}\n\nfunction TaskRow({\n task: t,\n group,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs: contributeTabs,\n headerExtra,\n}: {\n task: TaskSnapshot;\n group: TaskSnapshot;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n extraTabs?: TaskExtraTabs;\n headerExtra?: TaskHeaderExtra;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n}) {\n const [expanded, setExpanded] = useState(false);\n const logs: LogEntry[] = t.logs ?? [];\n const hasLogs = logs.length > 0;\n const extraTabs = contributeTabs?.(t, group) ?? [];\n // A host that has nothing to add for this task returns null, and the default\n // metadata chips take over — so enriching one kind of task never costs the\n // rest their header.\n const header = headerExtra?.(t, group) ?? <TaskMetadataChips task={t} />;\n const hasOutput = !!t.stdout || !!t.stderr || extraTabs.length > 0;\n const execDetails = isTaskExecDetails(t.details) ? t.details : undefined;\n const processDetails = isTaskProcessDetails(t.details) ? t.details : undefined;\n const expandable = hasLogs || hasOutput || execDetails !== undefined || processDetails !== undefined;\n // Promote the latest warning message inline so a `warning` row shows its\n // reason without expanding. Suppressed when an error is already shown.\n const latestWarn = t.error ? undefined : logs.filter((l) => l.level === \"warn\").at(-1);\n // Bounded per-task progress (e.g. records emitted in a phase): render an x/y\n // count, a percentage, and a thin bar while the task runs.\n const done = t.progress ?? 0;\n // Only surface bounded progress once work has actually started — an untouched\n // task should not render a \"0/100 · 0%\" placeholder.\n const hasProgress = typeof t.maxValue === \"number\" && t.maxValue > 0 && done > 0;\n const pct = hasProgress ? Math.round((done / (t.maxValue as number)) * 100) : 0;\n\n return (\n <div\n className={cn(\n \"group flex items-start gap-3 border-b py-2 last:border-0\",\n expandable && \"-mx-1 cursor-pointer rounded px-1 hover:bg-muted/50\",\n )}\n onClick={expandable ? () => setExpanded((v) => !v) : undefined}\n >\n <Icon\n icon={taskStatusIcon(t.status)}\n className={cn(taskStatusColor(t.status), \"mt-0.5 text-lg\", t.status === \"running\" && \"animate-spin\")}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex min-w-0 items-center gap-1.5 text-sm font-medium\">\n <span className=\"truncate\">{t.name}</span>\n {t.error && <span className=\"truncate text-xs font-normal text-red-500\">{t.error}</span>}\n {latestWarn && (\n <span className={cn(\"truncate text-xs font-normal\", logLevelColor(\"warn\"))}>\n {latestWarn.message}\n </span>\n )}\n {expandable && (\n <span className=\"inline-flex shrink-0 items-center rounded-full bg-muted px-1.5 text-[10px] font-medium text-muted-foreground\">\n {logs.length + (t.stdout ? 1 : 0) + (t.stderr ? 1 : 0) + (execDetails || processDetails ? 1 : 0)}\n </span>\n )}\n </span>\n {header}\n <div className=\"flex shrink-0 items-center gap-1\">\n {t.duration && <span className=\"text-xs text-muted-foreground\">{t.duration}</span>}\n <CopyButton\n value={() => taskMarkdown(t)}\n label={`Copy ${t.name}`}\n className=\"opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100\"\n iconClassName=\"text-xs\"\n />\n {onTaskControl && (\n <TaskControls\n target={t}\n labelSuffix={t.name}\n stopPropagation\n onControl={(action) => onTaskControl(action, t, group)}\n />\n )}\n </div>\n </div>\n {(t.description || hasProgress) && (\n <div className=\"mt-0.5 flex items-center gap-2\">\n {t.description && (\n <span className=\"min-w-0 flex-1 truncate text-xs text-muted-foreground\">{t.description}</span>\n )}\n {hasProgress && (\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {done}/{t.maxValue} · {pct}%\n </span>\n )}\n </div>\n )}\n {hasProgress && t.status === \"running\" && (\n <div className=\"mt-1\">\n <ProgressBar\n segments={[{ count: done, color: \"bg-blue-500\", label: \"done\" }]}\n total={t.maxValue as number}\n height=\"h-1\"\n />\n </div>\n )}\n {expanded && execDetails && <TaskExecDetailsView details={execDetails} />}\n {expanded && processDetails && (\n <TaskProcessDetailsView\n details={processDetails}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n />\n )}\n {expanded && hasLogs && (\n <div className=\"mt-1 ml-1 max-h-48 space-y-0.5 overflow-y-auto border-l-2 pl-2\">\n {logs.map((l, i) => (\n <div key={i} className={cn(\"text-xs\", logLevelColor(l.level))}>\n <span className=\"mr-1 font-mono text-muted-foreground\">{l.level.substring(0, 3)}</span>\n {l.message}\n </div>\n ))}\n </div>\n )}\n {expanded && <TaskStreamTabs task={t} {...(extraTabs.length > 0 ? { extraTabs } : {})} />}\n </div>\n </div>\n );\n}\n\nfunction TaskControls({\n target,\n onControl,\n labelSuffix,\n stopPropagation,\n}: {\n target: TaskSnapshot;\n onControl: (action: TaskControlAction, target: TaskSnapshot) => void | Promise<void>;\n labelSuffix?: string;\n stopPropagation?: boolean;\n}) {\n const [busy, setBusy] = useState<TaskControlAction | null>(null);\n const [error, setError] = useState(\"\");\n const icons: Record<TaskControlAction, typeof UiPlay> = {\n start: UiPlay,\n stop: UiStop,\n restart: UiRestart,\n drain: UiStop,\n retry: UiRefresh,\n };\n const invoke = async (action: TaskControlAction) => {\n setBusy(action);\n setError(\"\");\n try {\n await onControl(action, target);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : `Failed to ${action} task`);\n } finally {\n setBusy(null);\n }\n };\n return (\n <>\n {(target.controls ?? []).map((action) => {\n const ControlIcon = icons[action];\n const actionLabel = action === \"drain\" ? \"Stop after current\" : action[0]?.toUpperCase() + action.slice(1);\n const label = labelSuffix ? `${actionLabel} ${labelSuffix}` : actionLabel;\n return (\n <Button\n key={action}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={label}\n title={label}\n disabled={busy !== null}\n onClick={(event) => {\n if (stopPropagation) event.stopPropagation();\n void invoke(action);\n }}\n >\n <ControlIcon />\n </Button>\n );\n })}\n {error && <span role=\"alert\" className=\"text-xs text-red-600\">{error}</span>}\n </>\n );\n}\n"],"names":["cn","jsxs","jsx","useState","useCopyFlash","taskWorkProgress","bucketTasks","isFailedOrWarn","UiJson","taskGroupJson","UiWarningTriangle","taskGroupErrorCount","taskGroupErrors","Icon","taskStatusIcon","taskStatusColor","taskStatusBg","SplitButton","UiCheck","UiCopy","taskGroupMarkdown","ProgressBar","taskSegments","isTaskProcessDetails","TaskProcessDetailsView","isTaskExecDetails","TaskExecDetailsView","TaskMetadataChips","logLevelColor","CopyButton","taskMarkdown","TaskStreamTabs","UiPlay","UiStop","UiRestart","UiRefresh","Fragment","Button"],"mappings":"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"}
1
+ {"version":3,"file":"TaskProgress.cjs","sources":["../../src/data/TaskProgress.tsx"],"sourcesContent":["import { taskWorkProgress } from \"./task-work-progress\";\nimport { useState } from \"react\";\nimport { Button } from \"../components/button\";\nimport { CopyButton } from \"../components/CopyButton\";\nimport { SplitButton } from \"../components/SplitButton\";\nimport { useCopyFlash } from \"../components/clipboard\";\nimport { UiCheck, UiCopy, UiJson, UiPlay, UiRefresh, UiRestart, UiStop, UiWarningTriangle } from \"../icons\";\nimport { cn } from \"../lib/utils\";\nimport type { DropdownMenuItem } from \"../overlay/DropdownMenu\";\nimport { Icon } from \"./Icon\";\nimport { ProgressBar } from \"./ProgressBar\";\nimport { TaskProcessDetailsView } from \"./TaskProcessDetails\";\nimport { TaskExecDetailsView } from \"./TaskExecDetails\";\nimport type { LogEntry, TaskControlAction, TaskSnapshot } from \"./TaskSnapshot\";\nimport { type TaskHeaderExtra, TaskMetadataChips } from \"./TaskHeaderExtras\";\nimport { type TaskExtraTabs, TaskStreamTabs } from \"./TaskStreamTabs\";\nimport {\n isFailedOrWarn,\n taskGroupErrorCount,\n taskGroupErrors,\n taskGroupJson,\n taskGroupMarkdown,\n taskMarkdown,\n} from \"./task-copy\";\nimport { isTaskExecDetails } from \"./task-exec-details\";\nimport { isTaskProcessDetails } from \"./task-process-details\";\nimport {\n bucketTasks,\n logLevelColor,\n taskSegments,\n taskStatusBg,\n taskStatusColor,\n taskStatusIcon,\n} from \"./task-status\";\n\n// TaskProgress renders one or more clicky task runs (groups) and their child\n// tasks: a segmented progress bar per group plus collapsible per-task rows with\n// status icon, duration, error, and expandable logs. Presentational only —\n// callers feed it snapshots from useTaskRun (SSE) or any other source.\n\nconst MAX_COMPLETED = 5;\nconst MAX_PENDING = 3;\n\nexport interface TaskProgressProps {\n snapshots: TaskSnapshot[];\n title?: string;\n /** Tighter spacing for embedding in a panel. */\n compact?: boolean;\n /** Show every child task when the group first opens. */\n initialShowAllTasks?: boolean;\n className?: string;\n onControl?: (action: TaskControlAction, group: TaskSnapshot) => void | Promise<void>;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n /**\n * Contributes host-owned output panes alongside a task's own stdout/stderr —\n * an agent's session transcript, say, which this module has no way to fetch.\n */\n extraTabs?: TaskExtraTabs;\n /**\n * Replaces the content beside a task's name in its header row. Returning null\n * for a task falls back to the default, which chips the scalar values of its\n * process metadata.\n */\n headerExtra?: TaskHeaderExtra;\n}\n\nexport function TaskProgress({\n snapshots,\n title,\n compact,\n initialShowAllTasks,\n className,\n onControl,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs,\n headerExtra,\n}: TaskProgressProps) {\n const groups = snapshots.filter((s) => s.type === \"group\");\n const tasks = snapshots.filter((s) => s.type === \"task\");\n\n if (groups.length === 0) {\n return (\n <div className={cn(\"text-sm text-muted-foreground\", className)}>\n {title ? `${title}: ` : \"\"}No tasks yet.\n </div>\n );\n }\n\n return (\n <div className={cn(compact ? \"space-y-2\" : \"space-y-3\", className)}>\n {title && <h2 className=\"text-sm font-semibold\">{title}</h2>}\n {groups.map((g) => (\n <TaskGroupCard\n key={g.groupId || g.id}\n group={g}\n tasks={tasks.filter((t) => g.groupId ? t.groupId === g.groupId : t.group === g.id)}\n compact={compact}\n initialShowAllTasks={initialShowAllTasks}\n {...(onControl ? { onControl } : {})}\n {...(onTaskControl ? { onTaskControl } : {})}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n ))}\n </div>\n );\n}\n\nfunction TaskGroupCard({\n group: g,\n tasks,\n compact,\n initialShowAllTasks,\n onControl,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs,\n headerExtra,\n}: {\n group: TaskSnapshot;\n tasks: TaskSnapshot[];\n compact: boolean | undefined;\n initialShowAllTasks: boolean | undefined;\n extraTabs?: TaskExtraTabs;\n headerExtra?: TaskHeaderExtra;\n onControl?: (action: TaskControlAction, group: TaskSnapshot) => void | Promise<void>;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n}) {\n const [showAll, setShowAll] = useState(initialShowAllTasks ?? false);\n const { state: copyState, copy } = useCopyFlash();\n const work = taskWorkProgress(g);\n const total = g.work ? work.total : g.total ?? tasks.length;\n const counts = g.work ? work.counts : bucketTasks(tasks);\n const done = counts.ok + counts.warn + counts.fail + counts.canceled;\n const progress = g.work ? work.label : total > 0 ? `${done}/${total}` : \"\";\n\n const running = tasks.filter((t) => t.status === \"running\");\n const pending = tasks.filter((t) => t.status === \"pending\");\n const completed = tasks.filter((t) => t.status !== \"running\" && t.status !== \"pending\");\n const alwaysShow = completed.filter(isFailedOrWarn);\n const collapsible = completed.filter((t) => !isFailedOrWarn(t));\n\n const hiddenCompleted = collapsible.length - MAX_COMPLETED;\n const collapseCompleted = !showAll && hiddenCompleted > 0;\n const visibleSuccess = collapseCompleted ? collapsible.slice(-MAX_COMPLETED) : collapsible;\n\n const hiddenPending = pending.length - MAX_PENDING;\n const collapsePending = !showAll && hiddenPending > 0;\n const visiblePending = collapsePending ? pending.slice(0, MAX_PENDING) : pending;\n\n const isTerminal = g.status !== \"running\" && g.status !== \"pending\";\n\n const copyItems: DropdownMenuItem[] = [\n {\n label: \"Copy as JSON\",\n icon: UiJson,\n onSelect: () => copy(taskGroupJson(g, tasks)),\n },\n {\n label: \"Copy errors only\",\n icon: UiWarningTriangle,\n disabled: taskGroupErrorCount(tasks) === 0,\n onSelect: () => copy(taskGroupErrors(g, tasks)),\n },\n ];\n\n return (\n <div className={cn(\"rounded-lg border bg-card\", compact ? \"p-2\" : \"p-4\")}>\n <div className={cn(\"flex items-center justify-between gap-3\", compact ? \"mb-2\" : \"mb-3\")}>\n <h3 className=\"flex min-w-0 items-center gap-1.5 text-sm font-semibold\">\n <Icon\n icon={taskStatusIcon(g.status)}\n className={cn(\n \"shrink-0\",\n taskStatusColor(g.status),\n g.status === \"running\" && \"animate-spin\",\n )}\n />\n <span className=\"truncate\">{g.name}</span>\n {progress && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{progress}</span>\n )}\n {g.kind && (\n <span className=\"shrink-0 rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground\">\n {g.kind}\n </span>\n )}\n </h3>\n <div className=\"flex shrink-0 items-center gap-1\">\n {isTerminal && (\n <span\n className={cn(\n \"rounded-full px-2 py-0.5 text-xs\",\n taskStatusColor(g.status),\n taskStatusBg(g.status),\n )}\n >\n {g.status}\n </span>\n )}\n <SplitButton\n label={copyState === \"copied\" ? \"Copied\" : copyState === \"error\" ? \"Copy failed\" : \"Copy\"}\n icon={copyState === \"copied\" ? UiCheck : UiCopy}\n variant=\"ghost\"\n size=\"sm\"\n title=\"More copy options\"\n onClick={() => copy(taskGroupMarkdown(g, tasks))}\n items={copyItems}\n />\n {onControl && <TaskControls target={g} onControl={onControl} />}\n </div>\n </div>\n\n {total > 0 && (\n <div className={compact ? \"mb-2\" : \"mb-3\"}>\n <ProgressBar segments={taskSegments(counts)} total={total} height=\"h-1.5\" />\n </div>\n )}\n\n {isTaskProcessDetails(g.details) && (\n <TaskProcessDetailsView\n details={g.details}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n />\n )}\n\n {!isTaskProcessDetails(g.details) && isTaskExecDetails(g.details) && (\n <TaskExecDetailsView details={g.details} />\n )}\n\n {hiddenCompleted > 0 || hiddenPending > 0 ? (\n <button\n type=\"button\"\n className={cn(\"border-b text-xs text-muted-foreground hover:text-foreground\", compact ? \"py-1\" : \"py-1.5\")}\n onClick={() => setShowAll((v) => !v)}\n >\n {showAll\n ? \"▲ collapse\"\n : `... ${(collapseCompleted ? hiddenCompleted : 0) + (collapsePending ? hiddenPending : 0)} more tasks`}\n </button>\n ) : null}\n\n {[...visibleSuccess, ...alwaysShow, ...running, ...visiblePending].map((t) => (\n <TaskRow\n key={t.id}\n task={t}\n group={g}\n compact={compact}\n {...(onTaskControl ? { onTaskControl } : {})}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n {...(extraTabs ? { extraTabs } : {})}\n {...(headerExtra ? { headerExtra } : {})}\n />\n ))}\n </div>\n );\n}\n\nfunction TaskRow({\n task: t,\n group,\n compact,\n onTaskControl,\n metricsBaseUrl,\n connectionStatus,\n extraTabs: contributeTabs,\n headerExtra,\n}: {\n task: TaskSnapshot;\n group: TaskSnapshot;\n compact: boolean | undefined;\n metricsBaseUrl?: string;\n connectionStatus?: string;\n extraTabs?: TaskExtraTabs;\n headerExtra?: TaskHeaderExtra;\n onTaskControl?: (\n action: TaskControlAction,\n task: TaskSnapshot,\n group: TaskSnapshot,\n ) => void | Promise<void>;\n}) {\n const [expanded, setExpanded] = useState(false);\n const logs: LogEntry[] = t.logs ?? [];\n const hasLogs = logs.length > 0;\n const extraTabs = contributeTabs?.(t, group) ?? [];\n // A host that has nothing to add for this task returns null, and the default\n // metadata chips take over — so enriching one kind of task never costs the\n // rest their header.\n const header = headerExtra?.(t, group) ?? <TaskMetadataChips task={t} />;\n const hasOutput = !!t.stdout || !!t.stderr || extraTabs.length > 0;\n const execDetails = isTaskExecDetails(t.details) ? t.details : undefined;\n const processDetails = isTaskProcessDetails(t.details) ? t.details : undefined;\n const expandable = hasLogs || hasOutput || execDetails !== undefined || processDetails !== undefined;\n // Promote the latest warning message inline so a `warning` row shows its\n // reason without expanding. Suppressed when an error is already shown.\n const latestWarn = t.error ? undefined : logs.filter((l) => l.level === \"warn\").at(-1);\n // Bounded per-task progress (e.g. records emitted in a phase): render an x/y\n // count, a percentage, and a thin bar while the task runs.\n const done = t.progress ?? 0;\n // Only surface bounded progress once work has actually started — an untouched\n // task should not render a \"0/100 · 0%\" placeholder.\n const hasProgress = typeof t.maxValue === \"number\" && t.maxValue > 0 && done > 0;\n const pct = hasProgress ? Math.round((done / (t.maxValue as number)) * 100) : 0;\n\n return (\n <div\n className={cn(\n \"group flex items-start border-b last:border-0\",\n compact ? \"gap-2 py-1\" : \"gap-3 py-2\",\n expandable && \"-mx-1 cursor-pointer rounded px-1 hover:bg-muted/50\",\n )}\n onClick={expandable ? () => setExpanded((v) => !v) : undefined}\n >\n <Icon\n icon={taskStatusIcon(t.status)}\n className={cn(taskStatusColor(t.status), \"mt-0.5\", compact ? \"text-base\" : \"text-lg\", t.status === \"running\" && \"animate-spin\")}\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"flex min-w-0 items-center gap-1.5 text-sm font-medium\">\n <span className=\"truncate\">{t.name}</span>\n {t.error && <span className=\"truncate text-xs font-normal text-red-500\">{t.error}</span>}\n {latestWarn && (\n <span className={cn(\"truncate text-xs font-normal\", logLevelColor(\"warn\"))}>\n {latestWarn.message}\n </span>\n )}\n {expandable && (\n <span className=\"inline-flex shrink-0 items-center rounded-full bg-muted px-1.5 text-[10px] font-medium text-muted-foreground\">\n {logs.length + (t.stdout ? 1 : 0) + (t.stderr ? 1 : 0) + (execDetails || processDetails ? 1 : 0)}\n </span>\n )}\n </span>\n {header}\n <div className=\"flex shrink-0 items-center gap-1\">\n {t.duration && <span className=\"text-xs text-muted-foreground\">{t.duration}</span>}\n <CopyButton\n value={() => taskMarkdown(t)}\n label={`Copy ${t.name}`}\n className=\"opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100\"\n iconClassName=\"text-xs\"\n />\n {onTaskControl && (\n <TaskControls\n target={t}\n labelSuffix={t.name}\n stopPropagation\n onControl={(action) => onTaskControl(action, t, group)}\n />\n )}\n </div>\n </div>\n {(t.description || hasProgress) && (\n <div className=\"mt-0.5 flex items-center gap-2\">\n {t.description && (\n <span className=\"min-w-0 flex-1 truncate text-xs text-muted-foreground\">{t.description}</span>\n )}\n {hasProgress && (\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {done}/{t.maxValue} · {pct}%\n </span>\n )}\n </div>\n )}\n {hasProgress && t.status === \"running\" && (\n <div className=\"mt-1\">\n <ProgressBar\n segments={[{ count: done, color: \"bg-blue-500\", label: \"done\" }]}\n total={t.maxValue as number}\n height=\"h-1\"\n />\n </div>\n )}\n {expanded && execDetails && <TaskExecDetailsView details={execDetails} />}\n {expanded && processDetails && (\n <TaskProcessDetailsView\n details={processDetails}\n {...(metricsBaseUrl ? { metricsBaseUrl } : {})}\n {...(connectionStatus ? { connectionStatus } : {})}\n />\n )}\n {expanded && hasLogs && (\n <div className=\"mt-1 ml-1 max-h-48 space-y-0.5 overflow-y-auto border-l-2 pl-2\">\n {logs.map((l, i) => (\n <div key={i} className={cn(\"text-xs\", logLevelColor(l.level))}>\n <span className=\"mr-1 font-mono text-muted-foreground\">{l.level.substring(0, 3)}</span>\n {l.message}\n </div>\n ))}\n </div>\n )}\n {expanded && <TaskStreamTabs task={t} {...(extraTabs.length > 0 ? { extraTabs } : {})} />}\n </div>\n </div>\n );\n}\n\nfunction TaskControls({\n target,\n onControl,\n labelSuffix,\n stopPropagation,\n}: {\n target: TaskSnapshot;\n onControl: (action: TaskControlAction, target: TaskSnapshot) => void | Promise<void>;\n labelSuffix?: string;\n stopPropagation?: boolean;\n}) {\n const [busy, setBusy] = useState<TaskControlAction | null>(null);\n const [error, setError] = useState(\"\");\n const icons: Record<TaskControlAction, typeof UiPlay> = {\n start: UiPlay,\n stop: UiStop,\n restart: UiRestart,\n drain: UiStop,\n retry: UiRefresh,\n };\n const invoke = async (action: TaskControlAction) => {\n setBusy(action);\n setError(\"\");\n try {\n await onControl(action, target);\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : `Failed to ${action} task`);\n } finally {\n setBusy(null);\n }\n };\n return (\n <>\n {(target.controls ?? []).map((action) => {\n const ControlIcon = icons[action];\n const actionLabel = action === \"drain\" ? \"Stop after current\" : action[0]?.toUpperCase() + action.slice(1);\n const label = labelSuffix ? `${actionLabel} ${labelSuffix}` : actionLabel;\n return (\n <Button\n key={action}\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={label}\n title={label}\n disabled={busy !== null}\n onClick={(event) => {\n if (stopPropagation) event.stopPropagation();\n void invoke(action);\n }}\n >\n <ControlIcon />\n </Button>\n );\n })}\n {error && <span role=\"alert\" className=\"text-xs text-red-600\">{error}</span>}\n </>\n );\n}\n"],"names":["cn","jsxs","jsx","useState","useCopyFlash","taskWorkProgress","bucketTasks","isFailedOrWarn","UiJson","taskGroupJson","UiWarningTriangle","taskGroupErrorCount","taskGroupErrors","Icon","taskStatusIcon","taskStatusColor","taskStatusBg","SplitButton","UiCheck","UiCopy","taskGroupMarkdown","ProgressBar","taskSegments","isTaskProcessDetails","TaskProcessDetailsView","isTaskExecDetails","TaskExecDetailsView","TaskMetadataChips","logLevelColor","CopyButton","taskMarkdown","TaskStreamTabs","UiPlay","UiStop","UiRestart","UiRefresh","Fragment","Button"],"mappings":"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"}
@@ -6,6 +6,8 @@ export interface TaskProgressProps {
6
6
  title?: string;
7
7
  /** Tighter spacing for embedding in a panel. */
8
8
  compact?: boolean;
9
+ /** Show every child task when the group first opens. */
10
+ initialShowAllTasks?: boolean;
9
11
  className?: string;
10
12
  onControl?: (action: TaskControlAction, group: TaskSnapshot) => void | Promise<void>;
11
13
  onTaskControl?: (action: TaskControlAction, task: TaskSnapshot, group: TaskSnapshot) => void | Promise<void>;
@@ -23,5 +25,5 @@ export interface TaskProgressProps {
23
25
  */
24
26
  headerExtra?: TaskHeaderExtra;
25
27
  }
26
- export declare function TaskProgress({ snapshots, title, compact, className, onControl, onTaskControl, metricsBaseUrl, connectionStatus, extraTabs, headerExtra, }: TaskProgressProps): import("react").JSX.Element;
28
+ export declare function TaskProgress({ snapshots, title, compact, initialShowAllTasks, className, onControl, onTaskControl, metricsBaseUrl, connectionStatus, extraTabs, headerExtra, }: TaskProgressProps): import("react").JSX.Element;
27
29
  //# sourceMappingURL=TaskProgress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TaskProgress.d.ts","sourceRoot":"","sources":["../../src/data/TaskProgress.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAY,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,KAAK,eAAe,EAAqB,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AA4BtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,YAAY,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,KAAK,EACL,OAAO,EACP,SAAS,EACT,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,WAAW,GACZ,EAAE,iBAAiB,+BA+BnB"}
1
+ {"version":3,"file":"TaskProgress.d.ts","sourceRoot":"","sources":["../../src/data/TaskProgress.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAY,iBAAiB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,KAAK,eAAe,EAAqB,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,KAAK,aAAa,EAAkB,MAAM,kBAAkB,CAAC;AA4BtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,aAAa,CAAC,EAAE,CACd,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,YAAY,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;OAIG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,wBAAgB,YAAY,CAAC,EAC3B,SAAS,EACT,KAAK,EACL,OAAO,EACP,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,WAAW,GACZ,EAAE,iBAAiB,+BAgCnB"}
@@ -30,6 +30,7 @@ function TaskProgress({
30
30
  snapshots,
31
31
  title,
32
32
  compact,
33
+ initialShowAllTasks,
33
34
  className,
34
35
  onControl,
35
36
  onTaskControl,
@@ -54,6 +55,7 @@ function TaskProgress({
54
55
  group: g,
55
56
  tasks: tasks.filter((t) => g.groupId ? t.groupId === g.groupId : t.group === g.id),
56
57
  compact,
58
+ initialShowAllTasks,
57
59
  ...onControl ? { onControl } : {},
58
60
  ...onTaskControl ? { onTaskControl } : {},
59
61
  ...metricsBaseUrl ? { metricsBaseUrl } : {},
@@ -69,6 +71,7 @@ function TaskGroupCard({
69
71
  group: g,
70
72
  tasks,
71
73
  compact,
74
+ initialShowAllTasks,
72
75
  onControl,
73
76
  onTaskControl,
74
77
  metricsBaseUrl,
@@ -76,7 +79,7 @@ function TaskGroupCard({
76
79
  extraTabs,
77
80
  headerExtra
78
81
  }) {
79
- const [showAll, setShowAll] = useState(false);
82
+ const [showAll, setShowAll] = useState(initialShowAllTasks ?? false);
80
83
  const { state: copyState, copy } = useCopyFlash();
81
84
  const work = taskWorkProgress(g);
82
85
  const total = g.work ? work.total : g.total ?? tasks.length;
@@ -108,8 +111,8 @@ function TaskGroupCard({
108
111
  onSelect: () => copy(taskGroupErrors(g, tasks))
109
112
  }
110
113
  ];
111
- return /* @__PURE__ */ jsxs("div", { className: cn("rounded-lg border bg-card", compact ? "p-3" : "p-4"), children: [
112
- /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center justify-between gap-3", children: [
114
+ return /* @__PURE__ */ jsxs("div", { className: cn("rounded-lg border bg-card", compact ? "p-2" : "p-4"), children: [
115
+ /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-3", compact ? "mb-2" : "mb-3"), children: [
113
116
  /* @__PURE__ */ jsxs("h3", { className: "flex min-w-0 items-center gap-1.5 text-sm font-semibold", children: [
114
117
  /* @__PURE__ */ jsx(
115
118
  Icon,
@@ -153,7 +156,7 @@ function TaskGroupCard({
153
156
  onControl && /* @__PURE__ */ jsx(TaskControls, { target: g, onControl })
154
157
  ] })
155
158
  ] }),
156
- total > 0 && /* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(ProgressBar, { segments: taskSegments(counts), total, height: "h-1.5" }) }),
159
+ total > 0 && /* @__PURE__ */ jsx("div", { className: compact ? "mb-2" : "mb-3", children: /* @__PURE__ */ jsx(ProgressBar, { segments: taskSegments(counts), total, height: "h-1.5" }) }),
157
160
  isTaskProcessDetails(g.details) && /* @__PURE__ */ jsx(
158
161
  TaskProcessDetailsView,
159
162
  {
@@ -167,7 +170,7 @@ function TaskGroupCard({
167
170
  "button",
168
171
  {
169
172
  type: "button",
170
- className: "border-b py-1.5 text-xs text-muted-foreground hover:text-foreground",
173
+ className: cn("border-b text-xs text-muted-foreground hover:text-foreground", compact ? "py-1" : "py-1.5"),
171
174
  onClick: () => setShowAll((v) => !v),
172
175
  children: showAll ? "▲ collapse" : `... ${(collapseCompleted ? hiddenCompleted : 0) + (collapsePending ? hiddenPending : 0)} more tasks`
173
176
  }
@@ -177,6 +180,7 @@ function TaskGroupCard({
177
180
  {
178
181
  task: t,
179
182
  group: g,
183
+ compact,
180
184
  ...onTaskControl ? { onTaskControl } : {},
181
185
  ...metricsBaseUrl ? { metricsBaseUrl } : {},
182
186
  ...connectionStatus ? { connectionStatus } : {},
@@ -190,6 +194,7 @@ function TaskGroupCard({
190
194
  function TaskRow({
191
195
  task: t,
192
196
  group,
197
+ compact,
193
198
  onTaskControl,
194
199
  metricsBaseUrl,
195
200
  connectionStatus,
@@ -213,7 +218,8 @@ function TaskRow({
213
218
  "div",
214
219
  {
215
220
  className: cn(
216
- "group flex items-start gap-3 border-b py-2 last:border-0",
221
+ "group flex items-start border-b last:border-0",
222
+ compact ? "gap-2 py-1" : "gap-3 py-2",
217
223
  expandable && "-mx-1 cursor-pointer rounded px-1 hover:bg-muted/50"
218
224
  ),
219
225
  onClick: expandable ? () => setExpanded((v) => !v) : void 0,
@@ -222,7 +228,7 @@ function TaskRow({
222
228
  Icon,
223
229
  {
224
230
  icon: taskStatusIcon(t.status),
225
- className: cn(taskStatusColor(t.status), "mt-0.5 text-lg", t.status === "running" && "animate-spin")
231
+ className: cn(taskStatusColor(t.status), "mt-0.5", compact ? "text-base" : "text-lg", t.status === "running" && "animate-spin")
226
232
  }
227
233
  ),
228
234
  /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [