Skip to content

Commit a0d13e8

Browse files
authored
Adding package exporting injection tokens for cluster settings (lensapp#7395)
* Add clusterIconSettingsComponentInjectionToken Signed-off-by: Alex Andreev <[email protected]> * Adding tests for new token Signed-off-by: Alex Andreev <[email protected]> * Create cluster-settings package Signed-off-by: Alex Andreev <[email protected]> * Fix cluster-settings package build process Signed-off-by: Alex Andreev <[email protected]> * Use tolens from @k8slens/cluster-settings Signed-off-by: Alex Andreev <[email protected]> * Linter fixes Signed-off-by: Alex Andreev <[email protected]> * Remove typescript 5.x.x from cluster-settings package Signed-off-by: Alex Andreev <[email protected]> * Adding prepare:test command to package.json Signed-off-by: Alex Andreev <[email protected]> * Test small cleanup Signed-off-by: Alex Andreev <[email protected]> * Fix getByText check Signed-off-by: Alex Andreev <[email protected]> * Clean up Signed-off-by: Alex Andreev <[email protected]> * Linter fix Signed-off-by: Alex Andreev <[email protected]> --------- Signed-off-by: Alex Andreev <[email protected]>
1 parent 4a3f08d commit a0d13e8

12 files changed

+237
-23
lines changed

package-lock.json

+24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/cluster-settings/.swcrc

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "https://json.schemastore.org/swcrc",
3+
"jsc": {
4+
"parser": {
5+
"syntax": "typescript"
6+
},
7+
"target": "es2022"
8+
}
9+
}

packages/cluster-settings/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Description
2+
3+
The package exports tokens needed for external configuration of Cluster Settings page.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "@k8slens/cluster-settings",
3+
"version": "6.5.0-alpha.1",
4+
"description": "Injection token exporter for cluster settings configuration",
5+
"license": "MIT",
6+
"private": false,
7+
"mode": "production",
8+
"publishConfig": {
9+
"access": "public",
10+
"registry": "https://registry.npmjs.org/"
11+
},
12+
"main": "./dist/index.js",
13+
"types": "./dist/index.d.ts",
14+
"files": [
15+
"dist"
16+
],
17+
"scripts": {
18+
"clean": "rimraf dist/",
19+
"generate-types": "tsc --d --declarationDir ./dist --declarationMap --emitDeclarationOnly",
20+
"build": "npm run generate-types && swc ./src/index.ts -d ./dist",
21+
"prepare:test": "npm run build"
22+
},
23+
"devDependencies": {
24+
"@ogre-tools/injectable": "^15.1.2",
25+
"@swc/cli": "^0.1.61",
26+
"@swc/core": "^1.3.37",
27+
"@types/node": "^16.18.11",
28+
"@types/semver": "^7.3.13",
29+
"rimraf": "^4.1.2"
30+
}
31+
}
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { getInjectionToken } from "@ogre-tools/injectable";
2+
3+
type ClusterPreferences = {
4+
clusterName?: string;
5+
icon?: string | null;
6+
}
7+
8+
export interface ClusterIconMenuItem {
9+
id: string;
10+
title: string;
11+
disabled?: (preferences: ClusterPreferences) => boolean;
12+
onClick: (preferences: ClusterPreferences) => void;
13+
}
14+
15+
export interface ClusterIconSettingComponentProps {
16+
preferences: ClusterPreferences;
17+
}
18+
19+
export interface ClusterIconSettingsComponent {
20+
id: string;
21+
Component: React.ComponentType<ClusterIconSettingComponentProps>;
22+
}
23+
24+
export const clusterIconSettingsMenuInjectionToken = getInjectionToken<ClusterIconMenuItem>({
25+
id: "cluster-icon-settings-menu-injection-token",
26+
});
27+
28+
export const clusterIconSettingsComponentInjectionToken = getInjectionToken<ClusterIconSettingsComponent>({
29+
id: "cluster-icon-settings-component-injection-token",
30+
});
+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"outDir": "dist/",
5+
"paths": {
6+
"*": [
7+
"node_modules/*",
8+
"types/*"
9+
]
10+
},
11+
},
12+
"include": [
13+
"src/**/*",
14+
],
15+
"exclude": [
16+
"node_modules",
17+
]
18+
}

packages/core/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
"@astronautlabs/jsonpath": "^1.1.0",
121121
"@hapi/call": "^9.0.1",
122122
"@hapi/subtext": "^7.1.0",
123+
"@k8slens/cluster-settings": "^6.5.0-alpha.1",
123124
"@k8slens/node-fetch": "^6.5.0-alpha.1",
124125
"@kubernetes/client-node": "^0.18.1",
125126
"@material-ui/styles": "^4.11.5",

packages/core/src/renderer/components/cluster-settings/__tests__/__snapshots__/icon-settings.test.tsx.snap

+52
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,55 @@ exports[`Icon settings given no external registrations for cluster settings menu
5151
</div>
5252
</body>
5353
`;
54+
55+
exports[`Icon settings given no registrations for cluster settings component injection token renders 1`] = `
56+
<body>
57+
<div>
58+
<div>
59+
<div
60+
class="file-loader flex flex-row items-center"
61+
>
62+
<div
63+
class="mr-5"
64+
>
65+
<div
66+
class="FilePicker"
67+
>
68+
<label
69+
class="flex gaps align-center"
70+
for="file-upload"
71+
>
72+
<div
73+
class="Avatar rounded"
74+
style="width: 53px; height: 53px; background: rgb(9, 124, 92);"
75+
>
76+
skc
77+
</div>
78+
79+
</label>
80+
<input
81+
accept="image/*"
82+
id="file-upload"
83+
name="FilePicker"
84+
type="file"
85+
/>
86+
</div>
87+
</div>
88+
<i
89+
class="Icon material interactive focusable"
90+
data-testid="icon-for-menu-actions-for-cluster-icon-settings-for-some-entity-id"
91+
id="menu-actions-for-cluster-icon-settings-for-some-entity-id"
92+
tabindex="0"
93+
>
94+
<span
95+
class="icon"
96+
data-icon-name="more_horiz"
97+
>
98+
more_horiz
99+
</span>
100+
</i>
101+
</div>
102+
</div>
103+
</div>
104+
</body>
105+
`;

packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx

+56-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
* Copyright (c) OpenLens Authors. All rights reserved.
33
* Licensed under MIT License. See LICENSE in root directory for more information.
44
*/
5-
import type { DiContainer } from "@ogre-tools/injectable";
6-
import { getInjectable } from "@ogre-tools/injectable";
5+
76
import type { RenderResult } from "@testing-library/react";
87
import React from "react";
98
import { KubernetesCluster } from "../../../../common/catalog-entities";
@@ -13,13 +12,18 @@ import { renderFor } from "../../test-utils/renderFor";
1312
import { ClusterIconSetting } from "../icon-settings";
1413
import { screen } from "@testing-library/react";
1514
import userEvent from "@testing-library/user-event";
16-
import { clusterIconSettingsMenuInjectionToken } from "../cluster-settings-menu-injection-token";
15+
import type { ClusterIconSettingComponentProps } from "@k8slens/cluster-settings";
16+
import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";
1717
import { runInAction } from "mobx";
18+
import { getInjectable, type DiContainer } from "@ogre-tools/injectable";
1819

1920
const cluster = new Cluster({
2021
contextName: "some-context",
2122
id: "some-id",
2223
kubeConfigPath: "/some/path/to/kubeconfig",
24+
preferences: {
25+
clusterName: "some-cluster-name",
26+
},
2327
}, {
2428
clusterServerUrl: "https://localhost:9999",
2529
});
@@ -53,6 +57,29 @@ const newMenuItem = getInjectable({
5357
injectionToken: clusterIconSettingsMenuInjectionToken,
5458
});
5559

60+
function CustomSettingsComponent(props: ClusterIconSettingComponentProps) {
61+
return (
62+
<div data-testid="my-react-component">
63+
<span>Test React Component</span>
64+
<span>
65+
Cluster
66+
{props.preferences.clusterName}
67+
</span>
68+
</div>
69+
);
70+
}
71+
72+
const newSettingsReactComponent = getInjectable({
73+
id: "cluster-icon-settings-react-component",
74+
75+
instantiate: () => ({
76+
id: "test-react-component",
77+
Component: CustomSettingsComponent,
78+
}),
79+
80+
injectionToken: clusterIconSettingsComponentInjectionToken,
81+
});
82+
5683
describe("Icon settings", () => {
5784
let rendered: RenderResult;
5885
let di: DiContainer;
@@ -98,4 +125,30 @@ describe("Icon settings", () => {
98125
expect(rendered.getByText("Hello World")).toBeInTheDocument();
99126
});
100127
});
128+
129+
describe("given no registrations for cluster settings component injection token", () => {
130+
it("renders", () => {
131+
expect(rendered.baseElement).toMatchSnapshot();
132+
});
133+
134+
it("does not have any external components", async () => {
135+
expect(rendered.queryByTestId("test-react-component")).not.toBeInTheDocument();
136+
});
137+
});
138+
139+
describe("given registration for cluster settings component injection token", () => {
140+
beforeEach(() => {
141+
runInAction(() => {
142+
di.register(newSettingsReactComponent);
143+
});
144+
});
145+
146+
it("renders external component", async () => {
147+
expect(rendered.queryByTestId("my-react-component")).toBeInTheDocument();
148+
});
149+
150+
it("external component has cluster preferences in props", async () => {
151+
expect(rendered.getByText(/some-cluster-name/)).toBeInTheDocument();
152+
});
153+
});
101154
});

packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under MIT License. See LICENSE in root directory for more information.
44
*/
55
import { getInjectable } from "@ogre-tools/injectable";
6-
import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token";
6+
import { clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";
77

88
const clusterIconSettingsMenuClearItem = getInjectable({
99
id: "cluster-icon-settings-menu-clear-item",

packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts

-17
This file was deleted.

packages/core/src/renderer/components/cluster-settings/icon-settings.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import { FilePicker, OverSizeLimitStyle } from "../file-picker";
1515
import { MenuActions, MenuItem } from "../menu";
1616
import type { ShowNotification } from "../notifications";
1717
import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
18-
import type { ClusterIconMenuItem } from "./cluster-settings-menu-injection-token";
19-
import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token";
18+
import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";
19+
import type { ClusterIconMenuItem, ClusterIconSettingsComponent } from "@k8slens/cluster-settings";
2020

2121
export interface ClusterIconSettingProps {
2222
cluster: Cluster;
@@ -25,6 +25,7 @@ export interface ClusterIconSettingProps {
2525

2626
interface Dependencies {
2727
menuItems: IComputedValue<ClusterIconMenuItem[]>;
28+
settingComponents: IComputedValue<ClusterIconSettingsComponent[]>;
2829
showErrorNotification: ShowNotification;
2930
}
3031

@@ -95,6 +96,14 @@ const NonInjectedClusterIconSetting = observer((props: ClusterIconSettingProps &
9596
)}
9697
</MenuActions>
9798
</div>
99+
{props.settingComponents.get().map(item => {
100+
return (
101+
<item.Component
102+
key={item.id}
103+
preferences={cluster.preferences}
104+
/>
105+
);
106+
})}
98107
</div>
99108
);
100109
});
@@ -106,6 +115,7 @@ export const ClusterIconSetting = withInjectables<Dependencies, ClusterIconSetti
106115
return {
107116
...props,
108117
menuItems: computedInjectMany(clusterIconSettingsMenuInjectionToken),
118+
settingComponents: computedInjectMany(clusterIconSettingsComponentInjectionToken),
109119
showErrorNotification: di.inject(showErrorNotificationInjectable),
110120
};
111121
},

0 commit comments

Comments
 (0)