1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
function chipClass(status) {
if (status === "ok") return "good";
if (status === "failed" || status === "lost" || status === "killed") return "bad";
if (status === "running" || status === "busy" || status === "starting") return "warn";
return "muted";
}
function when(ts) {
if (!ts) return "";
return new Date(ts * 1000).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
}
function summary(jobs) {
const running = jobs.filter((j) => ["running", "busy", "starting"].includes(j.status)).length;
const failed = jobs.filter((j) => ["failed", "lost", "killed"].includes(j.status)).length;
const parts = [];
if (running) parts.push(`${running} running`);
if (failed) parts.push(`${failed} failed`);
if (!parts.length) parts.push(jobs.length ? `${jobs.length} recent` : "idle");
return parts.join(" · ");
}
export default {
title: "Build VM",
interval: 5,
mount(el) {
el.innerHTML = `<div class="sbb"><div class="sbb-summary muted"></div><div class="sbb-list"></div></div>`;
},
update(state, el) {
const sum = el.querySelector(".sbb-summary");
const list = el.querySelector(".sbb-list");
if (state.offline) {
sum.textContent = "";
list.textContent = "build VM unreachable";
return;
}
const jobs = state.jobs ?? [];
sum.textContent = summary(jobs);
list.textContent = "";
for (const job of jobs.slice(0, 8)) {
const row = document.createElement("div");
row.className = "row job";
const kind = document.createElement("span");
kind.className = "kind";
kind.textContent = job.kind || "job";
const time = document.createElement("span");
time.className = "muted num";
time.textContent = when(job.created);
const status = document.createElement("span");
status.className = chipClass(job.status);
status.textContent = job.status;
row.append(kind, time, status);
list.append(row);
}
},
};
|