From fd768c6eb103e6cbfef33aaf70a6258f5b6e7a36 Mon Sep 17 00:00:00 2001 From: Pulse Monitor Date: Tue, 26 Aug 2025 11:32:37 +0000 Subject: [PATCH] feat: extend search filtering to Storage and Backups tabs - Node tables now dynamically update based on search in all tabs - Storage tab filters nodes to show only those with matching storage - Backups tab filters nodes to show only those with matching backups - Counts update to reflect filtered items in each tab - Consistent search experience across Dashboard, Storage, and Backups --- .../src/components/Backups/UnifiedBackups.tsx | 2 + .../src/components/Storage/Storage.tsx | 2 + .../src/components/shared/PVENodeTable.tsx | 53 ++++++++++++++----- .../components/shared/UnifiedNodeSelector.tsx | 5 +- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/frontend-modern/src/components/Backups/UnifiedBackups.tsx b/frontend-modern/src/components/Backups/UnifiedBackups.tsx index 0a7d01349..df0baa1bd 100644 --- a/frontend-modern/src/components/Backups/UnifiedBackups.tsx +++ b/frontend-modern/src/components/Backups/UnifiedBackups.tsx @@ -790,6 +790,8 @@ const UnifiedBackups: Component = () => { setIsSearchLocked(false); } }} + filteredBackups={filteredData()} + searchTerm={searchTerm()} /> {/* Removed old PBS table */} diff --git a/frontend-modern/src/components/Storage/Storage.tsx b/frontend-modern/src/components/Storage/Storage.tsx index 5b816345e..745b3bb14 100644 --- a/frontend-modern/src/components/Storage/Storage.tsx +++ b/frontend-modern/src/components/Storage/Storage.tsx @@ -194,6 +194,8 @@ const Storage: Component = () => { {/* Storage Filter */} diff --git a/frontend-modern/src/components/shared/PVENodeTable.tsx b/frontend-modern/src/components/shared/PVENodeTable.tsx index 7a230126b..ab7122999 100644 --- a/frontend-modern/src/components/shared/PVENodeTable.tsx +++ b/frontend-modern/src/components/shared/PVENodeTable.tsx @@ -13,30 +13,54 @@ interface PVENodeTableProps { selectedNode: string | null; onNodeClick: (nodeId: string) => void; searchTerm?: string; + filteredBackups?: any[]; } export const PVENodeTable: Component = (props) => { - // Check if we have active filtering (receiving filtered guests) + // Check if we have active filtering const hasActiveFilter = createMemo(() => { - // If vms or containers props are explicitly passed, we're filtering - return props.vms !== undefined || props.containers !== undefined; + // Check based on current tab + switch (props.currentTab) { + case 'dashboard': + return props.vms !== undefined || props.containers !== undefined; + case 'storage': + return props.storage !== undefined; + case 'backups': + return props.filteredBackups !== undefined; + default: + return false; + } }); - // Filter and sort nodes - only show nodes with matching guests when filtering + // Filter and sort nodes based on current tab const sortedNodes = createMemo(() => { if (!props.nodes) return []; let nodes = [...props.nodes]; - // If we have filtered guests, only show nodes that have at least one matching guest - if (hasActiveFilter() && props.currentTab === 'dashboard') { - const nodesWithGuests = new Set(); - props.vms?.forEach(vm => nodesWithGuests.add(vm.node)); - props.containers?.forEach(ct => nodesWithGuests.add(ct.node)); + // Filter nodes based on the current tab and filtered data + if (hasActiveFilter()) { + const nodesWithItems = new Set(); - // Only show nodes that have filtered guests - if (nodesWithGuests.size > 0) { - nodes = nodes.filter(node => nodesWithGuests.has(node.name)); + switch (props.currentTab) { + case 'dashboard': + // Filter based on VMs and containers + props.vms?.forEach(vm => nodesWithItems.add(vm.node)); + props.containers?.forEach(ct => nodesWithItems.add(ct.node)); + break; + case 'storage': + // Filter based on storage + props.storage?.forEach(s => nodesWithItems.add(s.node)); + break; + case 'backups': + // Filter based on backups + props.filteredBackups?.forEach(b => nodesWithItems.add(b.node)); + break; + } + + // Only show nodes that have filtered items + if (nodesWithItems.size > 0) { + nodes = nodes.filter(node => nodesWithItems.has(node.name)); } } @@ -71,6 +95,11 @@ export const PVENodeTable: Component = (props) => { const storageCount = props.storage?.filter(s => s.node === node.name).length || 0; return [storageCount]; case 'backups': + // If we have filtered backups, count those; otherwise use the provided counts + if (props.filteredBackups !== undefined) { + const backupCount = props.filteredBackups.filter(b => b.node === node.name).length; + return [backupCount]; + } return [props.backupCounts?.[node.name] || 0]; default: return []; diff --git a/frontend-modern/src/components/shared/UnifiedNodeSelector.tsx b/frontend-modern/src/components/shared/UnifiedNodeSelector.tsx index 946a63098..3f2fd76ff 100644 --- a/frontend-modern/src/components/shared/UnifiedNodeSelector.tsx +++ b/frontend-modern/src/components/shared/UnifiedNodeSelector.tsx @@ -8,6 +8,8 @@ interface UnifiedNodeSelectorProps { onNodeSelect?: (nodeId: string | null, nodeType: 'pve' | 'pbs' | null) => void; filteredVms?: any[]; filteredContainers?: any[]; + filteredStorage?: any[]; + filteredBackups?: any[]; searchTerm?: string; } @@ -86,12 +88,13 @@ export const UnifiedNodeSelector: Component = (props) nodes={state.nodes} vms={props.filteredVms !== undefined ? props.filteredVms : state.vms} containers={props.filteredContainers !== undefined ? props.filteredContainers : state.containers} - storage={state.storage} + storage={props.filteredStorage !== undefined ? props.filteredStorage : state.storage} backupCounts={backupCounts()} currentTab={props.currentTab} selectedNode={selectedNode()} onNodeClick={handlePVENodeClick} searchTerm={props.searchTerm} + filteredBackups={props.filteredBackups} /> 0}>