1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Expose reactive ways to hide items in cluster frame using Extension API - PART 7 (#5824)

* Kludge "isEnabledForCluster" work again for cluster pages

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Kludge "isEnabledForCluster" work again for kube object details

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose reactive way to hide kube object detail items in Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose reactive way to hide kube object menu items in Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose reactive way to hide kube object status items in Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose reactive way to hide workload overview detail items in Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose reactive way to disable pages in Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Expose a way to access active cluster from Extension API

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Deprecate "isEnabledForCluster" in favor of individual enabled or visible properties for each registration

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-07-13 20:47:03 +03:00 committed by GitHub
parent ca40c51117
commit d66e6c23c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 679 additions and 33 deletions

View File

@ -0,0 +1,70 @@
/**
* 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 { IObservableValue } from "mobx";
import { observable, runInAction, computed } from "mobx";
import React from "react";
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
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";
describe("reactively disable cluster pages", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
let rendererTestExtension: TestExtensionRenderer;
beforeEach(async () => {
builder = getApplicationBuilder();
builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false);
const testExtension = getExtensionFake({
id: "test-extension-id",
name: "test-extension",
rendererOptions: {
clusterPages: [{
components: {
Page: () => <div data-testid="some-test-page">Some page</div>,
},
enabled: computed(() => someObservable.get()),
}],
},
});
rendered = await builder.render();
builder.extensions.enable(testExtension);
rendererTestExtension = testExtension.renderer;
});
it("when navigating to the page, does not show the page", () => {
rendererTestExtension.navigate();
const actual = rendered.queryByTestId("some-test-page");
expect(actual).not.toBeInTheDocument();
});
it("given page becomes enabled, when navigating to the page, shows the page", () => {
runInAction(() => {
someObservable.set(true);
});
rendererTestExtension.navigate();
const actual = rendered.queryByTestId("some-test-page");
expect(actual).toBeInTheDocument();
});
});

View File

@ -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<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.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: () => (
<div data-testid="some-kube-object-detail-item">
Some detail
</div>
),
},
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: () => <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: "",
},
});

View File

@ -18,7 +18,6 @@ import { routeSpecificComponentInjectionToken } from "../../../../renderer/route
import { KubeObject } from "../../../../common/k8s-api/kube-object"; import { KubeObject } from "../../../../common/k8s-api/kube-object";
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable"; import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
import { KubeObjectMenu } from "../../../../renderer/components/kube-object-menu"; import { KubeObjectMenu } from "../../../../renderer/components/kube-object-menu";
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
describe("disable kube object menu items when cluster is not relevant", () => { describe("disable kube object menu items when cluster is not relevant", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
@ -30,10 +29,6 @@ describe("disable kube object menu items when cluster is not relevant", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
builder.beforeApplicationStart(({ mainDi }) => {
mainDi.override(apiManagerInjectable, () => ({}));
});
const rendererDi = builder.dis.rendererDi; const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable); rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);

View File

@ -0,0 +1,126 @@
/**
* 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 { observable, runInAction, 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 { KubeObjectMenu } from "../../../../renderer/components/kube-object-menu";
describe("reactively hide kube object menu item", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
beforeEach(async () => {
builder = getApplicationBuilder();
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: {
kubeObjectMenuItems: [
{
kind: "some-kind",
apiVersions: ["some-api-version"],
components: {
MenuItem: () => (
<div data-testid="some-kube-object-menu-item">Some menu item</div>
),
},
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 menu item", () => {
const actual = rendered.queryByTestId("some-kube-object-menu-item");
expect(actual).not.toBeInTheDocument();
});
it("given item should be shown, shows the kube object menu item", () => {
runInAction(() => {
someObservable.set(true);
});
const actual = rendered.queryByTestId("some-kube-object-menu-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: () => (
<KubeObjectMenu
toolbar={true}
object={getKubeObjectStub("some-kind", "some-api-version")}
/>
),
}),
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: "",
},
});

View File

@ -0,0 +1,132 @@
/**
* 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 { observable, runInAction, 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 extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
import { KubeObject } from "../../../../common/k8s-api/kube-object";
import { KubeObjectStatusLevel } from "../../../../common/k8s-api/kube-object-status";
import { KubeObjectStatusIcon } from "../../../../renderer/components/kube-object-status-icon";
describe("reactively hide kube object status", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
beforeEach(async () => {
builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
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: {
kubeObjectStatusTexts: [
{
kind: "some-kind",
apiVersions: ["some-api-version"],
resolve: () => ({
level: KubeObjectStatusLevel.CRITICAL,
text: "some-kube-object-status-text",
}),
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 status", () => {
const actual = rendered.baseElement.querySelectorAll(
".KubeObjectStatusIcon",
);
expect(actual).toHaveLength(0);
});
it("given item should be shown, shows the kube object status", () => {
runInAction(() => {
someObservable.set(true);
});
const actual = rendered.baseElement.querySelectorAll(
".KubeObjectStatusIcon",
);
expect(actual).toHaveLength(1);
});
});
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: () => (
<KubeObjectStatusIcon
object={getKubeObjectStub("some-kind", "some-api-version")}
/>
),
}),
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: "",
},
});

View File

@ -0,0 +1,75 @@
/**
* 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 { IObservableValue } from "mobx";
import { computed, observable, runInAction } from "mobx";
import React from "react";
import navigateToWorkloadsOverviewInjectable from "../../../../../common/front-end-routing/routes/cluster/workloads/overview/navigate-to-workloads-overview.injectable";
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";
describe("reactively hide workloads overview details item", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
beforeEach(async () => {
builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false);
const testExtension = getExtensionFake({
id: "test-extension-id",
name: "test-extension",
rendererOptions: {
kubeWorkloadsOverviewItems: [
{
components: {
Details: () => (
<div data-testid="some-workload-overview-detail-item">Some detail component</div>
),
},
visible: computed(() => someObservable.get()),
},
],
},
});
rendered = await builder.render();
const navigateToWorkloadsOverview = rendererDi.inject(
navigateToWorkloadsOverviewInjectable,
);
navigateToWorkloadsOverview();
builder.extensions.enable(testExtension);
});
it("does not show the workload overview detail item", () => {
const actual = rendered.queryByTestId("some-workload-overview-detail-item");
expect(actual).not.toBeInTheDocument();
});
it("given item should be shown, shows the workload overview detail item", () => {
runInAction(() => {
someObservable.set(true);
});
const actual = rendered.queryByTestId("some-workload-overview-detail-item");
expect(actual).toBeInTheDocument();
});
});

View File

@ -0,0 +1,68 @@
/**
* 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 { IObservableValue } from "mobx";
import { observable, runInAction, computed } from "mobx";
import React from "react";
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
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";
describe("reactively disable global pages", () => {
let builder: ApplicationBuilder;
let rendered: RenderResult;
let someObservable: IObservableValue<boolean>;
let rendererTestExtension: TestExtensionRenderer;
beforeEach(async () => {
builder = getApplicationBuilder();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false);
const testExtension = getExtensionFake({
id: "test-extension-id",
name: "test-extension",
rendererOptions: {
globalPages: [{
components: {
Page: () => <div data-testid="some-test-page">Some page</div>,
},
enabled: computed(() => someObservable.get()),
}],
},
});
rendered = await builder.render();
builder.extensions.enable(testExtension);
rendererTestExtension = testExtension.renderer;
});
it("when navigating to the page, does not show the page", () => {
rendererTestExtension.navigate();
const actual = rendered.queryByTestId("some-test-page");
expect(actual).not.toBeInTheDocument();
});
it("given page becomes enabled, when navigating to the page, shows the page", () => {
runInAction(() => {
someObservable.set(true);
});
rendererTestExtension.navigate();
const actual = rendered.queryByTestId("some-test-page");
expect(actual).toBeInTheDocument();
});
});

View File

@ -90,6 +90,8 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
* called when the extension is created within a cluster frame. * called when the extension is created within a cluster frame.
* *
* The default implementation is to return `true` * The default implementation is to return `true`
*
* @deprecated Switch to using "enabled" or "visible" properties in each registration together with `activeCluster`
*/ */
async isEnabledForCluster(cluster: KubernetesCluster): Promise<Boolean> { async isEnabledForCluster(cluster: KubernetesCluster): Promise<Boolean> {
return (void cluster) || true; return (void cluster) || true;

View File

@ -2,6 +2,7 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { IComputedValue } from "mobx";
import type { PageParamInit, PageParam } from "../../renderer/navigation"; import type { PageParamInit, PageParam } from "../../renderer/navigation";
// Extensions-api -> Custom page registration // Extensions-api -> Custom page registration
@ -14,6 +15,7 @@ export interface PageRegistration {
id?: string; id?: string;
params?: PageParams<string | Omit<PageParamInit<any>, "name" | "prefix">>; params?: PageParams<string | Omit<PageParamInit<any>, "name" | "prefix">>;
components: PageComponents; components: PageComponents;
enabled?: IComputedValue<boolean>;
} }
export interface PageComponents { export interface PageComponents {

View File

@ -10,6 +10,7 @@ import type { Disposer } from "../../common/utils";
import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable"; import catalogCategoryRegistryInjectable from "../../common/catalog/category-registry.injectable";
import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api"; import { asLegacyGlobalForExtensionApi } from "../as-legacy-globals-for-extension-api/as-legacy-global-object-for-extension-api";
import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable"; import catalogEntityRegistryInjectable from "../../renderer/api/catalog/entity/registry.injectable";
import activeKubernetesClusterInjectable from "../../renderer/cluster-frame-context/active-kubernetes-cluster.injectable";
export const catalogCategories = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable); export const catalogCategories = asLegacyGlobalForExtensionApi(catalogCategoryRegistryInjectable);
@ -53,3 +54,7 @@ export class CatalogEntityRegistry {
} }
export const catalogEntities = new CatalogEntityRegistry(); export const catalogEntities = new CatalogEntityRegistry();
export const activeCluster = asLegacyGlobalForExtensionApi(
activeKubernetesClusterInjectable,
);

View File

@ -38,9 +38,13 @@ const workloadOverviewDetailRegistratorInjectable = getInjectable({
instantiate: () => ({ instantiate: () => ({
Component: registration.components.Details, Component: registration.components.Details,
enabled: computed(() => enabled: computed(() => {
extensionShouldBeEnabledForClusterFrame.value.get(), if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
), return false;
}
return registration.visible ? registration.visible.get() : true;
}),
orderNumber: orderNumber:
0.5 + (registration.priority ? 100 - registration.priority : 50), 0.5 + (registration.priority ? 100 - registration.priority : 50),

View File

@ -1,3 +1,9 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { IComputedValue } from "mobx";
/** /**
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
@ -9,4 +15,5 @@ interface WorkloadsOverviewDetailComponents {
export interface WorkloadsOverviewDetailRegistration { export interface WorkloadsOverviewDetailRegistration {
components: WorkloadsOverviewDetailComponents; components: WorkloadsOverviewDetailComponents;
priority?: number; priority?: number;
visible?: IComputedValue<boolean>;
} }

View File

@ -10,9 +10,7 @@ import extensionShouldBeEnabledForClusterFrameInjectable from "../../../extensio
import { kubeObjectDetailItemInjectionToken } from "./kube-object-detail-item-injection-token"; import { kubeObjectDetailItemInjectionToken } from "./kube-object-detail-item-injection-token";
import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token"; import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token";
import currentKubeObjectInDetailsInjectable from "../current-kube-object-in-details.injectable"; import currentKubeObjectInDetailsInjectable from "../current-kube-object-in-details.injectable";
import { import { kubeObjectMatchesToKindAndApiVersion } from "./kube-object-matches-to-kind-and-api-version";
kubeObjectMatchesToKindAndApiVersion,
} from "./kube-object-matches-to-kind-and-api-version";
const kubeObjectDetailItemRegistratorInjectable = getInjectable({ const kubeObjectDetailItemRegistratorInjectable = getInjectable({
id: "kube-object-detail-item-registrator", id: "kube-object-detail-item-registrator",
@ -45,20 +43,24 @@ const kubeObjectDetailItemRegistratorInjectable = getInjectable({
id, id,
instantiate: (di) => { instantiate: (di) => {
const kubeObject = di.inject( const kubeObject = di.inject(currentKubeObjectInDetailsInjectable);
currentKubeObjectInDetailsInjectable,
);
return { return {
kind: registration.kind, kind: registration.kind,
apiVersions: registration.apiVersions, apiVersions: registration.apiVersions,
Component: registration.components.Details, Component: registration.components.Details,
enabled: computed( enabled: computed(() => {
() => if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
extensionShouldBeEnabledForClusterFrame.value.get() && return false;
isRelevantKubeObject(kubeObject.get()), }
),
if (!isRelevantKubeObject(kubeObject.get())) {
return false;
}
return registration.visible ? registration.visible.get() : true;
}),
orderNumber: 300 - (registration.priority || 50), orderNumber: 300 - (registration.priority || 50),
}; };

View File

@ -5,6 +5,7 @@
import type { KubeObject } from "../../../common/k8s-api/kube-object"; import type { KubeObject } from "../../../common/k8s-api/kube-object";
import type { KubeObjectDetailsProps } from "./kube-object-details"; import type { KubeObjectDetailsProps } from "./kube-object-details";
import type React from "react"; import type React from "react";
import type { IComputedValue } from "mobx";
export interface KubeObjectDetailComponents<T extends KubeObject = KubeObject> { export interface KubeObjectDetailComponents<T extends KubeObject = KubeObject> {
Details: React.ComponentType<KubeObjectDetailsProps<T>>; Details: React.ComponentType<KubeObjectDetailsProps<T>>;
@ -15,4 +16,5 @@ export interface KubeObjectDetailRegistration<T extends KubeObject = KubeObject>
apiVersions: string[]; apiVersions: string[];
components: KubeObjectDetailComponents<T>; components: KubeObjectDetailComponents<T>;
priority?: number; priority?: number;
visible?: IComputedValue<boolean>;
} }

View File

@ -40,9 +40,13 @@ const kubeObjectMenuItemRegistratorInjectable = getInjectable({
apiVersions: registration.apiVersions, apiVersions: registration.apiVersions,
Component: registration.components.MenuItem, Component: registration.components.MenuItem,
enabled: computed(() => enabled: computed(() => {
extensionShouldBeEnabledForClusterFrame.value.get(), if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
), return false;
}
return registration.visible ? registration.visible.get() : true;
}),
orderNumber: 100, orderNumber: 100,
}), }),

View File

@ -3,6 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { IComputedValue } from "mobx";
import type React from "react"; import type React from "react";
import type { KubeObject } from "../../../common/k8s-api/kube-object"; import type { KubeObject } from "../../../common/k8s-api/kube-object";
@ -19,4 +20,5 @@ export interface KubeObjectMenuRegistration {
kind: string; kind: string;
apiVersions: string[]; apiVersions: string[];
components: KubeObjectMenuComponents; components: KubeObjectMenuComponents;
visible?: IComputedValue<boolean>;
} }

View File

@ -2,6 +2,7 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { IComputedValue } from "mobx";
import type { KubeObject } from "../../../common/k8s-api/kube-object"; import type { KubeObject } from "../../../common/k8s-api/kube-object";
import type { KubeObjectStatus } from "../../../common/k8s-api/kube-object-status"; import type { KubeObjectStatus } from "../../../common/k8s-api/kube-object-status";
@ -9,4 +10,5 @@ export interface KubeObjectStatusRegistration {
kind: string; kind: string;
apiVersions: string[]; apiVersions: string[];
resolve: (object: KubeObject) => KubeObjectStatus; resolve: (object: KubeObject) => KubeObjectStatus;
visible?: IComputedValue<boolean>;
} }

View File

@ -38,9 +38,13 @@ const kubeObjectStatusTextRegistratorInjectable = getInjectable({
instantiate: () => ({ instantiate: () => ({
...registration, ...registration,
enabled: computed(() => enabled: computed(() => {
extensionShouldBeEnabledForClusterFrame.value.get(), if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
), return false;
}
return registration.visible ? registration.visible.get() : true;
}),
}), }),
injectionToken: kubeObjectStatusTextInjectionToken, injectionToken: kubeObjectStatusTextInjectionToken,

View File

@ -35,16 +35,22 @@ const extensionRouteRegistratorInjectable = getInjectable({
return [ return [
...extension.globalPages.map( ...extension.globalPages.map(
toRouteInjectable( toRouteInjectable(false, (registration) =>
false, computed(() =>
computed(() => true), registration.enabled ? registration.enabled.get() : true,
),
), ),
), ),
...extension.clusterPages.map( ...extension.clusterPages.map(
toRouteInjectable( toRouteInjectable(true, (registration) =>
true, computed(() => {
computed(() => extensionShouldBeEnabledForClusterFrame.value.get()), if (!extensionShouldBeEnabledForClusterFrame.value.get()) {
return false;
}
return registration.enabled ? registration.enabled.get() : true;
}),
), ),
), ),
].flat(); ].flat();
@ -61,7 +67,7 @@ const toRouteInjectableFor =
di: DiContainerForInjection, di: DiContainerForInjection,
extension: LensRendererExtension, extension: LensRendererExtension,
) => ) =>
(clusterFrame: boolean, isEnabled: IComputedValue<boolean>) => (clusterFrame: boolean, getIsEnabled: (registration: PageRegistration) => IComputedValue<boolean>) =>
(registration: PageRegistration) => { (registration: PageRegistration) => {
const routeInjectable = getInjectable({ const routeInjectable = getInjectable({
id: `route-${registration.id}-for-extension-${extension.sanitizedExtensionId}`, id: `route-${registration.id}-for-extension-${extension.sanitizedExtensionId}`,
@ -69,7 +75,7 @@ const toRouteInjectableFor =
instantiate: () => ({ instantiate: () => ({
path: getExtensionRoutePath(extension, registration.id), path: getExtensionRoutePath(extension, registration.id),
clusterFrame, clusterFrame,
isEnabled, isEnabled: getIsEnabled(registration),
extension, extension,
}), }),