tubeless 0.2.2 → 0.2.3
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/README.md +5 -5
- package/dist/core/child-execution.js +8 -1
- package/dist/core/child-execution.js.map +1 -1
- package/dist/core/lifecycle.js +2 -0
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/pipeline-execute.d.ts +2 -0
- package/dist/core/pipeline-execute.js +132 -395
- package/dist/core/pipeline-execute.js.map +1 -1
- package/dist/core/pipeline-plan.js +96 -34
- package/dist/core/pipeline-plan.js.map +1 -1
- package/dist/core/pipeline-run-state.d.ts +49 -0
- package/dist/core/pipeline-run-state.js +284 -0
- package/dist/core/pipeline-run-state.js.map +1 -0
- package/dist/core/pipeline-step-executor.d.ts +20 -0
- package/dist/core/pipeline-step-executor.js +52 -0
- package/dist/core/pipeline-step-executor.js.map +1 -0
- package/dist/core/pipeline-types.d.ts +11 -2
- package/dist/core/pipeline-types.js.map +1 -1
- package/dist/core/pipeline-validation.d.ts +6 -0
- package/dist/core/pipeline-validation.js +41 -0
- package/dist/core/pipeline-validation.js.map +1 -0
- package/dist/run-store/run-store-ndjson.js +2 -295
- package/dist/run-store/run-store-ndjson.js.map +1 -1
- package/dist/run-store/run-store-sqlite.js +91 -42
- package/dist/run-store/run-store-sqlite.js.map +1 -1
- package/dist/run-store/run-store.d.ts +3 -2
- package/dist/run-store/run-store.js +38 -195
- package/dist/run-store/run-store.js.map +1 -1
- package/dist/studio/run-store-ui-client-controller.d.ts +9 -0
- package/dist/studio/run-store-ui-client-controller.js +479 -0
- package/dist/studio/run-store-ui-client-controller.js.map +1 -0
- package/dist/studio/run-store-ui-client-form.d.ts +9 -0
- package/dist/studio/run-store-ui-client-form.js +44 -0
- package/dist/studio/run-store-ui-client-form.js.map +1 -0
- package/dist/studio/run-store-ui-client-model.d.ts +40 -0
- package/dist/studio/run-store-ui-client-model.js +211 -0
- package/dist/studio/run-store-ui-client-model.js.map +1 -0
- package/dist/studio/run-store-ui-client-source.js +1 -1
- package/dist/studio/run-store-ui-client-transport.d.ts +25 -0
- package/dist/studio/run-store-ui-client-transport.js +322 -0
- package/dist/studio/run-store-ui-client-transport.js.map +1 -0
- package/dist/studio/run-store-ui-client-views.d.ts +24 -0
- package/dist/studio/run-store-ui-client-views.js +676 -0
- package/dist/studio/run-store-ui-client-views.js.map +1 -0
- package/dist/studio/run-store-ui-client.d.ts +2 -14
- package/dist/studio/run-store-ui-client.js +7 -1360
- package/dist/studio/run-store-ui-client.js.map +1 -1
- package/dist/studio/run-store-ui-page.d.ts +1 -1
- package/dist/studio/run-store-ui.js +44 -25
- package/dist/studio/run-store-ui.js.map +1 -1
- package/dist/tracing/tracing-codec.d.ts +6 -0
- package/dist/tracing/tracing-codec.js +829 -0
- package/dist/tracing/tracing-codec.js.map +1 -0
- package/dist/tracing/tracing-constants.d.ts +4 -0
- package/dist/tracing/tracing-constants.js +5 -0
- package/dist/tracing/tracing-constants.js.map +1 -0
- package/dist/tracing/tracing-internal.js +116 -81
- package/dist/tracing/tracing-internal.js.map +1 -1
- package/dist/tracing/tracing-otel.js +19 -3
- package/dist/tracing/tracing-otel.js.map +1 -1
- package/dist/tracing/tracing.d.ts +149 -10
- package/dist/tracing/tracing.js.map +1 -1
- package/dist/workbench/workbench-history.js +8 -1
- package/dist/workbench/workbench-history.js.map +1 -1
- package/dist/workbench/workbench-ui.js +26 -6
- package/dist/workbench/workbench-ui.js.map +1 -1
- package/docs/README.md +21 -15
- package/docs/agent-guide.md +48 -35
- package/docs/agent-skills.md +59 -0
- package/docs/api-reference.md +28 -12
- package/docs/api-report.json +29 -13
- package/docs/child-pipeline-composition.md +142 -193
- package/docs/cli.md +83 -61
- package/docs/comparison.md +63 -62
- package/docs/concepts.md +210 -272
- package/docs/getting-started.md +59 -48
- package/docs/llms.txt +7 -4
- package/docs/recipes.md +21 -18
- package/docs/remote-step-composition.md +69 -74
- package/docs/studio.md +146 -71
- package/examples/catalog/pipelines/enrich.ts +2 -2
- package/examples/catalog/tubeless.project.ts +4 -2
- package/examples/host-embedding.ts +4 -5
- package/examples/remote-steps.ts +8 -5
- package/package.json +11 -10
- package/skills/tubeless/SKILL.md +83 -0
- package/skills/tubeless-make-pipeline/SKILL.md +126 -0
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
import { createStudioRunIndex } from "./run-store-ui-client-model.js";
|
|
2
|
+
import { serializeLaunchValues, serializePlanInput } from "./run-store-ui-client-form.js";
|
|
3
|
+
import { createStudioApi } from "./run-store-ui-client-transport.js";
|
|
4
|
+
import { commandDescription as describeCommand, escapeHtml, renderCommandFormFields, renderMetrics, renderPipelinesView, renderPlanView, renderRunsView, shortId as abbreviateId, } from "./run-store-ui-client-views.js";
|
|
5
|
+
function selectedRunFingerprint(state) {
|
|
6
|
+
const run = state.runIndex.runById(state.selectedRunId);
|
|
7
|
+
return run ? [run.runId, run.eventCount, run.status].join(":") : null;
|
|
8
|
+
}
|
|
9
|
+
/** Refresh selected-run detail without allowing its optional endpoint to fail snapshot polling. */
|
|
10
|
+
export async function loadSelectedRunDetail(state, loadRunDetail) {
|
|
11
|
+
if (!state.selectedRunId) {
|
|
12
|
+
state.detail = null;
|
|
13
|
+
state.detailFingerprint = null;
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const requestedRunId = state.selectedRunId;
|
|
17
|
+
const fingerprint = selectedRunFingerprint(state);
|
|
18
|
+
if (!fingerprint) {
|
|
19
|
+
state.detail = null;
|
|
20
|
+
state.detailFingerprint = null;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (fingerprint === state.detailFingerprint && state.detail)
|
|
24
|
+
return;
|
|
25
|
+
let detail;
|
|
26
|
+
try {
|
|
27
|
+
detail = await loadRunDetail(requestedRunId);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
/* Detail is optional; retain the last successful detail and snapshot connection state. */
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (state.selectedRunId !== requestedRunId)
|
|
34
|
+
return;
|
|
35
|
+
if (!detail) {
|
|
36
|
+
state.detail = null;
|
|
37
|
+
state.detailFingerprint = null;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
state.detail = detail;
|
|
41
|
+
state.detailFingerprint = fingerprint;
|
|
42
|
+
}
|
|
43
|
+
/** DOM event and polling controller for one Studio client state instance. */
|
|
44
|
+
export function createStudioController(state) {
|
|
45
|
+
const api = createStudioApi();
|
|
46
|
+
const $ = (selector) => {
|
|
47
|
+
const node = document.querySelector(selector);
|
|
48
|
+
if (!(node instanceof HTMLElement))
|
|
49
|
+
throw new Error("Missing " + selector);
|
|
50
|
+
// SAFETY: Studio markup uses HTML elements that expose value/checked/disabled.
|
|
51
|
+
return node;
|
|
52
|
+
};
|
|
53
|
+
const nodes = (selector) => Array.from(document.querySelectorAll(selector), (node) => {
|
|
54
|
+
// SAFETY: Studio event selectors only match HTML elements on this page.
|
|
55
|
+
return node;
|
|
56
|
+
});
|
|
57
|
+
const queryNode = (selector) => {
|
|
58
|
+
const node = document.querySelector(selector);
|
|
59
|
+
if (!(node instanceof HTMLElement))
|
|
60
|
+
return null;
|
|
61
|
+
// SAFETY: Parameter controls in the launch form are HTML inputs, selects, or textareas.
|
|
62
|
+
return node;
|
|
63
|
+
};
|
|
64
|
+
function setConnected(connected) {
|
|
65
|
+
$("#connectionLabel").textContent = connected ? "Connected · local" : "Connection lost";
|
|
66
|
+
$(".pulse").classList.toggle("lost", !connected);
|
|
67
|
+
}
|
|
68
|
+
function selectedCommand() {
|
|
69
|
+
return state.commands.find((command) => command.id === $("#launchCommand").value);
|
|
70
|
+
}
|
|
71
|
+
function bindExclusiveSelections(command, scope) {
|
|
72
|
+
const fields = command.parameters.flatMap((parameter, index) => {
|
|
73
|
+
if (!parameter.exclusive || !parameter.multiple)
|
|
74
|
+
return [];
|
|
75
|
+
const field = queryNode("[data-" + scope + '-parameter-index="' + index + '"]');
|
|
76
|
+
return field ? [field] : [];
|
|
77
|
+
});
|
|
78
|
+
const clear = (field) => {
|
|
79
|
+
if (field.tagName === "SELECT")
|
|
80
|
+
Array.from(field.options).forEach((option) => {
|
|
81
|
+
option.selected = false;
|
|
82
|
+
});
|
|
83
|
+
else
|
|
84
|
+
field.value = "";
|
|
85
|
+
};
|
|
86
|
+
fields.forEach((field) => {
|
|
87
|
+
field.addEventListener("change", () => {
|
|
88
|
+
if (field.selectedOptions?.length || field.value) {
|
|
89
|
+
fields.forEach((other) => {
|
|
90
|
+
if (other !== field)
|
|
91
|
+
clear(other);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function renderCommandForm() {
|
|
98
|
+
const command = selectedCommand();
|
|
99
|
+
$("#launchTitle").textContent = command?.name || "Run a pipeline";
|
|
100
|
+
$("#launchDescription").textContent = command
|
|
101
|
+
? describeCommand(command)
|
|
102
|
+
: "Choose a declared pipeline and provide its inputs.";
|
|
103
|
+
if (!command) {
|
|
104
|
+
$("#parameterFields").innerHTML = "";
|
|
105
|
+
$("#previewPlan").classList.add("hidden");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
$("#parameterFields").innerHTML = renderCommandFormFields(command);
|
|
109
|
+
bindExclusiveSelections(command, "run");
|
|
110
|
+
$("#previewPlan").classList.toggle("hidden", !command.canPlan);
|
|
111
|
+
invalidatePlan();
|
|
112
|
+
}
|
|
113
|
+
function parameterValues(parameter, index, scope) {
|
|
114
|
+
const control = queryNode("[data-" + scope + '-parameter-index="' + index + '"]');
|
|
115
|
+
if (!control)
|
|
116
|
+
return [];
|
|
117
|
+
if (parameter.type === "boolean")
|
|
118
|
+
return [control.checked];
|
|
119
|
+
const rawValues = parameter.multiple
|
|
120
|
+
? control.tagName === "SELECT"
|
|
121
|
+
? Array.from(control.selectedOptions).map((option) => option.value)
|
|
122
|
+
: control.value
|
|
123
|
+
.split(/\r?\n/)
|
|
124
|
+
.map((value) => value.trim())
|
|
125
|
+
.filter(Boolean)
|
|
126
|
+
: [control.value];
|
|
127
|
+
return parameter.type === "number"
|
|
128
|
+
? rawValues.map((value) => (value === "" ? value : Number(value)))
|
|
129
|
+
: rawValues;
|
|
130
|
+
}
|
|
131
|
+
function parameterLaunchValues(command) {
|
|
132
|
+
return serializeLaunchValues(command, (parameter, index) => parameterValues(parameter, index, "run"));
|
|
133
|
+
}
|
|
134
|
+
function currentPlanInput(command) {
|
|
135
|
+
return serializePlanInput(command, (parameter, index) => parameterValues(parameter, index, "run"));
|
|
136
|
+
}
|
|
137
|
+
function invalidatePlan() {
|
|
138
|
+
state.planVersion += 1;
|
|
139
|
+
$("#planResult").classList.add("hidden");
|
|
140
|
+
$("#planResult").innerHTML = "";
|
|
141
|
+
}
|
|
142
|
+
function showLaunchError(message) {
|
|
143
|
+
$("#launchError").textContent = message;
|
|
144
|
+
$("#launchError").classList.toggle("hidden", !message);
|
|
145
|
+
}
|
|
146
|
+
function closeLaunch() {
|
|
147
|
+
if (state.launching || state.planning)
|
|
148
|
+
return;
|
|
149
|
+
$("#launchModal").classList.add("hidden");
|
|
150
|
+
showLaunchError("");
|
|
151
|
+
}
|
|
152
|
+
function openLaunch(commandId) {
|
|
153
|
+
if (commandId)
|
|
154
|
+
$("#launchCommand").value = commandId;
|
|
155
|
+
$("#launchModal").classList.remove("hidden");
|
|
156
|
+
renderCommandForm();
|
|
157
|
+
const firstField = $("#parameterFields").querySelector("input, select, textarea");
|
|
158
|
+
if (firstField instanceof HTMLElement)
|
|
159
|
+
firstField.focus();
|
|
160
|
+
}
|
|
161
|
+
function showToast(message) {
|
|
162
|
+
const toast = $("#toast");
|
|
163
|
+
toast.textContent = message;
|
|
164
|
+
toast.classList.remove("hidden");
|
|
165
|
+
setTimeout(() => toast.classList.add("hidden"), 4200);
|
|
166
|
+
}
|
|
167
|
+
function showClearHistoryError(message) {
|
|
168
|
+
$("#clearHistoryError").textContent = message;
|
|
169
|
+
$("#clearHistoryError").classList.toggle("hidden", !message);
|
|
170
|
+
}
|
|
171
|
+
function closeClearHistory() {
|
|
172
|
+
if (state.clearing)
|
|
173
|
+
return;
|
|
174
|
+
$("#clearHistoryModal").classList.add("hidden");
|
|
175
|
+
showClearHistoryError("");
|
|
176
|
+
}
|
|
177
|
+
function openClearHistory() {
|
|
178
|
+
if (!state.canClearHistory)
|
|
179
|
+
return;
|
|
180
|
+
const runCount = state.snapshot?.runs.length ?? 0;
|
|
181
|
+
const eventCount = state.snapshot?.runs.reduce((total, run) => total + run.eventCount, 0) ?? 0;
|
|
182
|
+
const activeRunCount = state.snapshot?.activeRunCount ?? 0;
|
|
183
|
+
$("#clearHistoryCopy").textContent =
|
|
184
|
+
"Remove " +
|
|
185
|
+
runCount +
|
|
186
|
+
" recorded run" +
|
|
187
|
+
(runCount === 1 ? "" : "s") +
|
|
188
|
+
" and " +
|
|
189
|
+
eventCount +
|
|
190
|
+
" event" +
|
|
191
|
+
(eventCount === 1 ? "" : "s") +
|
|
192
|
+
" from this SQLite store." +
|
|
193
|
+
(activeRunCount
|
|
194
|
+
? " " +
|
|
195
|
+
activeRunCount +
|
|
196
|
+
" recorded run" +
|
|
197
|
+
(activeRunCount === 1 ? " is" : "s are") +
|
|
198
|
+
" still marked active; continue only if no external process is writing to this store."
|
|
199
|
+
: "");
|
|
200
|
+
$("#clearHistoryModal").classList.remove("hidden");
|
|
201
|
+
$("#confirmClearHistory").focus();
|
|
202
|
+
}
|
|
203
|
+
async function clearHistory() {
|
|
204
|
+
if (state.clearing)
|
|
205
|
+
return;
|
|
206
|
+
state.clearing = true;
|
|
207
|
+
const button = $("#confirmClearHistory");
|
|
208
|
+
button.disabled = true;
|
|
209
|
+
button.textContent = "Clearing…";
|
|
210
|
+
showClearHistoryError("");
|
|
211
|
+
try {
|
|
212
|
+
const result = await api.clearHistory();
|
|
213
|
+
state.selectedRunId = null;
|
|
214
|
+
$("#clearHistoryModal").classList.add("hidden");
|
|
215
|
+
showToast("Cleared " + result.eventCount + " recorded event" + (result.eventCount === 1 ? "" : "s"));
|
|
216
|
+
await refresh(true);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
showClearHistoryError(error instanceof Error ? error.message || String(error) : String(error));
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
state.clearing = false;
|
|
223
|
+
button.disabled = false;
|
|
224
|
+
button.textContent = "Clear history";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
function renderRuns() {
|
|
228
|
+
const matchedRoots = state.query ? state.runIndex.matchingRootIds(state.query) : null;
|
|
229
|
+
const roots = state.runIndex.roots
|
|
230
|
+
.filter((run) => !matchedRoots || matchedRoots.has(run.runId))
|
|
231
|
+
.sort((left, right) => Number(state.runIndex.subtreeIsRunning(right.runId)) -
|
|
232
|
+
Number(state.runIndex.subtreeIsRunning(left.runId)) ||
|
|
233
|
+
right.startedAtMs - left.startedAtMs);
|
|
234
|
+
if (!state.selectedRunId ||
|
|
235
|
+
!roots.some((run) => run.runId === state.runIndex.rootRunId(state.selectedRunId)))
|
|
236
|
+
state.selectedRunId = roots[0]?.runId ?? null;
|
|
237
|
+
const selected = state.detail?.run?.runId === state.selectedRunId ? state.detail.run : null;
|
|
238
|
+
$("#content").innerHTML = renderRunsView({
|
|
239
|
+
canCancel: state.canCancel,
|
|
240
|
+
cancelling: state.cancelling,
|
|
241
|
+
liveRunIds: state.snapshot?.liveRunIds ?? [],
|
|
242
|
+
nowMs: Date.now(),
|
|
243
|
+
roots,
|
|
244
|
+
runIndex: state.runIndex,
|
|
245
|
+
selectedRun: selected,
|
|
246
|
+
selectedRunId: state.selectedRunId,
|
|
247
|
+
totalRunCount: state.snapshot?.runs.length ?? 0,
|
|
248
|
+
});
|
|
249
|
+
nodes("[data-run-id]").forEach((button) => button.addEventListener("click", () => {
|
|
250
|
+
void selectRun(button.dataset.runId);
|
|
251
|
+
}));
|
|
252
|
+
nodes("[data-detail-run-id]").forEach((button) => button.addEventListener("click", () => {
|
|
253
|
+
void selectRun(button.dataset.detailRunId);
|
|
254
|
+
}));
|
|
255
|
+
nodes("[data-cancel-run-id]").forEach((button) => button.addEventListener("click", (event) => {
|
|
256
|
+
event.stopPropagation();
|
|
257
|
+
void cancelRun(button.dataset.cancelRunId);
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
function renderPipelines() {
|
|
261
|
+
const query = state.query.toLowerCase();
|
|
262
|
+
const commands = state.commands.filter((command) => !query ||
|
|
263
|
+
command.name.toLowerCase().includes(query) ||
|
|
264
|
+
describeCommand(command).toLowerCase().includes(query));
|
|
265
|
+
$("#content").innerHTML = renderPipelinesView(commands);
|
|
266
|
+
nodes("[data-command-id]").forEach((button) => button.addEventListener("click", () => openLaunch(button.dataset.commandId)));
|
|
267
|
+
}
|
|
268
|
+
function render() {
|
|
269
|
+
if (!state.snapshot)
|
|
270
|
+
return;
|
|
271
|
+
const isPipelines = state.view === "pipelines";
|
|
272
|
+
$("#pageTitle").textContent = isPipelines ? "Pipelines" : "Runs";
|
|
273
|
+
$("#pageLede").textContent = isPipelines
|
|
274
|
+
? "Choose a declared workflow to configure and run."
|
|
275
|
+
: "Live work and durable history in one place.";
|
|
276
|
+
$("#search").placeholder = isPipelines ? "Filter pipelines" : "Filter runs or IDs";
|
|
277
|
+
$("#metrics").innerHTML = renderMetrics(state.snapshot, state.commands.length);
|
|
278
|
+
$("#pipelineCount").textContent = String(state.commands.length);
|
|
279
|
+
$("#runCount").textContent = String(state.snapshot.runs.length);
|
|
280
|
+
$("#clearHistoryButton").disabled = state.snapshot.runs.length === 0;
|
|
281
|
+
$("#clearHistoryButton").title =
|
|
282
|
+
state.snapshot.activeRunCount > 0
|
|
283
|
+
? "Clear history, including runs left active by an interrupted process"
|
|
284
|
+
: "Clear history";
|
|
285
|
+
nodes("[data-view]").forEach((button) => button.classList.toggle("active", button.dataset.view === state.view));
|
|
286
|
+
if (isPipelines)
|
|
287
|
+
renderPipelines();
|
|
288
|
+
else
|
|
289
|
+
renderRuns();
|
|
290
|
+
}
|
|
291
|
+
async function selectRun(runId) {
|
|
292
|
+
state.selectedRunId = runId ?? null;
|
|
293
|
+
render();
|
|
294
|
+
await loadSelectedRunDetail(state, api.loadRunDetail);
|
|
295
|
+
render();
|
|
296
|
+
}
|
|
297
|
+
async function refresh(manual = false) {
|
|
298
|
+
if (state.loading)
|
|
299
|
+
return;
|
|
300
|
+
state.loading = true;
|
|
301
|
+
if (manual)
|
|
302
|
+
$("#refresh").classList.add("spinning");
|
|
303
|
+
try {
|
|
304
|
+
const snapshot = await api.loadSnapshot();
|
|
305
|
+
state.snapshot = snapshot;
|
|
306
|
+
state.runIndex = createStudioRunIndex(snapshot.runs);
|
|
307
|
+
render();
|
|
308
|
+
await loadSelectedRunDetail(state, api.loadRunDetail);
|
|
309
|
+
setConnected(true);
|
|
310
|
+
render();
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
/* Snapshot fetch failed; keep the last rendered run list and mark the connection lost. */
|
|
314
|
+
setConnected(false);
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
state.loading = false;
|
|
318
|
+
$("#refresh").classList.remove("spinning");
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
async function loadCommands() {
|
|
322
|
+
try {
|
|
323
|
+
state.commands = await api.loadCommands();
|
|
324
|
+
$("#pipelineNav").classList.toggle("hidden", state.commands.length === 0);
|
|
325
|
+
$("#launchButton").classList.toggle("hidden", state.commands.length === 0);
|
|
326
|
+
$("#launchCommand").innerHTML = state.commands
|
|
327
|
+
.map((command) => '<option value="' +
|
|
328
|
+
escapeHtml(command.id) +
|
|
329
|
+
'">' +
|
|
330
|
+
escapeHtml(command.name) +
|
|
331
|
+
"</option>")
|
|
332
|
+
.join("");
|
|
333
|
+
if (state.commands.length > 0)
|
|
334
|
+
state.view = "pipelines";
|
|
335
|
+
renderCommandForm();
|
|
336
|
+
render();
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
/* Optional studio endpoints; keep the last successful client state. */
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function loadCapabilities() {
|
|
343
|
+
try {
|
|
344
|
+
const capabilities = await api.loadCapabilities();
|
|
345
|
+
state.canClearHistory = capabilities.canClearHistory;
|
|
346
|
+
state.canCancel = capabilities.canCancel;
|
|
347
|
+
$("#clearHistoryButton").classList.toggle("hidden", !state.canClearHistory);
|
|
348
|
+
render();
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
/* Optional studio endpoints; keep the last successful client state. */
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function renderPlan(plan) {
|
|
355
|
+
$("#planResult").innerHTML = renderPlanView(plan);
|
|
356
|
+
$("#planResult").classList.remove("hidden");
|
|
357
|
+
}
|
|
358
|
+
async function previewPlan() {
|
|
359
|
+
const command = selectedCommand();
|
|
360
|
+
if (!command?.canPlan || state.planning)
|
|
361
|
+
return;
|
|
362
|
+
state.planning = true;
|
|
363
|
+
const planVersion = state.planVersion;
|
|
364
|
+
$("#previewPlan").disabled = true;
|
|
365
|
+
$("#previewPlan").textContent = "Planning…";
|
|
366
|
+
$("#submitLaunch").disabled = true;
|
|
367
|
+
showLaunchError("");
|
|
368
|
+
try {
|
|
369
|
+
const plan = await api.previewPlan(command.id, currentPlanInput(command));
|
|
370
|
+
if (state.planVersion === planVersion)
|
|
371
|
+
renderPlan(plan);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
showLaunchError(error instanceof Error ? error.message || String(error) : String(error));
|
|
375
|
+
}
|
|
376
|
+
finally {
|
|
377
|
+
state.planning = false;
|
|
378
|
+
$("#previewPlan").disabled = false;
|
|
379
|
+
$("#previewPlan").textContent = "Preview plan";
|
|
380
|
+
$("#submitLaunch").disabled = false;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async function cancelRun(runId) {
|
|
384
|
+
if (!state.canCancel || !runId || state.cancelling)
|
|
385
|
+
return;
|
|
386
|
+
state.cancelling = true;
|
|
387
|
+
render();
|
|
388
|
+
try {
|
|
389
|
+
await api.cancelRun(runId);
|
|
390
|
+
showToast("Run cancelled · " + abbreviateId(runId));
|
|
391
|
+
setTimeout(() => refresh(true), 80);
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
showToast(error instanceof Error ? error.message || String(error) : String(error));
|
|
395
|
+
}
|
|
396
|
+
finally {
|
|
397
|
+
state.cancelling = false;
|
|
398
|
+
render();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
async function launch(event) {
|
|
402
|
+
event.preventDefault();
|
|
403
|
+
const command = selectedCommand();
|
|
404
|
+
if (!command || state.launching)
|
|
405
|
+
return;
|
|
406
|
+
const values = parameterLaunchValues(command);
|
|
407
|
+
state.launching = true;
|
|
408
|
+
$("#previewPlan").disabled = true;
|
|
409
|
+
$("#submitLaunch").disabled = true;
|
|
410
|
+
$("#submitLaunch").textContent = "Starting…";
|
|
411
|
+
showLaunchError("");
|
|
412
|
+
try {
|
|
413
|
+
const runId = await api.launch(command.id, values);
|
|
414
|
+
state.selectedRunId = runId;
|
|
415
|
+
state.view = "runs";
|
|
416
|
+
$("#launchModal").classList.add("hidden");
|
|
417
|
+
renderCommandForm();
|
|
418
|
+
showToast("Run accepted · " + abbreviateId(runId));
|
|
419
|
+
setTimeout(() => refresh(true), 80);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
showLaunchError(error instanceof Error ? error.message || String(error) : String(error));
|
|
423
|
+
}
|
|
424
|
+
finally {
|
|
425
|
+
state.launching = false;
|
|
426
|
+
$("#previewPlan").disabled = false;
|
|
427
|
+
$("#submitLaunch").disabled = false;
|
|
428
|
+
$("#submitLaunch").textContent = "Run";
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
bind() {
|
|
433
|
+
nodes("[data-view]").forEach((button) => button.addEventListener("click", () => {
|
|
434
|
+
state.view = button.dataset.view ?? state.view;
|
|
435
|
+
render();
|
|
436
|
+
}));
|
|
437
|
+
$("#search").addEventListener("input", (event) => {
|
|
438
|
+
const target = event.target;
|
|
439
|
+
if (target instanceof HTMLInputElement) {
|
|
440
|
+
state.query = target.value.trim();
|
|
441
|
+
render();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
$("#refresh").addEventListener("click", () => refresh(true));
|
|
445
|
+
$("#launchButton").addEventListener("click", () => openLaunch());
|
|
446
|
+
$("#clearHistoryButton").addEventListener("click", openClearHistory);
|
|
447
|
+
$("#confirmClearHistory").addEventListener("click", clearHistory);
|
|
448
|
+
$("#closeClearHistory").addEventListener("click", closeClearHistory);
|
|
449
|
+
$("#cancelClearHistory").addEventListener("click", closeClearHistory);
|
|
450
|
+
$("#previewPlan").addEventListener("click", previewPlan);
|
|
451
|
+
$("#closeLaunch").addEventListener("click", closeLaunch);
|
|
452
|
+
$("#cancelLaunch").addEventListener("click", closeLaunch);
|
|
453
|
+
$("#launchCommand").addEventListener("change", renderCommandForm);
|
|
454
|
+
$("#runPane").addEventListener("input", invalidatePlan);
|
|
455
|
+
$("#launchForm").addEventListener("submit", launch);
|
|
456
|
+
$("#launchModal").addEventListener("click", (event) => {
|
|
457
|
+
if (event.target === $("#launchModal"))
|
|
458
|
+
closeLaunch();
|
|
459
|
+
});
|
|
460
|
+
$("#clearHistoryModal").addEventListener("click", (event) => {
|
|
461
|
+
if (event.target === $("#clearHistoryModal"))
|
|
462
|
+
closeClearHistory();
|
|
463
|
+
});
|
|
464
|
+
document.addEventListener("keydown", (event) => {
|
|
465
|
+
if (event.key === "Escape") {
|
|
466
|
+
closeLaunch();
|
|
467
|
+
closeClearHistory();
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
},
|
|
471
|
+
start() {
|
|
472
|
+
void loadCommands();
|
|
473
|
+
void loadCapabilities();
|
|
474
|
+
void refresh();
|
|
475
|
+
setInterval(() => void refresh(), 1200);
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
//# sourceMappingURL=run-store-ui-client-controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-store-ui-client-controller.js","sourceRoot":"","sources":["../../src/studio/run-store-ui-client-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CliParameterDescriptor } from \"../cli/cli.js\";\nimport type { PipelinePlan } from \"../core/pipeline.js\";\nimport type { PipelineRunStudioCommand } from \"./run-store-ui-protocol.js\";\nimport { createStudioRunIndex } from \"./run-store-ui-client-model.js\";\nimport type { StudioRunDetail, StudioState } from \"./run-store-ui-client-model.js\";\nimport { serializeLaunchValues, serializePlanInput } from \"./run-store-ui-client-form.js\";\nimport { createStudioApi } from \"./run-store-ui-client-transport.js\";\nimport {\n commandDescription as describeCommand,\n escapeHtml,\n renderCommandFormFields,\n renderMetrics,\n renderPipelinesView,\n renderPlanView,\n renderRunsView,\n shortId as abbreviateId,\n} from \"./run-store-ui-client-views.js\";\n\ninterface StudioNode extends HTMLElement {\n checked: boolean;\n disabled: boolean;\n options: HTMLOptionsCollection;\n placeholder: string;\n selectedOptions: HTMLCollectionOf<HTMLOptionElement>;\n value: string;\n}\n\nexport interface StudioController {\n bind(): void;\n start(): void;\n}\n\nfunction selectedRunFingerprint(state: StudioState) {\n const run = state.runIndex.runById(state.selectedRunId);\n return run ? [run.runId, run.eventCount, run.status].join(\":\") : null;\n}\n\n/** Refresh selected-run detail without allowing its optional endpoint to fail snapshot polling. */\nexport async function loadSelectedRunDetail(\n state: StudioState,\n loadRunDetail: (runId: string) => Promise<StudioRunDetail | null>\n): Promise<void> {\n if (!state.selectedRunId) {\n state.detail = null;\n state.detailFingerprint = null;\n return;\n }\n const requestedRunId = state.selectedRunId;\n const fingerprint = selectedRunFingerprint(state);\n if (!fingerprint) {\n state.detail = null;\n state.detailFingerprint = null;\n return;\n }\n if (fingerprint === state.detailFingerprint && state.detail) return;\n let detail: StudioRunDetail | null;\n try {\n detail = await loadRunDetail(requestedRunId);\n } catch {\n /* Detail is optional; retain the last successful detail and snapshot connection state. */\n return;\n }\n if (state.selectedRunId !== requestedRunId) return;\n if (!detail) {\n state.detail = null;\n state.detailFingerprint = null;\n return;\n }\n state.detail = detail;\n state.detailFingerprint = fingerprint;\n}\n\n/** DOM event and polling controller for one Studio client state instance. */\nexport function createStudioController(state: StudioState): StudioController {\n const api = createStudioApi();\n const $ = (selector: string): StudioNode => {\n const node = document.querySelector(selector);\n if (!(node instanceof HTMLElement)) throw new Error(\"Missing \" + selector);\n // SAFETY: Studio markup uses HTML elements that expose value/checked/disabled.\n return node as StudioNode;\n };\n const nodes = (selector: string): StudioNode[] =>\n Array.from(document.querySelectorAll(selector), (node) => {\n // SAFETY: Studio event selectors only match HTML elements on this page.\n return node as StudioNode;\n });\n const queryNode = (selector: string): StudioNode | null => {\n const node = document.querySelector(selector);\n if (!(node instanceof HTMLElement)) return null;\n // SAFETY: Parameter controls in the launch form are HTML inputs, selects, or textareas.\n return node as StudioNode;\n };\n function setConnected(connected: boolean) {\n $(\"#connectionLabel\").textContent = connected ? \"Connected · local\" : \"Connection lost\";\n $(\".pulse\").classList.toggle(\"lost\", !connected);\n }\n function selectedCommand(): PipelineRunStudioCommand | undefined {\n return state.commands.find((command) => command.id === $(\"#launchCommand\").value);\n }\n function bindExclusiveSelections(command: PipelineRunStudioCommand, scope: string) {\n const fields = command.parameters.flatMap((parameter, index) => {\n if (!parameter.exclusive || !parameter.multiple) return [];\n const field = queryNode(\"[data-\" + scope + '-parameter-index=\"' + index + '\"]');\n return field ? [field] : [];\n });\n const clear = (field: StudioNode) => {\n if (field.tagName === \"SELECT\")\n Array.from(field.options).forEach((option) => {\n option.selected = false;\n });\n else field.value = \"\";\n };\n fields.forEach((field) => {\n field.addEventListener(\"change\", () => {\n if (field.selectedOptions?.length || field.value) {\n fields.forEach((other) => {\n if (other !== field) clear(other);\n });\n }\n });\n });\n }\n function renderCommandForm() {\n const command = selectedCommand();\n $(\"#launchTitle\").textContent = command?.name || \"Run a pipeline\";\n $(\"#launchDescription\").textContent = command\n ? describeCommand(command)\n : \"Choose a declared pipeline and provide its inputs.\";\n if (!command) {\n $(\"#parameterFields\").innerHTML = \"\";\n $(\"#previewPlan\").classList.add(\"hidden\");\n return;\n }\n $(\"#parameterFields\").innerHTML = renderCommandFormFields(command);\n bindExclusiveSelections(command, \"run\");\n $(\"#previewPlan\").classList.toggle(\"hidden\", !command.canPlan);\n invalidatePlan();\n }\n function parameterValues(parameter: CliParameterDescriptor, index: number, scope: string) {\n const control = queryNode(\"[data-\" + scope + '-parameter-index=\"' + index + '\"]');\n if (!control) return [];\n if (parameter.type === \"boolean\") return [control.checked];\n const rawValues = parameter.multiple\n ? control.tagName === \"SELECT\"\n ? Array.from(control.selectedOptions).map((option) => option.value)\n : control.value\n .split(/\\r?\\n/)\n .map((value) => value.trim())\n .filter(Boolean)\n : [control.value];\n return parameter.type === \"number\"\n ? rawValues.map((value) => (value === \"\" ? value : Number(value)))\n : rawValues;\n }\n function parameterLaunchValues(command: PipelineRunStudioCommand) {\n return serializeLaunchValues(command, (parameter, index) =>\n parameterValues(parameter, index, \"run\")\n );\n }\n function currentPlanInput(command: PipelineRunStudioCommand) {\n return serializePlanInput(command, (parameter, index) =>\n parameterValues(parameter, index, \"run\")\n );\n }\n function invalidatePlan() {\n state.planVersion += 1;\n $(\"#planResult\").classList.add(\"hidden\");\n $(\"#planResult\").innerHTML = \"\";\n }\n function showLaunchError(message: string) {\n $(\"#launchError\").textContent = message;\n $(\"#launchError\").classList.toggle(\"hidden\", !message);\n }\n function closeLaunch() {\n if (state.launching || state.planning) return;\n $(\"#launchModal\").classList.add(\"hidden\");\n showLaunchError(\"\");\n }\n function openLaunch(commandId?: string) {\n if (commandId) $(\"#launchCommand\").value = commandId;\n $(\"#launchModal\").classList.remove(\"hidden\");\n renderCommandForm();\n const firstField = $(\"#parameterFields\").querySelector(\"input, select, textarea\");\n if (firstField instanceof HTMLElement) firstField.focus();\n }\n function showToast(message: string) {\n const toast = $(\"#toast\");\n toast.textContent = message;\n toast.classList.remove(\"hidden\");\n setTimeout(() => toast.classList.add(\"hidden\"), 4200);\n }\n function showClearHistoryError(message: string) {\n $(\"#clearHistoryError\").textContent = message;\n $(\"#clearHistoryError\").classList.toggle(\"hidden\", !message);\n }\n function closeClearHistory() {\n if (state.clearing) return;\n $(\"#clearHistoryModal\").classList.add(\"hidden\");\n showClearHistoryError(\"\");\n }\n function openClearHistory() {\n if (!state.canClearHistory) return;\n const runCount = state.snapshot?.runs.length ?? 0;\n const eventCount = state.snapshot?.runs.reduce((total, run) => total + run.eventCount, 0) ?? 0;\n const activeRunCount = state.snapshot?.activeRunCount ?? 0;\n $(\"#clearHistoryCopy\").textContent =\n \"Remove \" +\n runCount +\n \" recorded run\" +\n (runCount === 1 ? \"\" : \"s\") +\n \" and \" +\n eventCount +\n \" event\" +\n (eventCount === 1 ? \"\" : \"s\") +\n \" from this SQLite store.\" +\n (activeRunCount\n ? \" \" +\n activeRunCount +\n \" recorded run\" +\n (activeRunCount === 1 ? \" is\" : \"s are\") +\n \" still marked active; continue only if no external process is writing to this store.\"\n : \"\");\n $(\"#clearHistoryModal\").classList.remove(\"hidden\");\n $(\"#confirmClearHistory\").focus();\n }\n async function clearHistory() {\n if (state.clearing) return;\n state.clearing = true;\n const button = $(\"#confirmClearHistory\");\n button.disabled = true;\n button.textContent = \"Clearing…\";\n showClearHistoryError(\"\");\n try {\n const result = await api.clearHistory();\n state.selectedRunId = null;\n $(\"#clearHistoryModal\").classList.add(\"hidden\");\n showToast(\n \"Cleared \" + result.eventCount + \" recorded event\" + (result.eventCount === 1 ? \"\" : \"s\")\n );\n await refresh(true);\n } catch (error) {\n showClearHistoryError(\n error instanceof Error ? error.message || String(error) : String(error)\n );\n } finally {\n state.clearing = false;\n button.disabled = false;\n button.textContent = \"Clear history\";\n }\n }\n function renderRuns() {\n const matchedRoots = state.query ? state.runIndex.matchingRootIds(state.query) : null;\n const roots = state.runIndex.roots\n .filter((run) => !matchedRoots || matchedRoots.has(run.runId))\n .sort(\n (left, right) =>\n Number(state.runIndex.subtreeIsRunning(right.runId)) -\n Number(state.runIndex.subtreeIsRunning(left.runId)) ||\n right.startedAtMs - left.startedAtMs\n );\n if (\n !state.selectedRunId ||\n !roots.some((run) => run.runId === state.runIndex.rootRunId(state.selectedRunId))\n )\n state.selectedRunId = roots[0]?.runId ?? null;\n const selected = state.detail?.run?.runId === state.selectedRunId ? state.detail.run : null;\n $(\"#content\").innerHTML = renderRunsView({\n canCancel: state.canCancel,\n cancelling: state.cancelling,\n liveRunIds: state.snapshot?.liveRunIds ?? [],\n nowMs: Date.now(),\n roots,\n runIndex: state.runIndex,\n selectedRun: selected,\n selectedRunId: state.selectedRunId,\n totalRunCount: state.snapshot?.runs.length ?? 0,\n });\n nodes(\"[data-run-id]\").forEach((button) =>\n button.addEventListener(\"click\", () => {\n void selectRun(button.dataset.runId);\n })\n );\n nodes(\"[data-detail-run-id]\").forEach((button) =>\n button.addEventListener(\"click\", () => {\n void selectRun(button.dataset.detailRunId);\n })\n );\n nodes(\"[data-cancel-run-id]\").forEach((button) =>\n button.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n void cancelRun(button.dataset.cancelRunId);\n })\n );\n }\n function renderPipelines() {\n const query = state.query.toLowerCase();\n const commands = state.commands.filter(\n (command) =>\n !query ||\n command.name.toLowerCase().includes(query) ||\n describeCommand(command).toLowerCase().includes(query)\n );\n $(\"#content\").innerHTML = renderPipelinesView(commands);\n nodes(\"[data-command-id]\").forEach((button) =>\n button.addEventListener(\"click\", () => openLaunch(button.dataset.commandId))\n );\n }\n function render() {\n if (!state.snapshot) return;\n const isPipelines = state.view === \"pipelines\";\n $(\"#pageTitle\").textContent = isPipelines ? \"Pipelines\" : \"Runs\";\n $(\"#pageLede\").textContent = isPipelines\n ? \"Choose a declared workflow to configure and run.\"\n : \"Live work and durable history in one place.\";\n $(\"#search\").placeholder = isPipelines ? \"Filter pipelines\" : \"Filter runs or IDs\";\n $(\"#metrics\").innerHTML = renderMetrics(state.snapshot, state.commands.length);\n $(\"#pipelineCount\").textContent = String(state.commands.length);\n $(\"#runCount\").textContent = String(state.snapshot.runs.length);\n $(\"#clearHistoryButton\").disabled = state.snapshot.runs.length === 0;\n $(\"#clearHistoryButton\").title =\n state.snapshot.activeRunCount > 0\n ? \"Clear history, including runs left active by an interrupted process\"\n : \"Clear history\";\n nodes(\"[data-view]\").forEach((button) =>\n button.classList.toggle(\"active\", button.dataset.view === state.view)\n );\n if (isPipelines) renderPipelines();\n else renderRuns();\n }\n async function selectRun(runId: string | undefined) {\n state.selectedRunId = runId ?? null;\n render();\n await loadSelectedRunDetail(state, api.loadRunDetail);\n render();\n }\n async function refresh(manual = false) {\n if (state.loading) return;\n state.loading = true;\n if (manual) $(\"#refresh\").classList.add(\"spinning\");\n try {\n const snapshot = await api.loadSnapshot();\n state.snapshot = snapshot;\n state.runIndex = createStudioRunIndex(snapshot.runs);\n render();\n await loadSelectedRunDetail(state, api.loadRunDetail);\n setConnected(true);\n render();\n } catch {\n /* Snapshot fetch failed; keep the last rendered run list and mark the connection lost. */\n setConnected(false);\n } finally {\n state.loading = false;\n $(\"#refresh\").classList.remove(\"spinning\");\n }\n }\n async function loadCommands() {\n try {\n state.commands = await api.loadCommands();\n $(\"#pipelineNav\").classList.toggle(\"hidden\", state.commands.length === 0);\n $(\"#launchButton\").classList.toggle(\"hidden\", state.commands.length === 0);\n $(\"#launchCommand\").innerHTML = state.commands\n .map(\n (command) =>\n '<option value=\"' +\n escapeHtml(command.id) +\n '\">' +\n escapeHtml(command.name) +\n \"</option>\"\n )\n .join(\"\");\n if (state.commands.length > 0) state.view = \"pipelines\";\n renderCommandForm();\n render();\n } catch {\n /* Optional studio endpoints; keep the last successful client state. */\n }\n }\n async function loadCapabilities() {\n try {\n const capabilities = await api.loadCapabilities();\n state.canClearHistory = capabilities.canClearHistory;\n state.canCancel = capabilities.canCancel;\n $(\"#clearHistoryButton\").classList.toggle(\"hidden\", !state.canClearHistory);\n render();\n } catch {\n /* Optional studio endpoints; keep the last successful client state. */\n }\n }\n function renderPlan(plan: PipelinePlan) {\n $(\"#planResult\").innerHTML = renderPlanView(plan);\n $(\"#planResult\").classList.remove(\"hidden\");\n }\n async function previewPlan() {\n const command = selectedCommand();\n if (!command?.canPlan || state.planning) return;\n state.planning = true;\n const planVersion = state.planVersion;\n $(\"#previewPlan\").disabled = true;\n $(\"#previewPlan\").textContent = \"Planning…\";\n $(\"#submitLaunch\").disabled = true;\n showLaunchError(\"\");\n try {\n const plan = await api.previewPlan(command.id, currentPlanInput(command));\n if (state.planVersion === planVersion) renderPlan(plan);\n } catch (error) {\n showLaunchError(error instanceof Error ? error.message || String(error) : String(error));\n } finally {\n state.planning = false;\n $(\"#previewPlan\").disabled = false;\n $(\"#previewPlan\").textContent = \"Preview plan\";\n $(\"#submitLaunch\").disabled = false;\n }\n }\n async function cancelRun(runId: string | undefined) {\n if (!state.canCancel || !runId || state.cancelling) return;\n state.cancelling = true;\n render();\n try {\n await api.cancelRun(runId);\n showToast(\"Run cancelled · \" + abbreviateId(runId));\n setTimeout(() => refresh(true), 80);\n } catch (error) {\n showToast(error instanceof Error ? error.message || String(error) : String(error));\n } finally {\n state.cancelling = false;\n render();\n }\n }\n async function launch(event: Event) {\n event.preventDefault();\n const command = selectedCommand();\n if (!command || state.launching) return;\n const values = parameterLaunchValues(command);\n state.launching = true;\n $(\"#previewPlan\").disabled = true;\n $(\"#submitLaunch\").disabled = true;\n $(\"#submitLaunch\").textContent = \"Starting…\";\n showLaunchError(\"\");\n try {\n const runId = await api.launch(command.id, values);\n state.selectedRunId = runId;\n state.view = \"runs\";\n $(\"#launchModal\").classList.add(\"hidden\");\n renderCommandForm();\n showToast(\"Run accepted · \" + abbreviateId(runId));\n setTimeout(() => refresh(true), 80);\n } catch (error) {\n showLaunchError(error instanceof Error ? error.message || String(error) : String(error));\n } finally {\n state.launching = false;\n $(\"#previewPlan\").disabled = false;\n $(\"#submitLaunch\").disabled = false;\n $(\"#submitLaunch\").textContent = \"Run\";\n }\n }\n return {\n bind() {\n nodes(\"[data-view]\").forEach((button) =>\n button.addEventListener(\"click\", () => {\n state.view = button.dataset.view ?? state.view;\n render();\n })\n );\n $(\"#search\").addEventListener(\"input\", (event: Event) => {\n const target = event.target;\n if (target instanceof HTMLInputElement) {\n state.query = target.value.trim();\n render();\n }\n });\n $(\"#refresh\").addEventListener(\"click\", () => refresh(true));\n $(\"#launchButton\").addEventListener(\"click\", () => openLaunch());\n $(\"#clearHistoryButton\").addEventListener(\"click\", openClearHistory);\n $(\"#confirmClearHistory\").addEventListener(\"click\", clearHistory);\n $(\"#closeClearHistory\").addEventListener(\"click\", closeClearHistory);\n $(\"#cancelClearHistory\").addEventListener(\"click\", closeClearHistory);\n $(\"#previewPlan\").addEventListener(\"click\", previewPlan);\n $(\"#closeLaunch\").addEventListener(\"click\", closeLaunch);\n $(\"#cancelLaunch\").addEventListener(\"click\", closeLaunch);\n $(\"#launchCommand\").addEventListener(\"change\", renderCommandForm);\n $(\"#runPane\").addEventListener(\"input\", invalidatePlan);\n $(\"#launchForm\").addEventListener(\"submit\", launch);\n $(\"#launchModal\").addEventListener(\"click\", (event: Event) => {\n if (event.target === $(\"#launchModal\")) closeLaunch();\n });\n $(\"#clearHistoryModal\").addEventListener(\"click\", (event: Event) => {\n if (event.target === $(\"#clearHistoryModal\")) closeClearHistory();\n });\n document.addEventListener(\"keydown\", (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n closeLaunch();\n closeClearHistory();\n }\n });\n },\n start() {\n void loadCommands();\n void loadCapabilities();\n void refresh();\n setInterval(() => void refresh(), 1200);\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CliParameterDescriptor } from "../cli/cli.js";
|
|
2
|
+
import type { PipelineRunControls } from "../core/pipeline.js";
|
|
3
|
+
import type { PipelineRunStudioCommand, PipelineRunStudioLaunchRequest } from "./run-store-ui-protocol.js";
|
|
4
|
+
export type StudioParameterValue = boolean | number | string;
|
|
5
|
+
export type ReadStudioParameterValues = (parameter: CliParameterDescriptor, index: number) => readonly StudioParameterValue[];
|
|
6
|
+
/** Convert launch-form values into the bounded wire shape expected by the Studio API. */
|
|
7
|
+
export declare function serializeLaunchValues(command: PipelineRunStudioCommand, readValues: ReadStudioParameterValues): PipelineRunStudioLaunchRequest["values"];
|
|
8
|
+
/** Select only execution controls for plan requests. */
|
|
9
|
+
export declare function serializePlanInput(command: PipelineRunStudioCommand, readValues: ReadStudioParameterValues): PipelineRunControls;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Convert launch-form values into the bounded wire shape expected by the Studio API. */
|
|
2
|
+
export function serializeLaunchValues(command, readValues) {
|
|
3
|
+
const values = {};
|
|
4
|
+
command.parameters.forEach((parameter, index) => {
|
|
5
|
+
const parameterValue = readValues(parameter, index);
|
|
6
|
+
if (parameter.type === "boolean") {
|
|
7
|
+
const checked = parameterValue[0];
|
|
8
|
+
if (checked !== Boolean(parameter.default))
|
|
9
|
+
values[parameter.key] = checked;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (parameter.multiple) {
|
|
13
|
+
values[parameter.key] =
|
|
14
|
+
parameter.type === "number"
|
|
15
|
+
? parameterValue.filter((value) => typeof value === "number")
|
|
16
|
+
: parameterValue.filter((value) => typeof value === "string");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const single = parameterValue[0];
|
|
20
|
+
if (single !== "" && single !== undefined)
|
|
21
|
+
values[parameter.key] = single;
|
|
22
|
+
});
|
|
23
|
+
return values;
|
|
24
|
+
}
|
|
25
|
+
/** Select only execution controls for plan requests. */
|
|
26
|
+
export function serializePlanInput(command, readValues) {
|
|
27
|
+
const input = {};
|
|
28
|
+
command.parameters.forEach((parameter, index) => {
|
|
29
|
+
if (parameter.group !== "execution")
|
|
30
|
+
return;
|
|
31
|
+
const values = readValues(parameter, index);
|
|
32
|
+
if (parameter.type === "boolean") {
|
|
33
|
+
if (values[0] === true)
|
|
34
|
+
input[parameter.key] = true;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (parameter.multiple && values.length) {
|
|
38
|
+
input[parameter.key] = values.filter((value) => typeof value === "string");
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// SAFETY: Execution controls are plan selections; the server parser ignores unknown keys.
|
|
42
|
+
return input;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=run-store-ui-client-form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-store-ui-client-form.js","sourceRoot":"","sources":["../../src/studio/run-store-ui-client-form.ts"],"names":[],"mappings":"AAcA,yFAAyF;AACzF,MAAM,UAAU,qBAAqB,CACnC,OAAiC,EACjC,UAAqC;IAErC,MAAM,MAAM,GAA6C,EAAE,CAAC;IAC5D,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,OAAO,KAAK,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;gBAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YAC5E,OAAO;QACT,CAAC;QACD,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;YACvB,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC;gBACnB,SAAS,CAAC,IAAI,KAAK,QAAQ;oBACzB,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;oBAC9E,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC;IAC5E,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,kBAAkB,CAChC,OAAiC,EACjC,UAAqC;IAErC,MAAM,KAAK,GAAgD,EAAE,CAAC;IAC9D,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;QAC9C,IAAI,SAAS,CAAC,KAAK,KAAK,WAAW;YAAE,OAAO;QAC5C,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5C,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;gBAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YACpD,OAAO;QACT,CAAC;QACD,IAAI,SAAS,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACxC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC,CAAC,CAAC;IACH,0FAA0F;IAC1F,OAAO,KAA4B,CAAC;AACtC,CAAC","sourcesContent":["import type { CliParameterDescriptor } from \"../cli/cli.js\";\nimport type { PipelineRunControls } from \"../core/pipeline.js\";\nimport type {\n PipelineRunStudioCommand,\n PipelineRunStudioLaunchRequest,\n} from \"./run-store-ui-protocol.js\";\n\nexport type StudioParameterValue = boolean | number | string;\n\nexport type ReadStudioParameterValues = (\n parameter: CliParameterDescriptor,\n index: number\n) => readonly StudioParameterValue[];\n\n/** Convert launch-form values into the bounded wire shape expected by the Studio API. */\nexport function serializeLaunchValues(\n command: PipelineRunStudioCommand,\n readValues: ReadStudioParameterValues\n): PipelineRunStudioLaunchRequest[\"values\"] {\n const values: PipelineRunStudioLaunchRequest[\"values\"] = {};\n command.parameters.forEach((parameter, index) => {\n const parameterValue = readValues(parameter, index);\n if (parameter.type === \"boolean\") {\n const checked = parameterValue[0];\n if (checked !== Boolean(parameter.default)) values[parameter.key] = checked;\n return;\n }\n if (parameter.multiple) {\n values[parameter.key] =\n parameter.type === \"number\"\n ? parameterValue.filter((value): value is number => typeof value === \"number\")\n : parameterValue.filter((value): value is string => typeof value === \"string\");\n return;\n }\n const single = parameterValue[0];\n if (single !== \"\" && single !== undefined) values[parameter.key] = single;\n });\n return values;\n}\n\n/** Select only execution controls for plan requests. */\nexport function serializePlanInput(\n command: PipelineRunStudioCommand,\n readValues: ReadStudioParameterValues\n): PipelineRunControls {\n const input: Record<string, boolean | readonly string[]> = {};\n command.parameters.forEach((parameter, index) => {\n if (parameter.group !== \"execution\") return;\n const values = readValues(parameter, index);\n if (parameter.type === \"boolean\") {\n if (values[0] === true) input[parameter.key] = true;\n return;\n }\n if (parameter.multiple && values.length) {\n input[parameter.key] = values.filter((value): value is string => typeof value === \"string\");\n }\n });\n // SAFETY: Execution controls are plan selections; the server parser ignores unknown keys.\n return input as PipelineRunControls;\n}\n"]}
|