feat: recover progressive identity after partial snapshots
Closes #1431
This commit is contained in:
1 parent
97a36ea22f
commit
26288d364c
20 files changed
+228
-42
No files matched your search
@@ -44,9 +44,14 @@ function createContextPoller({
|
||||
const freshness = snapshot && snapshot.freshness;
|
||||
const sections = freshness && freshness.sections;
|
||||
const sectionValues = sections && Object.values(sections);
|
||||
const degradedRetrySeconds = (sectionValues || [])
|
||||
.filter(section => section.degraded)
|
||||
.map(section => Number(section.retry_in_seconds ?? freshness.retry_in_seconds))
|
||||
.filter(seconds => Number.isFinite(seconds) && seconds > 0);
|
||||
const failedSectionDelay = degradedRetrySeconds.length ?
|
||||
Math.min(...degradedRetrySeconds) * 1000 : null;
|
||||
if (sectionValues && sectionValues.length && sectionValues.every(section => section.degraded)) {
|
||||
const retrySeconds = Number(freshness.retry_in_seconds);
|
||||
if (Number.isFinite(retrySeconds) && retrySeconds > 0) return retrySeconds * 1000;
|
||||
return failedSectionDelay || intervalMs;
|
||||
}
|
||||
const freshForSeconds = Number(freshness && freshness.fresh_for_seconds);
|
||||
const healthyDeadlines = (sectionValues || [])
|
||||
@@ -55,10 +60,10 @@ function createContextPoller({
|
||||
.filter(seconds => Number.isFinite(seconds));
|
||||
if (Number.isFinite(freshForSeconds) && freshForSeconds > 0 && healthyDeadlines.length) {
|
||||
const earliestDeadline = Math.min(...healthyDeadlines);
|
||||
if (earliestDeadline <= 0 && sectionValues.some(section => !section.degraded && section.revalidating)) {
|
||||
return intervalMs;
|
||||
}
|
||||
return Math.max(0, earliestDeadline) * 1000;
|
||||
const healthyDelay = earliestDeadline <= 0 &&
|
||||
sectionValues.some(section => !section.degraded && section.revalidating) ?
|
||||
intervalMs : Math.max(0, earliestDeadline) * 1000;
|
||||
return failedSectionDelay === null ? healthyDelay : Math.min(healthyDelay, failedSectionDelay);
|
||||
}
|
||||
return intervalMs;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ function createProgressiveHumanGates(options = {}) {
|
||||
});
|
||||
const liveSnapshot = options.liveSnapshot || null;
|
||||
const getIdentity = options.getIdentity || (async () => {
|
||||
const response = liveSnapshot ? await liveSnapshot.acquire() :
|
||||
const response = liveSnapshot ? await liveSnapshot.acquire({requireIdentity:true}) :
|
||||
await fetchJson('api/v1/live', {headers:{Accept:'application/json'}});
|
||||
const user = response?.context?.user || {};
|
||||
const login = String(user.login || '').trim();
|
||||
|
||||
@@ -2,9 +2,18 @@ function createProgressiveLiveSnapshot({fetchSnapshot}) {
|
||||
let value = null;
|
||||
let flight = null;
|
||||
|
||||
const acquire = () => {
|
||||
if (value) return Promise.resolve(value);
|
||||
if (flight) return flight;
|
||||
const hasIdentity = snapshot => {
|
||||
const user = snapshot?.context?.user || {};
|
||||
return Boolean(String(user.login || '').trim());
|
||||
};
|
||||
const requireUsable = (snapshot, options) => {
|
||||
if (!options?.requireIdentity || hasIdentity(snapshot)) return snapshot;
|
||||
if (value === snapshot) value = null;
|
||||
throw new Error('Authenticated account identity is unavailable.');
|
||||
};
|
||||
const acquire = (options = {}) => {
|
||||
if (value) return Promise.resolve().then(() => requireUsable(value, options));
|
||||
if (flight) return flight.then(snapshot => requireUsable(snapshot, options));
|
||||
flight = Promise.resolve().then(() => fetchSnapshot()).then(snapshot => {
|
||||
value = snapshot;
|
||||
flight = null;
|
||||
@@ -13,7 +22,7 @@ function createProgressiveLiveSnapshot({fetchSnapshot}) {
|
||||
flight = null;
|
||||
throw error;
|
||||
});
|
||||
return flight;
|
||||
return flight.then(snapshot => requireUsable(snapshot, options));
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -24,6 +24,7 @@ function createProgressiveMyWork({
|
||||
let poller = null;
|
||||
let detailTrigger = null;
|
||||
let openWork = null;
|
||||
let contextUnavailable = false;
|
||||
const deferredQueues = {
|
||||
today:'Today', agenda:'Agenda', later:'Later', draft:'Drafts',
|
||||
};
|
||||
@@ -89,7 +90,8 @@ function createProgressiveMyWork({
|
||||
const render = () => {
|
||||
if (stopped || !list) return;
|
||||
const visible = visibleItems();
|
||||
list.innerHTML = deferredQueues[active] ?
|
||||
list.innerHTML = contextUnavailable && !items.length ?
|
||||
'<div class="muted">Assigned work is reconnecting…</div>' : deferredQueues[active] ?
|
||||
'<div class="muted">' + deferredQueues[active] + ' is still loading…</div>' : visible.length ? visible.map((item, index) => {
|
||||
const title = escapeHtml(item.title || item.key || 'Untitled work');
|
||||
const context = escapeHtml(item.key || '');
|
||||
@@ -128,6 +130,17 @@ function createProgressiveMyWork({
|
||||
if (stopped) return false;
|
||||
const transferable = snapshot && typeof snapshot === 'object' &&
|
||||
Object.prototype.hasOwnProperty.call(snapshot, 'context');
|
||||
const contextDegraded = transferable && (
|
||||
!snapshot.context || snapshot.freshness?.sections?.context?.degraded
|
||||
);
|
||||
if (contextDegraded) {
|
||||
contextUnavailable = true;
|
||||
render();
|
||||
notify();
|
||||
if (status) status.textContent = 'Assigned work is reconnecting…';
|
||||
return false;
|
||||
}
|
||||
contextUnavailable = false;
|
||||
if (transferable) liveSnapshot = snapshot;
|
||||
const context = snapshot?.context || snapshot || {};
|
||||
confirmedLogin = String(context.user?.login || '').trim();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const BASE = new URL('./', self.location.href).pathname;
|
||||
importScripts(BASE + 'static/private-data-registry.js');
|
||||
importScripts(BASE + 'static/background-issue-sync.js');
|
||||
const CACHE = 'stackchain-dashboard-shell-v143';
|
||||
const CACHE = 'stackchain-dashboard-shell-v144';
|
||||
const OFFLINE_LEASE_URL = new URL(BASE + '__offline-session-lease', self.location.origin).href;
|
||||
const OUTAGE_STATUSES = new Set([500, 502, 503, 504]);
|
||||
const NAVIGATION_TIMEOUT_MS = self.__STACKCHAIN_NAVIGATION_TIMEOUT_MS || 4000;
|
||||
|
||||
Reference in new issue
Block a user