diff --git a/extensions/example-extension/renderer.tsx b/extensions/example-extension/renderer.tsx index 4deb08558b..2f1db0dd7a 100644 --- a/extensions/example-extension/renderer.tsx +++ b/extensions/example-extension/renderer.tsx @@ -8,16 +8,16 @@ export default class ExampleExtension extends LensRendererExtension { } registerClusterPage(registry: Registry.ClusterPageRegistry) { - this.disposers.push( - registry.add({ + return [ + { path: "/extension-example", title: "Example Extension", components: { Page: () => , MenuIcon: ExampleIcon, } - }) - ) + } + ] } onDeactivate() { diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index 2b4b4f07e9..9189ddc77e 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -4,8 +4,8 @@ import React from "react" export default class ClusterMetricsFeatureExtension extends LensRendererExtension { registerClusterFeatures(registry: Registry.ClusterFeatureRegistry) { - this.disposers.push( - registry.add({ + return [ + { title: "Metrics Stack", components: { Description: () => { @@ -19,7 +19,7 @@ export default class ClusterMetricsFeatureExtension extends LensRendererExtensio } }, feature: new MetricsFeature() - }) - ) + } + ] } } diff --git a/extensions/node-menu/renderer.tsx b/extensions/node-menu/renderer.tsx index b3e3ffd121..8cc8d5f2bc 100644 --- a/extensions/node-menu/renderer.tsx +++ b/extensions/node-menu/renderer.tsx @@ -1,6 +1,6 @@ import { Registry, LensRendererExtension } from "@k8slens/extensions"; import React from "react" -import { NodeMenu } from "./src/node-menu" +import { NodeMenu, NodeMenuProps } from "./src/node-menu" export default class NodeMenuRendererExtension extends LensRendererExtension { async onActivate() { @@ -8,14 +8,14 @@ export default class NodeMenuRendererExtension extends LensRendererExtension { } registerKubeObjectMenus(registry: Registry.KubeObjectMenuRegistry) { - this.disposers.push( - registry.add({ + return [ + { kind: "Node", apiVersions: ["v1"], components: { - MenuItem: (props) => + MenuItem: (props: NodeMenuProps) => } - }) - ) + } + ] } } diff --git a/extensions/node-menu/src/node-menu.tsx b/extensions/node-menu/src/node-menu.tsx index 09ef251d60..8c7466694e 100644 --- a/extensions/node-menu/src/node-menu.tsx +++ b/extensions/node-menu/src/node-menu.tsx @@ -1,7 +1,10 @@ import React from "react"; import { Component, K8sApi, Navigation} from "@k8slens/extensions" -export function NodeMenu(props: Component.KubeObjectMenuProps) { +export interface NodeMenuProps extends Component.KubeObjectMenuProps { +} + +export function NodeMenu(props: NodeMenuProps) { const { object: node, toolbar } = props; if (!node) return null; const nodeName = node.getName(); diff --git a/extensions/pod-menu/renderer.tsx b/extensions/pod-menu/renderer.tsx index 1340d835d0..3e5445b22c 100644 --- a/extensions/pod-menu/renderer.tsx +++ b/extensions/pod-menu/renderer.tsx @@ -1,6 +1,6 @@ import { Registry, LensRendererExtension } from "@k8slens/extensions"; -import { PodShellMenu } from "./src/shell-menu" -import { PodLogsMenu } from "./src/logs-menu" +import { PodShellMenu, PodShellMenuProps } from "./src/shell-menu" +import { PodLogsMenu, PodLogsMenuProps } from "./src/logs-menu" import React from "react" export default class PodMenuRendererExtension extends LensRendererExtension { @@ -9,23 +9,21 @@ export default class PodMenuRendererExtension extends LensRendererExtension { } registerKubeObjectMenus(registry: Registry.KubeObjectMenuRegistry) { - this.disposers.push( - registry.add({ + return [ + { kind: "Pod", apiVersions: ["v1"], components: { - MenuItem: (props) => + MenuItem: (props: PodShellMenuProps) => } - }) - ) - this.disposers.push( - registry.add({ + }, + { kind: "Pod", apiVersions: ["v1"], components: { - MenuItem: (props) => + MenuItem: (props: PodLogsMenuProps) => } - }) - ) + } + ] } } diff --git a/extensions/pod-menu/src/logs-menu.tsx b/extensions/pod-menu/src/logs-menu.tsx index 8932318dc6..7ea6056caa 100644 --- a/extensions/pod-menu/src/logs-menu.tsx +++ b/extensions/pod-menu/src/logs-menu.tsx @@ -1,10 +1,10 @@ import React from "react"; import { Component, K8sApi, Util, Navigation } from "@k8slens/extensions"; -interface Props extends Component.KubeObjectMenuProps { +export interface PodLogsMenuProps extends Component.KubeObjectMenuProps { } -export class PodLogsMenu extends React.Component { +export class PodLogsMenu extends React.Component { showLogs(container: K8sApi.IPodContainer) { Navigation.hideDetails(); const pod = this.props.object; diff --git a/extensions/pod-menu/src/shell-menu.tsx b/extensions/pod-menu/src/shell-menu.tsx index 74a0180516..d16188c6e7 100644 --- a/extensions/pod-menu/src/shell-menu.tsx +++ b/extensions/pod-menu/src/shell-menu.tsx @@ -3,10 +3,10 @@ import React from "react"; import { Component, K8sApi, Util, Navigation } from "@k8slens/extensions"; -interface Props extends Component.KubeObjectMenuProps { +export interface PodShellMenuProps extends Component.KubeObjectMenuProps { } -export class PodShellMenu extends React.Component { +export class PodShellMenu extends React.Component { async execShell(container?: string) { Navigation.hideDetails(); const { object: pod } = this.props diff --git a/extensions/support-page/main.ts b/extensions/support-page/main.ts index 133df0b890..875e83d17c 100644 --- a/extensions/support-page/main.ts +++ b/extensions/support-page/main.ts @@ -6,9 +6,9 @@ export default class SupportPageMainExtension extends LensMainExtension { console.log("support page extension activated") } - async registerAppMenus(registry: Registry.MenuRegistry) { - this.disposers.push( - registry.add({ + registerAppMenus(registry: Registry.MenuRegistry) { + return [ + { parentId: "help", label: "Support", click() { @@ -17,7 +17,7 @@ export default class SupportPageMainExtension extends LensMainExtension { url: supportPageURL(), }); } - }) - ) + } + ] } } diff --git a/extensions/support-page/renderer.tsx b/extensions/support-page/renderer.tsx index 84e7f87f65..c607ef6cdb 100644 --- a/extensions/support-page/renderer.tsx +++ b/extensions/support-page/renderer.tsx @@ -8,22 +8,22 @@ export default class SupportPageRendererExtension extends LensRendererExtension console.log("support page extension activated") } - registerGlobalPage(registry: Registry.GlobalPageRegistry) { - this.disposers.push( - registry.add({ + registerGlobalPages(registry: Registry.GlobalPageRegistry) { + return [ + { ...supportPageRoute, url: supportPageURL(), hideInMenu: true, components: { Page: Support, } - }) - ) + } + ] } - registerStatusBarItem(registry: Registry.StatusBarRegistry) { - this.disposers.push( - registry.add({ + registerStatusBarItems(registry: Registry.StatusBarRegistry) { + return [ + { item: (
Support
) - }) - ) + } + ] } } diff --git a/extensions/telemetry/renderer.tsx b/extensions/telemetry/renderer.tsx index 3988e97097..cbd219e245 100644 --- a/extensions/telemetry/renderer.tsx +++ b/extensions/telemetry/renderer.tsx @@ -12,15 +12,15 @@ export default class TelemetryRendererExtension extends LensRendererExtension { } registerAppPreferences(registry: Registry.AppPreferenceRegistry) { - this.disposers.push( - registry.add({ + return [ + { title: "Telemetry & Usage Tracking", components: { Hint: () => , Input: () => } - }) - ) + } + ] } onDeactivate() { diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index 0e831af9f8..4609a3b355 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -36,26 +36,26 @@ export class ExtensionLoader { loadOnMain() { logger.info('[EXTENSIONS-LOADER]: load on main') - this.autoloadExtensions((instance: LensMainExtension) => { - instance.registerAppMenus(menuRegistry); + this.autoloadExtensions((extension: LensMainExtension) => { + extension.register(menuRegistry, extension.registerAppMenus(menuRegistry)) }) } loadOnClusterManagerRenderer() { logger.info('[EXTENSIONS-LOADER]: load on main renderer (cluster manager)') - this.autoloadExtensions((instance: LensRendererExtension) => { - instance.registerGlobalPage(globalPageRegistry) - instance.registerAppPreferences(appPreferenceRegistry) - instance.registerClusterFeatures(clusterFeatureRegistry) - instance.registerStatusBarItem(statusBarRegistry) + this.autoloadExtensions((extension: LensRendererExtension) => { + extension.register(globalPageRegistry, extension.registerGlobalPages(globalPageRegistry)) + extension.register(appPreferenceRegistry, extension.registerAppPreferences(appPreferenceRegistry)) + extension.register(clusterFeatureRegistry, extension.registerClusterFeatures(clusterFeatureRegistry)) + extension.register(statusBarRegistry, extension.registerStatusBarItems(statusBarRegistry)) }) } loadOnClusterRenderer() { logger.info('[EXTENSIONS-LOADER]: load on cluster renderer (dashboard)') - this.autoloadExtensions((instance: LensRendererExtension) => { - instance.registerClusterPage(clusterPageRegistry) - instance.registerKubeObjectMenus(kubeObjectMenuRegistry) + this.autoloadExtensions((extension: LensRendererExtension) => { + extension.register(clusterPageRegistry, extension.registerClusterPages(clusterPageRegistry)) + extension.register(kubeObjectMenuRegistry, extension.registerKubeObjectMenus(kubeObjectMenuRegistry)) }) } diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index b348cd6868..b8aba8c6a3 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -1,6 +1,7 @@ import { readJsonSync } from "fs-extra"; import { action, observable, toJS } from "mobx"; import logger from "../main/logger"; +import { BaseRegistry } from "./registries/base-registry"; export type ExtensionId = string | ExtensionPackageJsonPath; export type ExtensionPackageJsonPath = string; @@ -25,7 +26,7 @@ export interface ExtensionManifest extends ExtensionModel { export class LensExtension implements ExtensionModel { public id: ExtensionId; public updateUrl: string; - protected disposers: Function[] = []; + protected disposers: (() => void)[] = []; @observable name = ""; @observable description = ""; @@ -77,6 +78,14 @@ export class LensExtension implements ExtensionModel { // mock } + register(registry: BaseRegistry, registryItems: T[]) { + const disposers = registryItems.map(item => registry.add(item)); + this.disposers.push(...disposers); + return () => { + this.disposers = this.disposers.filter(disposer => !disposers.includes(disposer)) + }; + } + getMeta() { return toJS({ id: this.id, diff --git a/src/extensions/lens-main-extension.ts b/src/extensions/lens-main-extension.ts index 9ad858d0c6..45a2c0e8e1 100644 --- a/src/extensions/lens-main-extension.ts +++ b/src/extensions/lens-main-extension.ts @@ -1,12 +1,12 @@ import { LensExtension } from "./lens-extension" -import type { MenuRegistry } from "./registries/menu-registry"; +import type { MenuRegistration, MenuRegistry } from "./registries/menu-registry"; export class LensMainExtension extends LensExtension { - registerAppMenus(registry: MenuRegistry) { - // + registerAppMenus(registry: MenuRegistry): MenuRegistration[] { + return [] } - registerPrometheusProviders(registry: any) { - // + registerPrometheusProviders(registry: any): any[] { + return [] } } diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 4c2e25ebdf..2134dad696 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -1,28 +1,28 @@ import { LensExtension } from "./lens-extension" -import type { GlobalPageRegistry, ClusterPageRegistry, AppPreferenceRegistry, StatusBarRegistry, KubeObjectMenuRegistry, ClusterFeatureRegistry } from "./registries" +import type { GlobalPageRegistry, ClusterPageRegistry, AppPreferenceRegistry, StatusBarRegistry, KubeObjectMenuRegistry, ClusterFeatureRegistry, PageRegistration, AppPreferenceRegistration, ClusterFeatureRegistration, StatusBarRegistration, KubeObjectMenuRegistration } from "./registries" export class LensRendererExtension extends LensExtension { - registerGlobalPage(registry: GlobalPageRegistry) { - return + registerGlobalPages(registry: GlobalPageRegistry): PageRegistration[] { + return [] } - registerClusterPage(registry: ClusterPageRegistry) { - return + registerClusterPages(registry: ClusterPageRegistry): PageRegistration[] { + return [] } - registerAppPreferences(registry: AppPreferenceRegistry) { - return + registerAppPreferences(registry: AppPreferenceRegistry): AppPreferenceRegistration[] { + return [] } - registerClusterFeatures(registry: ClusterFeatureRegistry) { - return + registerClusterFeatures(registry: ClusterFeatureRegistry): ClusterFeatureRegistration[] { + return [] } - registerStatusBarItem(registry: StatusBarRegistry) { - return + registerStatusBarItems(registry: StatusBarRegistry): StatusBarRegistration[] { + return [] } - registerKubeObjectMenus(registry: KubeObjectMenuRegistry) { - return + registerKubeObjectMenus(registry: KubeObjectMenuRegistry): KubeObjectMenuRegistration[] { + return [] } } diff --git a/src/extensions/registries/menu-registry.ts b/src/extensions/registries/menu-registry.ts index d31d124f30..4b98201073 100644 --- a/src/extensions/registries/menu-registry.ts +++ b/src/extensions/registries/menu-registry.ts @@ -1,11 +1,10 @@ // Extensions API -> Global menu customizations -import type { MenuTopId } from "../../main/menu"; import type { MenuItemConstructorOptions } from "electron"; import { BaseRegistry } from "./base-registry"; export interface MenuRegistration extends MenuItemConstructorOptions { - parentId?: MenuTopId; + parentId: string; } export class MenuRegistry extends BaseRegistry { diff --git a/src/main/menu.ts b/src/main/menu.ts index 7bb340b5ce..935d71b519 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -209,7 +209,7 @@ export function buildMenu(windowManager: WindowManager) { // Modify menu from extensions-api menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { try { - const topMenu = appMenu[parentId].submenu as MenuItemConstructorOptions[]; + const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; topMenu.push(menuItem); } catch (err) { logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem })