From c6b1e9a080617b4f2892a9e3bf9d2e4a2da0a610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=80=D0=B5=D0=B2?= Date: Sun, 7 Jun 2026 01:40:50 +0300 Subject: [PATCH] fix: defer auto refresh while editing --- admin-web/static/app.js | 36 ++++++++++++++++++++++++++++++++---- admin-web/static/index.html | 4 ++-- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/admin-web/static/app.js b/admin-web/static/app.js index 23a6791..b6405b9 100644 --- a/admin-web/static/app.js +++ b/admin-web/static/app.js @@ -538,6 +538,7 @@ const state = { qrLink: "", pendingUsers: new Set(), refreshingAll: false, + deferredRefresh: false, autoRefreshEnabled: localStorage.getItem("pcatelegram_web-auto-refresh") !== "0", }; @@ -616,7 +617,7 @@ function syncAutoRefreshTimer() { } if (!state.autoRefreshEnabled) return; autoRefreshTimer = setInterval(() => { - refreshAll().catch((err) => toast(err.message)); + refreshAll({ background: true }).catch((err) => toast(err.message)); }, AUTO_REFRESH_MS); } @@ -627,6 +628,22 @@ function setAutoRefresh(enabled) { syncAutoRefreshTimer(); } +function activeEditable() { + const el = document.activeElement; + if (!el || el === document.body) return null; + return el.closest?.("input, select, textarea, [contenteditable='true']"); +} + +function isUserEditing() { + return Boolean(activeEditable()); +} + +function runDeferredRefresh() { + if (!state.deferredRefresh || isUserEditing()) return; + state.deferredRefresh = false; + refreshAll({ background: true }).catch((err) => toast(err.message)); +} + async function api(path, options = {}) { const headers = { "Accept": "application/json", @@ -1516,11 +1533,15 @@ function renderRoutingSettings(payload = null) { setRoutingNotes(routing); } -async function refreshAll() { +async function refreshAll(options = {}) { + if (options.background && isUserEditing()) { + state.deferredRefresh = true; + return; + } if (state.refreshingAll) return; state.refreshingAll = true; const btn = $("#refreshBtn"); - btn.disabled = true; + if (!options.background) btn.disabled = true; try { state.overview = await api("/api/overview"); state.backupSchedule = state.overview.backup_schedule || state.backupSchedule; @@ -1543,6 +1564,10 @@ async function refreshAll() { status: state.overview.stats_status || state.stats.status || {}, }; } + if (options.background && isUserEditing()) { + state.deferredRefresh = true; + return; + } renderOverview(); renderUsers(); renderRoutingSettings(); @@ -1556,7 +1581,7 @@ async function refreshAll() { } catch (err) { toast(err.message); } finally { - btn.disabled = false; + if (!options.background) btn.disabled = false; state.refreshingAll = false; updateAutoRefreshToggle(); } @@ -2041,6 +2066,9 @@ $("#routingPort").addEventListener("change", (eventObj) => checkRoutingPort(even $("#warpSettingsForm").addEventListener("submit", saveWarpSettings); $("#warpScope").addEventListener("change", renderWarpSettings); $("#warpUserSelect").addEventListener("change", renderWarpSettings); +document.addEventListener("focusout", () => { + setTimeout(runDeferredRefresh, 120); +}); window.addEventListener("hashchange", () => setPage((location.hash || "#dashboard").slice(1), false)); setPage((location.hash || "#dashboard").slice(1), false); diff --git a/admin-web/static/index.html b/admin-web/static/index.html index 8d1ef33..2f23ca1 100644 --- a/admin-web/static/index.html +++ b/admin-web/static/index.html @@ -11,7 +11,7 @@ document.documentElement.dataset.theme = theme; }()); - +
@@ -482,6 +482,6 @@
- +