Replace toRelative with toHuman

Signed-off-by: yubiuser <github@yubiuser.dev>
This commit is contained in:
yubiuser
2025-11-09 13:08:09 +01:00
committed by Adam Warner
parent 2b5df96028
commit f34135b47f
5 changed files with 75 additions and 5 deletions

View File

@@ -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();

View File

@@ -389,7 +389,7 @@ function formatInfo(data) {
ttlInfo =
divStart +
"Time-to-live (TTL):&nbsp;&nbsp;" +
luxon.Duration.fromObject({ seconds: data.ttl }).toRelative() +
luxon.Duration.fromObject({ seconds: data.ttl }).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) +
" (" +
data.ttl +
"s)</div>";

View File

@@ -156,7 +156,7 @@ function datetime(date, html, humanReadable) {
html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z";
const timestr = luxon.DateTime.fromMillis(Math.floor(date)).toFormat(format).trim();
return humanReadable
? '<span title="' + timestr + '">' + luxon.DateTime.fromMillis(Math.floor(date)).toRelative() + "</span>"
? '<span title="' + timestr + '">' + luxon.DateTime.fromMillis(Math.floor(date)).toHuman({smallestUnit: "seconds", maxUnits: 2, stripZeroUnits: "all"}) + "</span>"
: 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,

View File

@@ -132,4 +132,5 @@ is_authenticated = mg.request_info.is_authenticated
<script src="<?=pihole.fileversion('vendor/bootstrap/js/bootstrap.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/adminLTE/adminlte.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/nprogress/nprogress.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/luxon/luxon.min.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/js/utils.js')?>"></script>

View File

@@ -16,7 +16,6 @@ mg.include('header.lp','r')
<script src="<?=pihole.fileversion('vendor/datatables-buttons/datatables.buttons.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs/chart.umd.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs-plugin-deferred/chartjs-plugin-deferred.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/luxon/luxon.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/chartjs-adapter-luxon/chartjs-adapter-luxon.umd.min.js')?>"></script>
<script src="<?=pihole.fileversion('vendor/hammer/hammer.min.js')?>"></script> <!-- Needed for chartjs-plugin-zoom -->
<script src="<?=pihole.fileversion('vendor/chartjs-plugin-zoom/chartjs-plugin-zoom.min.js')?>"></script>