diff --git a/scripts/js/footer.js b/scripts/js/footer.js index 49ccc1a6..3b58f063 100644 --- a/scripts/js/footer.js +++ b/scripts/js/footer.js @@ -377,13 +377,13 @@ function updateSystemInfo() { $("#status").prop( "title", "System uptime: " + - luxon.Duration.fromMillis(1000 * system.uptime).toRelative() + + luxon.Duration.fromMillis(1000 * system.uptime).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) + " (running since " + startdate + ")" ); $("#sysinfo-uptime").text( - luxon.Duration.fromMillis(1000 * system.uptime).toRelative() + " (running since " + startdate + ")" + luxon.Duration.fromMillis(1000 * system.uptime).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) + " (running since " + startdate + ")" ); $("#sysinfo-system-overlay").hide(); diff --git a/scripts/js/queries.js b/scripts/js/queries.js index e2997db4..5ec76f0c 100644 --- a/scripts/js/queries.js +++ b/scripts/js/queries.js @@ -389,7 +389,7 @@ function formatInfo(data) { ttlInfo = divStart + "Time-to-live (TTL):  " + - luxon.Duration.fromObject({ seconds: data.ttl }).toRelative() + + luxon.Duration.fromObject({ seconds: data.ttl }).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) + " (" + data.ttl + "s)"; diff --git a/scripts/js/utils.js b/scripts/js/utils.js index aaeabaa1..9d8fc73f 100644 --- a/scripts/js/utils.js +++ b/scripts/js/utils.js @@ -156,7 +156,7 @@ function datetime(date, html, humanReadable) { html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD []HH:mm:ss z"; const timestr = luxon.DateTime.fromMillis(Math.floor(date)).toFormat(format).trim(); return humanReadable - ? '' + luxon.DateTime.fromMillis(Math.floor(date)).toRelative() + "" + ? '' + luxon.DateTime.fromMillis(Math.floor(date)).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) + "" : timestr; } @@ -665,6 +665,76 @@ function toggleBoxCollapse(box, expand = true) { } } +// Convert a luxon Duration to a human-readable string +// Currently, luxon's toHuman() method is broken for milliseconds +// See https://github.com/moment/luxon/issues/1134 +// This is a wrapper that extends the Duration prototype +const Duration = luxon.Duration; +Duration.prototype.__toHuman__ = Duration.prototype.toHuman; +Duration.prototype.toHuman = function(opts = {}) { + let duration = this.normalize(); + let durationUnits = []; + let precision; + if (typeof opts.precision == "object") { + precision = Duration.fromObject(opts.precision); + } + let remainingDuration = duration; + //list of all available units + const allUnits = ["years", "months", "days", "hours", "minutes", "seconds", "milliseconds"]; + let smallestUnitIndex; + let biggestUnitIndex; + // check if user has specified a smallest unit that should be displayed + if (opts.smallestUnit) { + smallestUnitIndex = allUnits.indexOf(opts.smallestUnit); + } + // check if user has specified a biggest unit + if (opts.biggestUnit) { + biggestUnitIndex = allUnits.indexOf(opts.biggestUnit); + } + // use seconds and years as default for smallest and biggest unit + if (!((smallestUnitIndex >= 0) && (smallestUnitIndex < allUnits.length))) smallestUnitIndex = allUnits.indexOf("seconds"); + if (!((biggestUnitIndex <= smallestUnitIndex) && (biggestUnitIndex < allUnits.length))) biggestUnitIndex = allUnits.indexOf("years"); + + for (let unit of allUnits.slice(biggestUnitIndex, smallestUnitIndex + 1)) { + const durationInUnit = remainingDuration.as(unit); + if (durationInUnit >= 1) { + durationUnits.push(unit); + let tmp = {}; + tmp[unit] = Math.floor(remainingDuration.as(unit)); + remainingDuration = remainingDuration.minus(Duration.fromObject(tmp)).normalize(); + + // check if remaining duration is smaller than precision + if (remainingDuration < precision) { + // ok, we're allowed to remove the remaining parts and to round the current unit + break; + } + } + + // check if we have already the maximum count of units allowed + if (durationUnits.length >= opts.maxUnits) { + break; + } + } + // after gathering of units that shall be displayed has finished, remove the remaining duration to avoid non-integers + duration = duration.minus(remainingDuration).normalize(); + duration = duration.shiftTo(...durationUnits); + if (opts.stripZeroUnits == "all") { + durationUnits = durationUnits.filter(unit => duration.values[unit] > 0); + } else if (opts.stripZeroUnits == "end") { + let mayStrip = true; + durationUnits = durationUnits.reverse().filter((unit, index) => { + if (!mayStrip) return true; + if (duration.values[unit] == 0) { + return false; + } else { + mayStrip = false; + } + return true; + }); + } + return duration.shiftTo(...durationUnits).__toHuman__(opts); +} + globalThis.utils = (function () { return { escapeHtml, diff --git a/scripts/lua/header.lp b/scripts/lua/header.lp index 860a1d6f..8035550c 100644 --- a/scripts/lua/header.lp +++ b/scripts/lua/header.lp @@ -132,4 +132,5 @@ is_authenticated = mg.request_info.is_authenticated + diff --git a/scripts/lua/header_authenticated.lp b/scripts/lua/header_authenticated.lp index 2518fe26..23c9cde6 100644 --- a/scripts/lua/header_authenticated.lp +++ b/scripts/lua/header_authenticated.lp @@ -16,7 +16,6 @@ mg.include('header.lp','r') -