feat: add tooltip to status page
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
// Click-to-expand for compact display mode on the public status page.
|
||||
// Loaded by status pages that have at least one monitor in compact mode.
|
||||
// Public status page client JS:
|
||||
// 1. Bar tooltips (always active) — hover any heartbeat bar to see the
|
||||
// bucket time range and uptime breakdown.
|
||||
// 2. Click-to-expand for compact display mode (only fires when there are
|
||||
// compact monitors on the page).
|
||||
// Reads its config from window.PINGQL_PAGE.
|
||||
(function () {
|
||||
var cfg = window.PINGQL_PAGE || {};
|
||||
@@ -8,6 +11,81 @@
|
||||
var showResponseTime = !!cfg.show_response_time;
|
||||
if (!slug) return;
|
||||
|
||||
// ── Bar tooltips ──────────────────────────────────────────────────────
|
||||
var tooltip = document.getElementById("bar-tooltip");
|
||||
if (tooltip) {
|
||||
var bucketSpanMs = (defaultWindow === "24h") ? 3600 * 1000
|
||||
: (defaultWindow === "7d") ? 86400 * 1000
|
||||
: (defaultWindow === "30d") ? 86400 * 1000
|
||||
: 7 * 86400 * 1000;
|
||||
function fmtBucketRange(startIso) {
|
||||
var start = new Date(startIso);
|
||||
var end = new Date(start.getTime() + bucketSpanMs);
|
||||
var sameDay = start.toDateString() === new Date(end.getTime() - 1).toDateString();
|
||||
var dateOpts = { month: "short", day: "numeric" };
|
||||
var timeOpts = { hour: "2-digit", minute: "2-digit" };
|
||||
if (defaultWindow === "24h") {
|
||||
return start.toLocaleDateString(undefined, dateOpts) + ", " +
|
||||
start.toLocaleTimeString(undefined, timeOpts) + " — " +
|
||||
end.toLocaleTimeString(undefined, timeOpts);
|
||||
}
|
||||
if (defaultWindow === "7d" || defaultWindow === "30d") {
|
||||
return start.toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric" });
|
||||
}
|
||||
// 90d → weekly buckets
|
||||
var endLabel = new Date(end.getTime() - 1).toLocaleDateString(undefined, dateOpts);
|
||||
return "Week of " + start.toLocaleDateString(undefined, dateOpts) + " — " + endLabel;
|
||||
}
|
||||
function uptimeBand(p) {
|
||||
if (p == null) return "";
|
||||
if (p >= 99.9) return "good";
|
||||
if (p >= 99.0) return "warn";
|
||||
return "bad";
|
||||
}
|
||||
|
||||
function showTooltipForBar(bar, evt) {
|
||||
var total = parseInt(bar.getAttribute("data-total") || "0", 10);
|
||||
var up = parseInt(bar.getAttribute("data-up") || "0", 10);
|
||||
var start = bar.getAttribute("data-start");
|
||||
if (!start) return;
|
||||
var pct = total > 0 ? Math.round(1000 * up / total) / 10 : null;
|
||||
var pctText = pct == null ? "—" : (pct === 100 ? "100%" : pct.toFixed(1) + "%");
|
||||
var html = '<div class="head">' + fmtBucketRange(start) + "</div>";
|
||||
if (total > 0) {
|
||||
html += '<div class="row"><span>Checks</span><span>' + total + "</span></div>";
|
||||
html += '<div class="row"><span>Successful</span><span>' + up + "</span></div>";
|
||||
html += '<div class="row"><span>Uptime</span><span class="pct ' + uptimeBand(pct) + '">' + pctText + "</span></div>";
|
||||
} else {
|
||||
html += '<div class="row"><span>No data</span><span>—</span></div>';
|
||||
}
|
||||
tooltip.innerHTML = html;
|
||||
tooltip.style.display = "block";
|
||||
var rect = bar.getBoundingClientRect();
|
||||
// Position at top-center of the bar.
|
||||
tooltip.style.left = (rect.left + rect.width / 2) + "px";
|
||||
tooltip.style.top = rect.top + "px";
|
||||
}
|
||||
function hideTooltip() {
|
||||
tooltip.style.display = "none";
|
||||
}
|
||||
|
||||
// Delegate from each .bars container so dynamically-rendered bars
|
||||
// (compact mode click-to-expand) work too.
|
||||
document.addEventListener("mouseover", function (e) {
|
||||
var bar = e.target && e.target.closest && e.target.closest(".bar");
|
||||
if (bar && bar.parentElement && bar.parentElement.classList.contains("bars")) {
|
||||
showTooltipForBar(bar, e);
|
||||
}
|
||||
});
|
||||
document.addEventListener("mouseout", function (e) {
|
||||
var bar = e.target && e.target.closest && e.target.closest(".bar");
|
||||
if (bar) hideTooltip();
|
||||
});
|
||||
// Hide on scroll so the tooltip doesn't lag behind the bar.
|
||||
window.addEventListener("scroll", hideTooltip, { passive: true });
|
||||
}
|
||||
// ── End bar tooltips ──────────────────────────────────────────────────
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s)
|
||||
.replace(/&/g, "&")
|
||||
|
||||
Reference in New Issue
Block a user