From dec9dd288c24695dfd3ee36658d9d10b5666cd3d Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Sat, 12 Sep 2026 22:41:08 -0700 Subject: [PATCH] style: format layer loading feedback helpers --- scripts/package-boundaries.json | 208 ++++++----------------- src/data/installationFeedback.js | 9 +- src/loadingFeedback.js | 274 +++++++++++++++++++++---------- 3 files changed, 245 insertions(+), 246 deletions(-) diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 73807b350..971bed61b 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -10,47 +10,27 @@ "src/data/localGeojsonCore.js", "src/data/localGeojsonLod.js" ], - "external": [ - "cesium" - ] + "external": ["cesium"] }, "application": { - "exports": [ - "./application" - ], - "modules": [ - "src/app/application.js" - ], + "exports": ["./application"], + "modules": ["src/app/application.js"], "external": [] }, "viewer": { - "exports": [ - "./application/viewer" - ], - "modules": [ - "src/app/viewer.js" - ], - "external": [ - "cesium" - ] + "exports": ["./application/viewer"], + "modules": ["src/app/viewer.js"], + "external": ["cesium"] }, "vite-build": { "runtime": "node", - "exports": [ - "./build/vite" - ], - "modules": [ - "build/vite.js" - ], - "external": [ - "vite-plugin-cesium" - ] + "exports": ["./build/vite"], + "modules": ["build/vite.js"], + "external": ["vite-plugin-cesium"] }, "live-providers": { "runtime": "node", - "exports": [ - "./server/providers/live" - ], + "exports": ["./server/providers/live"], "modules": [ "server/providers/live.js", "server/providers/common/http.js", @@ -65,24 +45,16 @@ "src/data/aisStreamAdapter.js", "src/data/aisWatchdog.js" ], - "external": [ - "ws" - ] + "external": ["ws"] }, "adsb-lol-source": { - "exports": [ - "./sources/adsb-lol" - ], - "modules": [ - "src/data/adsbLolFallback.js" - ], + "exports": ["./sources/adsb-lol"], + "modules": ["src/data/adsbLolFallback.js"], "external": [] }, "place-providers": { "runtime": "node", - "exports": [ - "./server/providers/places" - ], + "exports": ["./server/providers/places"], "modules": [ "server/providers/places.js", "server/providers/places/google.js", @@ -97,19 +69,13 @@ "external": [] }, "place-payloads": { - "exports": [ - "./sources/places" - ], - "modules": [ - "src/data/placeProviderPayloads.js" - ], + "exports": ["./sources/places"], + "modules": ["src/data/placeProviderPayloads.js"], "external": [] }, "space-providers": { "runtime": "node", - "exports": [ - "./server/providers/space" - ], + "exports": ["./server/providers/space"], "modules": [ "server/providers/space.js", "server/providers/space/celestrak.js", @@ -120,19 +86,13 @@ "external": [] }, "space-requests": { - "exports": [ - "./sources/space" - ], - "modules": [ - "src/data/spaceProviderRequests.js" - ], + "exports": ["./sources/space"], + "modules": ["src/data/spaceProviderRequests.js"], "external": [] }, "terrain-provider": { "runtime": "node", - "exports": [ - "./server/providers/terrain" - ], + "exports": ["./server/providers/terrain"], "modules": [ "server/providers/terrain.js", "src/data/terrainHeightsProxy.js" @@ -140,50 +100,30 @@ "external": [] }, "terrain-source": { - "exports": [ - "./sources/terrain" - ], - "modules": [ - "src/data/terrainHeightsProxy.js" - ], + "exports": ["./sources/terrain"], + "modules": ["src/data/terrainHeightsProxy.js"], "external": [] }, "traffic-provider": { "runtime": "node", - "exports": [ - "./server/providers/traffic" - ], - "modules": [ - "server/providers/traffic.js", - "src/data/tomtomTiles.js" - ], + "exports": ["./server/providers/traffic"], + "modules": ["server/providers/traffic.js", "src/data/tomtomTiles.js"], "external": [] }, "traffic-source": { - "exports": [ - "./sources/traffic" - ], - "modules": [ - "src/data/tomtomTiles.js" - ], + "exports": ["./sources/traffic"], + "modules": ["src/data/tomtomTiles.js"], "external": [] }, "firms-provider": { "runtime": "node", - "exports": [ - "./server/providers/firms" - ], - "modules": [ - "server/providers/firms.js", - "src/data/firmsCsv.js" - ], + "exports": ["./server/providers/firms"], + "modules": ["server/providers/firms.js", "src/data/firmsCsv.js"], "external": [] }, "gbfs-provider": { "runtime": "node", - "exports": [ - "./server/providers/gbfs" - ], + "exports": ["./server/providers/gbfs"], "modules": [ "server/providers/gbfs.js", "server/providers/common/http.js", @@ -192,19 +132,13 @@ "external": [] }, "gbfs-source": { - "exports": [ - "./sources/gbfs" - ], - "modules": [ - "src/data/gbfsSource.js" - ], + "exports": ["./sources/gbfs"], + "modules": ["src/data/gbfsSource.js"], "external": [] }, "cctv-provider": { "runtime": "node", - "exports": [ - "./server/providers/cctv" - ], + "exports": ["./server/providers/cctv"], "modules": [ "server/providers/cctv.js", "server/providers/cctv/catalog.js", @@ -221,9 +155,7 @@ }, "radio-provider": { "runtime": "node", - "exports": [ - "./server/providers/radio" - ], + "exports": ["./server/providers/radio"], "modules": [ "server/providers/radio.js", "server/providers/radio/catalog.js", @@ -237,9 +169,7 @@ }, "overpass-provider": { "runtime": "node", - "exports": [ - "./server/providers/overpass" - ], + "exports": ["./server/providers/overpass"], "modules": [ "server/providers/common/geo.js", "server/providers/common/http.js", @@ -258,9 +188,7 @@ }, "military-installations-provider": { "runtime": "node", - "exports": [ - "./server/providers/military-installations" - ], + "exports": ["./server/providers/military-installations"], "modules": [ "server/providers/common/http.js", "server/providers/common/query.js", @@ -277,9 +205,7 @@ }, "regional-provider": { "runtime": "node", - "exports": [ - "./server/providers/regional" - ], + "exports": ["./server/providers/regional"], "modules": [ "server/providers/common/http.js", "server/providers/common/query.js", @@ -298,9 +224,7 @@ }, "openai-provider": { "runtime": "node", - "exports": [ - "./server/providers/openai" - ], + "exports": ["./server/providers/openai"], "modules": [ "server/providers/common/rate-limit.js", "server/providers/common/request.js", @@ -320,9 +244,7 @@ }, "standalone-key-setup": { "runtime": "node", - "exports": [ - "./server/standalone/key-setup" - ], + "exports": ["./server/standalone/key-setup"], "modules": [ "scripts/pinokio-environment.mjs", "server/providers/common/source-root.js", @@ -333,9 +255,7 @@ "external": [] }, "place-search": { - "exports": [ - "./search" - ], + "exports": ["./search"], "modules": [ "src/search/index.js", "src/search/placeSearch.js", @@ -345,27 +265,17 @@ "external": [] }, "panel-disclosure": { - "exports": [ - "./ui/panels" - ], - "modules": [ - "src/ui/panelDisclosure.js" - ], + "exports": ["./ui/panels"], + "modules": ["src/ui/panelDisclosure.js"], "external": [] }, "surface-keyboard": { - "exports": [ - "./ui/surfaces" - ], - "modules": [ - "src/ui/surfaceKeyboard.js" - ], + "exports": ["./ui/surfaces"], + "modules": ["src/ui/surfaceKeyboard.js"], "external": [] }, "panel-rail-layout": { - "exports": [ - "./ui/layout" - ], + "exports": ["./ui/layout"], "modules": [ "src/ui/panelRails.js", "src/ui/leftPanelRail.js", @@ -377,9 +287,7 @@ "external": [] }, "visual-input": { - "exports": [ - "./ui/input" - ], + "exports": ["./ui/input"], "modules": [ "src/ui/visualInput.js", "src/ui/applicationShortcuts.js", @@ -388,19 +296,12 @@ "external": [] }, "display-controls": { - "exports": [ - "./ui/display" - ], - "modules": [ - "src/ui/displayControls.js" - ], + "exports": ["./ui/display"], + "modules": ["src/ui/displayControls.js"], "external": [] }, "visual-effects": { - "exports": [ - "./ui/effects", - "./ui/effects/bloom" - ], + "exports": ["./ui/effects", "./ui/effects/bloom"], "modules": [ "src/ui/effects.js", "src/ui/visualEffects.js", @@ -413,14 +314,10 @@ "src/styles/noir.js", "src/styles/snow.js" ], - "external": [ - "cesium" - ] + "external": ["cesium"] }, "map-source-controls": { - "exports": [ - "./ui/maps" - ], + "exports": ["./ui/maps"], "modules": [ "src/ui/mapSource.js", "src/ui/mapSourceControls.js", @@ -430,10 +327,7 @@ "external": [] }, "layer-panel": { - "exports": [ - "./ui/layers", - "./ui/layers/feedback" - ], + "exports": ["./ui/layers", "./ui/layers/feedback"], "modules": [ "src/ui/layers.js", "src/ui/layerPanel.js", diff --git a/src/data/installationFeedback.js b/src/data/installationFeedback.js index 974568a45..f33ce59ab 100644 --- a/src/data/installationFeedback.js +++ b/src/data/installationFeedback.js @@ -5,14 +5,17 @@ export function installationFeedback(stats = {}, now = Date.now()) { timeout: 'Overpass timed out', query_failed: 'Overpass could not complete the query', }; - const reason = reasons[stats.failureReason] || 'Overpass temporarily unavailable'; - if (stats.loading) return stats.retrying ? 'Retrying mapped sites…' : 'Fetching mapped sites…'; + const reason = + reasons[stats.failureReason] || 'Overpass temporarily unavailable'; + if (stats.loading) + return stats.retrying ? 'Retrying mapped sites…' : 'Fetching mapped sites…'; if (stats.retryAt > 0) { const seconds = Math.max(0, Math.ceil((stats.retryAt - now) / 1000)); return `${reason} — ${seconds ? `retrying in ${seconds}s` : 'retry pending'}`; } if (stats.status === 'unavailable') return reason; - if (stats.status === 'zoom-in') return 'Zoom in to search mapped installations'; + if (stats.status === 'zoom-in') + return 'Zoom in to search mapped installations'; if (stats.stale) return 'Showing cached mapped sites'; if (stats.status === 'idle') return 'Mapped sites not loaded'; return 'Mapped sites loaded'; diff --git a/src/loadingFeedback.js b/src/loadingFeedback.js index a5540e1ce..85eb38606 100644 --- a/src/loadingFeedback.js +++ b/src/loadingFeedback.js @@ -16,21 +16,34 @@ function finiteCount(value) { /** Normalize one manager layer into a small loading-feedback record. */ export function normalizeLayerLoading(layer = {}) { const stats = layer.stats || {}; - const lifecycleState = String(layer.lifecycleState || (layer.enabled ? 'enabled' : 'disabled')); + const lifecycleState = String( + layer.lifecycleState || (layer.enabled ? 'enabled' : 'disabled'), + ); const status = String(stats.status || '').toLowerCase(); const disabling = lifecycleState === 'disabling'; - const loading = lifecycleState === 'enabling' || disabling || stats.loading === true || stats.refreshing === true; + const loading = + lifecycleState === 'enabling' || + disabling || + stats.loading === true || + stats.refreshing === true; const count = finiteCount(stats.count); - const stoppingInstallations = layer.id === 'military-installations' && disabling; + const stoppingInstallations = + layer.id === 'military-installations' && disabling; // Guidance statuses ask the user to act (zoom in, run a search). They are // normal operation, never a batch failure — mirrors layerFeedState's carve-out // so a prompt stored alongside the status cannot turn the chip red. const guidance = GUIDANCE_STATUSES.includes(status); - const error = stoppingInstallations ? null - : (!guidance && stats.error) || stats.lastError || stats.managerRefreshError || null; - const unavailable = !stoppingInstallations && (stats.unavailable === true - || stats.available === false - || ['unavailable', 'offline', 'down', 'error'].includes(status)); + const error = stoppingInstallations + ? null + : (!guidance && stats.error) || + stats.lastError || + stats.managerRefreshError || + null; + const unavailable = + !stoppingInstallations && + (stats.unavailable === true || + stats.available === false || + ['unavailable', 'offline', 'down', 'error'].includes(status)); const keyRequired = stats.keyRequired === true || stats.missingKey === true; const degraded = stats.degraded === true || Boolean(error); const accepted = Boolean(stats.lastUpdate) || count > 0; @@ -39,7 +52,8 @@ export function normalizeLayerLoading(layer = {}) { label: String(layer.name || layer.id || 'Layer'), loading, disabling, - refresh: loading && layer.enabled && (stats.refreshing === true || accepted), + refresh: + loading && layer.enabled && (stats.refreshing === true || accepted), lifecycleState, count, accepted, @@ -47,18 +61,27 @@ export function normalizeLayerLoading(layer = {}) { unavailable, keyRequired, degraded, - installationRetry: layer.id === 'military-installations' && layer.enabled && !disabling - ? { retryAt: Number(stats.retryAt) || 0, retrying: stats.retrying === true, - failureReason: stats.failureReason, loading, status: stats.status } - : null, + installationRetry: + layer.id === 'military-installations' && layer.enabled && !disabling + ? { + retryAt: Number(stats.retryAt) || 0, + retrying: stats.retrying === true, + failureReason: stats.failureReason, + loading, + status: stats.status, + } + : null, }; } function terminalFromParticipantStats(summary, participantIds) { if (!participantIds?.length) return null; const participants = new Set(participantIds); - return summary.records.some((record) => participants.has(record.id) - && (record.error || record.unavailable || record.keyRequired)) + return summary.records.some( + (record) => + participants.has(record.id) && + (record.error || record.unavailable || record.keyRequired), + ) ? 'error' : null; } @@ -67,13 +90,17 @@ function terminalFromParticipantStats(summary, participantIds) { export function aggregateLayerLoading(layers = []) { const records = layers.map(normalizeLayerLoading); const active = records.filter((record) => record.loading); - const disabling = active.length > 0 && active.every((record) => record.disabling); + const disabling = + active.length > 0 && active.every((record) => record.disabling); return { records, active, activeIds: active.map((record) => record.id), disabling, - refresh: !disabling && active.length > 0 && active.every((record) => record.refresh), + refresh: + !disabling && + active.length > 0 && + active.every((record) => record.refresh), }; } @@ -92,11 +119,11 @@ export function createLoadingFeedbackState() { } /** Create a top-center status notice, optionally persistent until explicitly cleared. */ -export function createGlobalStatusNotice(message, nowMs = 0, { - state = 'error', - detail = '', - persistent = false, -} = {}) { +export function createGlobalStatusNotice( + message, + nowMs = 0, + { state = 'error', detail = '', persistent = false } = {}, +) { const label = String(message || '').trim(); if (!label) return null; return { @@ -117,9 +144,11 @@ export function presentGlobalStatusNotice(notice, nowMs = 0) { const now = Number.isFinite(nowMs) ? nowMs : 0; if (!notice?.label) return null; if (!notice.persistent && !Number.isFinite(notice.hideAt)) { - notice.hideAt = now + (Number.isFinite(notice.dwellMs) - ? notice.dwellMs - : LOADING_FAILURE_DWELL_MS); + notice.hideAt = + now + + (Number.isFinite(notice.dwellMs) + ? notice.dwellMs + : LOADING_FAILURE_DWELL_MS); } if (Number.isFinite(notice.hideAt) && now >= notice.hideAt) return null; return { @@ -130,10 +159,16 @@ export function presentGlobalStatusNotice(notice, nowMs = 0) { } /** Whether deferred notice work still owns the current presentation epoch. */ -export function canPresentDeferredStatusNotice(expectedGeneration, currentGeneration, disposed = false) { - return !disposed - && Number.isSafeInteger(expectedGeneration) - && expectedGeneration === currentGeneration; +export function canPresentDeferredStatusNotice( + expectedGeneration, + currentGeneration, + disposed = false, +) { + return ( + !disposed && + Number.isSafeInteger(expectedGeneration) && + expectedGeneration === currentGeneration + ); } /** @@ -141,9 +176,19 @@ export function canPresentDeferredStatusNotice(expectedGeneration, currentGenera * hide a terminal manager failure. Failure dwell starts when the manager * reports it, so it must remain the highest-priority presentation while live. */ -export function presentGlobalLoadingStatus(notice, loadingState, summary, nowMs = 0) { - const loadingPresentation = presentLoadingFeedback(loadingState, summary, nowMs); - if (['error', 'retry'].includes(loadingPresentation?.state)) return loadingPresentation; +export function presentGlobalLoadingStatus( + notice, + loadingState, + summary, + nowMs = 0, +) { + const loadingPresentation = presentLoadingFeedback( + loadingState, + summary, + nowMs, + ); + if (['error', 'retry'].includes(loadingPresentation?.state)) + return loadingPresentation; return presentGlobalStatusNotice(notice, nowMs) || loadingPresentation; } @@ -162,11 +207,11 @@ export function createTrafficSyncFeedbackState() { * Reduce one sampled Street Traffic status without extending completion on * every animation-loop poll. Coverage describes accepted data, not work. */ -export function reduceTrafficSyncFeedback(previous, { - enabled = false, - stats = {}, - forceShow = false, -} = {}, nowMs = 0) { +export function reduceTrafficSyncFeedback( + previous, + { enabled = false, stats = {}, forceShow = false } = {}, + nowMs = 0, +) { const state = previous || createTrafficSyncFeedbackState(); const now = Number.isFinite(nowMs) ? nowMs : 0; if (!enabled) return createTrafficSyncFeedbackState(); @@ -174,10 +219,13 @@ export function reduceTrafficSyncFeedback(previous, { const hasProgress = Number.isFinite(stats.phaseProgressPct); const progressPct = hasProgress ? Math.max(0, Math.min(100, Math.round(stats.phaseProgressPct))) - : (stats.loading ? 1 : 100); - const busy = stats.loading === true - || stats.worldJumping === true - || (hasProgress && (progressPct < 100 || (stats.prewarmQueueDepth ?? 0) > 0)); + : stats.loading + ? 1 + : 100; + const busy = + stats.loading === true || + stats.worldJumping === true || + (hasProgress && (progressPct < 100 || (stats.prewarmQueueDepth ?? 0) > 0)); const label = String(stats.phaseLabel || stats.loadingLabel || '').trim(); if (busy) { @@ -193,13 +241,13 @@ export function reduceTrafficSyncFeedback(previous, { }; } - const existingConfirmation = state.confirmationUntil > now - ? state.confirmationUntil - : 0; - const confirmationUntil = existingConfirmation || (state.busy || forceShow - ? now + TRAFFIC_SYNC_CONFIRM_MS - : 0); - const visible = confirmationUntil > now && progressPct >= 100 && Boolean(label); + const existingConfirmation = + state.confirmationUntil > now ? state.confirmationUntil : 0; + const confirmationUntil = + existingConfirmation || + (state.busy || forceShow ? now + TRAFFIC_SYNC_CONFIRM_MS : 0); + const visible = + confirmationUntil > now && progressPct >= 100 && Boolean(label); return { busy: false, visible, @@ -217,7 +265,8 @@ export function reduceTrafficSyncFeedback(previous, { function terminalFromEvent(event) { const type = String(event?.type || ''); - if (type === 'visibility-failed' || type === 'refresh-failed' || event?.error) return 'error'; + if (type === 'visibility-failed' || type === 'refresh-failed' || event?.error) + return 'error'; if (type === 'visibility-cancelled' || event?.cancelled) return 'cancelled'; if (type === 'visibility' || type === 'refresh') return 'complete'; return null; @@ -238,7 +287,9 @@ export function reduceLoadingFeedback(previous, summary, nowMs, event = null) { const beginning = state.phase !== 'loading'; const startedAt = beginning ? now : state.startedAt; const priorParticipants = beginning ? [] : state.activeIds; - const activeIds = [...new Set([...priorParticipants, ...summary.activeIds])]; + const activeIds = [ + ...new Set([...priorParticipants, ...summary.activeIds]), + ]; const eventLayerId = String(event?.layerId || ''); const eventParticipates = eventLayerId && activeIds.includes(eventLayerId); const batchOutcome = mergeTerminalOutcome( @@ -257,27 +308,41 @@ export function reduceLoadingFeedback(previous, summary, nowMs, event = null) { activeIds, batchOutcome, terminal: null, - operation: summary.disabling ? 'disabling' : summary.refresh ? 'refresh' : 'loading', - failedEventIds: [...new Set([ - ...(beginning ? [] : state.failedEventIds || []), - ...(eventParticipates && terminalFromEvent(event) === 'error' ? [eventLayerId] : []), - ])], + operation: summary.disabling + ? 'disabling' + : summary.refresh + ? 'refresh' + : 'loading', + failedEventIds: [ + ...new Set([ + ...(beginning ? [] : state.failedEventIds || []), + ...(eventParticipates && terminalFromEvent(event) === 'error' + ? [eventLayerId] + : []), + ]), + ], }; } if (state.phase === 'loading') { const eventLayerId = String(event?.layerId || ''); - const eventParticipates = eventLayerId && state.activeIds.includes(eventLayerId); - const terminal = mergeTerminalOutcome( + const eventParticipates = + eventLayerId && state.activeIds.includes(eventLayerId); + const terminal = mergeTerminalOutcome( - state.batchOutcome, - terminalFromParticipantStats(summary, state.activeIds), - ), - eventParticipates ? terminalFromEvent(event) : null, - ) || 'complete'; + mergeTerminalOutcome( + state.batchOutcome, + terminalFromParticipantStats(summary, state.activeIds), + ), + eventParticipates ? terminalFromEvent(event) : null, + ) || 'complete'; const wasVisible = state.visible || now >= state.showAt; - if (!wasVisible && terminal === 'complete') return createLoadingFeedbackState(); - const dwell = terminal === 'error' ? LOADING_FAILURE_DWELL_MS : LOADING_TERMINAL_DWELL_MS; + if (!wasVisible && terminal === 'complete') + return createLoadingFeedbackState(); + const dwell = + terminal === 'error' + ? LOADING_FAILURE_DWELL_MS + : LOADING_TERMINAL_DWELL_MS; return { ...state, phase: 'terminal', @@ -285,10 +350,14 @@ export function reduceLoadingFeedback(previous, summary, nowMs, event = null) { hideAt: now + dwell, batchOutcome: terminal, terminal, - failedEventIds: [...new Set([ - ...(state.failedEventIds || []), - ...(eventParticipates && terminalFromEvent(event) === 'error' ? [eventLayerId] : []), - ])], + failedEventIds: [ + ...new Set([ + ...(state.failedEventIds || []), + ...(eventParticipates && terminalFromEvent(event) === 'error' + ? [eventLayerId] + : []), + ]), + ], }; } @@ -298,11 +367,17 @@ export function reduceLoadingFeedback(previous, summary, nowMs, event = null) { /** Build the user-facing status copy for the current loading state. */ export function presentLoadingFeedback(state, summary, nowMs) { - const site = summary.records.find(record => record.installationRetry?.retryAt > 0); - const otherFailure = summary.records.some(record => record.id !== 'military-installations' - && (state?.activeIds || []).includes(record.id) - && (record.error || record.unavailable || record.keyRequired)) - || (state?.failedEventIds || []).some(id => id !== 'military-installations'); + const site = summary.records.find( + (record) => record.installationRetry?.retryAt > 0, + ); + const otherFailure = + summary.records.some( + (record) => + record.id !== 'military-installations' && + (state?.activeIds || []).includes(record.id) && + (record.error || record.unavailable || record.keyRequired), + ) || + (state?.failedEventIds || []).some((id) => id !== 'military-installations'); // Keep the actual retry visible between attempts, without hiding another // participant's failure or pretending that a scheduled retry is fetching. if (site && !summary.active.length && !otherFailure) { @@ -312,28 +387,55 @@ export function presentLoadingFeedback(state, summary, nowMs) { } if (!state?.visible) return null; if (state.phase === 'terminal') { - const labels = { complete: 'LOAD COMPLETE', cancelled: 'LOAD CANCELLED', error: 'LOAD FAILED' }; - const label = state.operation === 'disabling' && state.terminal === 'complete' - ? 'LIVE DATA OFF' - : state.terminal === 'complete' && state.activeIds?.length === 1 && state.activeIds[0] === 'military-installations' - ? 'MAPPED SITES LOADED' : labels[state.terminal] || 'LOAD COMPLETE'; + const labels = { + complete: 'LOAD COMPLETE', + cancelled: 'LOAD CANCELLED', + error: 'LOAD FAILED', + }; + const label = + state.operation === 'disabling' && state.terminal === 'complete' + ? 'LIVE DATA OFF' + : state.terminal === 'complete' && + state.activeIds?.length === 1 && + state.activeIds[0] === 'military-installations' + ? 'MAPPED SITES LOADED' + : labels[state.terminal] || 'LOAD COMPLETE'; return { state: state.terminal, label, detail: '' }; } const active = summary.active; - if (active.length === 1 && active[0].installationRetry && !summary.disabling) { - return { state: 'loading', label: active[0].installationRetry.retrying - ? 'RETRYING MAPPED SITES' : 'FETCHING MAPPED SITES', detail: 'OpenStreetMap · Overpass' }; + if ( + active.length === 1 && + active[0].installationRetry && + !summary.disabling + ) { + return { + state: 'loading', + label: active[0].installationRetry.retrying + ? 'RETRYING MAPPED SITES' + : 'FETCHING MAPPED SITES', + detail: 'OpenStreetMap · Overpass', + }; } const elapsed = Math.max(0, nowMs - state.startedAt); const label = summary.disabling ? 'TURNING OFF LIVE DATA' - : summary.refresh ? 'REFRESHING LIVE DATA' : 'LOADING LIVE DATA'; - const names = active.slice(0, 2).map((record) => record.label).join(' · '); + : summary.refresh + ? 'REFRESHING LIVE DATA' + : 'LOADING LIVE DATA'; + const names = active + .slice(0, 2) + .map((record) => record.label) + .join(' · '); const suffix = active.length > 2 ? ` +${active.length - 2}` : ''; return { - state: elapsed >= LOADING_LONG_THRESHOLD_MS - ? 'long' - : summary.disabling ? 'disabling' : summary.refresh ? 'refresh' : 'loading', + state: + elapsed >= LOADING_LONG_THRESHOLD_MS + ? 'long' + : summary.disabling + ? 'disabling' + : summary.refresh + ? 'refresh' + : 'loading', label, detail: `${names}${suffix}`, };