Skip to content

Commit 53a2c2a

Browse files
committed
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
1 parent f4e3f62 commit 53a2c2a

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

frontend-modern/src/components/Settings/UnifiedAgents.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ export const UnifiedAgents: Component = () => {
240240
return `curl -fsSL ${pulseUrl()}/install.sh | sudo bash -s -- --uninstall`;
241241
};
242242

243+
// Track previously seen host types to prevent flapping when one source temporarily has no data
244+
// This preserves types we've seen before even if one array briefly becomes empty
245+
let previousHostTypes = new Map<string, Set<'host' | 'docker'>>();
246+
243247
const allHosts = createMemo(() => {
244248
const hosts = state.hosts || [];
245249
const dockerHosts = state.dockerHosts || [];
@@ -296,6 +300,33 @@ export const UnifiedAgents: Component = () => {
296300
}
297301
});
298302

303+
// Preserve previously seen types to prevent flapping
304+
// If we previously saw both 'host' and 'docker' for a hostname, keep both
305+
// unless BOTH sources are now empty (indicating intentional removal)
306+
const newHostTypes = new Map<string, Set<'host' | 'docker'>>();
307+
unified.forEach((entry, key) => {
308+
const currentTypes = new Set(entry.types);
309+
const prevTypes = previousHostTypes.get(key);
310+
311+
if (prevTypes && prevTypes.size > currentTypes.size) {
312+
// We previously had more types - check if source data exists
313+
// Only add back types if the corresponding source has ANY data
314+
// (prevents permanent stickiness if a host is truly removed)
315+
if (prevTypes.has('host') && !currentTypes.has('host') && hosts.length > 0) {
316+
// Host type disappeared but we still have host data overall
317+
// This is likely a transient state - preserve the host type
318+
entry.types = Array.from(new Set([...entry.types, 'host']));
319+
}
320+
if (prevTypes.has('docker') && !currentTypes.has('docker') && dockerHosts.length > 0) {
321+
// Docker type disappeared but we still have docker data overall
322+
entry.types = Array.from(new Set([...entry.types, 'docker']));
323+
}
324+
}
325+
326+
newHostTypes.set(key, new Set(entry.types));
327+
});
328+
previousHostTypes = newHostTypes;
329+
299330
return Array.from(unified.values()).sort((a, b) => a.hostname.localeCompare(b.hostname));
300331
});
301332

0 commit comments

Comments
 (0)