From 7130d2bd569e3e5a3dfc33a81cee90a610ce98c1 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Mon, 11 May 2026 11:22:02 +0100 Subject: [PATCH] Persist include-resolved across Patrol findings polling loadDashboardData and other unscoped loadPatrolFindings callers were overwriting the Resolved/All tab data set with the active-only payload on every poll, causing those tabs to blink empty between refreshes. A module-level sticky preference now flips to true the first time any caller asks for includeResolved and keeps subsequent unscoped loads expanded, so the Resolved and All tabs hold their data across polling. --- frontend-modern/src/stores/aiIntelligence.ts | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frontend-modern/src/stores/aiIntelligence.ts b/frontend-modern/src/stores/aiIntelligence.ts index f59db57edc..bd158599e8 100644 --- a/frontend-modern/src/stores/aiIntelligence.ts +++ b/frontend-modern/src/stores/aiIntelligence.ts @@ -200,6 +200,15 @@ const [findingsError, setFindingsError] = createSignal(null); const [patrolFindings, setPatrolFindings] = createSignal([]); const [patrolFindingsLoading, setPatrolFindingsLoading] = createSignal(false); const [patrolFindingsError, setPatrolFindingsError] = createSignal(null); +// Sticky preference: once a surface asks for include-resolved data, +// subsequent unscoped loadPatrolFindings calls (from polling, dashboard +// refresh, etc.) keep returning the expanded set. Otherwise the +// Resolved/All tabs would intermittently empty whenever a polling +// loadDashboardData overwrote the include-resolved load with the +// active-only default. Reset to false when nothing on screen needs the +// expanded set (no current call site does this; FindingsPanel's effect +// would set it back to true the moment Resolved/All becomes active). +let patrolFindingsIncludeResolvedPreference = false; function normalizeUnifiedFindingRecord(item: UnifiedFindingRecord, now: number): UnifiedFinding { const alertIdentifier = item.alertIdentifier; @@ -443,10 +452,22 @@ export const aiIntelligenceStore = { }, async loadPatrolFindings(options?: { includeResolved?: boolean }) { + // Sticky preference: once a caller has explicitly asked for the + // expanded set, treat all subsequent loads (including unscoped + // polling refreshes) as expanded so the Resolved/All tab data does + // not blink to empty between polls. The Patrol findings endpoint + // is cheap; the per-finding cap keeps the payload bounded. + if (options?.includeResolved) { + patrolFindingsIncludeResolvedPreference = true; + } + const includeResolved = + options?.includeResolved === true || patrolFindingsIncludeResolvedPreference; setPatrolFindingsLoading(true); setPatrolFindingsError(null); try { - const findings = await getPatrolFindings(options); + const findings = await getPatrolFindings( + includeResolved ? { includeResolved: true } : undefined, + ); const now = Date.now(); setPatrolFindings(findings.map((item) => normalizePatrolFindingRecord(item, now))); } catch (e) {