feat: survive dashboard HTTP outages (#230)
This commit is contained in:
1 parent
bb00d3cf35
commit
3ed3a2be58
5 files changed
+80
-12
No files matched your search
+17
-4
@@ -1186,6 +1186,7 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
function handleContextError(e) {
|
||||
console.error('context failed', e);
|
||||
liveMode = false;
|
||||
if (!hasContextSnapshot && hydrateOfflineWork('outage')) return;
|
||||
setStatus(hasContextSnapshot ? 'Update failed · showing last snapshot' : 'Unavailable');
|
||||
if (!hasContextSnapshot) {
|
||||
qs('#context').innerHTML = '<div class="muted">Context unavailable.</div>';
|
||||
@@ -2095,6 +2096,8 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
}
|
||||
|
||||
function renderLiveSnapshot(snapshot) {
|
||||
setOfflineWorkMode(false);
|
||||
offlineStatus.hidden = true;
|
||||
const contextFreshness = snapshot.freshness?.sections?.context;
|
||||
const eventsFreshness = snapshot.freshness?.sections?.events;
|
||||
const notificationFreshness = snapshot.freshness?.sections?.notifications;
|
||||
@@ -3033,9 +3036,10 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
['#find-work', '#start-work-session', '#load-more-work', '#load-more-notifications', '#bulk-mark-read']
|
||||
.forEach(selector => { const button = qs(selector); if (button) button.disabled = value; });
|
||||
}
|
||||
function hydrateOfflineWork() {
|
||||
function hydrateOfflineWork(mode = 'offline') {
|
||||
const saved = offlineWorkStore.load();
|
||||
if (!saved) return false;
|
||||
const outage = mode === 'outage';
|
||||
lastNotifications = saved.notifications || [];
|
||||
notificationPagination = saved.notification_pagination || { page:1, total:lastNotifications.length, has_more:false };
|
||||
workPagination = saved.work_pagination || {};
|
||||
@@ -3044,9 +3048,18 @@ textarea { resize: vertical; min-height: 120px; }
|
||||
paintMyWork(saved);
|
||||
setOfflineWorkMode(true);
|
||||
const savedLabel = fmt(saved.saved_at);
|
||||
qs('#my-work-status').textContent = 'Offline · saved ' + savedLabel + ' · read-only';
|
||||
offlineStatus.textContent = 'Offline · showing private My Work saved ' + savedLabel + '. Live details and actions require reconnection.';
|
||||
offlineWorkStatus.textContent = 'Offline · saved ' + savedLabel + ' · expires after 7 days.';
|
||||
if (outage) {
|
||||
qs('#my-work-status').textContent = 'Outage · saved ' + savedLabel + ' · read-only';
|
||||
offlineStatus.textContent = 'Server unavailable · showing private My Work saved ' + savedLabel + '. Live details and actions will return automatically.';
|
||||
offlineWorkStatus.textContent = 'Outage · saved ' + savedLabel + ' · expires after 7 days.';
|
||||
setStatus('Outage · saved snapshot');
|
||||
} else {
|
||||
qs('#my-work-status').textContent = 'Offline · saved ' + savedLabel + ' · read-only';
|
||||
offlineStatus.textContent = 'Offline · showing private My Work saved ' + savedLabel + '. Live details and actions require reconnection.';
|
||||
offlineWorkStatus.textContent = 'Offline · saved ' + savedLabel + ' · expires after 7 days.';
|
||||
setStatus('Offline · saved snapshot');
|
||||
}
|
||||
offlineStatus.hidden = false;
|
||||
return true;
|
||||
}
|
||||
function showOfflineStatus() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const CACHE = 'stackchain-dashboard-shell-v3';
|
||||
const CACHE = 'stackchain-dashboard-shell-v4';
|
||||
const OUTAGE_STATUSES = new Set([500, 502, 503, 504]);
|
||||
const BASE = new URL('./', self.location.href).pathname;
|
||||
const SHELL = [
|
||||
BASE,
|
||||
@@ -41,9 +42,12 @@ self.addEventListener('fetch', event => {
|
||||
if (request.mode === 'navigate') {
|
||||
event.respondWith(
|
||||
fetch(request).then(async response => {
|
||||
const cache = await caches.open(CACHE);
|
||||
if (response.ok) {
|
||||
const cache = await caches.open(CACHE);
|
||||
await cache.put(BASE, response.clone());
|
||||
} else if (OUTAGE_STATUSES.has(response.status)) {
|
||||
const cached = await cache.match(BASE);
|
||||
if (cached) return cached;
|
||||
}
|
||||
return response;
|
||||
}).catch(async () => {
|
||||
|
||||
Reference in new issue
Block a user