blob: bc9554cc4395bd7bdc2199348f9e665356187c8d (
plain) (
tree)
|
|
const ICON_VIEW = "⬇";
const ICON_MAINT = "↻";
const ICON_EVENT = "ϟ";
const ICON_PASS = "✔";
const ICON_FAIL = "✖";
let version = null;
let latest_job = -1;
async function api(x) {
let r = await fetch(x);
return r.json();
}
function icon_progress() {
// Use random braille glyphs to create a moving progress effect.
let i = Math.floor(Math.random() * (0x28ff - 0x2801)) + 0x2801;
return `&#${i};`;
}
function set_progress(element, x) {
if (x !== null || element.className == "") {
element.className = (x === null ? "progress" : "");
element.innerHTML = (x === null ? icon_progress() : x);
}
}
function set_time(element) {
let timestamp = element.dataset.timestamp;
let seconds = Math.floor((Date.now() / 1000) - timestamp);
let minutes = Math.floor(seconds / 60);
let hours = Math.floor(minutes / 60);
let days = Math.floor(hours / 24);
if (seconds < 120) {
element.innerText = `${seconds} seconds ago`;
} else if (minutes < 120) {
element.innerText = `${minutes} minutes ago`;
} else if (hours < 48) {
element.innerText = `${hours} hours ago`;
} else {
element.innerText = `${days} days ago`;
}
}
function touch_job(list, job) {
// New job, new <div>
if (document.getElementById(`${job.job}`) === null) {
let abv_hash = job.hash.substring(0, 16);
let reason = (job.reason == "event" ? ICON_EVENT : ICON_MAINT);
let element = document.createElement("div");
list.insertBefore(element, list.childNodes[0]);
element.innerHTML = `
<div class="box" id="${job.job}">
<div class="box-title">
<a href="/api/log/${job.job}/%($CYCHE_LOG_FILENAME%)">
<span class="button">${ICON_VIEW}</span>
</a>
#${job.job}
${job.service}
<small><i>${abv_hash}</i></small>
<span class="right">
<span class="time" id="${job.job}_time"
data-timestamp="${job.time}"></span>
<span id="${job.job}_result"></span>
${reason}
</span>
</div>
<div class="box-text">
<pre id="${job.job}_log"></pre>
</div>
</div>`;
let time = document.getElementById(`${job.job}_time`);
set_time(time);
}
// Update existing
let box = document.getElementById(`${job.job}`);
let result = document.getElementById(`${job.job}_result`);
let log = document.getElementById(`${job.job}_log`);
let cn = (job.reason == "remove" ? "standout" : job.result);
box.className = `box ${cn}`;
switch (job.result) {
case "active": set_progress(result, null); break;
case "fail": set_progress(result, ICON_FAIL); break;
case "pass": set_progress(result, ICON_PASS); break;
}
log.innerText = job.log;
}
async function update_jobs() {
let nav_progress = document.getElementById("nav_progress");
let no_server = document.getElementById("no_server");
let no_jobs = document.getElementById("no_jobs");
let list = document.getElementById("list");
let timeout = %($CYCHE_ACTIVE_UPDATE%);
try {
let status = await api("/api/status");
if (version === null) { version = status.version; }
if (version != status.version) { location.reload(); }
if (!status.active) { timeout = %($CYCHE_IDLE_UPDATE%); }
set_progress(nav_progress, (status.active ? null : ""));
for (let i = status.oldest; i <= status.newest; i++) {
if (i >= latest_job) {
let job = await api(`/api/job/${i}`);
touch_job(list, job);
latest_job = i;
}
}
if (list.childElementCount > 0) {
list.classList.remove("hidden");
no_jobs.classList.add("hidden");
}
no_server.classList.add("hidden");
} catch (ex) {
no_server.classList.remove("hidden");
console.log(ex);
}
setTimeout(update_jobs, timeout);
}
function update_times() {
let elements = document.getElementsByClassName("time");
for (let e of elements) {
set_time(e);
}
}
function update_progress() {
let elements = document.getElementsByClassName("progress");
for (let e of elements) {
e.innerHTML = icon_progress();
}
}
update_jobs();
update_progress();
setInterval(update_times, 1000);
setInterval(update_progress, %($CYCHE_PROGRESS_ANIM_SPEED%));
|