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 = `
`; }, 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); } }, };