|
1 | | -import { createSignal, Show, onMount, onCleanup } from 'solid-js'; |
| 1 | +import { createSignal, Show, onMount, onCleanup, createEffect } from 'solid-js'; |
2 | 2 | import { UpdatesAPI, type UpdateStatus } from '@/api/updates'; |
3 | 3 |
|
4 | 4 | interface UpdateProgressModalProps { |
5 | 5 | isOpen: boolean; |
6 | 6 | onClose: () => void; |
7 | 7 | onViewHistory: () => void; |
| 8 | + connected?: () => boolean; |
| 9 | + reconnecting?: () => boolean; |
8 | 10 | } |
9 | 11 |
|
10 | 12 | export function UpdateProgressModal(props: UpdateProgressModalProps) { |
11 | 13 | const [status, setStatus] = createSignal<UpdateStatus | null>(null); |
12 | 14 | const [isComplete, setIsComplete] = createSignal(false); |
13 | 15 | const [hasError, setHasError] = createSignal(false); |
14 | 16 | const [isRestarting, setIsRestarting] = createSignal(false); |
| 17 | + const [wsDisconnected, setWsDisconnected] = createSignal(false); |
15 | 18 | let pollInterval: number | undefined; |
16 | 19 | let healthCheckTimer: number | undefined; |
17 | 20 | let healthCheckAttempts = 0; |
@@ -113,6 +116,36 @@ export function UpdateProgressModal(props: UpdateProgressModalProps) { |
113 | 116 | healthCheckTimer = window.setTimeout(checkHealth, 0); |
114 | 117 | }; |
115 | 118 |
|
| 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 | + |
116 | 149 | onMount(() => { |
117 | 150 | if (props.isOpen) { |
118 | 151 | // Start polling immediately |
@@ -252,7 +285,11 @@ export function UpdateProgressModal(props: UpdateProgressModalProps) { |
252 | 285 | <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" /> |
253 | 286 | </svg> |
254 | 287 | <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> |
256 | 293 | </div> |
257 | 294 | </div> |
258 | 295 | </div> |
|
0 commit comments