From 9b0c26846aa1f39cfc30da86593e4454df321023 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:59:07 +0100 Subject: [PATCH] fix(sync): guard the Sync-now button against concurrent runs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clicking Sync twice started a second concurrent runSyncNow, and the click event was passed as runSyncNow's `_attempt` retry counter (so the "Syncing…" toast and 412-retry bound were both broken). Wrapped the handler: disable the button while a sync runs, and call runSyncNow() with no arg. Internal retries are unaffected. Co-Authored-By: Claude Opus 4.8 --- js/app.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/js/app.js b/js/app.js index 60c1695..642a48c 100644 --- a/js/app.js +++ b/js/app.js @@ -8938,7 +8938,15 @@ async function init() { Bridge.setPref(SYNC_PREFS.preBackup, e.target.checked ? '1' : '')); if (syncSetPwd) syncSetPwd.addEventListener('click', syncSetEncPwdFlow); if (syncTest) syncTest.addEventListener('click', syncTestConnection); - if (syncNow) syncNow.addEventListener('click', runSyncNow); + // Guard the user entry point: ignore clicks while a sync is running (no + // concurrent syncs) and call runSyncNow() with NO arg — the click event + // must not land in its `_attempt` retry counter. Internal retries call + // runSyncNow directly, so they're unaffected. + if (syncNow) syncNow.addEventListener('click', async () => { + if (syncNow.disabled) return; + syncNow.disabled = true; + try { await runSyncNow(); } finally { syncNow.disabled = false; } + }); $('#settingAutoBackupEnabled').addEventListener('change', onToggleAutoBackup); $('#autoBackupPickDirBtn').addEventListener('click', pickAutoBackupFolder);