diff --git a/src/behaviours/cluster/kube-object-details/extension-api/reactively-hide-kube-object-detail-item.test.tsx b/src/behaviours/cluster/kube-object-details/extension-api/reactively-hide-kube-object-detail-item.test.tsx new file mode 100644 index 0000000000..77c9c24552 --- /dev/null +++ b/src/behaviours/cluster/kube-object-details/extension-api/reactively-hide-kube-object-detail-item.test.tsx @@ -0,0 +1,138 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { RenderResult } from "@testing-library/react"; +import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; +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 type { IObservableValue } from "mobx"; +import { runInAction, computed, observable } 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 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("reactively hide kube object detail item", () => { + let builder: ApplicationBuilder; + let rendered: RenderResult; + let someObservable: IObservableValue; + + 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.register(testRouteInjectable, testRouteComponentInjectable); + + builder.setEnvironmentToClusterFrame(); + + const getExtensionFake = getExtensionFakeFor(builder); + + someObservable = observable.box(false); + + const testExtension = getExtensionFake({ + id: "test-extension-id", + name: "test-extension", + + rendererOptions: { + kubeObjectDetailItems: [ + { + kind: "some-kind", + apiVersions: ["some-api-version"], + + components: { + Details: () => ( +
+ Some detail +
+ ), + }, + + visible: computed(() => someObservable.get()), + }, + ], + }, + }); + + rendered = await builder.render(); + + const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); + const testRoute = rendererDi.inject(testRouteInjectable); + + navigateToRoute(testRoute); + + builder.extensions.enable(testExtension); + }); + + it("does not show the kube object detail item", () => { + const actual = rendered.queryByTestId("some-kube-object-detail-item"); + + expect(actual).not.toBeInTheDocument(); + }); + + it("given item should be shown, shows the kube object detail item", () => { + runInAction(() => { + someObservable.set(true); + }); + + const actual = rendered.queryByTestId("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: () => , + }), + + 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: "", + }, + }); diff --git a/src/renderer/components/kube-object-details/kube-object-detail-items/kube-object-detail-item-registrator.injectable.ts b/src/renderer/components/kube-object-details/kube-object-detail-items/kube-object-detail-item-registrator.injectable.ts index 74d7adf894..bf7e296921 100644 --- a/src/renderer/components/kube-object-details/kube-object-detail-items/kube-object-detail-item-registrator.injectable.ts +++ b/src/renderer/components/kube-object-details/kube-object-detail-items/kube-object-detail-item-registrator.injectable.ts @@ -10,9 +10,7 @@ import extensionShouldBeEnabledForClusterFrameInjectable from "../../../extensio import { kubeObjectDetailItemInjectionToken } from "./kube-object-detail-item-injection-token"; import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token"; import currentKubeObjectInDetailsInjectable from "../current-kube-object-in-details.injectable"; -import { - kubeObjectMatchesToKindAndApiVersion, -} from "./kube-object-matches-to-kind-and-api-version"; +import { kubeObjectMatchesToKindAndApiVersion } from "./kube-object-matches-to-kind-and-api-version"; const kubeObjectDetailItemRegistratorInjectable = getInjectable({ id: "kube-object-detail-item-registrator", @@ -45,20 +43,24 @@ const kubeObjectDetailItemRegistratorInjectable = getInjectable({ id, instantiate: (di) => { - const kubeObject = di.inject( - currentKubeObjectInDetailsInjectable, - ); + const kubeObject = di.inject(currentKubeObjectInDetailsInjectable); return { kind: registration.kind, apiVersions: registration.apiVersions, Component: registration.components.Details, - enabled: computed( - () => - extensionShouldBeEnabledForClusterFrame.value.get() && - isRelevantKubeObject(kubeObject.get()), - ), + enabled: computed(() => { + if (!extensionShouldBeEnabledForClusterFrame.value.get()) { + return false; + } + + if (!isRelevantKubeObject(kubeObject.get())) { + return false; + } + + return registration.visible ? registration.visible.get() : true; + }), orderNumber: 300 - (registration.priority || 50), }; diff --git a/src/renderer/components/kube-object-details/kube-object-detail-registration.ts b/src/renderer/components/kube-object-details/kube-object-detail-registration.ts index ba5ec84f2e..c755630a80 100644 --- a/src/renderer/components/kube-object-details/kube-object-detail-registration.ts +++ b/src/renderer/components/kube-object-details/kube-object-detail-registration.ts @@ -5,6 +5,7 @@ import type { KubeObject } from "../../../common/k8s-api/kube-object"; import type { KubeObjectDetailsProps } from "./kube-object-details"; import type React from "react"; +import type { IComputedValue } from "mobx"; export interface KubeObjectDetailComponents { Details: React.ComponentType>; @@ -15,4 +16,5 @@ export interface KubeObjectDetailRegistration apiVersions: string[]; components: KubeObjectDetailComponents; priority?: number; + visible?: IComputedValue; }