From 454022ee895c4dd72832f452d58a2315cfb9d813 Mon Sep 17 00:00:00 2001 From: timmy Date: Sun, 9 Aug 2026 02:37:32 +0000 Subject: [PATCH] feat: sync Later deferrals across devices (#363) --- README.md | 8 +- frontend/dashboard.js | 24 +++ frontend/index.html | 2 + frontend/later-sync.js | 164 +++++++++++++++++ frontend/later-work.js | 34 +++- frontend/service-worker.js | 3 +- src/later_store.py | 124 +++++++++++++ src/main.py | 47 ++++- tests/test_later_store.py | 94 ++++++++++ tests/test_later_sync.py | 210 ++++++++++++++++++++++ tests/test_markdown_renderer.py | 2 +- tests/test_mobile_composer_integration.py | 2 +- tests/test_service_worker.py | 9 +- tests/test_today_work.py | 2 +- 14 files changed, 706 insertions(+), 19 deletions(-) create mode 100644 frontend/later-sync.js create mode 100644 src/later_store.py create mode 100644 tests/test_later_store.py create mode 100644 tests/test_later_sync.py diff --git a/README.md b/README.md index f46b198..6430e91 100644 --- a/README.md +++ b/README.md @@ -211,13 +211,15 @@ filter, preserves the selected release lane, shows the current draft count, resp the device safe area, and moves out of the way while a full-screen task is open. Desktop layout is unchanged. -My Work also has a local **Later** queue. **Later today** defers an item for four +My Work also has an account-synced **Later** queue. **Later today** defers an item for four hours, while **Tomorrow** returns it at 09:00 in the device's local timezone. Deferred items leave normal and Attention queues without marking notifications read or changing any Gitea issue or pull request. They automatically return to their existing priority position at the wake time, and **Bring back now** restores them -early. Later state is stored only in this browser, scoped to the confirmed Gitea -login, and removed when fully loaded work confirms that an item no longer exists. +early. Later wake times are scoped to the confirmed Gitea login and synchronize +across signed-in tabs and devices. Offline changes apply immediately, survive reload, +and replay after reconnect; `STACKCHAIN_LATER_DB` can override the default durable +store at `.stackchain-state/later.sqlite3`. After one successful online load, the installed dashboard precaches a versioned, subpath-scoped application shell. During a network outage or a dashboard HTTP diff --git a/frontend/dashboard.js b/frontend/dashboard.js index 0312572..2d3cbbd 100644 --- a/frontend/dashboard.js +++ b/frontend/dashboard.js @@ -160,11 +160,33 @@ const laterWork = createLaterWork({ storage: localStorage, getLogin: () => planningOwnerLogin, + onChange: (action, itemId, wakeAt) => { + if (laterSync.enqueue(action, itemId, wakeAt)) laterSync.flush(); + }, + onExpire: ids => { + const queued = ids.map(id => laterSync.enqueue('restore', id)).every(Boolean); + if (queued) laterSync.flush(); + }, onWake: () => { qs('#my-work-action-status').textContent = 'Deferred work is ready again.'; refreshMyWorkView(); }, }); + const laterSync = createLaterSync({ + storage: localStorage, + getLogin: () => planningOwnerLogin, + fetchJson: fetchReviewJson, + onRemoteRecords: records => { + if (!planningOwnerLogin || !laterWork.adopt(records)) return; + refreshMyWorkView(); + }, + onStatus: state => { + qs('#later-sync-status').textContent = state === 'saved' ? 'Later saved to account.' : + (state === 'pending' ? 'Later saved on this device · sync pending.' : + 'Later sync unavailable · changes stay on this device.'); + }, + }); + laterSync.startLifecycle({ window, document }); document.addEventListener('visibilitychange', () => { if (!document.hidden) refreshMyWorkView(); }); @@ -2017,6 +2039,8 @@ if (planningOwnerLogin) { todaySync.migrate(todayWork.read()); todaySync.flush(); + laterSync.migrate(laterWork.read()); + laterSync.flush(); } const contextIdentityFresh = !snapshot.context.error && !contextFreshness?.stale && !contextFreshness?.degraded && !contextFreshness?.revalidating; diff --git a/frontend/index.html b/frontend/index.html index b9d43cc..7cb13bd 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -100,6 +100,7 @@
Today is saved on this device.
+
Later is saved on this device.