diff --git a/docs/release-control/v6/internal/subsystems/storage-recovery.md b/docs/release-control/v6/internal/subsystems/storage-recovery.md index dbb9c76d0..6e7cb49de 100644 --- a/docs/release-control/v6/internal/subsystems/storage-recovery.md +++ b/docs/release-control/v6/internal/subsystems/storage-recovery.md @@ -779,7 +779,10 @@ That same shared page-controls contract applies to recovery search width too. The protected-items and recovery-events workspaces should keep the search field on the standard full-width shared search row, and any counts or utility cues should live in the toolbar actions instead of narrowing the search row through -recovery-local grid overrides or width hacks. +recovery-local grid overrides or width hacks. Protected-items controls should +also use the same shared `Reset all` page-controls action pattern as storage +and workloads when visible filters are active, instead of forcing operators to +clear each inventory filter manually. That same handoff should keep recovery on the standard Pulse summary density. `RecoverySummary.tsx` should use the shared default `SummaryPanel` / `SummaryMetricCard` rhythm that infrastructure and workloads use, instead of diff --git a/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx b/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx index c9d99e646..522672079 100644 --- a/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx +++ b/frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx @@ -195,6 +195,15 @@ export const RecoveryProtectedInventorySection: Component< } }); + const resetProtectedFilters = () => { + props.setQueryFilter(''); + props.setPlatformFilter('all'); + props.setItemTypeFilter('all'); + props.setHistoryOutcomeFilter('all'); + props.setVerificationFilter('all'); + props.setProtectedStaleOnly(false); + }; + return (
@@ -220,6 +229,12 @@ export const RecoveryProtectedInventorySection: Component< onToggle: () => setProtectedFiltersOpen((open) => !open), count: protectedActiveFilterCount(), }} + resetAction={{ + show: protectedActiveFilterCount() > 0, + onClick: resetProtectedFilters, + label: 'Reset all', + title: 'Reset protected item filters', + }} showFilters={!props.isMobile || protectedFiltersOpen()} toolbarClass="gap-3 lg:flex-nowrap" > diff --git a/frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx b/frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx index c9289876c..1b9b5091d 100644 --- a/frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx +++ b/frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx @@ -682,6 +682,24 @@ describe('Recovery', () => { }); }); + it('uses the shared reset action for protected item filters', async () => { + render(() => ); + + expect(await screen.findByText('VM 123')).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Reset all' })).not.toBeInTheDocument(); + + fireEvent.change(screen.getByLabelText('Platform'), { target: { value: 'truenas' } }); + + const resetButton = await screen.findByRole('button', { name: 'Reset all' }); + fireEvent.click(resetButton); + + await waitFor(() => { + expect(screen.getByLabelText('Platform')).toHaveValue('all'); + expect(screen.getByText('VM 123')).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: 'Reset all' })).not.toBeInTheDocument(); + }); + }); + it('keeps recovery filter surfaces on canonical platform vocabulary', async () => { render(() => );