Hide idle Patrol filter bar

Hide the Patrol findings filter bar when there are no findings or special queues to navigate, keeping empty-state Patrol surfaces focused on the actual assessment rather than inert controls.
This commit is contained in:
rcourtman 2026-03-25 16:52:35 +00:00
parent fadd3ef2bd
commit 2bd7c39b9b
3 changed files with 25 additions and 1 deletions

View file

@ -195,6 +195,10 @@ That same control bar should also stay proportional to the current findings
set. Sort controls belong only when there are multiple Patrol findings to
order; the empty state or single-finding state should not spend header space
on a no-op sort selector.
The same proportionality rule applies to the findings filter bar itself. When
there are no Patrol findings and no special approval or attention queues to
navigate, the findings surface should not render filter pills that lead only
to the same empty state.
When Patrol is currently running, that strip should still stay factual rather
than switching to another verdict label: the runtime may add an explicit
in-progress indicator, but the primary activity label remains recent activity

View file

@ -206,6 +206,11 @@ export const FindingsPanel: Component<FindingsPanelProps> = (props) => {
});
// Filter to only show Patrol findings (exclude threshold alerts)
const allPatrolFindings = createMemo(() =>
aiIntelligenceStore.findings.filter(
(f) => f.source !== 'threshold' && !f.isThreshold && !hasTriggeringAlert(f),
),
);
const patrolFindings = createMemo(() =>
filteredFindings().filter(
(f) => f.source !== 'threshold' && !f.isThreshold && !hasTriggeringAlert(f),
@ -226,6 +231,13 @@ export const FindingsPanel: Component<FindingsPanelProps> = (props) => {
}),
);
const emptyStateTone = createMemo(() => getSemanticTonePresentation(emptyStateCopy().tone));
const showFilterControls = createMemo(
() =>
props.showControls !== false &&
(allPatrolFindings().length > 0 ||
aiIntelligenceStore.needsAttentionCount > 0 ||
aiIntelligenceStore.pendingApprovalCount > 0),
);
const isOutOfScope = (finding: UnifiedFinding): boolean => {
if (!props.showScopeWarnings) {
@ -1009,7 +1021,7 @@ export const FindingsPanel: Component<FindingsPanelProps> = (props) => {
return (
<div class="space-y-4">
{/* Controls */}
<Show when={props.showControls !== false}>
<Show when={showFilterControls()}>
<div class="flex items-center justify-between">
<div class="flex text-xs">
<For each={filterOptions()}>

View file

@ -176,6 +176,14 @@ describe('aiFindingPresentation', () => {
expect(findingsPanelSource).toContain('<Show when={patrolFindings().length > 1}>');
expect(findingsPanelSource).toContain('<option value="severity">By Severity</option>');
});
it('hides the filter bar when there are no Patrol findings or special buckets to navigate', () => {
expect(findingsPanelSource).toContain('const showFilterControls = createMemo(');
expect(findingsPanelSource).toContain('allPatrolFindings().length > 0');
expect(findingsPanelSource).toContain('aiIntelligenceStore.needsAttentionCount > 0');
expect(findingsPanelSource).toContain('aiIntelligenceStore.pendingApprovalCount > 0');
expect(findingsPanelSource).toContain('<Show when={showFilterControls()}>');
});
});
describe('sourceColors', () => {