From 01035371ff73b06c9ab8b7eaedb2c7c4d1e21a86 Mon Sep 17 00:00:00 2001 From: marvin Date: Sun, 13 Sep 2026 20:23:33 -0400 Subject: [PATCH] Performance tab: add time-range selector, fix gap between Trend and Per-route panels --- package.json | 2 +- src/public/app.js | 6 ++++-- src/public/index.html | 2 +- src/public/styles.css | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 9a469ce..e74b79f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "site-gateway", - "version": "0.11.63", + "version": "0.11.64", "private": true, "description": "Site Gateway: simple self-hosted website publishing, reverse proxying, and automatic HTTPS.", "type": "module", diff --git a/src/public/app.js b/src/public/app.js index 82b399d..0230e2a 100644 --- a/src/public/app.js +++ b/src/public/app.js @@ -242,7 +242,8 @@ function renderPerformance() { $("#performance-host").value = selected; const label = selected ? escapeHtml(selected) : "all domains"; $("#performance-summary").innerHTML = `${data.liveRequests} request${data.liveRequests === 1 ? "" : "s"} in the last minute across ${label} · Checked ${escapeHtml(formatTime(data.checkedAt))}`; - $("#performance-trend-title").textContent = `Requests · last 6 hours${selected ? ` · ${selected}` : ""}`; + const rangeLabel = $("#performance-range").selectedOptions[0]?.textContent || "Last 6 hours"; + $("#performance-trend-title").textContent = `Requests · ${rangeLabel.toLowerCase()}${selected ? ` · ${selected}` : ""}`; const points = data.trend || []; const max = Math.max(1, ...points.map(point => point.count)); const left = 34, right = 8, top = 10, bottom = 20, width = 600, height = 140; @@ -306,7 +307,7 @@ function renderUsers() { async function loadFeatureView() { if (state.view === "certificates") { [state.certificates, state.readiness] = await Promise.all([api("/api/certificates"), api("/api/readiness")]); renderCertificates(); } if (state.view === "logs") { state.logs = await api(`/api/logs?host=${encodeURIComponent($("#log-host").value)}`); renderLogs(); } - if (state.view === "performance") { state.performance = await api(`/api/performance?host=${encodeURIComponent($("#performance-host").value)}`); renderPerformance(); } + if (state.view === "performance") { state.performance = await api(`/api/performance?host=${encodeURIComponent($("#performance-host").value)}&hours=${encodeURIComponent($("#performance-range").value || "6")}`); renderPerformance(); } if (state.view === "administration") { [state.users, state.settings, state.backups] = await Promise.all([api("/api/users"), api("/api/settings"), api("/api/backups")]); renderUsers(); window.renderExtendedViews?.(); } if (["redirects","access","documentation"].includes(state.view)) window.renderExtendedViews?.(); restoreAdminTab(); @@ -403,6 +404,7 @@ $("#dashboard-view").addEventListener("click", event => { const target = event.t $("#refresh-logs").addEventListener("click", () => loadFeatureView().catch(error => toast(error.message))); $("#log-host").addEventListener("change", () => loadFeatureView().catch(error => toast(error.message))); $("#performance-host").addEventListener("change", () => loadFeatureView().catch(error => toast(error.message))); +$("#performance-range").addEventListener("change", () => loadFeatureView().catch(error => toast(error.message))); $("#log-status").addEventListener("change", renderLogs); $("#event-severity").addEventListener("change", renderLogs); $("#event-category").addEventListener("change", renderLogs); diff --git a/src/public/index.html b/src/public/index.html index 05b5c8b..213e1bb 100644 --- a/src/public/index.html +++ b/src/public/index.html @@ -141,7 +141,7 @@

Gateway events

Activity and errors

Configuration, certificate, and health events recorded by Site Gateway.