146 lines
4.5 KiB
JavaScript
146 lines
4.5 KiB
JavaScript
(function () {
|
|
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, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """);
|
|
}
|
|
|
|
function shortTime(iso) {
|
|
if (!iso) return "";
|
|
// keep local-looking wall clock from ISO when possible
|
|
var m = String(iso).match(/T(\d{2}:\d{2})/);
|
|
if (m) return m[1];
|
|
return String(iso).slice(0, 16);
|
|
}
|
|
|
|
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 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 renderTree(data) {
|
|
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";
|
|
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 builtAt = row.built_at || "";
|
|
var buildSec = row.build_seconds;
|
|
var isDefault = branch === defaultBranch;
|
|
var metaBits = [];
|
|
if (tip) metaBits.push("@" + tip);
|
|
if (tipTime) metaBits.push("tip " + shortTime(tipTime));
|
|
if (buildSec != null && buildSec !== "")
|
|
metaBits.push("build " + fmtBuildSec(buildSec));
|
|
if (builtAt) metaBits.push("at " + shortTime(builtAt));
|
|
var label =
|
|
esc(prefix) +
|
|
"<code>" +
|
|
esc(branch) +
|
|
"</code>" +
|
|
(metaBits.length
|
|
? '<span class="tip"> ' + esc(metaBits.join(" · ")) + "</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) +
|
|
'"' +
|
|
(parent ? ' data-parent="' + esc(parent) + '"' : "") +
|
|
(isDefault ? ' data-default="1"' : "") +
|
|
' title="Switch build to ' +
|
|
esc(branch) +
|
|
(tip ? " @ " + esc(tip) : "") +
|
|
(tipTime ? " tip=" + esc(tipTime) : "") +
|
|
(buildSec != null ? " build=" + esc(fmtBuildSec(buildSec)) : "") +
|
|
'">' +
|
|
label +
|
|
"</a>"
|
|
);
|
|
}
|
|
html.push("</div>");
|
|
if (timing && timing.wall_seconds != null) {
|
|
html.push(
|
|
'<div class="cascade-timing">last full pass ~' +
|
|
esc(String(timing.wall_seconds)) +
|
|
"s · built " +
|
|
esc(String(timing.built || 0)) +
|
|
" / skipped " +
|
|
esc(String(timing.skipped || 0)) +
|
|
" / " +
|
|
esc(String(timing.branches || list.length)) +
|
|
"</div>"
|
|
);
|
|
}
|
|
mount.innerHTML = html.join("");
|
|
markActive(mount, cookieEdition());
|
|
}
|
|
|
|
var edition = cookieEdition();
|
|
var mount = document.getElementById("cascade-tree");
|
|
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);
|
|
})
|
|
.catch(function () {
|
|
if (mount) {
|
|
mount.innerHTML =
|
|
'<a class="cascade-tree-row" href="/_cascade/use/flask" data-edition="flask"><code>flask</code></a>' +
|
|
'<span class="tip"> (branch-status unavailable)</span>';
|
|
markActive(mount, edition);
|
|
}
|
|
});
|
|
})();
|