From cf03e6f742f4797c8dd96b3fcd15d4518fd21ea6 Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Sun, 31 Aug 2025 06:58:10 +0000 Subject: [PATCH] fix: broadcast state updates after alert acknowledgment (addresses #380) - Add WebSocket hub reference to AlertHandlers - Broadcast state after acknowledge, clear, and bulk operations - Ensures UI acknowledgment counts update immediately without refresh - Fixes issue where acknowledgment would disappear after 2 seconds --- internal/api/alerts.go | 42 +++++++++++++++++++++++++++++++++++++++++- internal/api/router.go | 2 +- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/internal/api/alerts.go b/internal/api/alerts.go index 0e37d2d57..7490f3368 100644 --- a/internal/api/alerts.go +++ b/internal/api/alerts.go @@ -10,18 +10,21 @@ import ( "github.com/rcourtman/pulse-go-rewrite/internal/mock" "github.com/rcourtman/pulse-go-rewrite/internal/monitoring" "github.com/rcourtman/pulse-go-rewrite/internal/utils" + "github.com/rcourtman/pulse-go-rewrite/internal/websocket" "github.com/rs/zerolog/log" ) // AlertHandlers handles alert-related HTTP endpoints type AlertHandlers struct { monitor *monitoring.Monitor + wsHub *websocket.Hub } // NewAlertHandlers creates new alert handlers -func NewAlertHandlers(monitor *monitoring.Monitor) *AlertHandlers { +func NewAlertHandlers(monitor *monitoring.Monitor, wsHub *websocket.Hub) *AlertHandlers { return &AlertHandlers{ monitor: monitor, + wsHub: wsHub, } } @@ -150,6 +153,13 @@ func (h *AlertHandlers) AcknowledgeAlert(w http.ResponseWriter, r *http.Request) Str("user", user). Msg("Alert acknowledged successfully") + // Broadcast updated state to all WebSocket clients + if h.wsHub != nil { + state := h.monitor.GetState() + h.wsHub.BroadcastState(state) + log.Debug().Msg("Broadcasted state after alert acknowledgment") + } + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]bool{"success": true}) } @@ -166,6 +176,13 @@ func (h *AlertHandlers) ClearAlert(w http.ResponseWriter, r *http.Request) { h.monitor.GetAlertManager().ClearAlert(alertID) + // Broadcast updated state to all WebSocket clients + if h.wsHub != nil { + state := h.monitor.GetState() + h.wsHub.BroadcastState(state) + log.Debug().Msg("Broadcasted state after alert clear") + } + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]bool{"success": true}) } @@ -205,6 +222,22 @@ func (h *AlertHandlers) BulkAcknowledgeAlerts(w http.ResponseWriter, r *http.Req results = append(results, result) } + // Broadcast updated state to all WebSocket clients if any alerts were acknowledged + if h.wsHub != nil { + hasSuccess := false + for _, result := range results { + if success, ok := result["success"].(bool); ok && success { + hasSuccess = true + break + } + } + if hasSuccess { + state := h.monitor.GetState() + h.wsHub.BroadcastState(state) + log.Debug().Msg("Broadcasted state after bulk alert acknowledgment") + } + } + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "results": results, @@ -237,6 +270,13 @@ func (h *AlertHandlers) BulkClearAlerts(w http.ResponseWriter, r *http.Request) results = append(results, result) } + // Broadcast updated state to all WebSocket clients + if h.wsHub != nil && len(results) > 0 { + state := h.monitor.GetState() + h.wsHub.BroadcastState(state) + log.Debug().Msg("Broadcasted state after bulk alert clear") + } + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]interface{}{ "results": results, diff --git a/internal/api/router.go b/internal/api/router.go index 1ced9a394..afc6c1b20 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -80,7 +80,7 @@ func NewRouter(cfg *config.Config, monitor *monitoring.Monitor, wsHub *websocket // setupRoutes configures all routes func (r *Router) setupRoutes() { // Create handlers - alertHandlers := NewAlertHandlers(r.monitor) + alertHandlers := NewAlertHandlers(r.monitor, r.wsHub) notificationHandlers := NewNotificationHandlers(r.monitor) guestMetadataHandler := NewGuestMetadataHandler(r.config.DataPath) configHandlers := NewConfigHandlers(r.config, r.monitor, r.reloadFunc, r.wsHub, guestMetadataHandler)