extract sync orchestration into sync.js, unify on sync.tick heartbeat

caldav.js was carrying the core sync timer, autosync toggle, relay
settings and every poller hook alongside its actual CalDAV/calendar
config concerns. Split out:

- New sync.js owns the single background timer, header Sync button,
  autosync pause toggle, configurable interval, and emits `sync.tick`
  so plugins can fan out without their own setIntervals.
- collab-buckets + chat now subscribe to sync.tick instead of running
  their own pollers, so the manual Sync button refreshes them too and
  the Autosync pause actually pauses everything.
- Replace the number input for sync interval with a stepped slider
  (5s..1h snap points) and a live label, bumped to 1.9.2.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-15 19:02:44 +02:00
1 parent b7f450e41f
commit 1d6499e5dd
11 files changed
+400 -335

No files matched your search

+6
View File
@@ -410,6 +410,12 @@ function init() {
restartPoll();
}
});
// Also refresh on the global sync heartbeat. Our own timer keeps
// the faster flyout-open cadence (UX-specific); tick guarantees
// that the header Sync button refreshes chat too, even when the
// flyout is closed and our own timer sits at 20s.
hyprcrd.hooks?.on?.('sync.tick', () => { pollOnce().catch(() => {}); });
}
if (document.readyState === 'loading') {
+13 -32
View File
@@ -4,9 +4,9 @@
// rows in the standard bucket bar. The plugin just owns the sync + the
// visual unread-state decoration:
//
// - Polls /api/collab-buckets/poll every POLL_INTERVAL_MS. The backend
// mirrors each remote bucket into the main `buckets` table so the core
// bucket bar renders it automatically.
// - Polls /api/collab-buckets/poll on every `sync.tick` (shared timer
// in sync.js). The backend mirrors each remote bucket into the main
// `buckets` table so the core bucket bar renders it automatically.
// - Exposes `window._collabBucketsCreateDialog` — an async function that
// the core + Bucket button calls so we can pop a richer "new bucket"
// modal with an optional "collaborative" checkbox + member picker.
@@ -26,14 +26,9 @@ const $ = (id) => document.getElementById(id);
let collabByUid = new Map();
// card_id (number) -> true for cards with foreign edits we haven't opened yet
let unreadCards = new Set();
let pollHandle = null;
// The core CalDAV/relay sync cadence (Settings → Relay → Sync frequency,
// default 15s) also drives the collab poll. Users can dial up or down
// without touching code. Defaults + clamp mirror the core helper.
function getPollIntervalMs() {
const v = parseInt(localStorage.getItem('hyprcrd-sync-interval-sec'));
return (Number.isFinite(v) && v >= 5 ? v : 15) * 1000;
}
// Collab card sync is driven by the shared `sync.tick` hook from
// sync.js — one timer fans out to every plugin poller, the central
// timer honors the Autosync pause for us.
// Phase 4: edit locks (now exclusive — server-enforced)
// card_uid -> { bucket_uid, holder_username, expires_at }
@@ -171,24 +166,11 @@ function showQueuedToast(message) {
setTimeout(() => { toast.classList.add('fade-out'); setTimeout(() => toast.remove(), 400); }, 6000);
}
function startPolling() {
stopPolling();
pollHandle = setInterval(pollOnce, getPollIntervalMs());
}
function stopPolling() {
if (pollHandle) { clearInterval(pollHandle); pollHandle = null; }
}
// Restart when the user changes the sync interval in settings.
hyprcrd.hooks?.on?.('sync.interval.changed', () => {
if (pollHandle) startPolling();
});
// Pause / resume alongside the header autosync toggle.
hyprcrd.hooks?.on?.('autosync.changed', (on) => {
if (on) startPolling();
else stopPolling();
});
// Subscribe to the global sync heartbeat. The central timer in sync.js
// honors the Autosync pause + the configurable interval for us, and
// the header Sync button emits the same tick so manual sync pushes
// collab cards too.
hyprcrd.hooks?.on?.('sync.tick', () => { pollOnce().catch(() => {}); });
// ── Bucket bar decoration ─────────────────────────────────────────
@@ -992,9 +974,8 @@ async function init() {
decorateBucketBar();
decorateBoardLocks();
decorateBoardUnread();
// Respect the header autosync toggle — if the user has paused it,
// skip the recurring poll entirely. Hook above restarts when toggled.
if (localStorage.getItem('hyprcrd-autosync-enabled') !== '0') startPolling();
// No local timer: subsequent polls come from the global `sync.tick`
// hook (central timer in sync.js honors Autosync pause + interval).
}
// Defer init until the CSRF token is live — `checkAuth()` sets it async on
+1 -1
View File
@@ -5,7 +5,7 @@
// Backup is created before and auto-restored after every run.
import { getCsrf } from '../../js/modules/util.js';
import { stopBackgroundSync, startBackgroundSync } from '../../js/modules/caldav.js';
import { stopBackgroundSync, startBackgroundSync } from '../../js/modules/sync.js';
// Suites live on window so two runner.js instances (one cached and loaded
// by test files via bare imports, one fresh and loaded by loader.js with