From 749a52dd5ae3c2b962d9802ef78b4b4035ae0760 Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Sun, 7 Sep 2025 07:13:56 +0000 Subject: [PATCH] fix: resolve PBS alert toggle and offline alert issues (addresses #426) - Fixed PBS alert toggle not responding in thresholds settings - PBS servers now use connectivity toggle like nodes instead of disabled toggle - Added support for disableConnectivity flag on PBS instances in backend - Fixed PBS ID format mismatch between frontend and backend - PBS offline alerts now properly respect the disableConnectivity setting - Prevents spam alerts by checking disableConnectivity flag for PBS offline alerts --- .../src/components/Alerts/ResourceTable.tsx | 18 +++++---- .../src/components/Alerts/ThresholdsTable.tsx | 37 +++++++++++-------- internal/alerts/alerts.go | 8 ++-- scripts/hot-dev.sh | 18 ++++++++- 4 files changed, 51 insertions(+), 30 deletions(-) diff --git a/frontend-modern/src/components/Alerts/ResourceTable.tsx b/frontend-modern/src/components/Alerts/ResourceTable.tsx index 4dc96ccc0..cba9c41ee 100644 --- a/frontend-modern/src/components/Alerts/ResourceTable.tsx +++ b/frontend-modern/src/components/Alerts/ResourceTable.tsx @@ -250,16 +250,17 @@ export function ResourceTable(props: ResourceTableProps) { {resource.disabled ? 'Disabled' : 'Enabled'} - + @@ -471,16 +472,17 @@ export function ResourceTable(props: ResourceTableProps) { {resource.disabled ? 'Disabled' : 'Enabled'} - + diff --git a/frontend-modern/src/components/Alerts/ThresholdsTable.tsx b/frontend-modern/src/components/Alerts/ThresholdsTable.tsx index df5463441..a5d1b1ab4 100644 --- a/frontend-modern/src/components/Alerts/ThresholdsTable.tsx +++ b/frontend-modern/src/components/Alerts/ThresholdsTable.tsx @@ -238,7 +238,8 @@ export function ThresholdsTable(props: ThresholdsTableProps) { const pbsInstances = props.pbsInstances || []; const pbsServers = pbsInstances.filter((pbs) => (pbs.cpu || 0) > 0 || (pbs.memory?.usage || 0) > 0).map((pbs) => { - const pbsId = `pbs-${pbs.id}`; + // PBS IDs already have "pbs-" prefix from backend, don't double it + const pbsId = pbs.id; const override = overridesMap.get(pbsId); // Check if any threshold values actually differ from defaults @@ -264,6 +265,7 @@ export function ThresholdsTable(props: ThresholdsTableProps) { uptime: pbs.uptime, hasOverride: hasCustomThresholds || false, disabled: false, + disableConnectivity: override?.disableConnectivity || false, thresholds: override?.thresholds || {}, defaults: { cpu: props.nodeDefaults.cpu, @@ -502,15 +504,18 @@ export function ThresholdsTable(props: ThresholdsTableProps) { }; - const toggleNodeConnectivity = (nodeId: string, forceState?: boolean) => { - const node = nodesWithOverrides().find(r => r.id === nodeId); - if (!node || node.type !== 'node') return; + const toggleNodeConnectivity = (resourceId: string, forceState?: boolean) => { + // Find the resource - could be a node or PBS server + const nodes = nodesWithOverrides(); + const pbsServers = pbsServersWithOverrides(); + const resource = [...nodes, ...pbsServers].find(r => r.id === resourceId); + if (!resource || (resource.type !== 'node' && resource.type !== 'pbs')) return; // Get existing override if it exists - const existingOverride = props.overrides().find(o => o.id === nodeId); + const existingOverride = props.overrides().find(o => o.id === resourceId); - // Determine the current state - use the node's computed state, not just the override - const currentDisableConnectivity = node.disableConnectivity; + // Determine the current state - use the resource's computed state, not just the override + const currentDisableConnectivity = resource.disableConnectivity; const newDisableConnectivity = forceState !== undefined ? forceState : !currentDisableConnectivity; // Clean the thresholds to exclude any unwanted fields @@ -521,25 +526,25 @@ export function ThresholdsTable(props: ThresholdsTableProps) { // If enabling connectivity alerts (disableConnectivity = false) and no custom thresholds exist, remove the override entirely if (!newDisableConnectivity && Object.keys(cleanThresholds).length === 0) { // Remove the override completely - props.setOverrides(props.overrides().filter(o => o.id !== nodeId)); + props.setOverrides(props.overrides().filter(o => o.id !== resourceId)); // Remove from raw config const newRawConfig = { ...props.rawOverridesConfig() }; - delete newRawConfig[nodeId]; + delete newRawConfig[resourceId]; props.setRawOverridesConfig(newRawConfig); } else { // Update or create the override const override: Override = { - id: nodeId, - name: node.name, - type: node.type, - resourceType: node.resourceType, + id: resourceId, + name: resource.name, + type: resource.type as 'node' | 'guest' | 'storage', + resourceType: resource.resourceType, disableConnectivity: newDisableConnectivity, thresholds: cleanThresholds }; // Update overrides list - const existingIndex = props.overrides().findIndex(o => o.id === nodeId); + const existingIndex = props.overrides().findIndex(o => o.id === resourceId); if (existingIndex >= 0) { const newOverrides = [...props.overrides()]; newOverrides[existingIndex] = override; @@ -566,7 +571,7 @@ export function ThresholdsTable(props: ThresholdsTableProps) { hysteresisThresholds.disableConnectivity = true; } - newRawConfig[nodeId] = hysteresisThresholds; + newRawConfig[resourceId] = hysteresisThresholds; props.setRawOverridesConfig(newRawConfig); } @@ -915,7 +920,7 @@ export function ThresholdsTable(props: ThresholdsTableProps) { onSaveEdit={saveEdit} onCancelEdit={cancelEdit} onRemoveOverride={removeOverride} - onToggleDisabled={toggleDisabled} + onToggleNodeConnectivity={toggleNodeConnectivity} editingId={editingId} editingThresholds={editingThresholds} setEditingThresholds={setEditingThresholds} diff --git a/internal/alerts/alerts.go b/internal/alerts/alerts.go index bc0f40eac..03fa8e432 100644 --- a/internal/alerts/alerts.go +++ b/internal/alerts/alerts.go @@ -1408,14 +1408,14 @@ func (m *Manager) checkPBSOffline(pbs models.PBSInstance) { m.mu.Lock() defer m.mu.Unlock() - // Check if PBS offline alerts are disabled - if override, exists := m.config.Overrides[pbs.ID]; exists && override.Disabled { - // PBS alerts are disabled, clear any existing alert and return + // Check if PBS offline alerts are disabled via disableConnectivity flag + if override, exists := m.config.Overrides[pbs.ID]; exists && (override.Disabled || override.DisableConnectivity) { + // PBS connectivity alerts are disabled, clear any existing alert and return if _, alertExists := m.activeAlerts[alertID]; alertExists { delete(m.activeAlerts, alertID) log.Debug(). Str("pbs", pbs.Name). - Msg("PBS offline alert cleared (alerts disabled)") + Msg("PBS offline alert cleared (connectivity alerts disabled)") } return } diff --git a/scripts/hot-dev.sh b/scripts/hot-dev.sh index 3cf99b771..9481ce4e9 100755 --- a/scripts/hot-dev.sh +++ b/scripts/hot-dev.sh @@ -40,8 +40,11 @@ pkill -f vite 2>/dev/null pkill -f "npm run dev" 2>/dev/null pkill -f "npm exec" 2>/dev/null -# Kill Pulse binary (exact match only) +# Kill Pulse binary - first try gracefully, then force pkill -x "pulse" 2>/dev/null +sleep 1 +# Force kill if still running +pkill -9 -x "pulse" 2>/dev/null # Force-kill ANYTHING on our ports kill_port 7655 @@ -158,11 +161,22 @@ EOF cleanup() { echo "" echo "Stopping services..." - kill $BACKEND_PID 2>/dev/null + # Try graceful shutdown first + if [ -n "$BACKEND_PID" ] && kill -0 $BACKEND_PID 2>/dev/null; then + kill $BACKEND_PID 2>/dev/null + sleep 1 + # Force kill if still running + if kill -0 $BACKEND_PID 2>/dev/null; then + echo "Backend not responding to SIGTERM, force killing..." + kill -9 $BACKEND_PID 2>/dev/null + fi + fi rm -f vite.config.dev.ts # Clean up any leftover Vite processes pkill -f vite 2>/dev/null pkill -f "npm run dev" 2>/dev/null + # Final cleanup of any stuck pulse processes + pkill -9 -x "pulse" 2>/dev/null echo "Hot-dev stopped. To restart normal service, run: sudo systemctl start pulse-backend" exit }