Skip to content

Commit 48e47c4

Browse files
fix(ui): refresh button triggers full reload and update restart auto-recovers (#168)
SessionsHub refresh button now clears caches and does a full page reload (matching the CommandPalette refresh). This also naturally re-triggers the update check on mount. UpdateBanner polling now detects when the server bounces during a restart — tracks the server going down (null responses), then reloads the page when it comes back. Previously the UI got stuck on 'Restarting...' because the restarted server returned status: idle which had no handler. Closes #167 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8fe0fa6 commit 48e47c4

2 files changed

Lines changed: 25 additions & 2 deletions

File tree

src/frontend/src/components/SessionsHub/SessionsHub.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,14 @@ export default function SessionsHub() {
119119

120120
async function handleRefresh() {
121121
setRefreshing(true);
122-
await loadSessions();
123-
setTimeout(() => setRefreshing(false), 600);
122+
try {
123+
if ('caches' in window && typeof window.caches?.keys === 'function') {
124+
const cacheNames = await caches.keys();
125+
await Promise.all(cacheNames.map((name) => caches.delete(name)));
126+
}
127+
} finally {
128+
location.reload();
129+
}
124130
}
125131

126132
function handleShare() {

src/frontend/src/components/common/UpdateBanner.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export default function UpdateBanner() {
5454
const commandRef = useRef('');
5555
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
5656
const copiedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
57+
const sawServerDownRef = useRef(false);
5758

5859
// Clean up copied timer on unmount
5960
useEffect(() => {
@@ -122,8 +123,24 @@ export default function UpdateBanner() {
122123
useEffect(() => {
123124
const isUpdating = state.kind === 'updating' || state.kind === 'restarting';
124125
if (isUpdating && !pollRef.current) {
126+
// Reset server-down tracking when entering restarting state
127+
if (state.kind === 'restarting') sawServerDownRef.current = false;
125128
pollRef.current = setInterval(async () => {
126129
const status = await getUpdateStatus();
130+
131+
// Detect server bounce during restart: server down → server back → reload
132+
if (state.kind === 'restarting') {
133+
if (!status) {
134+
sawServerDownRef.current = true;
135+
return;
136+
}
137+
if (sawServerDownRef.current || status.status === 'idle') {
138+
// Server came back after restart — reload to pick up new assets
139+
window.location.reload();
140+
return;
141+
}
142+
}
143+
127144
if (!status) return;
128145
if (status.status === 'complete') {
129146
setState({ kind: 'success', toVersion: status.toVersion || '?' });

0 commit comments

Comments
 (0)