Skip to content

Commit

Permalink
Kludge "isEnabledForCluster" work again for kube object details (#5805)
Browse files Browse the repository at this point in the history
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
  • Loading branch information
jansav authored Jul 12, 2022
1 parent 3011d92 commit f9f3787
Show file tree
Hide file tree
Showing 52 changed files with 2,865 additions and 561 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest";
import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import type { KubernetesCluster } from "../../../../common/catalog-entities";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import { computed } from "mobx";
import React from "react";
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
import { KubeObject } from "../../../../common/k8s-api/kube-object";
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
import { KubeObjectDetails } from "../../../../renderer/components/kube-object-details";
import type { ApiManager } from "../../../../common/k8s-api/api-manager";

describe("disable kube object detail items when cluster is not relevant", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let isEnabledForClusterMock: AsyncFnMock<
(cluster: KubernetesCluster) => Promise<boolean>
>;

beforeEach(async () => {
builder = getApplicationBuilder();

builder.beforeApplicationStart(({ rendererDi }) => {
rendererDi.override(
apiManagerInjectable,
() =>
({
getStore: () => ({
getByPath: () =>
getKubeObjectStub("some-kind", "some-api-version"),
}),
} as unknown as ApiManager),
);
});

const rendererDi = builder.dis.rendererDi;

rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);

rendererDi.register(testRouteInjectable, testRouteComponentInjectable);

builder.setEnvironmentToClusterFrame();

const getExtensionFake = getExtensionFakeFor(builder);

isEnabledForClusterMock = asyncFn();

const testExtension = getExtensionFake({
id: "test-extension-id",
name: "test-extension",

rendererOptions: {
isEnabledForCluster: isEnabledForClusterMock,

kubeObjectDetailItems: [
{
kind: "some-kind",
apiVersions: ["some-api-version"],
components: {
Details: () => (
<div data-testid="some-kube-object-detail-item">
Some detail
</div>
),
},
},
],
},
});

rendered = await builder.render();

const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
const testRoute = rendererDi.inject(testRouteInjectable);

navigateToRoute(testRoute);

builder.extensions.enable(testExtension);
});

describe("given not yet known if extension should be enabled for the cluster", () => {
it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});

it("does not show the kube object detail item", () => {
const actual = rendered.queryByTestId("some-kube-object-detail-item");

expect(actual).not.toBeInTheDocument();
});
});

describe("given extension shouldn't be enabled for the cluster", () => {
beforeEach(async () => {
await isEnabledForClusterMock.resolve(false);
});

it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});

it("does not show the kube object detail item", () => {
const actual = rendered.queryByTestId("some-kube-object-detail-item");

expect(actual).not.toBeInTheDocument();
});
});

describe("given extension should be enabled for the cluster", () => {
beforeEach(async () => {
await isEnabledForClusterMock.resolve(true);
});

it("renders", () => {
expect(rendered.baseElement).toMatchSnapshot();
});

it("shows the kube object detail item", () => {
const actual = rendered.getByTestId("some-kube-object-detail-item");

expect(actual).toBeInTheDocument();
});
});
});

const testRouteInjectable = getInjectable({
id: "test-route",

instantiate: () => ({
path: "/test-route",
clusterFrame: true,
isEnabled: computed(() => true),
}),

injectionToken: frontEndRouteInjectionToken,
});

const testRouteComponentInjectable = getInjectable({
id: "test-route-component",

instantiate: (di) => ({
route: di.inject(testRouteInjectable),

Component: () => <KubeObjectDetails />,
}),

injectionToken: routeSpecificComponentInjectionToken,
});

const getKubeObjectStub = (kind: string, apiVersion: string) =>
KubeObject.create({
apiVersion,
kind,
metadata: {
uid: "some-uid",
name: "some-name",
resourceVersion: "some-resource-version",
namespace: "some-namespace",
selfLink: "",
},
});
2 changes: 1 addition & 1 deletion src/extensions/common-api/registrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
export type { StatusBarRegistration } from "../../renderer/components/status-bar/status-bar-registration";
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../../renderer/components/kube-object-menu/kube-object-menu-registration";
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration";
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry";
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../../renderer/components/kube-object-details/kube-object-detail-registration";
export type { KubeObjectStatusRegistration } from "../../renderer/components/kube-object-status-icon/kube-object-status-registration";
export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry";
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ import { createExtensionInstanceInjectionToken } from "./create-extension-instan
import extensionInstancesInjectable from "./extension-instances.injectable";
import type { LensExtension } from "../lens-extension";
import extensionInjectable from "./extension/extension.injectable";
import type { LensRendererExtension } from "../lens-renderer-extension";
import extensionIsEnabledForClusterInjectable from "./extension-is-enabled-for-cluster.injectable";
import type { KubernetesCluster } from "../../common/catalog-entities";

const extensionLoaderInjectable = getInjectable({
id: "extension-loader",
Expand All @@ -21,11 +18,6 @@ const extensionLoaderInjectable = getInjectable({
createExtensionInstance: di.inject(createExtensionInstanceInjectionToken),
extensionInstances: di.inject(extensionInstancesInjectable),
getExtension: (instance: LensExtension) => di.inject(extensionInjectable, instance),

getExtensionIsEnabledForCluster: (extension: LensRendererExtension, cluster: KubernetesCluster) => di.inject(extensionIsEnabledForClusterInjectable, {
extension,
cluster,
}),
}),
});

Expand Down
30 changes: 2 additions & 28 deletions src/extensions/extension-loader/extension-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../..
import type { Disposer } from "../../common/utils";
import { isDefined, toJS } from "../../common/utils";
import logger from "../../main/logger";
import type { CatalogEntity, KubernetesCluster } from "../common-api/catalog";
import type { InstalledExtension } from "../extension-discovery/extension-discovery";
import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "../lens-extension";
import type { LensRendererExtension } from "../lens-renderer-extension";
Expand All @@ -32,7 +31,6 @@ interface Dependencies {
createExtensionInstance: CreateExtensionInstance;
readonly extensionInstances: ObservableMap<LensExtensionId, LensExtension>;
getExtension: (instance: LensExtension) => Extension;
getExtensionIsEnabledForCluster: (extension: LensRendererExtension, cluster: KubernetesCluster) => Promise<boolean>;
}

export interface ExtensionLoading {
Expand Down Expand Up @@ -275,34 +273,10 @@ export class ExtensionLoader {
});
};

loadOnClusterRenderer = (getCluster: () => CatalogEntity) => {
loadOnClusterRenderer = () => {
logger.debug(`${logModule}: load on cluster renderer (dashboard)`);

this.autoInitExtensions(async (ext) => {
const entity = getCluster() as KubernetesCluster;
const extension = ext as LensRendererExtension;

// getCluster must be a callback, as the entity might be available only after an extension has been loaded
const extensionIsEnabledForCluster = await this.dependencies.getExtensionIsEnabledForCluster(extension, entity);

if (!extensionIsEnabledForCluster) {
return [];
}

const removeItems = [
registries.KubeObjectDetailRegistry.getInstance().add(extension.kubeObjectDetailItems),
];

this.onRemoveExtensionId.addListener((removedExtensionId) => {
if (removedExtensionId === extension.id) {
removeItems.forEach(remove => {
remove();
});
}
});

return removeItems;
});
this.autoInitExtensions(async () => []);
};

protected async loadExtensions(installedExtensions: Map<string, InstalledExtension>, register: (ext: LensExtension) => Promise<Disposer[]>) {
Expand Down
3 changes: 2 additions & 1 deletion src/extensions/lens-renderer-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { getExtensionRoutePath } from "../renderer/routes/for-extension";
import type { LensRendererExtensionDependencies } from "./lens-extension-set-dependencies";
import type { KubeObjectHandlerRegistration } from "../renderer/kube-object/handler";
import type { AppPreferenceTabRegistration } from "../renderer/components/+preferences/app-preference-tab/app-preference-tab-registration";
import type { KubeObjectDetailRegistration } from "../renderer/components/kube-object-details/kube-object-detail-registration";

export class LensRendererExtension extends LensExtension<LensRendererExtensionDependencies> {
globalPages: registries.PageRegistration[] = [];
Expand All @@ -37,7 +38,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
appPreferenceTabs: AppPreferenceTabRegistration[] = [];
entitySettings: registries.EntitySettingRegistration[] = [];
statusBarItems: StatusBarRegistration[] = [];
kubeObjectDetailItems: registries.KubeObjectDetailRegistration[] = [];
kubeObjectDetailItems: KubeObjectDetailRegistration[] = [];
kubeObjectMenuItems: KubeObjectMenuRegistration[] = [];
kubeWorkloadsOverviewItems: WorkloadsOverviewDetailRegistration[] = [];
commands: CommandRegistration[] = [];
Expand Down
1 change: 0 additions & 1 deletion src/extensions/registries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

export * from "./page-registry";
export * from "./page-menu-registry";
export * from "./kube-object-detail-registry";
export * from "./entity-setting-registry";
export * from "./catalog-entity-detail-registry";
export * from "./protocol-handler";
37 changes: 0 additions & 37 deletions src/extensions/registries/kube-object-detail-registry.ts

This file was deleted.

6 changes: 0 additions & 6 deletions src/renderer/api/kube-object-detail-registry.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/renderer/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,6 @@ export async function bootstrap(di: DiContainer) {
logger.info(`${logPrefix} initializing EntitySettingsRegistry`);
initializers.initEntitySettingsRegistry();

logger.info(`${logPrefix} initializing KubeObjectDetailRegistry`);
initializers.initKubeObjectDetailRegistry();

logger.info(`${logPrefix} initializing CatalogEntityDetailRegistry`);
initializers.initCatalogEntityDetailRegistry();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const FlexVolume: VolumeVariantComponent<"flexVolume"> = (
{readOnly.toString()}
</DrawerItem>
{
...Object.entries(options)
Object.entries(options)
.map(([key, value]) => (
<DrawerItem key={key} name={`Option: ${key}`}>
{value}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { computed } from "mobx";
import kubeDetailsUrlParamInjectable from "../kube-detail-params/kube-details-url.injectable";
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
import loggerInjectable from "../../../common/logger.injectable";

const currentKubeObjectInDetailsInjectable = getInjectable({
id: "current-kube-object-in-details",

instantiate: (di) => {
const urlParam = di.inject(kubeDetailsUrlParamInjectable);
const apiManager = di.inject(apiManagerInjectable);
const logger = di.inject(loggerInjectable);

return computed(() => {
const path = urlParam.get();

try {
return apiManager.getStore(path)?.getByPath(path);
} catch (error) {
logger.error(
`[KUBE-OBJECT-DETAILS]: failed to get store or object ${path}: ${error}`,
);

return undefined;
}
});
},
});

export default currentKubeObjectInDetailsInjectable;
Loading

0 comments on commit f9f3787

Please sign in to comment.