koopa-admin-log/sites/dossiers.ngi.hacktivism.ch/cascade/_cascade/bar.js

298 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function () {
var POLL_MS = 30000;
function cookieEdition() {
var m = document.cookie.match(/(?:^|; )tdpd_edition=([^;]*)/);
if (!m) return "flask";
try {
return decodeURIComponent(m[1]) || "flask";
} catch (e) {
return "flask";
}
}
function esc(s) {
return String(s)
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;");
}
/** ISO → "YYYY-MM-DD HH:MM" (date required; clock-only was misleading across days). */
function shortTime(iso) {
if (!iso) return "";
var m = String(iso).match(
/^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})(?::\d{2})?/
);
if (m) return m[1] + " " + m[2];
return String(iso).slice(0, 16).replace("T", " ");
}
function fmtBuildSec(sec) {
if (sec == null || sec === "") return "";
var n = Number(sec);
if (!isFinite(n)) return "";
if (n < 10) return n.toFixed(1) + "s";
return Math.round(n) + "s";
}
function metaHtml(row) {
var tip = row.tip || "";
var tipTime = row.tip_time || "";
var builtAt = row.built_at || "";
var buildSec = row.build_seconds;
var parts = [];
if (tip) parts.push(esc("@" + tip));
if (tipTime) parts.push(esc(shortTime(tipTime)));
if (buildSec != null && buildSec !== "")
parts.push(esc(fmtBuildSec(buildSec)));
if (builtAt) parts.push(esc(shortTime(builtAt)));
// vs parent: +grün / −rot (omit when no parent)
var plus = row.vs_parent_plus;
var minus = row.vs_parent_minus;
if (row.parent && (plus != null || minus != null)) {
var p = plus == null ? 0 : Number(plus);
var m = minus == null ? 0 : Number(minus);
if (isFinite(p) && isFinite(m)) {
parts.push(
'<span class="diff-plus">+' +
esc(String(p)) +
'</span> <span class="diff-minus">−' +
esc(String(m)) +
"</span>"
);
}
}
return parts.join(" · ");
}
function rowTitle(row, buildSec) {
var tip = row.tip || "";
var tipTime = row.tip_time || "";
var plus = row.vs_parent_plus;
var minus = row.vs_parent_minus;
var vs = "";
if (row.parent && (plus != null || minus != null)) {
vs =
" vs " +
row.parent +
" +" +
String(plus == null ? 0 : plus) +
"/−" +
String(minus == null ? 0 : minus);
}
return (
"Switch build to " +
(row.branch || "") +
(tip ? " @ " + tip : "") +
(tipTime ? " tip=" + tipTime : "") +
(buildSec != null && buildSec !== ""
? " build=" + fmtBuildSec(buildSec)
: "") +
vs
);
}
function structureKey(list) {
var parts = [];
for (var i = 0; i < list.length; i++) {
var row = list[i];
parts.push(
(row.edition || "") +
"\t" +
(row.branch || "") +
"\t" +
(row.prefix || "") +
"\t" +
(row.parent || "")
);
}
return parts.join("\n");
}
function pinBar(timingMsg) {
var bar = document.getElementById("cascade-bar");
if (!bar) return;
if (timingMsg) {
bar.setAttribute("data-timing", timingMsg);
bar.setAttribute("title", timingMsg);
}
var h = bar.offsetHeight || 0;
document.documentElement.style.setProperty("--cascade-pad", h + "px");
}
function markActive(root, edition) {
var links = root.querySelectorAll("a[data-edition]");
for (var i = 0; i < links.length; i++) {
var a = links[i];
var ed = a.getAttribute("data-edition");
var on =
ed === edition ||
(edition === "flask" && a.getAttribute("data-default") === "1");
if (on) {
a.classList.add("is-active");
a.setAttribute("aria-current", "page");
} else {
a.classList.remove("is-active");
a.removeAttribute("aria-current");
}
}
}
function timingText(timing, listLen) {
if (!timing || timing.wall_seconds == null) return "";
return (
"last full pass ~" +
String(timing.wall_seconds) +
"s · built " +
String(timing.built || 0) +
" / skipped " +
String(timing.skipped || 0) +
" / " +
String(timing.branches || listLen)
);
}
function updateValues(mount, data) {
var list = (data && data.branches) || [];
var defaultBranch = (data && data.default_branch) || "feat/website-views";
var timing = (data && data.rebuild_timing) || null;
var rows = mount.querySelectorAll("a.cascade-tree-row[data-edition]");
if (rows.length !== list.length) return false;
for (var i = 0; i < list.length; i++) {
var row = list[i];
var a = rows[i];
if (a.getAttribute("data-edition") !== (row.edition || "")) return false;
if (a.getAttribute("data-branch") !== (row.branch || "")) return false;
var tipHtml = metaHtml(row);
var tipEl = a.querySelector(".tip");
var wantTip = tipHtml ? " " + tipHtml : "";
if (tipEl) {
if (tipEl.innerHTML !== wantTip) tipEl.innerHTML = wantTip;
} else if (wantTip) {
tipEl = document.createElement("span");
tipEl.className = "tip";
tipEl.innerHTML = wantTip;
a.appendChild(tipEl);
}
var defEl = a.querySelector(".cascade-default");
var isDefault = (row.branch || "") === defaultBranch;
if (isDefault && !defEl) {
defEl = document.createElement("span");
defEl.className = "cascade-default";
defEl.textContent = " · default";
a.appendChild(defEl);
} else if (!isDefault && defEl) {
defEl.parentNode.removeChild(defEl);
}
a.setAttribute("title", rowTitle(row, row.build_seconds));
}
var timingEl = mount.querySelector(".cascade-timing");
var t = timingText(timing, list.length);
if (t) {
if (!timingEl) {
timingEl = document.createElement("div");
timingEl.className = "cascade-timing";
mount.appendChild(timingEl);
}
if (timingEl.textContent !== t) timingEl.textContent = t;
} else if (timingEl) {
timingEl.parentNode.removeChild(timingEl);
}
markActive(mount, cookieEdition());
pinBar(t);
return true;
}
function renderTree(data, soft) {
var mount = document.getElementById("cascade-tree");
if (!mount) return;
var list = (data && data.branches) || [];
if (!list.length) {
mount.textContent = "No branches in branch-status.json";
pinBar();
return;
}
if (soft && mount.getAttribute("data-structure") === structureKey(list)) {
if (updateValues(mount, data)) return;
}
var defaultBranch = (data && data.default_branch) || "feat/website-views";
var timing = (data && data.rebuild_timing) || null;
var html = [];
html.push('<div class="cascade-tree-lines" role="group">');
for (var i = 0; i < list.length; i++) {
var row = list[i];
var edition = row.edition || "";
var branch = row.branch || "";
var tip = row.tip || "";
var prefix = row.prefix || "";
var parent = row.parent || "";
var tipTime = row.tip_time || "";
var buildSec = row.build_seconds;
var isDefault = branch === defaultBranch;
var tipHtml = metaHtml(row);
var label =
esc(prefix) +
"<code>" +
esc(branch) +
"</code>" +
(tipHtml ? '<span class="tip"> ' + tipHtml + "</span>" : "") +
(isDefault ? '<span class="cascade-default"> · default</span>' : "");
html.push(
'<a class="cascade-tree-row" role="treeitem" href="/_cascade/use/' +
esc(edition) +
'" data-edition="' +
esc(edition) +
'" data-branch="' +
esc(branch) +
'"' +
(parent ? ' data-parent="' + esc(parent) + '"' : "") +
(isDefault ? ' data-default="1"' : "") +
' title="' +
esc(rowTitle(row, buildSec)) +
'">' +
label +
"</a>"
);
}
html.push("</div>");
var t = timingText(timing, list.length);
if (t) {
html.push('<div class="cascade-timing">' + esc(t) + "</div>");
}
mount.innerHTML = html.join("");
mount.setAttribute("data-structure", structureKey(list));
markActive(mount, cookieEdition());
pinBar(t);
}
function loadStatus(soft) {
var mount = document.getElementById("cascade-tree");
return fetch("/branch-status.json", { cache: "no-store" })
.then(function (res) {
if (!res.ok) throw new Error("status");
return res.json();
})
.then(function (data) {
renderTree(data, !!soft);
})
.catch(function () {
if (!soft && mount && !mount.querySelector("a[data-edition]")) {
mount.innerHTML =
'<a class="cascade-tree-row" href="/_cascade/use/flask" data-edition="flask" data-branch="flask"><code>flask</code></a>' +
'<span class="tip"> (branch-status unavailable)</span>';
markActive(mount, cookieEdition());
pinBar();
}
});
}
loadStatus(false);
setInterval(function () {
loadStatus(true);
}, POLL_MS);
window.addEventListener("resize", function () {
pinBar();
});
})();