@gobing-ai/knowledge-kit 0.0.35 → 0.0.36
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.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +1 -1
- package/dist/board/collect/index.css +42 -0
- package/dist/board/collect/index.js +787 -0
- package/dist/board/daily-voice/index.css +13 -0
- package/dist/board/daily-voice/index.js +902 -0
- package/dist/board/itc/index.css +14 -0
- package/dist/board/itc/index.js +1026 -0
- package/dist/index.js +11768 -9249
- package/package.json +10 -9
- package/plugins/generations/content-gen/dist/index.js +1015 -10814
- package/plugins/generations/content-gen/package.json +1 -1
- package/plugins/generations/core-facts-gen/dist/index.js +1002 -10801
- package/plugins/generations/core-facts-gen/package.json +1 -1
- package/plugins/generations/daily-article-gen/dist/index.js +1004 -10803
- package/plugins/generations/daily-article-gen/package.json +1 -1
- package/plugins/generations/dailynews-gen/dist/index.js +1092 -10891
- package/plugins/generations/dailynews-gen/package.json +1 -1
- package/plugins/generations/episode-plan-gen/dist/index.js +1124 -10923
- package/plugins/generations/episode-plan-gen/package.json +1 -1
- package/plugins/generations/gemini-tts/dist/index.js +1104 -10903
- package/plugins/generations/gemini-tts/package.json +1 -1
- package/plugins/generations/image-gen/dist/index.js +1239 -11035
- package/plugins/generations/image-gen/package.json +1 -1
- package/plugins/generations/news-report-gen/dist/index.js +1048 -10847
- package/plugins/generations/news-report-gen/package.json +1 -1
- package/plugins/generations/voice-gen/dist/index.js +1062 -10861
- package/plugins/generations/voice-gen/package.json +1 -1
- package/plugins/generations/voxcpm-tts/README.md +72 -0
- package/plugins/generations/voxcpm-tts/dist/index.js +14006 -0
- package/plugins/generations/voxcpm-tts/package.json +16 -0
- package/plugins/generations/voxcpm-tts/plugin.json +6 -0
- package/plugins/generations/voxcpm-tts/profiles.json +10 -0
- package/plugins/generations/voxcpm-tts/pyproject.toml +9 -0
- package/plugins/generations/voxcpm-tts/python/worker.py +353 -0
- package/plugins/generations/voxcpm-tts/src/index.ts +42 -0
- package/plugins/generations/voxcpm-tts/src/voxcpm-client.ts +765 -0
- package/plugins/generations/voxcpm-tts/tsconfig.json +8 -0
- package/plugins/generations/voxcpm-tts/uv.lock +2571 -0
- package/plugins/ingestions/aihot-ingest/dist/index.js +1081 -10628
- package/plugins/ingestions/aihot-ingest/package.json +1 -1
- package/plugins/ingestions/horizon-ingest/dist/index.js +1013 -10812
- package/plugins/ingestions/horizon-ingest/package.json +1 -1
- package/plugins/ingestions/karakeep-local/dist/index.js +689 -10774
- package/plugins/ingestions/karakeep-local/package.json +1 -1
- package/plugins/ingestions/last30days-ingest/dist/index.js +1011 -10810
- package/plugins/ingestions/last30days-ingest/package.json +1 -1
- package/plugins/ingestions/web-search/dist/index.js +1250 -11033
- package/plugins/ingestions/web-search/package.json +1 -1
- package/plugins/kk/README.md +29 -2
- package/plugins/kk/plugin.json +1 -1
- package/plugins/kk/schedules/cron.tmpl +9 -1
- package/plugins/kk/schedules/kk-serve.launchd.plist.tmpl +79 -0
- package/plugins/kk/schedules/launchd.plist.tmpl +11 -1
- package/plugins/kk/scripts/daily-stages.ts +428 -46
- package/plugins/kk/scripts/kk-workflow-stages.ts +76 -146
- package/plugins/kk/skills/publish/SKILL.md +8 -4
- package/plugins/kk/workflows/feature-verification.yaml +93 -0
- package/plugins/kk/workflows/judge-gated-publish-example.yaml +1 -0
- package/plugins/kk/workflows/kk-collect.yaml +43 -11
- package/plugins/kk/workflows/kk-daily-ai-voice.yaml +4 -2
- package/plugins/kk/workflows/kk-daily-ai-voice2.yaml +86 -15
- package/plugins/kk/workflows/kk-daily-safety.yaml +15 -2
- package/plugins/kk/workflows/kk-itc.yaml +8 -1
- package/plugins/kk/workflows/kk-solo-podcast.yaml +2 -0
- package/plugins/publishings/emdash-pub/dist/index.js +987 -10814
- package/plugins/publishings/emdash-pub/package.json +1 -1
- package/plugins/publishings/infoq-pub/dist/index.js +1928 -11444
- package/plugins/publishings/infoq-pub/dist/profile-check.js +1677 -11199
- package/plugins/publishings/infoq-pub/package.json +1 -1
- package/plugins/publishings/infoq-pub/plugin.json +5 -1
- package/plugins/publishings/juejin-pub/dist/index.js +1940 -11456
- package/plugins/publishings/juejin-pub/dist/profile-check.js +1677 -11199
- package/plugins/publishings/juejin-pub/package.json +1 -1
- package/plugins/publishings/juejin-pub/plugin.json +5 -1
- package/plugins/publishings/medium-pub/dist/index.js +978 -10805
- package/plugins/publishings/medium-pub/package.json +1 -1
- package/plugins/publishings/podcast-pub/dist/index.js +1016 -10843
- package/plugins/publishings/podcast-pub/package.json +1 -1
- package/plugins/publishings/qiita-pub/dist/index.js +976 -10803
- package/plugins/publishings/qiita-pub/package.json +1 -1
- package/plugins/publishings/substack-pub/dist/index.js +1932 -11448
- package/plugins/publishings/substack-pub/dist/profile-check.js +1698 -11200
- package/plugins/publishings/substack-pub/package.json +1 -1
- package/plugins/publishings/substack-pub/plugin.json +4 -1
- package/plugins/publishings/substack-pub/src/profile-check.ts +36 -3
- package/plugins/publishings/surfdash-pub/dist/index.js +1151 -10834
- package/plugins/publishings/surfdash-pub/package.json +1 -1
- package/plugins/publishings/surfdash-pub/src/index.ts +137 -15
- package/plugins/publishings/surfdash-pub/src/patch.ts +144 -0
- package/plugins/publishings/threads-pub/dist/index.js +12394 -0
- package/plugins/publishings/threads-pub/package.json +17 -0
- package/plugins/publishings/threads-pub/plugin.json +7 -0
- package/plugins/publishings/threads-pub/src/index.ts +340 -0
- package/plugins/publishings/threads-pub/tsconfig.json +4 -0
- package/plugins/publishings/wechatmp-pub/dist/index.js +2508 -11695
- package/plugins/publishings/wechatmp-pub/dist/profile-check.js +1656 -11188
- package/plugins/publishings/wechatmp-pub/package.json +1 -1
- package/plugins/publishings/wechatmp-pub/plugin.json +5 -1
- package/plugins/publishings/wechatmp-pub/src/enrich.ts +244 -71
- package/plugins/publishings/wechatmp-pub/src/flow.ts +412 -96
- package/plugins/publishings/wechatmp-pub/src/index.ts +24 -3
- package/plugins/publishings/wechatmp-pub/src/page.ts +16 -0
- package/plugins/publishings/wechatmp-pub/src/profile-check.ts +40 -4
- package/plugins/publishings/weibo-pub/dist/index.js +21345 -0
- package/plugins/publishings/weibo-pub/dist/profile-check.js +20817 -0
- package/plugins/publishings/weibo-pub/package.json +19 -0
- package/plugins/publishings/weibo-pub/plugin.json +12 -0
- package/plugins/publishings/weibo-pub/src/index.ts +868 -0
- package/plugins/publishings/weibo-pub/src/profile-check.ts +20 -0
- package/plugins/publishings/weibo-pub/tsconfig.json +4 -0
- package/plugins/publishings/x-pub/dist/index.js +1948 -11440
- package/plugins/publishings/x-pub/dist/profile-check.js +1677 -11199
- package/plugins/publishings/x-pub/package.json +1 -1
- package/plugins/publishings/x-pub/plugin.json +5 -1
- package/plugins/publishings/xhs-pub/dist/index.js +1993 -11509
- package/plugins/publishings/xhs-pub/dist/profile-check.js +1697 -11212
- package/plugins/publishings/xhs-pub/package.json +1 -1
- package/plugins/publishings/xhs-pub/plugin.json +5 -1
- package/plugins/publishings/xhs-pub/src/profile-check.ts +72 -2
- package/plugins/publishings/zenn-pub/dist/index.js +988 -10815
- package/plugins/publishings/zenn-pub/package.json +1 -1
|
@@ -0,0 +1,787 @@
|
|
|
1
|
+
// ../board/src/collect/index.tsx
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
// ../board/src/shared/api.ts
|
|
5
|
+
var DEFAULT_READER_ORIGIN = "http://127.0.0.1:4340";
|
|
6
|
+
function readerOriginFrom(search) {
|
|
7
|
+
const override = new URLSearchParams(search).get("kkApi");
|
|
8
|
+
if (override === null)
|
|
9
|
+
return { origin: DEFAULT_READER_ORIGIN, diagnostic: null };
|
|
10
|
+
if (isLoopbackHttpOrigin(override))
|
|
11
|
+
return { origin: override, diagnostic: null };
|
|
12
|
+
return {
|
|
13
|
+
origin: DEFAULT_READER_ORIGIN,
|
|
14
|
+
diagnostic: {
|
|
15
|
+
code: "board.reader.origin-invalid",
|
|
16
|
+
message: "Ignored a non-loopback kkApi origin; using the default reader."
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function isLoopbackHttpOrigin(origin) {
|
|
21
|
+
let url;
|
|
22
|
+
try {
|
|
23
|
+
url = new URL(origin);
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (url.protocol !== "http:")
|
|
28
|
+
return false;
|
|
29
|
+
if (url.username !== "" || url.password !== "")
|
|
30
|
+
return false;
|
|
31
|
+
if (url.pathname !== "/" || url.search !== "" || url.hash !== "")
|
|
32
|
+
return false;
|
|
33
|
+
return url.hostname === "127.0.0.1" || url.hostname === "localhost" || url.hostname === "[::1]";
|
|
34
|
+
}
|
|
35
|
+
function origin(base) {
|
|
36
|
+
return base.replace(/\/+$/, "");
|
|
37
|
+
}
|
|
38
|
+
function createBoardClient(options) {
|
|
39
|
+
if (!isLoopbackHttpOrigin(options.readerOrigin)) {
|
|
40
|
+
throw new Error(`reader origin must be loopback http, got '${options.readerOrigin}'`);
|
|
41
|
+
}
|
|
42
|
+
if (!isLoopbackHttpOrigin(options.boardOrigin)) {
|
|
43
|
+
throw new Error(`board origin must be loopback http, got '${options.boardOrigin}'`);
|
|
44
|
+
}
|
|
45
|
+
const reader = origin(options.readerOrigin);
|
|
46
|
+
const board = origin(options.boardOrigin);
|
|
47
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
48
|
+
async function getJson(url) {
|
|
49
|
+
const response = await doFetch(url, { headers: { accept: "application/json" } });
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
throw new Error(`request failed (${response.status}): ${url}`);
|
|
52
|
+
}
|
|
53
|
+
return await response.json();
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
health: () => getJson(`${reader}/api/health`),
|
|
57
|
+
results: (workflow, runId) => getJson(`${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/results`),
|
|
58
|
+
config: (workflow, runId) => getJson(`${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/config`),
|
|
59
|
+
artifactUrl: (workflow, runId, artifactId) => `${reader}/api/workflows/${encodeURIComponent(workflow)}/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}`,
|
|
60
|
+
runs: (workflow, cursor) => {
|
|
61
|
+
const params = new URLSearchParams({ workflow, limit: "25" });
|
|
62
|
+
if (cursor !== undefined)
|
|
63
|
+
params.set("cursor", cursor);
|
|
64
|
+
return getJson(`${board}/api/runs?${params.toString()}`);
|
|
65
|
+
},
|
|
66
|
+
runDetail: (runId) => getJson(`${board}/api/runs/${encodeURIComponent(runId)}`),
|
|
67
|
+
progress: (runId) => getJson(`${board}/api/runs/${encodeURIComponent(runId)}/progress`)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ../board/src/shared/format.ts
|
|
72
|
+
function availabilityLabel(availability) {
|
|
73
|
+
switch (availability) {
|
|
74
|
+
case "available":
|
|
75
|
+
return "Available";
|
|
76
|
+
case "pending":
|
|
77
|
+
return "Not yet written";
|
|
78
|
+
case "missing":
|
|
79
|
+
return "Missing";
|
|
80
|
+
case "invalid":
|
|
81
|
+
return "Malformed";
|
|
82
|
+
case "oversized":
|
|
83
|
+
return "Too large to preview";
|
|
84
|
+
case "superseded":
|
|
85
|
+
return "Superseded by a later run";
|
|
86
|
+
case "unverified":
|
|
87
|
+
return "Unverified";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function diagnosticLine(diagnostic) {
|
|
91
|
+
return `${diagnostic.code}: ${diagnostic.message}`;
|
|
92
|
+
}
|
|
93
|
+
function formatElapsed(startedAt, now) {
|
|
94
|
+
if (startedAt === null || startedAt === undefined)
|
|
95
|
+
return "elapsed unknown";
|
|
96
|
+
const start = Date.parse(startedAt);
|
|
97
|
+
if (Number.isNaN(start))
|
|
98
|
+
return "elapsed unknown";
|
|
99
|
+
const seconds = Math.max(0, Math.round((now - start) / 1000));
|
|
100
|
+
if (seconds < 60)
|
|
101
|
+
return `${seconds}s`;
|
|
102
|
+
const minutes = Math.floor(seconds / 60);
|
|
103
|
+
if (minutes < 60)
|
|
104
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
105
|
+
return `${Math.floor(minutes / 60)}h ${minutes % 60}m`;
|
|
106
|
+
}
|
|
107
|
+
function dedupeDiagnostics(diagnostics) {
|
|
108
|
+
const seen = new Set;
|
|
109
|
+
return diagnostics.filter((diagnostic) => {
|
|
110
|
+
if (seen.has(diagnostic.code))
|
|
111
|
+
return false;
|
|
112
|
+
seen.add(diagnostic.code);
|
|
113
|
+
return true;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function formatTimestamp(iso) {
|
|
117
|
+
if (iso === null || iso === undefined)
|
|
118
|
+
return "time unknown";
|
|
119
|
+
const epoch = Date.parse(iso);
|
|
120
|
+
if (Number.isNaN(epoch))
|
|
121
|
+
return "time unknown";
|
|
122
|
+
return `${new Date(epoch).toLocaleString()} (${new Date(epoch).toISOString()})`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ../board/src/shared/collect.ts
|
|
126
|
+
function asCount(value) {
|
|
127
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
128
|
+
}
|
|
129
|
+
function asText(value) {
|
|
130
|
+
return typeof value === "string" && value !== "" ? value : null;
|
|
131
|
+
}
|
|
132
|
+
function collectSummary(results) {
|
|
133
|
+
const raw = results.summary ?? {};
|
|
134
|
+
const sources = raw.sourceCounts;
|
|
135
|
+
const sourceCounts = typeof sources === "object" && sources !== null && !Array.isArray(sources) ? sources : null;
|
|
136
|
+
return {
|
|
137
|
+
status: asText(raw.status),
|
|
138
|
+
startedAt: asText(raw.startedAt),
|
|
139
|
+
completedAt: asText(raw.completedAt),
|
|
140
|
+
sourceCounts,
|
|
141
|
+
inserted: asCount(raw.inserted),
|
|
142
|
+
updated: asCount(raw.updated),
|
|
143
|
+
unchanged: asCount(raw.unchanged),
|
|
144
|
+
labeled: asCount(raw.labeled),
|
|
145
|
+
model: asCount(raw.model),
|
|
146
|
+
fallback: asCount(raw.fallback),
|
|
147
|
+
verdict: asText(raw.verdict),
|
|
148
|
+
confidence: asText(raw.confidence),
|
|
149
|
+
factsPreview: asText(raw.factsPreview)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function count(value) {
|
|
153
|
+
return value === null ? "unavailable" : String(value);
|
|
154
|
+
}
|
|
155
|
+
function collectSummaryFacts(results, now) {
|
|
156
|
+
const summary = collectSummary(results);
|
|
157
|
+
const available = results.artifacts.filter((artifact) => artifact.availability === "available").length;
|
|
158
|
+
const facts = [
|
|
159
|
+
{
|
|
160
|
+
label: "Execution status",
|
|
161
|
+
value: summary.status ?? "unavailable",
|
|
162
|
+
availability: summary.status === null ? "unverified" : "available"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
label: "Result availability",
|
|
166
|
+
value: `${available}/${results.artifacts.length} artifacts available`,
|
|
167
|
+
availability: results.availability
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
label: "Started",
|
|
171
|
+
value: formatTimestamp(summary.startedAt),
|
|
172
|
+
availability: summary.startedAt === null ? "unverified" : "available"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
label: "Elapsed",
|
|
176
|
+
value: formatElapsed(summary.startedAt, now),
|
|
177
|
+
availability: summary.startedAt === null ? "unverified" : "available"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
label: "Inserted",
|
|
181
|
+
value: count(summary.inserted),
|
|
182
|
+
availability: summary.inserted === null ? "unverified" : "available"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
label: "Updated",
|
|
186
|
+
value: count(summary.updated),
|
|
187
|
+
availability: summary.updated === null ? "unverified" : "available"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
label: "Unchanged",
|
|
191
|
+
value: count(summary.unchanged),
|
|
192
|
+
availability: summary.unchanged === null ? "unverified" : "available"
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
label: "Labeled",
|
|
196
|
+
value: count(summary.labeled),
|
|
197
|
+
availability: summary.labeled === null ? "unverified" : "available"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
label: "Model labeled",
|
|
201
|
+
value: count(summary.model),
|
|
202
|
+
availability: summary.model === null ? "unverified" : "available"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
label: "Fallback labeled",
|
|
206
|
+
value: count(summary.fallback),
|
|
207
|
+
availability: summary.fallback === null ? "unverified" : "available"
|
|
208
|
+
}
|
|
209
|
+
];
|
|
210
|
+
if (summary.factsPreview !== null) {
|
|
211
|
+
const preview = truncatePreview(summary.factsPreview, PREVIEW_CHARS);
|
|
212
|
+
facts.push({
|
|
213
|
+
label: "Core facts",
|
|
214
|
+
value: preview.truncated ? `${preview.text} (truncated — the facts artifact holds the full text)` : preview.text,
|
|
215
|
+
availability: preview.truncated ? "oversized" : "available"
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (summary.verdict !== null) {
|
|
219
|
+
facts.push({
|
|
220
|
+
label: "Label verdict",
|
|
221
|
+
value: summary.confidence === null ? summary.verdict : `${summary.verdict} (${summary.confidence})`,
|
|
222
|
+
availability: "available"
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
for (const [file, sources] of Object.entries(summary.sourceCounts ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
|
|
226
|
+
facts.push({ label: `Source ${file}`, value: String(sources), availability: "available" });
|
|
227
|
+
}
|
|
228
|
+
return facts;
|
|
229
|
+
}
|
|
230
|
+
var PREVIEW_CHARS = 160;
|
|
231
|
+
function truncatePreview(text, max) {
|
|
232
|
+
const flat = text.replaceAll(/\s+/g, " ").trim();
|
|
233
|
+
if (flat === "")
|
|
234
|
+
return { text: "unavailable", truncated: false };
|
|
235
|
+
if (flat.length <= max)
|
|
236
|
+
return { text: flat, truncated: false };
|
|
237
|
+
return { text: `${flat.slice(0, max).trimEnd()}…`, truncated: true };
|
|
238
|
+
}
|
|
239
|
+
function timingOf(record) {
|
|
240
|
+
const durationMs = record.durationMs;
|
|
241
|
+
if (typeof durationMs === "number" && Number.isFinite(durationMs) && durationMs >= 0) {
|
|
242
|
+
return durationMs < 1000 ? `${Math.round(durationMs)}ms` : `${Math.round(durationMs / 1000)}s`;
|
|
243
|
+
}
|
|
244
|
+
const started = record.startedAt;
|
|
245
|
+
const completed = record.completedAt;
|
|
246
|
+
if (typeof started === "string" && typeof completed === "string")
|
|
247
|
+
return `${started} → ${completed}`;
|
|
248
|
+
return "timing unknown";
|
|
249
|
+
}
|
|
250
|
+
function operatorWaitOf(status, actions) {
|
|
251
|
+
const waitRe = /wait|pause|approv|hitl|question|escalat/i;
|
|
252
|
+
if (waitRe.test(status))
|
|
253
|
+
return true;
|
|
254
|
+
return actions.some((action) => {
|
|
255
|
+
if (typeof action !== "object" || action === null)
|
|
256
|
+
return false;
|
|
257
|
+
const key = action.actionKey;
|
|
258
|
+
return typeof key === "string" && waitRe.test(key);
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function progressRows(progress) {
|
|
262
|
+
if (typeof progress !== "object" || progress === null)
|
|
263
|
+
return [];
|
|
264
|
+
const states = progress.states;
|
|
265
|
+
if (!Array.isArray(states))
|
|
266
|
+
return [];
|
|
267
|
+
const rows = [];
|
|
268
|
+
for (const entry of states) {
|
|
269
|
+
if (typeof entry !== "object" || entry === null)
|
|
270
|
+
continue;
|
|
271
|
+
const record = entry;
|
|
272
|
+
if (typeof record.state !== "string")
|
|
273
|
+
continue;
|
|
274
|
+
const actions = Array.isArray(record.actions) ? record.actions : [];
|
|
275
|
+
rows.push({
|
|
276
|
+
state: record.state,
|
|
277
|
+
visit: typeof record.visit === "number" ? record.visit : 1,
|
|
278
|
+
status: typeof record.status === "string" ? record.status : "unknown",
|
|
279
|
+
timing: timingOf(record),
|
|
280
|
+
operatorWait: operatorWaitOf(typeof record.status === "string" ? record.status : "", actions),
|
|
281
|
+
actions: actions.map((action) => typeof action === "object" && action !== null ? `${String(action.actionKey ?? "action")} — ${String(action.status ?? "unknown")}` : null).filter((line) => line !== null)
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
return rows;
|
|
285
|
+
}
|
|
286
|
+
function artifactViews(results, readerOrigin) {
|
|
287
|
+
return results.artifacts.map((artifact) => ({
|
|
288
|
+
id: artifact.id,
|
|
289
|
+
label: artifact.label,
|
|
290
|
+
kind: artifact.kind,
|
|
291
|
+
availability: artifact.availability,
|
|
292
|
+
state: availabilityLabel(artifact.availability),
|
|
293
|
+
href: artifact.availability === "available" ? `${readerOrigin}/api/workflows/${results.workflow}/runs/${results.runId}/artifacts/${artifact.id}` : null
|
|
294
|
+
}));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ../board/src/shared/refresh.ts
|
|
298
|
+
var ACTIVE_POLL_MS = 5000;
|
|
299
|
+
var HISTORY_POLL_MS = 30000;
|
|
300
|
+
var MAX_BACKOFF_MS = 30000;
|
|
301
|
+
function initialRefresh(intervalMs) {
|
|
302
|
+
return { pending: false, failures: 0, backoffMs: intervalMs, lastSuccessAt: null, failingSince: null };
|
|
303
|
+
}
|
|
304
|
+
function tick(state) {
|
|
305
|
+
return state.pending ? state : { ...state, pending: true };
|
|
306
|
+
}
|
|
307
|
+
function succeeded(now, intervalMs) {
|
|
308
|
+
return { pending: false, failures: 0, backoffMs: intervalMs, lastSuccessAt: now, failingSince: null };
|
|
309
|
+
}
|
|
310
|
+
function failed(state, now) {
|
|
311
|
+
const failures = state.failures + 1;
|
|
312
|
+
return {
|
|
313
|
+
pending: false,
|
|
314
|
+
failures,
|
|
315
|
+
backoffMs: Math.min(state.backoffMs * 2, MAX_BACKOFF_MS),
|
|
316
|
+
lastSuccessAt: state.lastSuccessAt,
|
|
317
|
+
failingSince: state.failingSince ?? now
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function delayMs(state, intervalMs) {
|
|
321
|
+
return state.failures > 0 ? state.backoffMs : intervalMs;
|
|
322
|
+
}
|
|
323
|
+
function isStale(state) {
|
|
324
|
+
return state.failures > 0;
|
|
325
|
+
}
|
|
326
|
+
function freshnessLabel(state) {
|
|
327
|
+
if (state.lastSuccessAt === null)
|
|
328
|
+
return "Not yet loaded";
|
|
329
|
+
const updated = new Date(state.lastSuccessAt).toISOString();
|
|
330
|
+
return isStale(state) ? `Stale — last success ${updated}` : `Updated ${updated}`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ../board/src/shared/run-selection.ts
|
|
334
|
+
var BOARD_TABS = ["summary", "results", "progress", "config"];
|
|
335
|
+
function isBoardTab(value) {
|
|
336
|
+
return value !== null && value !== undefined && BOARD_TABS.includes(value);
|
|
337
|
+
}
|
|
338
|
+
function parseDeepLink(search) {
|
|
339
|
+
const params = new URLSearchParams(search.startsWith("?") ? search.slice(1) : search);
|
|
340
|
+
const diagnostics = [];
|
|
341
|
+
const rawTab = params.get("tab");
|
|
342
|
+
const rawRun = params.get("run");
|
|
343
|
+
let tab;
|
|
344
|
+
if (rawTab !== null) {
|
|
345
|
+
if (isBoardTab(rawTab)) {
|
|
346
|
+
tab = rawTab;
|
|
347
|
+
} else {
|
|
348
|
+
diagnostics.push({
|
|
349
|
+
code: "board.deeplink.unknown-tab",
|
|
350
|
+
message: `Unknown tab '${rawTab}'; showing Summary.`
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
let runId;
|
|
355
|
+
if (rawRun !== null) {
|
|
356
|
+
if (rawRun === "") {
|
|
357
|
+
diagnostics.push({ code: "board.deeplink.empty-run", message: "Empty run id ignored." });
|
|
358
|
+
} else {
|
|
359
|
+
runId = rawRun;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return { ...runId === undefined ? {} : { runId }, ...tab === undefined ? {} : { tab }, diagnostics };
|
|
363
|
+
}
|
|
364
|
+
function resolveSelection(rows, link) {
|
|
365
|
+
const tab = link.tab ?? "summary";
|
|
366
|
+
const diagnostics = [...link.diagnostics];
|
|
367
|
+
if (link.runId !== undefined) {
|
|
368
|
+
if (rows.some((row) => row.id === link.runId)) {
|
|
369
|
+
return { runId: link.runId, tab, diagnostics };
|
|
370
|
+
}
|
|
371
|
+
diagnostics.push({
|
|
372
|
+
code: "board.selection.unknown-run",
|
|
373
|
+
message: `Run '${link.runId}' is not in the loaded history; select a run.`
|
|
374
|
+
});
|
|
375
|
+
return { runId: null, tab, diagnostics };
|
|
376
|
+
}
|
|
377
|
+
return { runId: rows[0]?.id ?? null, tab, diagnostics };
|
|
378
|
+
}
|
|
379
|
+
function selectionQuery(selection, search = "") {
|
|
380
|
+
const params = new URLSearchParams;
|
|
381
|
+
if (selection.runId !== null)
|
|
382
|
+
params.set("run", selection.runId);
|
|
383
|
+
params.set("tab", selection.tab);
|
|
384
|
+
for (const [key, value] of new URLSearchParams(search)) {
|
|
385
|
+
if (key === "run" || key === "tab")
|
|
386
|
+
continue;
|
|
387
|
+
params.set(key, value);
|
|
388
|
+
}
|
|
389
|
+
return `?${params.toString()}`;
|
|
390
|
+
}
|
|
391
|
+
var COLLECT_MODULE_PATH = "/board/modules/kk-collect";
|
|
392
|
+
function selectionPath(selection, search = "", modulePath = COLLECT_MODULE_PATH) {
|
|
393
|
+
return `${modulePath}${selectionQuery(selection, search)}`;
|
|
394
|
+
}
|
|
395
|
+
function syncSelectionUrl(selection, target, modulePath = COLLECT_MODULE_PATH) {
|
|
396
|
+
if (target.location.pathname !== modulePath)
|
|
397
|
+
return;
|
|
398
|
+
const url = selectionPath(selection, target.location.search, modulePath);
|
|
399
|
+
if (`${target.location.pathname}${target.location.search}` === url)
|
|
400
|
+
return;
|
|
401
|
+
target.history.replaceState(target.history.state, "", url);
|
|
402
|
+
}
|
|
403
|
+
function mergeRunPages(existing, page) {
|
|
404
|
+
const seen = new Set(existing.map((row) => row.id));
|
|
405
|
+
const merged = [...existing, ...page.runs.filter((row) => !seen.has(row.id))];
|
|
406
|
+
return { runs: merged, count: merged.length, nextCursor: page.nextCursor, hasMore: page.hasMore };
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// ../board/src/collect/index.tsx
|
|
410
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
411
|
+
var TAB_LABELS = {
|
|
412
|
+
summary: "Summary",
|
|
413
|
+
results: "Results",
|
|
414
|
+
progress: "Execution progress",
|
|
415
|
+
config: "Workflow Config Summary"
|
|
416
|
+
};
|
|
417
|
+
function messageOf(error) {
|
|
418
|
+
return error instanceof Error ? error.message : String(error);
|
|
419
|
+
}
|
|
420
|
+
function usePolling(loader, intervalMs, refresh) {
|
|
421
|
+
const loaderRef = useRef(loader);
|
|
422
|
+
loaderRef.current = loader;
|
|
423
|
+
const refreshRef = useRef(refresh);
|
|
424
|
+
refreshRef.current = refresh;
|
|
425
|
+
useEffect(() => {
|
|
426
|
+
let cancelled = false;
|
|
427
|
+
let timer;
|
|
428
|
+
const loop = async () => {
|
|
429
|
+
if (!document.hidden) {
|
|
430
|
+
await loaderRef.current();
|
|
431
|
+
}
|
|
432
|
+
if (!cancelled)
|
|
433
|
+
timer = setTimeout(() => void loop(), delayMs(refreshRef.current, intervalMs));
|
|
434
|
+
};
|
|
435
|
+
loop();
|
|
436
|
+
return () => {
|
|
437
|
+
cancelled = true;
|
|
438
|
+
clearTimeout(timer);
|
|
439
|
+
};
|
|
440
|
+
}, [intervalMs]);
|
|
441
|
+
}
|
|
442
|
+
function CollectModule() {
|
|
443
|
+
const [link] = useState(() => parseDeepLink(window.location.search));
|
|
444
|
+
const [reader] = useState(() => readerOriginFrom(window.location.search));
|
|
445
|
+
const readerOrigin = reader.origin;
|
|
446
|
+
const client = useMemo(() => createBoardClient({ readerOrigin, boardOrigin: window.location.origin }), [readerOrigin]);
|
|
447
|
+
const [rows, setRows] = useState([]);
|
|
448
|
+
const [cursor, setCursor] = useState(null);
|
|
449
|
+
const [selection, setSelection] = useState({ runId: link.runId ?? null, tab: link.tab ?? "summary" });
|
|
450
|
+
const [diagnostics, setDiagnostics] = useState(() => [
|
|
451
|
+
...link.diagnostics,
|
|
452
|
+
...reader.diagnostic === null ? [] : [reader.diagnostic]
|
|
453
|
+
]);
|
|
454
|
+
const [historyRefresh, setHistoryRefresh] = useState(() => initialRefresh(HISTORY_POLL_MS));
|
|
455
|
+
const [readerRefresh, setReaderRefresh] = useState(() => initialRefresh(ACTIVE_POLL_MS));
|
|
456
|
+
const [results, setResults] = useState(null);
|
|
457
|
+
const [config, setConfig] = useState(null);
|
|
458
|
+
const [progress, setProgress] = useState(null);
|
|
459
|
+
const historyBusy = useRef(false);
|
|
460
|
+
const readerBusy = useRef(false);
|
|
461
|
+
const loadHistory = useCallback(async () => {
|
|
462
|
+
if (historyBusy.current)
|
|
463
|
+
return;
|
|
464
|
+
historyBusy.current = true;
|
|
465
|
+
setHistoryRefresh((state) => tick(state));
|
|
466
|
+
try {
|
|
467
|
+
const page = await client.runs("kk-collect");
|
|
468
|
+
setRows((existing) => mergeRunPages(existing, page).runs);
|
|
469
|
+
setCursor(page.nextCursor);
|
|
470
|
+
setHistoryRefresh(() => succeeded(Date.now(), HISTORY_POLL_MS));
|
|
471
|
+
} catch (error) {
|
|
472
|
+
setDiagnostics((existing) => [
|
|
473
|
+
...existing,
|
|
474
|
+
{ code: "board.history.unavailable", message: messageOf(error) }
|
|
475
|
+
]);
|
|
476
|
+
setHistoryRefresh((state) => failed(state, Date.now()));
|
|
477
|
+
} finally {
|
|
478
|
+
historyBusy.current = false;
|
|
479
|
+
}
|
|
480
|
+
}, [client]);
|
|
481
|
+
const loadReader = useCallback(async () => {
|
|
482
|
+
if (readerBusy.current)
|
|
483
|
+
return;
|
|
484
|
+
const runId = selectionRef.current.runId;
|
|
485
|
+
if (runId === null)
|
|
486
|
+
return;
|
|
487
|
+
readerBusy.current = true;
|
|
488
|
+
setReaderRefresh((state) => tick(state));
|
|
489
|
+
try {
|
|
490
|
+
const [nextResults, nextConfig] = await Promise.all([
|
|
491
|
+
client.results("kk-collect", runId),
|
|
492
|
+
client.config("kk-collect", runId)
|
|
493
|
+
]);
|
|
494
|
+
setResults(nextResults);
|
|
495
|
+
setConfig(nextConfig);
|
|
496
|
+
setReaderRefresh(() => succeeded(Date.now(), ACTIVE_POLL_MS));
|
|
497
|
+
} catch (error) {
|
|
498
|
+
setDiagnostics((existing) => [
|
|
499
|
+
...existing,
|
|
500
|
+
{ code: "board.reader.unavailable", message: messageOf(error) }
|
|
501
|
+
]);
|
|
502
|
+
setReaderRefresh((state) => failed(state, Date.now()));
|
|
503
|
+
} finally {
|
|
504
|
+
readerBusy.current = false;
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
setProgress(await client.progress(runId));
|
|
508
|
+
} catch {}
|
|
509
|
+
}, [client]);
|
|
510
|
+
const selectionRef = useRef(selection);
|
|
511
|
+
selectionRef.current = selection;
|
|
512
|
+
usePolling(loadHistory, HISTORY_POLL_MS, historyRefresh);
|
|
513
|
+
usePolling(loadReader, ACTIVE_POLL_MS, readerRefresh);
|
|
514
|
+
useEffect(() => {
|
|
515
|
+
if (selection.runId === null && rows.length > 0) {
|
|
516
|
+
setSelection((state) => state.runId === null ? resolveSelection(rows, link) : state);
|
|
517
|
+
}
|
|
518
|
+
}, [rows, selection.runId, link]);
|
|
519
|
+
useEffect(() => {
|
|
520
|
+
syncSelectionUrl(selection, { location: window.location, history: window.history });
|
|
521
|
+
}, [selection]);
|
|
522
|
+
const tab = selection.tab;
|
|
523
|
+
const now = Date.now();
|
|
524
|
+
const facts = results === null ? [] : collectSummaryFacts(results, now);
|
|
525
|
+
const artifacts = results === null ? [] : artifactViews(results, readerOrigin);
|
|
526
|
+
const steps = progressRows(progress);
|
|
527
|
+
const selectedRow = rows.find((row) => row.id === selection.runId);
|
|
528
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
529
|
+
className: "kk-board kk-board-collect",
|
|
530
|
+
children: [
|
|
531
|
+
/* @__PURE__ */ jsxs("header", {
|
|
532
|
+
className: "kk-board-header",
|
|
533
|
+
children: [
|
|
534
|
+
/* @__PURE__ */ jsx("h1", {
|
|
535
|
+
children: "Collect"
|
|
536
|
+
}),
|
|
537
|
+
/* @__PURE__ */ jsxs("p", {
|
|
538
|
+
children: [
|
|
539
|
+
"Run ",
|
|
540
|
+
/* @__PURE__ */ jsx("code", {
|
|
541
|
+
children: selection.runId ?? "none selected"
|
|
542
|
+
}),
|
|
543
|
+
" · ",
|
|
544
|
+
selectedRow?.status ?? "status unknown",
|
|
545
|
+
" ·",
|
|
546
|
+
" ",
|
|
547
|
+
freshnessLabel(readerRefresh)
|
|
548
|
+
]
|
|
549
|
+
}),
|
|
550
|
+
results === null ? null : /* @__PURE__ */ jsxs("p", {
|
|
551
|
+
children: [
|
|
552
|
+
"Results ",
|
|
553
|
+
results.availability
|
|
554
|
+
]
|
|
555
|
+
}),
|
|
556
|
+
/* @__PURE__ */ jsx("button", {
|
|
557
|
+
type: "button",
|
|
558
|
+
onClick: () => void loadReader(),
|
|
559
|
+
children: "Refresh"
|
|
560
|
+
}),
|
|
561
|
+
selection.runId === null ? null : /* @__PURE__ */ jsx("a", {
|
|
562
|
+
href: selectionPath(selection, window.location.search),
|
|
563
|
+
children: "Permanent link to this view"
|
|
564
|
+
})
|
|
565
|
+
]
|
|
566
|
+
}),
|
|
567
|
+
/* @__PURE__ */ jsx("nav", {
|
|
568
|
+
className: "kk-board-tabs",
|
|
569
|
+
"aria-label": "Collect tabs",
|
|
570
|
+
children: BOARD_TABS.map((candidate) => /* @__PURE__ */ jsx("button", {
|
|
571
|
+
type: "button",
|
|
572
|
+
"aria-current": candidate === tab ? "page" : undefined,
|
|
573
|
+
onClick: () => setSelection((state) => ({ ...state, tab: candidate })),
|
|
574
|
+
children: TAB_LABELS[candidate]
|
|
575
|
+
}, candidate))
|
|
576
|
+
}),
|
|
577
|
+
/* @__PURE__ */ jsxs("label", {
|
|
578
|
+
className: "kk-board-run-selector",
|
|
579
|
+
children: [
|
|
580
|
+
"Run",
|
|
581
|
+
/* @__PURE__ */ jsxs("select", {
|
|
582
|
+
value: selection.runId ?? "",
|
|
583
|
+
onChange: (event) => setSelection((state) => ({ ...state, runId: event.target.value || null })),
|
|
584
|
+
children: [
|
|
585
|
+
/* @__PURE__ */ jsx("option", {
|
|
586
|
+
value: "",
|
|
587
|
+
children: rows.length === 0 ? "No runs recorded" : "Select a run"
|
|
588
|
+
}),
|
|
589
|
+
rows.map((row) => /* @__PURE__ */ jsxs("option", {
|
|
590
|
+
value: row.id,
|
|
591
|
+
children: [
|
|
592
|
+
row.id,
|
|
593
|
+
" — ",
|
|
594
|
+
row.status
|
|
595
|
+
]
|
|
596
|
+
}, row.id))
|
|
597
|
+
]
|
|
598
|
+
})
|
|
599
|
+
]
|
|
600
|
+
}),
|
|
601
|
+
rows.length === 0 ? /* @__PURE__ */ jsxs("p", {
|
|
602
|
+
className: "kk-board-empty",
|
|
603
|
+
children: [
|
|
604
|
+
"No runs recorded for kk-collect. Configure the workflow in",
|
|
605
|
+
" ",
|
|
606
|
+
/* @__PURE__ */ jsx("a", {
|
|
607
|
+
href: "/board/settings/workflows",
|
|
608
|
+
children: "Settings → Workflows"
|
|
609
|
+
}),
|
|
610
|
+
"."
|
|
611
|
+
]
|
|
612
|
+
}) : null,
|
|
613
|
+
tab === "summary" ? /* @__PURE__ */ jsx(SummaryPanel, {
|
|
614
|
+
facts,
|
|
615
|
+
results
|
|
616
|
+
}) : null,
|
|
617
|
+
tab === "results" ? /* @__PURE__ */ jsx(ResultsPanel, {
|
|
618
|
+
artifacts
|
|
619
|
+
}) : null,
|
|
620
|
+
tab === "progress" ? /* @__PURE__ */ jsx(ProgressPanel, {
|
|
621
|
+
steps
|
|
622
|
+
}) : null,
|
|
623
|
+
tab === "config" ? /* @__PURE__ */ jsx(ConfigPanel, {
|
|
624
|
+
config
|
|
625
|
+
}) : null,
|
|
626
|
+
dedupeDiagnostics([...diagnostics, ...results?.diagnostics ?? []]).map((diagnostic) => /* @__PURE__ */ jsx("p", {
|
|
627
|
+
role: "status",
|
|
628
|
+
className: "kk-board-diagnostic",
|
|
629
|
+
children: diagnosticLine(diagnostic)
|
|
630
|
+
}, diagnostic.code)),
|
|
631
|
+
cursor === null ? null : /* @__PURE__ */ jsx("button", {
|
|
632
|
+
type: "button",
|
|
633
|
+
onClick: () => void loadHistory(),
|
|
634
|
+
children: "Load more runs"
|
|
635
|
+
}),
|
|
636
|
+
/* @__PURE__ */ jsxs("p", {
|
|
637
|
+
className: "kk-board-footnote",
|
|
638
|
+
children: [
|
|
639
|
+
"Run history every ",
|
|
640
|
+
HISTORY_POLL_MS / 1000,
|
|
641
|
+
"s; selected run every ",
|
|
642
|
+
ACTIVE_POLL_MS / 1000,
|
|
643
|
+
"s."
|
|
644
|
+
]
|
|
645
|
+
})
|
|
646
|
+
]
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
function SummaryPanel({
|
|
650
|
+
facts,
|
|
651
|
+
results
|
|
652
|
+
}) {
|
|
653
|
+
if (results === null)
|
|
654
|
+
return /* @__PURE__ */ jsx("p", {
|
|
655
|
+
children: "No captured results for the selected run."
|
|
656
|
+
});
|
|
657
|
+
return /* @__PURE__ */ jsx("dl", {
|
|
658
|
+
className: "kk-board-facts",
|
|
659
|
+
children: facts.map((fact) => /* @__PURE__ */ jsxs("div", {
|
|
660
|
+
children: [
|
|
661
|
+
/* @__PURE__ */ jsx("dt", {
|
|
662
|
+
children: fact.label
|
|
663
|
+
}),
|
|
664
|
+
/* @__PURE__ */ jsxs("dd", {
|
|
665
|
+
children: [
|
|
666
|
+
fact.value,
|
|
667
|
+
" ",
|
|
668
|
+
/* @__PURE__ */ jsx("span", {
|
|
669
|
+
className: "kk-board-state",
|
|
670
|
+
children: fact.availability
|
|
671
|
+
})
|
|
672
|
+
]
|
|
673
|
+
})
|
|
674
|
+
]
|
|
675
|
+
}, fact.label))
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
function ResultsPanel({ artifacts }) {
|
|
679
|
+
if (artifacts.length === 0)
|
|
680
|
+
return /* @__PURE__ */ jsx("p", {
|
|
681
|
+
children: "No artifact evidence for the selected run."
|
|
682
|
+
});
|
|
683
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
684
|
+
className: "kk-board-artifacts",
|
|
685
|
+
children: artifacts.map((artifact) => /* @__PURE__ */ jsx("li", {
|
|
686
|
+
children: artifact.href === null ? /* @__PURE__ */ jsxs("span", {
|
|
687
|
+
children: [
|
|
688
|
+
artifact.label,
|
|
689
|
+
" — ",
|
|
690
|
+
artifact.state
|
|
691
|
+
]
|
|
692
|
+
}) : /* @__PURE__ */ jsxs("a", {
|
|
693
|
+
href: artifact.href,
|
|
694
|
+
children: [
|
|
695
|
+
artifact.label,
|
|
696
|
+
" — ",
|
|
697
|
+
artifact.state
|
|
698
|
+
]
|
|
699
|
+
})
|
|
700
|
+
}, artifact.id))
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
function ProgressPanel({ steps }) {
|
|
704
|
+
if (steps.length === 0)
|
|
705
|
+
return /* @__PURE__ */ jsx("p", {
|
|
706
|
+
children: "Recorded progress is unavailable for the selected run."
|
|
707
|
+
});
|
|
708
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
709
|
+
className: "kk-board-progress",
|
|
710
|
+
children: steps.map((step) => /* @__PURE__ */ jsxs("li", {
|
|
711
|
+
children: [
|
|
712
|
+
/* @__PURE__ */ jsx("strong", {
|
|
713
|
+
children: step.state
|
|
714
|
+
}),
|
|
715
|
+
" visit ",
|
|
716
|
+
step.visit,
|
|
717
|
+
" — ",
|
|
718
|
+
step.status,
|
|
719
|
+
" · ",
|
|
720
|
+
step.timing,
|
|
721
|
+
step.operatorWait ? /* @__PURE__ */ jsx("span", {
|
|
722
|
+
className: "kk-board-state",
|
|
723
|
+
children: " operator wait"
|
|
724
|
+
}) : null,
|
|
725
|
+
step.actions.length === 0 ? null : /* @__PURE__ */ jsx("ul", {
|
|
726
|
+
children: step.actions.map((action) => /* @__PURE__ */ jsx("li", {
|
|
727
|
+
children: action
|
|
728
|
+
}, action))
|
|
729
|
+
})
|
|
730
|
+
]
|
|
731
|
+
}, `${step.state}-${step.visit}`))
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
function ConfigPanel({ config }) {
|
|
735
|
+
if (config === null)
|
|
736
|
+
return /* @__PURE__ */ jsx("p", {
|
|
737
|
+
children: "No captured configuration for the selected run."
|
|
738
|
+
});
|
|
739
|
+
const entries = Object.entries(config.settings);
|
|
740
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
741
|
+
className: "kk-board-config",
|
|
742
|
+
children: [
|
|
743
|
+
/* @__PURE__ */ jsxs("p", {
|
|
744
|
+
children: [
|
|
745
|
+
"Captured ",
|
|
746
|
+
formatTimestamp(config.capturedAt)
|
|
747
|
+
]
|
|
748
|
+
}),
|
|
749
|
+
entries.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
750
|
+
children: "Recorded configuration unavailable for this run."
|
|
751
|
+
}) : null,
|
|
752
|
+
/* @__PURE__ */ jsx("dl", {
|
|
753
|
+
children: entries.map(([key, value]) => /* @__PURE__ */ jsxs("div", {
|
|
754
|
+
children: [
|
|
755
|
+
/* @__PURE__ */ jsx("dt", {
|
|
756
|
+
children: key
|
|
757
|
+
}),
|
|
758
|
+
/* @__PURE__ */ jsx("dd", {
|
|
759
|
+
children: value
|
|
760
|
+
})
|
|
761
|
+
]
|
|
762
|
+
}, key))
|
|
763
|
+
}),
|
|
764
|
+
config.unavailableKeys.length === 0 ? null : /* @__PURE__ */ jsxs("p", {
|
|
765
|
+
children: [
|
|
766
|
+
"Uncaptured keys: ",
|
|
767
|
+
config.unavailableKeys.join(", ")
|
|
768
|
+
]
|
|
769
|
+
}),
|
|
770
|
+
/* @__PURE__ */ jsxs("p", {
|
|
771
|
+
children: [
|
|
772
|
+
"Current definitions and defaults live in ",
|
|
773
|
+
/* @__PURE__ */ jsx("a", {
|
|
774
|
+
href: "/board/settings/workflows",
|
|
775
|
+
children: "Settings → Workflows"
|
|
776
|
+
}),
|
|
777
|
+
"."
|
|
778
|
+
]
|
|
779
|
+
})
|
|
780
|
+
]
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
var webModule = { apiVersion: 1, component: CollectModule };
|
|
784
|
+
export {
|
|
785
|
+
CollectModule,
|
|
786
|
+
webModule
|
|
787
|
+
};
|