@crewhaus/hangar-ui 0.5.0
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 +309 -0
- package/assets/hangar.css +1726 -0
- package/assets/index.html +21 -0
- package/assets/js/api.js +368 -0
- package/assets/js/app.js +734 -0
- package/assets/js/dom.js +228 -0
- package/assets/js/keys.js +159 -0
- package/assets/js/markdown.js +131 -0
- package/assets/js/notify.js +152 -0
- package/assets/js/omnibox.js +307 -0
- package/assets/js/router.js +280 -0
- package/assets/js/routes.js +793 -0
- package/assets/js/shapes.js +36 -0
- package/assets/js/supervision.js +1334 -0
- package/assets/js/util.js +426 -0
- package/assets/js/views/activity.js +140 -0
- package/assets/js/views/approvals.js +155 -0
- package/assets/js/views/channels.js +455 -0
- package/assets/js/views/control.js +253 -0
- package/assets/js/views/costs.js +103 -0
- package/assets/js/views/creds.js +610 -0
- package/assets/js/views/data.js +456 -0
- package/assets/js/views/deploy.js +106 -0
- package/assets/js/views/evals-lab.js +1029 -0
- package/assets/js/views/evals.js +342 -0
- package/assets/js/views/feedback.js +555 -0
- package/assets/js/views/health.js +176 -0
- package/assets/js/views/inbox.js +103 -0
- package/assets/js/views/inspect.js +751 -0
- package/assets/js/views/jobs.js +110 -0
- package/assets/js/views/library.js +605 -0
- package/assets/js/views/memory-fabric.js +2026 -0
- package/assets/js/views/memory.js +228 -0
- package/assets/js/views/onboarding.js +253 -0
- package/assets/js/views/overview.js +196 -0
- package/assets/js/views/panes.js +132 -0
- package/assets/js/views/proc.js +280 -0
- package/assets/js/views/review.js +164 -0
- package/assets/js/views/runs.js +452 -0
- package/assets/js/views/runtime.js +450 -0
- package/assets/js/views/schedulers.js +133 -0
- package/assets/js/views/security.js +925 -0
- package/assets/js/views/sessions.js +265 -0
- package/assets/js/views/settings.js +489 -0
- package/assets/js/views/spec-edit.js +1289 -0
- package/assets/js/views/spec.js +66 -0
- package/assets/js/views/thredz.js +1853 -0
- package/assets/js/views/token.js +49 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +145 -0
- package/package.json +36 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The global job queue — running, pending, and interrupted work.
|
|
3
|
+
*
|
|
4
|
+
* `interrupted` is the row that matters most and appears least: a job that
|
|
5
|
+
* was RUNNING when the previous manager died is closed as interrupted at the
|
|
6
|
+
* next boot rather than silently re-run, because a half-finished `compile`
|
|
7
|
+
* or `eval` re-run without an operator's say-so is how a console loses
|
|
8
|
+
* someone's afternoon. The panel says so rather than hiding an empty group.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { api } from "../api.js";
|
|
12
|
+
import { clear, dot, el, emptyState, skeleton, toast } from "../dom.js";
|
|
13
|
+
import { JOB_COMMANDS, jobQueueModel, jobRow } from "../supervision.js";
|
|
14
|
+
import { cliTwin, runAction } from "./control.js";
|
|
15
|
+
|
|
16
|
+
/** Submit one job and report it — the shared path for every action face. */
|
|
17
|
+
export async function submitJob(btn, id, kind, options, onOk) {
|
|
18
|
+
return runAction(
|
|
19
|
+
btn,
|
|
20
|
+
kind,
|
|
21
|
+
() => api.submitJob(id, kind, options),
|
|
22
|
+
(result) => {
|
|
23
|
+
const jobId = typeof result?.job?.jobId === "string" ? result.job.jobId : "";
|
|
24
|
+
toast(`Queued ${kind}${jobId !== "" ? ` (${jobId})` : ""}`, "info");
|
|
25
|
+
if (onOk) onOk(result);
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** A button that enqueues a job and shows the command it will run. */
|
|
31
|
+
export function jobButton(label, id, kind, options, onOk) {
|
|
32
|
+
const btn = el("button", { class: "btn", type: "button", text: label });
|
|
33
|
+
btn.addEventListener("click", () => submitJob(btn, id, kind, options, onOk));
|
|
34
|
+
return el("div", { class: "job-action" }, [btn, cliTwin(JOB_COMMANDS[kind] ?? null)]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function jobsTable(rows) {
|
|
38
|
+
const tbody = el("tbody");
|
|
39
|
+
for (const row of rows) {
|
|
40
|
+
tbody.appendChild(
|
|
41
|
+
el("tr", null, [
|
|
42
|
+
el("td", null, [dot(row.dot, row.state)]),
|
|
43
|
+
el("td", { class: "mono", text: row.kind }),
|
|
44
|
+
el("td", { class: "mono sub", title: row.harnessDir, text: row.harnessDir }),
|
|
45
|
+
el("td", { class: "mono", text: row.argv.join(" ") }),
|
|
46
|
+
el("td", null, [
|
|
47
|
+
el("span", { text: row.enqueued }),
|
|
48
|
+
row.mutating ? el("span", { class: "chip chip-warn", text: "mutating" }) : null,
|
|
49
|
+
]),
|
|
50
|
+
el("td", { class: "muted", text: row.error ?? "" }),
|
|
51
|
+
]),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return el("div", { class: "table-scroll" }, [
|
|
55
|
+
el("table", { class: "fleet" }, [
|
|
56
|
+
el(
|
|
57
|
+
"thead",
|
|
58
|
+
null,
|
|
59
|
+
el(
|
|
60
|
+
"tr",
|
|
61
|
+
null,
|
|
62
|
+
["State", "Kind", "Harness", "Command", "Queued", "Error"].map((h) =>
|
|
63
|
+
el("th", { text: h }),
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
tbody,
|
|
68
|
+
]),
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Render the queue panel into `root` (it loads itself). */
|
|
73
|
+
export async function renderJobs(root) {
|
|
74
|
+
clear(root).appendChild(skeleton(3));
|
|
75
|
+
let payload;
|
|
76
|
+
try {
|
|
77
|
+
payload = await api.jobs();
|
|
78
|
+
} catch (err) {
|
|
79
|
+
clear(root).appendChild(
|
|
80
|
+
el("p", { class: "muted", text: err instanceof Error ? err.message : String(err) }),
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const nowMs = Date.now();
|
|
85
|
+
const model = jobQueueModel(payload);
|
|
86
|
+
clear(root);
|
|
87
|
+
if (model.total === 0) {
|
|
88
|
+
root.appendChild(emptyState("No jobs queued", "crewhaus doctor (or Run now on any harness)"));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const section = (title, jobs, note) => {
|
|
92
|
+
if (jobs.length === 0) return null;
|
|
93
|
+
return el("div", { class: "job-group" }, [
|
|
94
|
+
el("h4", { class: "sub-title", text: `${title} · ${jobs.length}` }),
|
|
95
|
+
note ? el("p", { class: "muted", text: note }) : null,
|
|
96
|
+
jobsTable(jobs.map((j) => jobRow(j, nowMs))),
|
|
97
|
+
]);
|
|
98
|
+
};
|
|
99
|
+
root.appendChild(
|
|
100
|
+
el("div", { class: "job-groups" }, [
|
|
101
|
+
section("Running", model.running),
|
|
102
|
+
section("Pending", model.pending),
|
|
103
|
+
section(
|
|
104
|
+
"Interrupted",
|
|
105
|
+
model.interrupted,
|
|
106
|
+
"these were running when a manager died — closed at boot, never silently re-run",
|
|
107
|
+
),
|
|
108
|
+
]),
|
|
109
|
+
);
|
|
110
|
+
}
|