From 53a2c2a587949d4393efadd84477665f9a0e69ff Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 2 Dec 2025 11:29:03 +0000 Subject: [PATCH] fix: Prevent agent type badge flapping in UnifiedAgents view Track previously seen host types and preserve them when one data source temporarily has no entry for a hostname. This prevents the "Host" or "Docker" type badge from disappearing and reappearing when websocket updates cause momentary state inconsistencies. The fix only preserves types if the corresponding source array has any data at all, ensuring that intentional host removal (both arrays empty for that host) still works correctly. Related to #773 --- .../src/components/Settings/UnifiedAgents.tsx | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/frontend-modern/src/components/Settings/UnifiedAgents.tsx b/frontend-modern/src/components/Settings/UnifiedAgents.tsx index 61b595b..c64da50 100644 --- a/frontend-modern/src/components/Settings/UnifiedAgents.tsx +++ b/frontend-modern/src/components/Settings/UnifiedAgents.tsx @@ -240,6 +240,10 @@ export const UnifiedAgents: Component = () => { return `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --uninstall`; }; + // Track previously seen host types to prevent flapping when one source temporarily has no data + // This preserves types we've seen before even if one array briefly becomes empty + let previousHostTypes = new Map>(); + const allHosts = createMemo(() => { const hosts = state.hosts || []; const dockerHosts = state.dockerHosts || []; @@ -296,6 +300,33 @@ export const UnifiedAgents: Component = () => { } }); + // Preserve previously seen types to prevent flapping + // If we previously saw both 'host' and 'docker' for a hostname, keep both + // unless BOTH sources are now empty (indicating intentional removal) + const newHostTypes = new Map>(); + unified.forEach((entry, key) => { + const currentTypes = new Set(entry.types); + const prevTypes = previousHostTypes.get(key); + + if (prevTypes && prevTypes.size > currentTypes.size) { + // We previously had more types - check if source data exists + // Only add back types if the corresponding source has ANY data + // (prevents permanent stickiness if a host is truly removed) + if (prevTypes.has('host') && !currentTypes.has('host') && hosts.length > 0) { + // Host type disappeared but we still have host data overall + // This is likely a transient state - preserve the host type + entry.types = Array.from(new Set([...entry.types, 'host'])); + } + if (prevTypes.has('docker') && !currentTypes.has('docker') && dockerHosts.length > 0) { + // Docker type disappeared but we still have docker data overall + entry.types = Array.from(new Set([...entry.types, 'docker'])); + } + } + + newHostTypes.set(key, new Set(entry.types)); + }); + previousHostTypes = newHostTypes; + return Array.from(unified.values()).sort((a, b) => a.hostname.localeCompare(b.hostname)); });