mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Allow specifying ResourceName in KubeObjectListLayout (#6926)
* Allow specifying ResourceName in KubeObjectListLayout Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com> * Fix comment syntax. Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com> Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
This commit is contained in:
parent
904200f72f
commit
c9418f6362
@ -0,0 +1,121 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`kube-object-list-layout given pod store renders 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div>
|
||||
<div
|
||||
class="ItemListLayout flex column KubeObjectListLayout Pods"
|
||||
>
|
||||
<div
|
||||
class="header flex gaps align-center"
|
||||
>
|
||||
<h5
|
||||
class="title"
|
||||
>
|
||||
Pods
|
||||
</h5>
|
||||
<div
|
||||
class="info-panel box grow"
|
||||
>
|
||||
0 items
|
||||
</div>
|
||||
<div
|
||||
class="NamespaceSelectFilterParent"
|
||||
data-testid="namespace-select-filter"
|
||||
>
|
||||
<div
|
||||
class="Select theme-dark NamespaceSelect NamespaceSelectFilter css-b62m3t-container"
|
||||
>
|
||||
<span
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
id="react-select-kube-object-list-layout-namespace-select-input-live-region"
|
||||
/>
|
||||
<span
|
||||
aria-atomic="false"
|
||||
aria-live="polite"
|
||||
aria-relevant="additions text"
|
||||
class="css-1f43avz-a11yText-A11yText"
|
||||
/>
|
||||
<div
|
||||
class="Select__control css-13cymwt-control"
|
||||
>
|
||||
<div
|
||||
class="Select__value-container Select__value-container--is-multi css-1fdsijx-ValueContainer"
|
||||
>
|
||||
<div
|
||||
class="Select__placeholder css-1jqq78o-placeholder"
|
||||
id="react-select-kube-object-list-layout-namespace-select-input-placeholder"
|
||||
>
|
||||
All namespaces
|
||||
</div>
|
||||
<div
|
||||
class="Select__input-container css-qbdosj-Input"
|
||||
data-value=""
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-describedby="react-select-kube-object-list-layout-namespace-select-input-placeholder"
|
||||
aria-expanded="false"
|
||||
aria-haspopup="true"
|
||||
autocapitalize="none"
|
||||
autocomplete="off"
|
||||
autocorrect="off"
|
||||
class="Select__input"
|
||||
id="kube-object-list-layout-namespace-select-input"
|
||||
role="combobox"
|
||||
spellcheck="false"
|
||||
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
|
||||
tabindex="0"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
|
||||
>
|
||||
<span
|
||||
class="Select__indicator-separator css-1u9des2-indicatorSeparator"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="Select__indicator Select__dropdown-indicator css-1xc3v61-indicatorContainer"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="css-tj5bde-Svg"
|
||||
focusable="false"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
width="20"
|
||||
>
|
||||
<path
|
||||
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="items box grow flex column"
|
||||
>
|
||||
<div
|
||||
class="Table flex column KubeObjectListLayout Pods box grow dark selectable scrollable autoSize virtual"
|
||||
>
|
||||
<div
|
||||
class="Spinner singleColor center"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="AddRemoveButtons flex gaps"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -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((
|
||||
<div>
|
||||
<KubeObjectListLayout
|
||||
className="Pods"
|
||||
store={podStore}
|
||||
tableId = "workloads_pods"
|
||||
isConfigurable
|
||||
renderHeaderTitle="Pods"
|
||||
renderTableContents={pod => [
|
||||
<div key={pod.getName()}>{pod.getName()}</div>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
|
||||
expect(result.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("given resourcename", () => {
|
||||
it("uses resourcename in search placeholder", () => {
|
||||
result = render((
|
||||
<div>
|
||||
<KubeObjectListLayout
|
||||
className="Pods"
|
||||
store={podStore}
|
||||
tableId = "workloads_pods"
|
||||
isConfigurable
|
||||
renderHeaderTitle="Pods"
|
||||
renderTableContents={pod => [
|
||||
<div key={pod.getName()}>{pod.getName()}</div>,
|
||||
]}
|
||||
resourceName="My Custom Items"
|
||||
searchFilters={[() => null]}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
|
||||
expect(result.getByPlaceholderText("Search My Custom Items...")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -40,6 +40,12 @@ export interface KubeObjectListLayoutProps<
|
||||
store: KubeObjectStore<K, A, D>;
|
||||
dependentStores?: SubscribableStore[];
|
||||
subscribeStores?: boolean;
|
||||
|
||||
/**
|
||||
* Customize resource name for e.g. search input ("Search <ResourceName>..."")
|
||||
* 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 (
|
||||
<ItemListLayout<K, false>
|
||||
@ -151,7 +157,7 @@ class NonInjectedKubeObjectListLayout<
|
||||
),
|
||||
searchProps: {
|
||||
...searchProps,
|
||||
placeholder: `Search ${placeholderString}...`,
|
||||
placeholder: `Search ${resourceName}...`,
|
||||
},
|
||||
info: (
|
||||
<>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user