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')
-