diff --git a/frontend-modern/src/App.tsx b/frontend-modern/src/App.tsx index 992f241d0d..8870bd2c59 100644 --- a/frontend-modern/src/App.tsx +++ b/frontend-modern/src/App.tsx @@ -486,15 +486,26 @@ function App() { } }; - // Subscribe to theme change events + // Handle WebSocket reconnection - refresh alert config to restore activation state + // This fixes issue where alert toggle appears disabled after connection loss + const handleWebSocketReconnected = () => { + logger.info('WebSocket reconnected, refreshing alert configuration'); + void alertsActivation.refreshConfig(); + void alertsActivation.refreshActiveAlerts(); + }; + + // Subscribe to events eventBus.on('theme_changed', handleThemeChange); + eventBus.on('websocket_reconnected', handleWebSocketReconnected); // Cleanup on unmount onCleanup(() => { eventBus.off('theme_changed', handleThemeChange); + eventBus.off('websocket_reconnected', handleWebSocketReconnected); }); }); + // Check auth on mount onMount(async () => { logger.debug('[App] Starting auth check...'); diff --git a/frontend-modern/src/stores/events.ts b/frontend-modern/src/stores/events.ts index 63f019d998..44ffb098d8 100644 --- a/frontend-modern/src/stores/events.ts +++ b/frontend-modern/src/stores/events.ts @@ -6,7 +6,8 @@ export type EventType = | 'refresh_nodes' | 'discovery_updated' | 'discovery_status' - | 'theme_changed'; + | 'theme_changed' + | 'websocket_reconnected'; // Event data types export interface NodeAutoRegisteredData { @@ -51,6 +52,7 @@ export type EventDataMap = { discovery_updated: DiscoveryUpdatedData; discovery_status: DiscoveryStatusData; theme_changed: string; // 'light' or 'dark' + websocket_reconnected: void; // Emitted when WebSocket successfully reconnects }; // Generic event handler diff --git a/frontend-modern/src/stores/websocket.ts b/frontend-modern/src/stores/websocket.ts index efbb51251e..3505e08e89 100644 --- a/frontend-modern/src/stores/websocket.ts +++ b/frontend-modern/src/stores/websocket.ts @@ -308,6 +308,7 @@ export function createWebSocketStore(url: string) { ws.onopen = () => { logger.debug('connect'); + const wasReconnecting = reconnectAttempt > 0; setConnected(true); setReconnecting(false); // Clear reconnecting state reconnectAttempt = 0; // Reset reconnect attempts on successful connection @@ -329,9 +330,17 @@ export function createWebSocketStore(url: string) { } }, heartbeatIntervalMs); + // Emit reconnection event so App can refresh alert config + // This ensures the alert activation state is re-fetched after connection loss + if (wasReconnecting) { + logger.info('WebSocket reconnected, emitting event for config refresh'); + eventBus.emit('websocket_reconnected'); + } + // Alerts will come with the initial state broadcast }; + ws.onmessage = (event) => { let data; try {