src-gui/js/ui-polling.js
Rama main · réplica de lectura del repositorio original.
// SPDX-License-Identifier: GPL-3.0-or-later
/* === Auto-refresh polling === */
let autoRefresh = true;
let pollTimer = null;
let pollBusy = false;
function reportSignature(d) {
if (!d) return "";
return JSON.stringify([d.generatedAt || "", d.score || 0, d.scoreDelta || 0, d.findings || [], d.diffSinceLast || null]);
}
function pollPaused() {
if (!autoRefresh || document.hidden || pollBusy) return true;
if ($("#rerun").disabled) return true;
if ($("#search").value.trim()) return true;
if (activeFilter && activeFilter !== "all") return true;
// Only cards the user can actually see pause the refresh — an open card
// in a hidden Overview must not freeze updates forever.
if (document.getElementById("view-overview")?.hidden) return false;
return document.querySelectorAll("#report details[open]").length > 0;
}
function syncAutoPausedUI() {
const autoBtn = $("#autorefresh");
if (!autoBtn) return;
const paused = pollPaused();
autoBtn.classList.toggle("paused", paused && autoRefresh);
if (!autoRefresh) autoBtn.title = "Auto-refresh off \u2014 click to enable";
else if (paused) autoBtn.title = "Paused \u2014 clear filter/search or collapse cards to resume";
else autoBtn.title = "Auto-refresh every 5s";
autoBtn.setAttribute("aria-pressed", String(autoRefresh));
autoBtn.setAttribute("aria-label", autoBtn.title);
}
async function poll() {
if (pollPaused()) return;
pollBusy = true;
try {
const data = await fetchReport();
if (reportSignature(data) !== reportSignature(lastData)) {
render(data);
// Quiet confirmation that the background refresh changed something —
// a green pulse on the Auto button, gone in ~1.5s. No toast noise.
const btn = $("#autorefresh");
if (btn) {
btn.classList.add("updated");
setTimeout(() => btn.classList.remove("updated"), 1600);
}
}
} catch {}
finally { pollBusy = false; }
}
function startPolling() {
clearInterval(pollTimer);
pollTimer = setInterval(poll, POLL_MS);
}
function setupPolling() {
const autoBtn = $("#autorefresh");
if (autoBtn) {
autoBtn.setAttribute("aria-pressed", String(autoRefresh));
autoBtn.addEventListener("click", () => {
autoRefresh = !autoRefresh;
autoBtn.classList.toggle("on", autoRefresh);
syncAutoPausedUI();
showToast(autoRefresh ? "Auto-refresh on" : "Auto-refresh off");
});
}
setInterval(syncAutoPausedUI, 1000);
document.addEventListener("toggle", (e) => {
if (e.target.matches("#report details")) syncAutoPausedUI();
if (e.target.classList.contains("ev") && e.target.open) {
const ev = e.target.querySelector(".evidence");
const btn = e.target.querySelector(".ev-expand");
if (ev && btn && ev.scrollHeight > 228) btn.hidden = false;
}
}, true);
document.addEventListener("visibilitychange", () => {
if (document.hidden) { clearInterval(pollTimer); }
else { startPolling(); }
});
}