aboutsummaryrefslogtreecommitdiffstats
path: root/static/modules/sbbuilder.js
blob: 02493af597c292d4a7f66d70d6f83a4342ef43b4 (plain)
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
const gib = (b) => (b == null ? "?" : (b / 1073741824).toFixed(1));
const pct = (n) => (n == null ? "?" : `${Math.round(n)}%`);
const up = (s) => {
  if (s == null) return "?";
  const d = Math.floor(s / 86400);
  const h = Math.floor((s % 86400) / 3600);
  return d ? `${d}d ${h}h` : `${h}h`;
};
const ago = (ts) => {
  if (!ts) return "—";
  const d = Math.max(0, Math.floor(Date.now() / 1000 - ts));
  if (d < 3600) return `${Math.floor(d / 60)}m`;
  if (d < 86400) return `${Math.floor(d / 3600)}h`;
  return `${Math.floor(d / 86400)}d`;
};

const ACTIVE = ["running", "busy", "starting"];

function metric(label, value) {
  const row = document.createElement("div");
  row.className = "metric";
  const k = document.createElement("span");
  k.className = "k";
  k.textContent = label;
  const v = document.createElement("span");
  v.className = "v num";
  v.textContent = value;
  row.append(k, v);
  return row;
}

export default {
  title: "Build VM",
  interval: 10,

  mount(el) {
    el.innerHTML = `<div class="sbb"></div>`;
  },

  update(state, el) {
    const box = el.querySelector(".sbb");
    box.textContent = "";
    if (state.offline) {
      box.textContent = "build VM unreachable";
      return;
    }
    const s = state.stats ?? {};
    const p = s.packages ?? {};
    const sr = s.slackrepo ?? {};
    const jobs = state.jobs ?? [];

    const running = jobs.find((j) => ACTIVE.includes(j.status));
    const now = document.createElement("div");
    now.className = "sbb-now";
    now.textContent = running ? `● ${running.kind || "job"} running` : "idle";
    now.classList.toggle("warn", Boolean(running));
    box.append(now);

    const overlays = Object.entries(p).filter(([k]) => k !== "total" && k !== "shadowed");
    const results = Object.entries(sr.results ?? {});
    box.append(
      metric("CPU · load", `${pct(s.cpu)} · ${s.load ? s.load[0].toFixed(2) : "?"}`),
      metric("Uptime", up(s.uptime)),
      metric("Memory", `${gib((s.mem?.total ?? 0) - (s.mem?.available ?? 0))} / ${gib(s.mem?.total)} GiB`),
      metric("Disk free", `${gib(s.disk?.free)} / ${gib(s.disk?.total)} GiB`),
      metric("Packages", `${p.total ?? "?"}${overlays.length ? " · " + overlays.map(([k, v]) => `${k} ${v}`).join(" · ") : ""}`),
      metric("Shadowed · orphans", `${p.shadowed ?? "?"} · ${s.orphans ?? "?"}`),
      metric("Built · results", `${sr.built ?? "?"}${results.length ? " · " + results.map(([k, v]) => `${v} ${k}`).join(" · ") : ""}`),
      metric("Overlay pulls", Object.entries(s.sync ?? {}).map(([k, v]) => `${k} ${ago(v)}`).join(" · ") || "—"),
    );
  },
};