Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding package exporting injection tokens for cluster settings #7395

Merged
merged 13 commits into from
Mar 23, 2023
24 changes: 24 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/cluster-settings/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2022"
}
}
3 changes: 3 additions & 0 deletions packages/cluster-settings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Description

The package exports tokens needed for external configuration of Cluster Settings page.
31 changes: 31 additions & 0 deletions packages/cluster-settings/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@k8slens/cluster-settings",
"version": "6.5.0-alpha.1",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this should probably be 1.0.0-alpha.1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following same versioning as other internal packages. Keeping 6.5.0-alpha.1 for now until clarification. Will change it if needed in follow up PR.

"description": "Injection token exporter for cluster settings configuration",
"license": "MIT",
"private": false,
"mode": "production",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "rimraf dist/",
"generate-types": "tsc --d --declarationDir ./dist --declarationMap --emitDeclarationOnly",
"build": "npm run generate-types && swc ./src/index.ts -d ./dist",
"prepare:test": "npm run build"
},
"devDependencies": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we include typescript as dev dependency as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. It works well without specify typescript here. Probably it uses some globally installed typescript somehow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, try to remove global ‘typescript’ package and check again.

"@ogre-tools/injectable": "^15.1.2",
"@swc/cli": "^0.1.61",
"@swc/core": "^1.3.37",
"@types/node": "^16.18.11",
"@types/semver": "^7.3.13",
"rimraf": "^4.1.2"
}
}
30 changes: 30 additions & 0 deletions packages/cluster-settings/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { getInjectionToken } from "@ogre-tools/injectable";

type ClusterPreferences = {
clusterName?: string;
icon?: string | null;
}

export interface ClusterIconMenuItem {
id: string;
title: string;
disabled?: (preferences: ClusterPreferences) => boolean;
onClick: (preferences: ClusterPreferences) => void;
}

export interface ClusterIconSettingComponentProps {
preferences: ClusterPreferences;
}

export interface ClusterIconSettingsComponent {
id: string;
Component: React.ComponentType<ClusterIconSettingComponentProps>;
}

export const clusterIconSettingsMenuInjectionToken = getInjectionToken<ClusterIconMenuItem>({
id: "cluster-icon-settings-menu-injection-token",
});

export const clusterIconSettingsComponentInjectionToken = getInjectionToken<ClusterIconSettingsComponent>({
id: "cluster-icon-settings-component-injection-token",
});
18 changes: 18 additions & 0 deletions packages/cluster-settings/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist/",
"paths": {
"*": [
"node_modules/*",
"types/*"
]
},
},
"include": [
"src/**/*",
],
"exclude": [
"node_modules",
]
}
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
"@astronautlabs/jsonpath": "^1.1.0",
"@hapi/call": "^9.0.1",
"@hapi/subtext": "^7.1.0",
"@k8slens/cluster-settings": "^6.5.0-alpha.1",
"@k8slens/node-fetch": "^6.5.0-alpha.1",
"@kubernetes/client-node": "^0.18.1",
"@material-ui/styles": "^4.11.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,55 @@ exports[`Icon settings given no external registrations for cluster settings menu
</div>
</body>
`;

exports[`Icon settings given no registrations for cluster settings component injection token renders 1`] = `
<body>
<div>
<div>
<div
class="file-loader flex flex-row items-center"
>
<div
class="mr-5"
>
<div
class="FilePicker"
>
<label
class="flex gaps align-center"
for="file-upload"
>
<div
class="Avatar rounded"
style="width: 53px; height: 53px; background: rgb(9, 124, 92);"
>
skc
</div>

</label>
<input
accept="image/*"
id="file-upload"
name="FilePicker"
type="file"
/>
</div>
</div>
<i
class="Icon material interactive focusable"
data-testid="icon-for-menu-actions-for-cluster-icon-settings-for-some-entity-id"
id="menu-actions-for-cluster-icon-settings-for-some-entity-id"
tabindex="0"
>
<span
class="icon"
data-icon-name="more_horiz"
>
more_horiz
</span>
</i>
</div>
</div>
</div>
</body>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
* 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 { getInjectable } from "@ogre-tools/injectable";

import type { RenderResult } from "@testing-library/react";
import React from "react";
import { KubernetesCluster } from "../../../../common/catalog-entities";
Expand All @@ -13,13 +12,18 @@ import { renderFor } from "../../test-utils/renderFor";
import { ClusterIconSetting } from "../icon-settings";
import { screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { clusterIconSettingsMenuInjectionToken } from "../cluster-settings-menu-injection-token";
import type { ClusterIconSettingComponentProps } from "@k8slens/cluster-settings";
import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";
import { runInAction } from "mobx";
import { getInjectable, type DiContainer } from "@ogre-tools/injectable";

const cluster = new Cluster({
contextName: "some-context",
id: "some-id",
kubeConfigPath: "/some/path/to/kubeconfig",
preferences: {
clusterName: "some-cluster-name",
},
}, {
clusterServerUrl: "https://localhost:9999",
});
Expand Down Expand Up @@ -53,6 +57,29 @@ const newMenuItem = getInjectable({
injectionToken: clusterIconSettingsMenuInjectionToken,
});

function CustomSettingsComponent(props: ClusterIconSettingComponentProps) {
return (
<div data-testid="my-react-component">
<span>Test React Component</span>
<span>
Cluster
{props.preferences.clusterName}
</span>
</div>
);
}

const newSettingsReactComponent = getInjectable({
id: "cluster-icon-settings-react-component",

instantiate: () => ({
id: "test-react-component",
Component: CustomSettingsComponent,
}),

injectionToken: clusterIconSettingsComponentInjectionToken,
});

describe("Icon settings", () => {
let rendered: RenderResult;
let di: DiContainer;
Expand Down Expand Up @@ -98,4 +125,30 @@ describe("Icon settings", () => {
expect(rendered.getByText("Hello World")).toBeInTheDocument();
});
});

describe("given no registrations for cluster settings component injection token", () => {
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});

it("does not have any external components", async () => {
expect(rendered.queryByTestId("test-react-component")).not.toBeInTheDocument();
});
});

describe("given registration for cluster settings component injection token", () => {
beforeEach(() => {
runInAction(() => {
di.register(newSettingsReactComponent);
});
});

it("renders external component", async () => {
expect(rendered.queryByTestId("my-react-component")).toBeInTheDocument();
});

it("external component has cluster preferences in props", async () => {
expect(rendered.getByText(/some-cluster-name/)).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token";
import { clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";

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

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import { FilePicker, OverSizeLimitStyle } from "../file-picker";
import { MenuActions, MenuItem } from "../menu";
import type { ShowNotification } from "../notifications";
import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable";
import type { ClusterIconMenuItem } from "./cluster-settings-menu-injection-token";
import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token";
import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings";
import type { ClusterIconMenuItem, ClusterIconSettingsComponent } from "@k8slens/cluster-settings";

export interface ClusterIconSettingProps {
cluster: Cluster;
Expand All @@ -25,6 +25,7 @@ export interface ClusterIconSettingProps {

interface Dependencies {
menuItems: IComputedValue<ClusterIconMenuItem[]>;
settingComponents: IComputedValue<ClusterIconSettingsComponent[]>;
showErrorNotification: ShowNotification;
}

Expand Down Expand Up @@ -95,6 +96,14 @@ const NonInjectedClusterIconSetting = observer((props: ClusterIconSettingProps &
)}
</MenuActions>
</div>
{props.settingComponents.get().map(item => {
return (
<item.Component
key={item.id}
preferences={cluster.preferences}
/>
);
})}
</div>
);
});
Expand All @@ -106,6 +115,7 @@ export const ClusterIconSetting = withInjectables<Dependencies, ClusterIconSetti
return {
...props,
menuItems: computedInjectMany(clusterIconSettingsMenuInjectionToken),
settingComponents: computedInjectMany(clusterIconSettingsComponentInjectionToken),
showErrorNotification: di.inject(showErrorNotificationInjectable),
};
},
Expand Down