diff --git a/src/renderer/components/kube-object-list-layout/__snapshots__/kube-object-list-layout.test.tsx.snap b/src/renderer/components/kube-object-list-layout/__snapshots__/kube-object-list-layout.test.tsx.snap
new file mode 100644
index 0000000000..b450030c9c
--- /dev/null
+++ b/src/renderer/components/kube-object-list-layout/__snapshots__/kube-object-list-layout.test.tsx.snap
@@ -0,0 +1,121 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`kube-object-list-layout given pod store renders 1`] = `
+
+
+
+`;
diff --git a/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx b/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx
new file mode 100644
index 0000000000..d50d70c723
--- /dev/null
+++ b/src/renderer/components/kube-object-list-layout/kube-object-list-layout.test.tsx
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) OpenLens Authors. All rights reserved.
+ * Licensed under MIT License. See LICENSE in root directory for more information.
+ */
+import type { DiContainer } from "@ogre-tools/injectable";
+import "@testing-library/jest-dom/extend-expect";
+import type { RenderResult } from "@testing-library/react";
+import React from "react";
+import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
+import { getDiForUnitTesting } from "../../getDiForUnitTesting";
+import kubeSelectedUrlParamInjectable from "../kube-detail-params/kube-selected-url.injectable";
+import toggleKubeDetailsPaneInjectable from "../kube-detail-params/toggle-details.injectable";
+import type { DiRender } from "../test-utils/renderFor";
+import { renderFor } from "../test-utils/renderFor";
+import { KubeObjectListLayout } from "./index";
+import appPathsStateInjectable from "../../../common/app-paths/app-paths-state.injectable";
+import podStoreInjectable from "../+workloads-pods/store.injectable";
+import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
+import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
+import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
+import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
+import createClusterInjectable from "../../../main/create-cluster/create-cluster.injectable";
+import type { PodStore } from "../+workloads-pods/store";
+
+describe("kube-object-list-layout", () => {
+ let di: DiContainer;
+ let render: DiRender;
+ let podStore: PodStore;
+
+ beforeEach(() => {
+ di = getDiForUnitTesting({ doGeneralOverrides: true });
+
+ di.override(directoryForUserDataInjectable, () => "/some-user-store-path");
+ di.override(directoryForKubeConfigsInjectable, () => "/some-kube-configs");
+ di.override(storesAndApisCanBeCreatedInjectable, () => true);
+
+ const createCluster = di.inject(createClusterInjectable);
+
+ di.override(hostedClusterInjectable, () => createCluster({
+ contextName: "some-context-name",
+ id: "some-cluster-id",
+ kubeConfigPath: "/some-path-to-a-kubeconfig",
+ }, {
+ clusterServerUrl: "https://localhost:8080",
+ }));
+
+ render = renderFor(di);
+
+ di.override(subscribeStoresInjectable, () => jest.fn().mockImplementation(() => jest.fn()));
+ di.override(kubeSelectedUrlParamInjectable, () => ({
+ get: () => "path",
+ }));
+ di.override(toggleKubeDetailsPaneInjectable, () => null);
+ di.override(appPathsStateInjectable, () => ({
+ get: () => ({}),
+ }));
+
+ podStore = di.inject(podStoreInjectable);
+ });
+
+ describe("given pod store", () => {
+ let result: RenderResult;
+
+ it("renders", () => {
+ result = render((
+
+
[
+ {pod.getName()}
,
+ ]}
+ />
+
+ ));
+
+ expect(result.baseElement).toMatchSnapshot();
+ });
+
+ describe("given resourcename", () => {
+ it("uses resourcename in search placeholder", () => {
+ result = render((
+
+
[
+ {pod.getName()}
,
+ ]}
+ resourceName="My Custom Items"
+ searchFilters={[() => null]}
+ />
+
+ ));
+
+ expect(result.getByPlaceholderText("Search My Custom Items...")).toBeInTheDocument();
+ });
+ });
+ });
+});
+
+
diff --git a/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx b/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx
index 463bb8dd35..82929e788c 100644
--- a/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx
+++ b/src/renderer/components/kube-object-list-layout/kube-object-list-layout.tsx
@@ -40,6 +40,12 @@ export interface KubeObjectListLayoutProps<
store: KubeObjectStore;
dependentStores?: SubscribableStore[];
subscribeStores?: boolean;
+
+ /**
+ * Customize resource name for e.g. search input ("Search ..."")
+ * If not provided, ResourceNames is used instead with a fallback to resource kind.
+ */
+ resourceName?: string;
}
interface Dependencies {
@@ -132,7 +138,7 @@ class NonInjectedKubeObjectListLayout<
onDetails,
...layoutProps
} = this.props;
- const placeholderString = ResourceNames[ResourceKindMap[store.api.kind]] || store.api.kind;
+ const resourceName = this.props.resourceName || ResourceNames[ResourceKindMap[store.api.kind]] || store.api.kind;
return (
@@ -151,7 +157,7 @@ class NonInjectedKubeObjectListLayout<
),
searchProps: {
...searchProps,
- placeholder: `Search ${placeholderString}...`,
+ placeholder: `Search ${resourceName}...`,
},
info: (
<>