diff --git a/frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx b/frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx index 3a0c64d851..273d9edd2f 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx @@ -5,6 +5,7 @@ import { WorkloadsSurface } from '@/components/Workloads/WorkloadsSurface'; import { useWorkloadsState } from '@/components/Workloads/useWorkloadsState'; import type { WorkloadsStatusOption } from '@/components/Workloads/workloadsFilterModel'; import { useUnifiedResources } from '@/hooks/useUnifiedResources'; +import { resourceMatchesSearch } from '@/utils/resourceSearchMatch'; import { PlatformErrorState, PlatformSectionTabs, @@ -116,6 +117,21 @@ function KubernetesOverview(props: KubernetesOverviewProps) { workloadsState.surfaceInitialDataReceived() && workloadsState.allGuests().length > 0, ); + const searchTerm = createMemo(() => workloadsState.search().trim()); + const filteredClusters = createMemo(() => { + if (!searchTerm()) return props.model().clusters; + return props.model().clusters.filter((cluster) => resourceMatchesSearch(cluster, searchTerm())); + }); + const filteredNodes = createMemo(() => { + if (!searchTerm()) return props.model().nodes; + return props.model().nodes.filter((node) => resourceMatchesSearch(node, searchTerm())); + }); + const filteredDeployments = createMemo(() => { + if (!searchTerm()) return props.model().deployments; + return props.model().deployments.filter((deployment) => + resourceMatchesSearch(deployment, searchTerm()), + ); + }); return (
@@ -159,7 +175,7 @@ function KubernetesOverview(props: KubernetesOverviewProps) {
0}> 0, ); + const filteredNodes = createMemo(() => { + const term = workloadsState.search(); + if (!term.trim()) return props.model().pveNodes; + return props.model().pveNodes.filter((node) => resourceMatchesSearch(node, term)); + }); return (
@@ -262,7 +268,7 @@ function ProxmoxOverview(props: ProxmoxOverviewProps) {
0, ); + const filteredSystems = createMemo(() => { + const term = workloadsState.search().trim(); + if (!term) return props.model().systems; + return props.model().systems.filter((system) => resourceMatchesSearch(system, term)); + }); return (
@@ -178,7 +184,7 @@ function TrueNASOverview(props: TrueNASOverviewProps) {
0, ); + const filteredHosts = createMemo(() => { + const term = workloadsState.search().trim(); + if (!term) return props.model().hosts; + return props.model().hosts.filter((host) => resourceMatchesSearch(host, term)); + }); return (
@@ -176,7 +182,7 @@ function VmwareOverview(props: VmwareOverviewProps) {
{ + const raw: Array = [ + resource.id, + resource.name, + resource.displayName, + resource.parentName, + resource.agent?.hostname, + resource.identity?.hostname, + resource.canonicalIdentity?.displayName, + resource.canonicalIdentity?.hostname, + resource.canonicalIdentity?.primaryId, + resource.docker?.hostname, + resource.kubernetes?.clusterName, + resource.kubernetes?.nodeName, + resource.kubernetes?.namespace, + resource.vmware?.runtimeHostName, + resource.vmware?.clusterName, + resource.vmware?.datacenterName, + resource.proxmox?.node, + resource.proxmox?.nodeName, + resource.proxmox?.clusterName, + ...(resource.canonicalIdentity?.aliases ?? []), + ...(resource.tags ?? []), + ]; + return raw + .filter((value): value is string => typeof value === 'string') + .map((value) => value.trim().toLowerCase()) + .filter((value) => value.length > 0); +}; + +export function resourceMatchesSearch(resource: Resource, term: string | null | undefined): boolean { + const needle = (term ?? '').trim().toLowerCase(); + if (!needle) return true; + return collectSearchCandidates(resource).some((value) => value.includes(needle)); +}