perf prevent overlapping refreshes

- skip a scheduled dashboard refresh while the previous cycle is active - reuse an in-flight probe chart request instead of issuing a duplicate

Commit
8e7769e1966d598152c576e6b53a824986b43632
Author
GPT-5 medium <codex@openai.com>
Author date
Committer
GPT-5 medium <codex@openai.com>
Committer date
Changed files
roles/dashboard/public/js/dashboard.js
index b1350044..7a84d19d 100644..100644
@@ -32,10 +32,19 @@
32 32 probes.loadDisplayed();
33 33 }
34 34
35 Added: let refreshInFlight = null;
36 Added:
35 37 function refreshDashboard() {
36 Removed: probes.loadDisplayed();
37 Removed: loadQuickReadings();
38 Removed: loadStatuses();
38 Added: if (refreshInFlight) return refreshInFlight;
39 Added:
40 Added: refreshInFlight = Promise.allSettled([
41 Added: probes.loadDisplayed(),
42 Added: loadQuickReadings(),
43 Added: loadStatuses()
44 Added: ]).finally(() => {
45 Added: refreshInFlight = null;
46 Added: });
47 Added: return refreshInFlight;
39 48 }
40 49
41 50 refreshDashboard();
roles/dashboard/public/js/dashboard/charts.js
index 6fd78fa1..4a596263 100644..100644
@@ -210,8 +210,9 @@
210 210
211 211 export function createProbeCharts(timeframe) {
212 212 const charts = new Map();
213 Added: const loading = new Map();
213 214
214 Removed: async function loadProbe(probe) {
215 Added: async function requestProbe(probe) {
215 216 const canvas = chartElement(probe);
216 217 if (!probe || !canvas) return;
217 218
@@ -268,6 +269,16 @@
268 269 }
269 270 }
270 271
272 Added: function loadProbe(probe) {
273 Added: if (loading.has(probe)) return loading.get(probe);
274 Added:
275 Added: const request = requestProbe(probe).finally(() => {
276 Added: if (loading.get(probe) === request) loading.delete(probe);
277 Added: });
278 Added: loading.set(probe, request);
279 Added: return request;
280 Added: }
281 Added:
271 282 function activateTab(probe) {
272 283 document.querySelectorAll(".tab-button").forEach(button => {
273 284 const active = button.dataset.probe === probe;
@@ -298,7 +309,7 @@
298 309 activateTab,
299 310 displayedProbes,
300 311 loadProbe,
301 Removed: loadDisplayed: () => displayedProbes().forEach(loadProbe),
312 Added: loadDisplayed: () => Promise.all(displayedProbes().map(loadProbe)),
302 313 probeFromLocation,
303 314 probeFromHash: () => window.location.hash.match(/^#probe-([a-z]+)$/)?.[1] || null
304 315 };