@flanksource/clicky-ui 0.3.48 → 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 (102) hide show
  1. package/dist/data/DataTable.cjs +18 -8
  2. package/dist/data/DataTable.cjs.map +1 -1
  3. package/dist/data/DataTable.d.ts +4 -0
  4. package/dist/data/DataTable.d.ts.map +1 -1
  5. package/dist/data/DataTable.js +18 -8
  6. package/dist/data/DataTable.js.map +1 -1
  7. package/dist/data/TaskManager.cjs +183 -159
  8. package/dist/data/TaskManager.cjs.map +1 -1
  9. package/dist/data/TaskManager.d.ts +3 -1
  10. package/dist/data/TaskManager.d.ts.map +1 -1
  11. package/dist/data/TaskManager.js +185 -161
  12. package/dist/data/TaskManager.js.map +1 -1
  13. package/dist/data/TaskManagerButton.cjs +1 -0
  14. package/dist/data/TaskManagerButton.cjs.map +1 -1
  15. package/dist/data/TaskManagerButton.js +1 -0
  16. package/dist/data/TaskManagerButton.js.map +1 -1
  17. package/dist/data/TaskProgress.cjs +13 -7
  18. package/dist/data/TaskProgress.cjs.map +1 -1
  19. package/dist/data/TaskProgress.d.ts +3 -1
  20. package/dist/data/TaskProgress.d.ts.map +1 -1
  21. package/dist/data/TaskProgress.js +13 -7
  22. package/dist/data/TaskProgress.js.map +1 -1
  23. package/dist/data/traces/ProcessTraceTree.cjs +93 -0
  24. package/dist/data/traces/ProcessTraceTree.cjs.map +1 -0
  25. package/dist/data/traces/ProcessTraceTree.d.ts +24 -0
  26. package/dist/data/traces/ProcessTraceTree.d.ts.map +1 -0
  27. package/dist/data/traces/ProcessTraceTree.js +93 -0
  28. package/dist/data/traces/ProcessTraceTree.js.map +1 -0
  29. package/dist/data/traces/Sparkline.cjs +23 -0
  30. package/dist/data/traces/Sparkline.cjs.map +1 -0
  31. package/dist/data/traces/Sparkline.d.ts +13 -0
  32. package/dist/data/traces/Sparkline.d.ts.map +1 -0
  33. package/dist/data/traces/Sparkline.js +23 -0
  34. package/dist/data/traces/Sparkline.js.map +1 -0
  35. package/dist/data/traces/SqlTraceTable.cjs +104 -0
  36. package/dist/data/traces/SqlTraceTable.cjs.map +1 -0
  37. package/dist/data/traces/SqlTraceTable.d.ts +19 -0
  38. package/dist/data/traces/SqlTraceTable.d.ts.map +1 -0
  39. package/dist/data/traces/SqlTraceTable.js +104 -0
  40. package/dist/data/traces/SqlTraceTable.js.map +1 -0
  41. package/dist/data/traces/TerminalCastPlayer.cjs +162 -0
  42. package/dist/data/traces/TerminalCastPlayer.cjs.map +1 -0
  43. package/dist/data/traces/TerminalCastPlayer.js +162 -0
  44. package/dist/data/traces/TerminalCastPlayer.js.map +1 -0
  45. package/dist/data/traces/TraceHarView.cjs +15 -0
  46. package/dist/data/traces/TraceHarView.cjs.map +1 -0
  47. package/dist/data/traces/TraceHarView.js +15 -0
  48. package/dist/data/traces/TraceHarView.js.map +1 -0
  49. package/dist/data/traces/TraceView.cjs +54 -0
  50. package/dist/data/traces/TraceView.cjs.map +1 -0
  51. package/dist/data/traces/TraceView.d.ts +18 -0
  52. package/dist/data/traces/TraceView.d.ts.map +1 -0
  53. package/dist/data/traces/TraceView.js +54 -0
  54. package/dist/data/traces/TraceView.js.map +1 -0
  55. package/dist/data/traces/cast.cjs +81 -0
  56. package/dist/data/traces/cast.cjs.map +1 -0
  57. package/dist/data/traces/cast.js +81 -0
  58. package/dist/data/traces/cast.js.map +1 -0
  59. package/dist/data/traces/har-adapter.cjs +83 -0
  60. package/dist/data/traces/har-adapter.cjs.map +1 -0
  61. package/dist/data/traces/har-adapter.js +83 -0
  62. package/dist/data/traces/har-adapter.js.map +1 -0
  63. package/dist/data/traces/index.d.ts +12 -0
  64. package/dist/data/traces/index.d.ts.map +1 -0
  65. package/dist/data/traces/process-tree.cjs +53 -0
  66. package/dist/data/traces/process-tree.cjs.map +1 -0
  67. package/dist/data/traces/process-tree.d.ts +21 -0
  68. package/dist/data/traces/process-tree.d.ts.map +1 -0
  69. package/dist/data/traces/process-tree.js +53 -0
  70. package/dist/data/traces/process-tree.js.map +1 -0
  71. package/dist/data/traces/sql-trace.cjs +39 -0
  72. package/dist/data/traces/sql-trace.cjs.map +1 -0
  73. package/dist/data/traces/sql-trace.d.ts +31 -0
  74. package/dist/data/traces/sql-trace.d.ts.map +1 -0
  75. package/dist/data/traces/sql-trace.js +39 -0
  76. package/dist/data/traces/sql-trace.js.map +1 -0
  77. package/dist/data/traces/terminal-screen.cjs +270 -0
  78. package/dist/data/traces/terminal-screen.cjs.map +1 -0
  79. package/dist/data/traces/terminal-screen.js +270 -0
  80. package/dist/data/traces/terminal-screen.js.map +1 -0
  81. package/dist/data/traces/terminal-timeline.cjs +48 -0
  82. package/dist/data/traces/terminal-timeline.cjs.map +1 -0
  83. package/dist/data/traces/terminal-timeline.js +48 -0
  84. package/dist/data/traces/terminal-timeline.js.map +1 -0
  85. package/dist/data/traces/types.d.ts +1 -3
  86. package/dist/data/traces/types.d.ts.map +1 -1
  87. package/dist/data/version-info.cjs +3 -3
  88. package/dist/data/version-info.cjs.map +1 -1
  89. package/dist/data/version-info.js +3 -3
  90. package/dist/data/version-info.js.map +1 -1
  91. package/dist/data.cjs +22 -0
  92. package/dist/data.cjs.map +1 -1
  93. package/dist/data.d.ts +1 -0
  94. package/dist/data.d.ts.map +1 -1
  95. package/dist/data.js +22 -0
  96. package/dist/data.js.map +1 -1
  97. package/dist/index.cjs +22 -0
  98. package/dist/index.cjs.map +1 -1
  99. package/dist/index.js +22 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/styles.css +1 -1
  102. package/package.json +1 -1
@@ -4,20 +4,83 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const react = require("react");
5
5
  const reactQuery = require("@tanstack/react-query");
6
6
  const utils = require("../lib/utils.cjs");
7
+ const format = require("../lib/format.cjs");
8
+ const useResourceClock = require("../hooks/use-resource-clock.cjs");
7
9
  const useTaskRun = require("../hooks/use-task-run.cjs");
8
10
  const Icon = require("./Icon.cjs");
11
+ const DataTable = require("./DataTable.cjs");
12
+ const tagUtils = require("./cells/tag-utils.cjs");
9
13
  const ProgressBar = require("./ProgressBar.cjs");
10
- const Timestamp = require("./cells/Timestamp.cjs");
11
14
  const TaskProgress = require("./TaskProgress.cjs");
12
15
  const taskWorkProgress = require("./task-work-progress.cjs");
13
16
  const taskQueryKeys = require("./task-query-keys.cjs");
14
17
  const taskStatus = require("./task-status.cjs");
18
+ const progressColumn = {
19
+ key: "progress",
20
+ label: "Progress",
21
+ minWidth: 180,
22
+ accessor: (row) => taskWorkProgress.taskWorkProgress(row.run).done,
23
+ render: (_, row) => {
24
+ const progress = taskWorkProgress.taskWorkProgress(row.run);
25
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-36 space-y-1", children: [
26
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs tabular-nums text-muted-foreground", children: progress.label }),
27
+ progress.total > 0 && /* @__PURE__ */ jsxRuntime.jsx(ProgressBar.ProgressBar, { segments: taskStatus.taskSegments(progress.counts), total: progress.total, height: "h-1.5" })
28
+ ] });
29
+ }
30
+ };
31
+ const startedColumn = { key: "startedAt", label: "Started", kind: "timestamp", sortable: true };
32
+ const durationColumn = {
33
+ key: "duration",
34
+ label: "Duration",
35
+ sortable: true,
36
+ accessor: (row) => row.startedAt ? Date.parse(row.finishedAt ?? (/* @__PURE__ */ new Date()).toISOString()) - Date.parse(row.startedAt) : null,
37
+ render: (_, row) => /* @__PURE__ */ jsxRuntime.jsx(RunDuration, { startedAt: row.startedAt, finishedAt: row.finishedAt })
38
+ };
39
+ const runColumns = [
40
+ { key: "name", label: "Run", sortable: true, grow: true, minWidth: 220 },
41
+ {
42
+ key: "status",
43
+ label: "Status",
44
+ sortable: true,
45
+ render: (_, row) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils.cn("inline-flex items-center gap-1.5 capitalize", taskStatus.taskStatusColor(row.status)), children: [
46
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: taskStatus.taskStatusIcon(row.status), ...row.status === "running" ? { className: "animate-spin" } : {} }),
47
+ row.status
48
+ ] })
49
+ },
50
+ durationColumn,
51
+ progressColumn,
52
+ { key: "labels", label: "Labels", kind: "tags", tags: { maxVisible: 2 }, minWidth: 160 },
53
+ startedColumn,
54
+ { key: "finishedAt", label: "Finished", kind: "timestamp", sortable: true }
55
+ ];
56
+ const compactRunColumns = [
57
+ {
58
+ key: "name",
59
+ label: "Run",
60
+ sortable: true,
61
+ grow: true,
62
+ minWidth: 220,
63
+ render: (_, row) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
64
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium", children: row.name }),
65
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
66
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: applicationLabel(row.kind) }),
67
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils.cn("inline-flex items-center gap-1 capitalize", taskStatus.taskStatusColor(row.status)), children: [
68
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: taskStatus.taskStatusIcon(row.status) }),
69
+ row.status
70
+ ] })
71
+ ] })
72
+ ] })
73
+ },
74
+ progressColumn,
75
+ startedColumn
76
+ ];
15
77
  function TaskManager({
16
78
  basePath,
17
79
  kind,
18
80
  labels,
19
81
  pollMs,
20
82
  className,
83
+ compact,
21
84
  selectedId,
22
85
  onSelectRun,
23
86
  extraTabs,
@@ -25,13 +88,21 @@ function TaskManager({
25
88
  }) {
26
89
  const [kindFilter, setKindFilter] = react.useState(kind ?? "");
27
90
  const [statusFilter, setStatusFilter] = react.useState("");
91
+ const [labelFilter, setLabelFilter] = react.useState("");
92
+ const [filterOptions, setFilterOptions] = react.useState({ kinds: [], labels: [] });
93
+ const [localSelectedId, setLocalSelectedId] = react.useState(null);
28
94
  const queryClient = reactQuery.useQueryClient();
29
95
  const apiBase = basePath ?? "/api/v1";
30
96
  const activeKind = kind ?? (kindFilter || void 0);
97
+ const activeLabels = react.useMemo(() => {
98
+ if (!labelFilter) return labels;
99
+ const selected = tagUtils.splitTagToken(labelFilter);
100
+ return { ...labels, [selected.key]: selected.value };
101
+ }, [labels, labelFilter]);
31
102
  const { runs, runsKey, status } = useTaskRun.useTaskRuns({
32
103
  basePath: apiBase,
33
104
  kind: activeKind,
34
- labels,
105
+ labels: activeLabels,
35
106
  status: statusFilter || void 0,
36
107
  pollMs
37
108
  });
@@ -40,79 +111,88 @@ function TaskManager({
40
111
  basePath: apiBase,
41
112
  kind: activeKind,
42
113
  status: statusFilter || void 0,
43
- labels
114
+ labels: activeLabels
44
115
  }),
45
- [activeKind, apiBase, labels, statusFilter]
116
+ [activeKind, apiBase, activeLabels, statusFilter]
46
117
  );
47
118
  react.useEffect(() => {
48
119
  if (!runsKey || reactQuery.hashKey(runsKey) !== reactQuery.hashKey(runsQueryKey)) return;
49
120
  queryClient.setQueryData(runsQueryKey, runs);
50
121
  }, [queryClient, runs, runsKey, runsQueryKey]);
51
- const kinds = react.useMemo(() => {
52
- const set = /* @__PURE__ */ new Set();
53
- for (const r of runs) if (r.kind) set.add(r.kind);
54
- return [...set].sort();
122
+ react.useEffect(() => {
123
+ setFilterOptions((previous) => {
124
+ const kinds = [.../* @__PURE__ */ new Set([...previous.kinds, ...runs.flatMap((run) => run.kind ? [run.kind] : [])])].sort();
125
+ const labels2 = [.../* @__PURE__ */ new Set([...previous.labels, ...runs.flatMap((run) => Object.entries(run.labels ?? {}).map(([key, value]) => `${key}=${value}`))])].sort();
126
+ if (kinds.length === previous.kinds.length && labels2.length === previous.labels.length) return previous;
127
+ return { kinds, labels: labels2 };
128
+ });
55
129
  }, [runs]);
56
- const applications = react.useMemo(() => groupRunsByApplication(runs), [runs]);
57
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("space-y-3", className), children: [
58
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
59
- !kind && /* @__PURE__ */ jsxRuntime.jsxs(
60
- "select",
61
- {
62
- className: "rounded-md border bg-background px-2 py-1 text-xs",
63
- value: kindFilter,
64
- onChange: (e) => setKindFilter(e.target.value),
65
- children: [
66
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "All kinds" }),
67
- kinds.map((k) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: k, children: k }, k))
68
- ]
69
- }
70
- ),
71
- /* @__PURE__ */ jsxRuntime.jsxs(
72
- "select",
73
- {
74
- className: "rounded-md border bg-background px-2 py-1 text-xs",
75
- value: statusFilter,
76
- onChange: (e) => setStatusFilter(e.target.value),
77
- children: [
78
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Any status" }),
79
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "running", children: "Running" }),
80
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "pending", children: "Pending" }),
81
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "success", children: "Success" }),
82
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "failed", children: "Failed" }),
83
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "warning", children: "Warning" }),
84
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "canceled", children: "Canceled" })
85
- ]
86
- }
87
- ),
88
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: status })
89
- ] }),
90
- runs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground", children: "No background tasks." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: applications.map((application) => /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
91
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-1 px-1 text-xs font-semibold text-muted-foreground", children: applicationLabel(application.kind) }),
92
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-lg border bg-card", children: application.runs.map((run) => /* @__PURE__ */ jsxRuntime.jsx(
93
- RunRow,
130
+ const filters = [
131
+ ...!kind ? [{ key: "kind", kind: "enum", label: "Kind", placeholder: "All kinds", value: kindFilter, options: filterOptions.kinds.map((value) => ({ value, label: applicationLabel(value) })), onChange: setKindFilter }] : [],
132
+ { key: "status", kind: "enum", label: "Status", placeholder: "Any status", value: statusFilter, options: [
133
+ { value: "running", label: "Running" },
134
+ { value: "pending", label: "Pending" },
135
+ { value: "success", label: "Success" },
136
+ { value: "failed", label: "Failed" },
137
+ { value: "warning", label: "Warning" },
138
+ { value: "canceled", label: "Canceled" }
139
+ ], onChange: setStatusFilter },
140
+ {
141
+ key: "labels",
142
+ kind: "enum",
143
+ label: "Labels",
144
+ placeholder: "Any label",
145
+ value: labelFilter,
146
+ options: filterOptions.labels.filter((token) => !(tagUtils.splitTagToken(token).key in (labels ?? {}))).map((value) => ({ value })),
147
+ onChange: setLabelFilter
148
+ }
149
+ ];
150
+ const rows = react.useMemo(() => runs.map((run) => ({
151
+ id: run.id,
152
+ name: run.name,
153
+ kind: run.kind || "other",
154
+ status: run.status,
155
+ ...run.startedAt ? { startedAt: run.startedAt } : {},
156
+ ...run.finishedAt ? { finishedAt: run.finishedAt } : {},
157
+ ...run.labels ? { labels: run.labels } : {},
158
+ run
159
+ })), [runs]);
160
+ const openId = onSelectRun ? selectedId : localSelectedId;
161
+ return /* @__PURE__ */ jsxRuntime.jsx(
162
+ DataTable.DataTable,
163
+ {
164
+ ...className ? { className } : {},
165
+ data: rows,
166
+ columns: compact ? compactRunColumns : runColumns,
167
+ emptyMessage: "No background tasks.",
168
+ externalFilters: filters,
169
+ filterBarProps: { trailing: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: status }) },
170
+ getRowId: (row) => row.id,
171
+ defaultSort: { key: "startedAt", dir: "desc" },
172
+ expandedRowIds: openId ? [openId] : [],
173
+ onExpandedRowIdsChange: (ids) => {
174
+ const next = ids.find((id) => id !== openId) ?? null;
175
+ if (onSelectRun) onSelectRun(next);
176
+ else setLocalSelectedId(next);
177
+ },
178
+ renderExpandedRow: (row) => /* @__PURE__ */ jsxRuntime.jsx(
179
+ ExpandedRun,
94
180
  {
95
- run,
181
+ run: row.run,
96
182
  basePath,
97
183
  pollMs,
98
- selectedId,
99
- onSelectRun,
100
184
  runsQueryKey,
101
185
  extraTabs,
102
186
  headerExtra
103
- },
104
- run.id
105
- )) })
106
- ] }, application.kind)) })
107
- ] });
187
+ }
188
+ )
189
+ }
190
+ );
108
191
  }
109
- function groupRunsByApplication(runs) {
110
- const grouped = /* @__PURE__ */ new Map();
111
- for (const run of runs) {
112
- const application = run.kind || "other";
113
- grouped.set(application, [...grouped.get(application) ?? [], run]);
114
- }
115
- return [...grouped].map(([kind, applicationRuns]) => ({ kind, runs: applicationRuns }));
192
+ function RunDuration({ startedAt, finishedAt }) {
193
+ const now = useResourceClock.useResourceClock(!!startedAt && !finishedAt);
194
+ if (!startedAt) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "—" });
195
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: format.formatDuration(Math.max(0, (finishedAt ? Date.parse(finishedAt) : now) - Date.parse(startedAt))) });
116
196
  }
117
197
  function applicationLabel(kind) {
118
198
  const names = {
@@ -124,98 +204,15 @@ function applicationLabel(kind) {
124
204
  };
125
205
  return names[kind] ?? kind;
126
206
  }
127
- function RunRow({
128
- run,
129
- basePath,
130
- pollMs,
131
- selectedId,
132
- onSelectRun,
133
- runsQueryKey,
134
- extraTabs,
135
- headerExtra
136
- }) {
137
- const [localOpen, setLocalOpen] = react.useState(false);
138
- const controlled = onSelectRun !== void 0;
139
- const open = controlled ? selectedId === run.id : localOpen;
140
- const toggle = () => {
141
- if (controlled) onSelectRun(open ? null : run.id);
142
- else setLocalOpen((v) => !v);
143
- };
144
- const isTerminal = run.status !== "running" && run.status !== "pending";
145
- const progress = taskWorkProgress.taskWorkProgress(run);
146
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b last:border-0", children: [
147
- /* @__PURE__ */ jsxRuntime.jsxs(
148
- "button",
149
- {
150
- type: "button",
151
- className: "flex w-full items-center justify-between gap-4 px-4 py-3 text-left hover:bg-muted/50",
152
- onClick: toggle,
153
- children: [
154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
155
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
156
- /* @__PURE__ */ jsxRuntime.jsx(
157
- Icon.Icon,
158
- {
159
- icon: taskStatus.taskStatusIcon(run.status),
160
- className: utils.cn(taskStatus.taskStatusColor(run.status), run.status === "running" && "animate-spin")
161
- }
162
- ),
163
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: run.name }),
164
- run.kind && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full bg-muted px-1.5 py-0 text-[10px] text-muted-foreground", children: run.kind }),
165
- isTerminal && /* @__PURE__ */ jsxRuntime.jsx(
166
- "span",
167
- {
168
- className: utils.cn(
169
- "rounded-full px-2 py-0.5 text-xs",
170
- taskStatus.taskStatusColor(run.status),
171
- taskStatus.taskStatusBg(run.status)
172
- ),
173
- children: run.status
174
- }
175
- )
176
- ] }),
177
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground", children: [
178
- run.startedAt && /* @__PURE__ */ jsxRuntime.jsx(Timestamp.Timestamp, { value: run.startedAt, format: "relative" }),
179
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: progress.label }),
180
- Object.entries(run.labels ?? {}).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
181
- k,
182
- "=",
183
- v
184
- ] }, k))
185
- ] })
186
- ] }),
187
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-40 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
188
- ProgressBar.ProgressBar,
189
- {
190
- segments: taskStatus.taskSegments(progress.counts),
191
- total: progress.total || 1,
192
- height: "h-1.5"
193
- }
194
- ) })
195
- ]
196
- }
197
- ),
198
- open && /* @__PURE__ */ jsxRuntime.jsx(
199
- ExpandedRun,
200
- {
201
- runId: run.id,
202
- basePath,
203
- pollMs,
204
- runsQueryKey,
205
- extraTabs,
206
- headerExtra
207
- }
208
- )
209
- ] });
210
- }
211
207
  function ExpandedRun({
212
- runId,
208
+ run,
213
209
  basePath,
214
210
  pollMs,
215
211
  runsQueryKey,
216
212
  extraTabs,
217
213
  headerExtra
218
214
  }) {
215
+ const runId = run.id;
219
216
  const { snapshots, status } = useTaskRun.useTaskRun({ id: runId, basePath, pollMs });
220
217
  const apiBase = basePath ?? "/api/v1";
221
218
  const queryClient = reactQuery.useQueryClient();
@@ -264,19 +261,46 @@ function ExpandedRun({
264
261
  action,
265
262
  target: task
266
263
  });
267
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t bg-muted/30 px-4 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
268
- TaskProgress.TaskProgress,
269
- {
270
- snapshots,
271
- connectionStatus: status,
272
- compact: true,
273
- onControl: control,
274
- onTaskControl: controlTask,
275
- metricsBaseUrl: `${apiBase}/tasks/metrics/`,
276
- ...extraTabs ? { extraTabs } : {},
277
- ...headerExtra ? { headerExtra } : {}
278
- }
279
- ) });
264
+ const progress = taskWorkProgress.taskWorkProgress(run);
265
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 bg-muted/20 px-4 py-4", children: [
266
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-5 gap-y-1 text-xs text-muted-foreground", children: [
267
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
268
+ progress.completed,
269
+ " completed"
270
+ ] }),
271
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
272
+ progress.running,
273
+ " running"
274
+ ] }),
275
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
276
+ progress.failed,
277
+ " failed"
278
+ ] }),
279
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
280
+ progress.counts.pending + progress.unstarted,
281
+ " waiting"
282
+ ] }),
283
+ Object.entries(run.labels ?? {}).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono", children: [
284
+ key,
285
+ "=",
286
+ value
287
+ ] }, key))
288
+ ] }),
289
+ /* @__PURE__ */ jsxRuntime.jsx(
290
+ TaskProgress.TaskProgress,
291
+ {
292
+ snapshots,
293
+ compact: true,
294
+ connectionStatus: status,
295
+ initialShowAllTasks: true,
296
+ onControl: control,
297
+ onTaskControl: controlTask,
298
+ metricsBaseUrl: `${apiBase}/tasks/metrics/`,
299
+ ...extraTabs ? { extraTabs } : {},
300
+ ...headerExtra ? { headerExtra } : {}
301
+ }
302
+ )
303
+ ] });
280
304
  }
281
305
  async function postTaskControl({ url, action, target }) {
282
306
  const context = `Failed to ${action} ${target.type} "${target.name}"`;
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.cjs","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":["useState","useQueryClient","useTaskRuns","useMemo","taskQueryKeys","useEffect","hashKey","cn","jsxs","jsx","taskWorkProgress","Icon","taskStatusIcon","taskStatusColor","taskStatusBg","Timestamp","ProgressBar","taskSegments","useTaskRun","useRef","useMutation","useCallback","TaskProgress"],"mappings":"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"}
1
+ {"version":3,"file":"TaskManager.cjs","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":["taskWorkProgress","jsxs","jsx","ProgressBar","taskSegments","cn","taskStatusColor","Icon","taskStatusIcon","useState","useQueryClient","useMemo","splitTagToken","useTaskRuns","taskQueryKeys","useEffect","hashKey","labels","DataTable","useResourceClock","formatDuration","useTaskRun","useRef","useMutation","useCallback","TaskProgress"],"mappings":"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"}
@@ -9,6 +9,8 @@ export interface TaskManagerProps {
9
9
  labels?: Record<string, string>;
10
10
  pollMs?: number;
11
11
  className?: string;
12
+ /** Keep the run columns usable in a narrow panel. */
13
+ compact?: boolean;
12
14
  /**
13
15
  * Currently-selected (expanded) run id, e.g. driven from the URL. When set,
14
16
  * the matching run renders expanded and selection is controlled — otherwise
@@ -31,5 +33,5 @@ export interface TaskManagerProps {
31
33
  */
32
34
  headerExtra?: TaskHeaderExtra;
33
35
  }
34
- export declare function TaskManager({ basePath, kind, labels, pollMs, className, selectedId, onSelectRun, extraTabs, headerExtra, }: TaskManagerProps): import("react").JSX.Element;
36
+ export declare function TaskManager({ basePath, kind, labels, pollMs, className, compact, selectedId, onSelectRun, extraTabs, headerExtra, }: TaskManagerProps): import("react").JSX.Element;
35
37
  //# sourceMappingURL=TaskManager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../src/data/TaskManager.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAatD,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,MAAM,EACN,SAAS,EACT,UAAU,EACV,WAAW,EACX,SAAS,EACT,WAAW,GACZ,EAAE,gBAAgB,+BAwGlB"}
1
+ {"version":3,"file":"TaskManager.d.ts","sourceRoot":"","sources":["../../src/data/TaskManager.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAYtD,MAAM,WAAW,gBAAgB;IAC/B,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C;;;OAGG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAoED,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,MAAM,EACN,SAAS,EACT,OAAO,EACP,UAAU,EACV,WAAW,EACX,SAAS,EACT,WAAW,GACZ,EAAE,gBAAgB,+BAsGlB"}