Skip to content

Commit adac6e9

Browse files
committed
fix: Update modal now properly detects when update completes
The update progress modal was stuck showing 'initializing' even after the backend restarted and websocket reconnected. Users could see the connection status badge reconnecting behind the modal, but the modal never cleared. Now the modal: - Watches websocket connection status during update - Detects when backend disconnects and reconnects - Verifies health after reconnection - Automatically reloads the page when update is complete - Shows clearer messaging about restart progress
1 parent d3ca954 commit adac6e9

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

frontend-modern/src/components/UpdateBanner.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { Show, createSignal, createEffect, For } from 'solid-js';
1+
import { Show, createSignal, createEffect, For, useContext } from 'solid-js';
22
import { useNavigate } from '@solidjs/router';
33
import { updateStore } from '@/stores/updates';
44
import { UpdatesAPI, type UpdatePlan } from '@/api/updates';
55
import { UpdateConfirmationModal } from './UpdateConfirmationModal';
66
import { UpdateProgressModal } from './UpdateProgressModal';
7+
import { WebSocketContext } from '@/App';
78

89
export function UpdateBanner() {
910
const navigate = useNavigate();
11+
const wsContext = useContext(WebSocketContext);
1012
const [isExpanded, setIsExpanded] = createSignal(false);
1113
const [updatePlan, setUpdatePlan] = createSignal<UpdatePlan | null>(null);
1214
const [showConfirmModal, setShowConfirmModal] = createSignal(false);
@@ -300,6 +302,8 @@ export function UpdateBanner() {
300302
setShowProgressModal(false);
301303
navigate('/settings/updates');
302304
}}
305+
connected={wsContext?.connected}
306+
reconnecting={wsContext?.reconnecting}
303307
/>
304308
</Show>
305309
);

frontend-modern/src/components/UpdateProgressModal.tsx

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
import { createSignal, Show, onMount, onCleanup } from 'solid-js';
1+
import { createSignal, Show, onMount, onCleanup, createEffect } from 'solid-js';
22
import { UpdatesAPI, type UpdateStatus } from '@/api/updates';
33

44
interface UpdateProgressModalProps {
55
isOpen: boolean;
66
onClose: () => void;
77
onViewHistory: () => void;
8+
connected?: () => boolean;
9+
reconnecting?: () => boolean;
810
}
911

1012
export function UpdateProgressModal(props: UpdateProgressModalProps) {
1113
const [status, setStatus] = createSignal<UpdateStatus | null>(null);
1214
const [isComplete, setIsComplete] = createSignal(false);
1315
const [hasError, setHasError] = createSignal(false);
1416
const [isRestarting, setIsRestarting] = createSignal(false);
17+
const [wsDisconnected, setWsDisconnected] = createSignal(false);
1518
let pollInterval: number | undefined;
1619
let healthCheckTimer: number | undefined;
1720
let healthCheckAttempts = 0;
@@ -113,6 +116,36 @@ export function UpdateProgressModal(props: UpdateProgressModalProps) {
113116
healthCheckTimer = window.setTimeout(checkHealth, 0);
114117
};
115118

119+
// Watch websocket status during restart
120+
createEffect(() => {
121+
if (!isRestarting()) return;
122+
123+
const connected = props.connected?.();
124+
const reconnecting = props.reconnecting?.();
125+
126+
// Track if websocket disconnected during restart
127+
if (connected === false && !reconnecting) {
128+
setWsDisconnected(true);
129+
}
130+
131+
// If websocket reconnected after being disconnected, the backend is likely back
132+
if (wsDisconnected() && connected === true && !reconnecting) {
133+
console.log('WebSocket reconnected after restart, verifying health...');
134+
// Give it a moment for the backend to fully initialize
135+
setTimeout(async () => {
136+
try {
137+
const response = await fetch('/api/health', { cache: 'no-store' });
138+
if (response.ok) {
139+
console.log('Backend healthy after websocket reconnect, reloading...');
140+
window.location.reload();
141+
}
142+
} catch (error) {
143+
console.warn('Health check failed after websocket reconnect, will keep trying');
144+
}
145+
}, 1000);
146+
}
147+
});
148+
116149
onMount(() => {
117150
if (props.isOpen) {
118151
// Start polling immediately
@@ -252,7 +285,11 @@ export function UpdateProgressModal(props: UpdateProgressModalProps) {
252285
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
253286
</svg>
254287
<div class="text-sm text-blue-800 dark:text-blue-200">
255-
Pulse is restarting with the new version. This page will reload automatically when ready.
288+
<Show when={wsDisconnected()} fallback={
289+
<span>Pulse is restarting with the new version...</span>
290+
}>
291+
<span>Waiting for Pulse to complete restart. This page will reload automatically.</span>
292+
</Show>
256293
</div>
257294
</div>
258295
</div>

0 commit comments

Comments
 (0)