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));
+}