diff --git a/locales/en/plugin__kuadrant-console-plugin.json b/locales/en/plugin__kuadrant-console-plugin.json index 316983e..6638bab 100644 --- a/locales/en/plugin__kuadrant-console-plugin.json +++ b/locales/en/plugin__kuadrant-console-plugin.json @@ -85,6 +85,7 @@ "Reference to an existing secret resource containing DNS provider credentials and configuration": "Reference to an existing secret resource containing DNS provider credentials and configuration", "Release Notes": "Release Notes", "Save": "Save", + "Search across name, namespace and/or resource type": "Search across name, namespace and/or resource type", "Select a gateway": "Select a gateway", "Select a Protocol": "Select a Protocol", "Select an ClusterIssuer": "Select an ClusterIssuer", diff --git a/src/components/ResourceList.tsx b/src/components/ResourceList.tsx index 8779284..d622d8e 100644 --- a/src/components/ResourceList.tsx +++ b/src/components/ResourceList.tsx @@ -11,6 +11,7 @@ import { EmptyStateBody, Title, Tooltip, + SearchInput, } from '@patternfly/react-core'; import { K8sResourceCommon, @@ -356,29 +357,27 @@ const ResourceList: React.FC = ({ loadErrors.length > 0 ? new Error(loadErrors.map((err) => err.message).join('; ')) : null; // Implement local filter state - const [filters, setFilters] = React.useState<{ [key: string]: string }>({}); + const [filters, setFilters] = React.useState(''); const [filteredData, setFilteredData] = React.useState([]); React.useEffect(() => { let data = allData; - // Apply filters - Object.keys(filters).forEach((key) => { - const value = filters[key]; - if (value) { - data = data.filter((item) => { - if (key === 'name') { - return item.metadata.name.toLowerCase().includes(value.toLowerCase()); - } else if (key === 'namespace') { - return item.metadata.namespace?.toLowerCase().includes(value.toLowerCase()); - } else if (key === 'type') { - return item.kind.toLowerCase().includes(value.toLowerCase()); - } - return true; - }); - } - }); - + if (filters) { + const search = filters.toLowerCase().trim().split(/\s+/).filter(Boolean); + data = data.filter((item) => { + const name = item.metadata?.name?.toLowerCase() || ''; + const namespace = item.metadata?.namespace?.toLowerCase() || ''; + const kind = item.kind?.toLowerCase() || ''; + const matches = search.some( + (searchValue) => + name.includes(searchValue) || + namespace.includes(searchValue) || + kind.includes(searchValue), + ); + return matches; + }); + } setFilteredData(data); }, [allData, filters]); @@ -442,6 +441,16 @@ const ResourceList: React.FC = ({ setCurrentPage(1); }; + const handleFilterChange = (value: string) => { + setCurrentPage(1); + setFilters(value); + }; + + const handleClear = () => { + setFilters(''); + setCurrentPage(1); + }; + const ResourceRow: React.FC> = ({ obj, activeColumnIDs }) => { const { apiVersion, kind } = obj; const [group, version] = apiVersion.includes('/') ? apiVersion.split('/') : ['', apiVersion]; @@ -521,36 +530,14 @@ const ResourceList: React.FC = ({ )}
- {/* Filter UI */} -
- { - setCurrentPage(1); - setFilters({ ...filters, name: e.target.value }); - }} - style={{ marginRight: '8px' }} - /> - { - setCurrentPage(1); - setFilters({ ...filters, namespace: e.target.value }); - }} - style={{ marginRight: '8px' }} - /> - { - setCurrentPage(1); - setFilters({ ...filters, type: e.target.value }); - }} +
+ handleFilterChange(value)} + onClear={handleClear} + aria-label="Global search input" + style={{ marginRight: '8px', width: '350px' }} />