diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index 1fbac0bc4..0a657fdec 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -83,7 +83,9 @@ Patrol-specific presentation helpers. The same source boundary owns loading and error state: Patrol findings must render from `patrolFindings`, `patrolFindingsLoading`, and `patrolFindingsError` instead of letting a pending unified findings request - mask direct Patrol evidence that has already loaded. + mask direct Patrol evidence that has already loaded. Background Patrol + refreshes must preserve already-loaded findings instead of replacing the + workspace with a blocking loading state. 2. Keep Patrol-specific copy and badge logic inside the governed Patrol presentation helpers instead of page-local branches Patrol assessment copy must not present an all-clear health prediction while active Patrol findings or Patrol runtime issues are still present. The diff --git a/frontend-modern/src/components/AI/FindingsPanel.tsx b/frontend-modern/src/components/AI/FindingsPanel.tsx index b807d1aaf..44e519f14 100644 --- a/frontend-modern/src/components/AI/FindingsPanel.tsx +++ b/frontend-modern/src/components/AI/FindingsPanel.tsx @@ -165,11 +165,15 @@ export const FindingsPanel: Component = (props) => { const sourceFindings = createMemo(() => isPatrolFindingsSource() ? aiIntelligenceStore.patrolFindings : aiIntelligenceStore.findings, ); + const sourceHasFindings = createMemo(() => sourceFindings().length > 0); const sourceFindingsLoading = createMemo(() => isPatrolFindingsSource() ? aiIntelligenceStore.patrolFindingsLoading : aiIntelligenceStore.findingsLoading, ); + const shouldShowLoadingState = createMemo( + () => sourceFindingsLoading() && !sourceHasFindings(), + ); const sourceFindingsError = createMemo(() => isPatrolFindingsSource() ? aiIntelligenceStore.patrolFindingsError @@ -1806,7 +1810,7 @@ export const FindingsPanel: Component = (props) => { {/* Loading/Error states */} - +
Loading findings... @@ -1819,7 +1823,7 @@ export const FindingsPanel: Component = (props) => {
- + {/* Content */}
diff --git a/frontend-modern/src/components/AI/__tests__/FindingsPanel.links.test.tsx b/frontend-modern/src/components/AI/__tests__/FindingsPanel.links.test.tsx index 9e61e0b6e..a5c6737e8 100644 --- a/frontend-modern/src/components/AI/__tests__/FindingsPanel.links.test.tsx +++ b/frontend-modern/src/components/AI/__tests__/FindingsPanel.links.test.tsx @@ -237,4 +237,15 @@ describe('FindingsPanel resource links', () => { expect(screen.queryByText('Loading findings...')).not.toBeInTheDocument(); expect(screen.getByText('Provider connection issue')).toBeInTheDocument(); }); + + it('keeps loaded Patrol findings visible during a Patrol refresh', async () => { + mockState.patrolFindingsLoading = true; + + render(() => ); + + await waitFor(() => expect(mockState.loadPatrolFindings).toHaveBeenCalled()); + + expect(screen.queryByText('Loading findings...')).not.toBeInTheDocument(); + expect(screen.getByText('Provider connection issue')).toBeInTheDocument(); + }); }); diff --git a/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts b/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts index ca70d8926..36290361b 100644 --- a/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts +++ b/frontend-modern/src/components/AI/__tests__/FindingsPanel.test.ts @@ -675,6 +675,8 @@ describe('aiFindingPresentation', () => { expect(findingsPanelSource).toContain("findingsSource?: 'unified' | 'patrol'"); expect(findingsPanelSource).toContain('aiIntelligenceStore.loadPatrolFindings()'); expect(findingsPanelSource).toContain('aiIntelligenceStore.patrolFindings'); + expect(findingsPanelSource).toContain('const sourceHasFindings = createMemo('); + expect(findingsPanelSource).toContain('const shouldShowLoadingState = createMemo('); expect(findingsPanelSource).toContain('aiIntelligenceStore.patrolFindingsLoading'); expect(findingsPanelSource).toContain('aiIntelligenceStore.patrolFindingsError'); expect(findingsPanelSource).toContain('aiIntelligenceStore.patrolFindingsSignal()');