diff --git a/extensions/example-extension/index.tsx b/extensions/example-extension/index.tsx new file mode 100644 index 0000000000..1fd4a4c666 --- /dev/null +++ b/extensions/example-extension/index.tsx @@ -0,0 +1,24 @@ +import { DynamicPageType, LensRendererExtension, PageStore } from "@lens/ui-extensions"; +import { examplePage, ExtensionIcon } from "./page" + +export default class ExampleExtension extends LensRendererExtension { + onActivate() { + console.log('EXAMPLE EXTENSION RENDERER: ACTIVATED', this.getMeta()); + } + + registerPages(pageStore: PageStore) { + this.registerPage(pageStore, { + type: DynamicPageType.CLUSTER, + path: "/extension-example", + title: "Example Extension", + components: { + Page: examplePage(this), + MenuIcon: ExtensionIcon, + } + }) + } + + onDeactivate() { + console.log('EXAMPLE EXTENSION RENDERER: DEACTIVATED', this.getMeta()); + } +} diff --git a/extensions/example-extension/main.ts b/extensions/example-extension/main.ts index c193836341..28e5feddee 100644 --- a/extensions/example-extension/main.ts +++ b/extensions/example-extension/main.ts @@ -1,10 +1,14 @@ -import { LensExtension } from "@lens/extensions"; +import { LensMainExtension } from "@lens/extensions"; -export default class ExampleExtensionMain extends LensExtension { +export default class ExampleExtensionMain extends LensMainExtension { onActivate() { console.log('EXAMPLE EXTENSION MAIN: ACTIVATED', this.getMeta()); } + onEvent(evt: any) { + // + } + onDeactivate() { console.log('EXAMPLE EXTENSION MAIN: DEACTIVATED', this.getMeta()); } diff --git a/extensions/example-extension/renderer.ts b/extensions/example-extension/renderer.ts index f52c896514..1fd4a4c666 100644 --- a/extensions/example-extension/renderer.ts +++ b/extensions/example-extension/renderer.ts @@ -10,7 +10,7 @@ export default class ExampleExtension extends LensRendererExtension { this.registerPage(pageStore, { type: DynamicPageType.CLUSTER, path: "/extension-example", - menuTitle: "Example Extension", + title: "Example Extension", components: { Page: examplePage(this), MenuIcon: ExtensionIcon, diff --git a/src/extensions/dynamic-page.tsx b/src/extensions/dynamic-page.tsx new file mode 100644 index 0000000000..b92d102f70 --- /dev/null +++ b/src/extensions/dynamic-page.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { cssNames } from "../renderer/utils"; +import { TabLayout } from "../renderer/components/layout/tab-layout"; +import { PageRegistration } from "./page-store" + +export class DynamicPage extends React.Component<{ page: PageRegistration }> { + render() { + const { className, components: { Page }, subPages = [] } = this.props.page; + return ( + + + + ) + } +} diff --git a/src/extensions/extension-renderer-api.ts b/src/extensions/extension-renderer-api.ts index 33a7b6933e..8de4873778 100644 --- a/src/extensions/extension-renderer-api.ts +++ b/src/extensions/extension-renderer-api.ts @@ -1,5 +1,5 @@ // Lens-extensions api developer's kit -export type { LensExtensionRuntimeEnv, PageStore } from "./lens-runtime"; +export type { LensExtensionRuntimeEnv, PageStore } from "./lens-renderer-runtime"; // APIs export * from "./lens-renderer-extension" diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 4ca4620522..0c48491bd1 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -1,4 +1,4 @@ -import type { PageStore } from "./lens-runtime" +import type { PageStore } from "./lens-renderer-runtime" import type { PageRegistration } from "./page-store" import { LensExtension } from "./lens-extension" diff --git a/src/extensions/lens-renderer-runtime.ts b/src/extensions/lens-renderer-runtime.ts new file mode 100644 index 0000000000..fef56fca07 --- /dev/null +++ b/src/extensions/lens-renderer-runtime.ts @@ -0,0 +1,21 @@ +// Lens extension runtime params available to renderer extensions after activation + +import logger from "../main/logger"; +import { navigate } from "../renderer/navigation"; +import { PageRegistration } from "./page-store"; + +export interface PageStore { + register(params: PageRegistration): () => void +} + +export interface LensExtensionRuntimeEnv { + logger: typeof logger; + navigate: typeof navigate; +} + +export function getLensRuntime(): LensExtensionRuntimeEnv { + return { + logger, + navigate + } +} diff --git a/src/extensions/lens-runtime.ts b/src/extensions/lens-runtime.ts index a9a5f727de..07e6a5cbaf 100644 --- a/src/extensions/lens-runtime.ts +++ b/src/extensions/lens-runtime.ts @@ -1,11 +1,6 @@ // Lens extension runtime params available to extensions after activation import logger from "../main/logger"; -import { PageRegistration } from "./page-store"; - -export interface PageStore { - register(params: PageRegistration): () => void -} export interface LensExtensionRuntimeEnv { logger: typeof logger; @@ -13,6 +8,6 @@ export interface LensExtensionRuntimeEnv { export function getLensRuntime(): LensExtensionRuntimeEnv { return { - logger, + logger } } diff --git a/src/extensions/page-store.ts b/src/extensions/page-store.ts index 78a9b767cf..53509534d8 100644 --- a/src/extensions/page-store.ts +++ b/src/extensions/page-store.ts @@ -2,18 +2,24 @@ import { computed, observable } from "mobx"; import React from "react"; -import type { IconProps } from "../renderer/components/icon"; +import { RouteProps } from "react-router"; +import { IconProps } from "../renderer/components/icon"; +import { IClassName } from "../renderer/utils"; +import { TabRoute } from "../renderer/components/layout/tab-layout"; export enum DynamicPageType { GLOBAL = "lens-scope", CLUSTER = "cluster-view-scope", } -export interface PageRegistration { +export interface PageRegistration extends RouteProps { + className?: IClassName; + url?: string; // initial url to be used for building menus and tabs, otherwise "path" applied by default path: string; // route-path - menuTitle: string; + title: React.ReactNode; // used in sidebar's & tabs-layout type: DynamicPageType; components: PageComponents; + subPages?: (PageRegistration & TabRoute)[]; } export interface PageComponents { diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index bd79258780..96f4333c71 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -37,6 +37,7 @@ import logger from "../../main/logger"; import { clusterIpc } from "../../common/cluster-ipc"; import { webFrame } from "electron"; import { pageStore } from "../../extensions/page-store"; +import { DynamicPage } from "../../extensions/dynamic-page"; import { extensionLoader } from "../../extensions/extension-loader"; import { getLensRuntime } from "../../extensions/lens-runtime"; @@ -77,8 +78,8 @@ export class App extends React.Component { - {pageStore.clusterPages.map(({ path, components: { Page } }) => { - return + {pageStore.clusterPages.map(page => { + return }/> })} diff --git a/src/renderer/components/cluster-manager/clusters-menu.tsx b/src/renderer/components/cluster-manager/clusters-menu.tsx index 5c9e9a1ae2..f20fddcf80 100644 --- a/src/renderer/components/cluster-manager/clusters-menu.tsx +++ b/src/renderer/components/cluster-manager/clusters-menu.tsx @@ -22,7 +22,7 @@ import { ConfirmDialog } from "../confirm-dialog"; import { clusterIpc } from "../../../common/cluster-ipc"; import { clusterViewURL } from "./cluster-view.route"; import { DragDropContext, Droppable, Draggable, DropResult, DroppableProvided, DraggableProvided } from "react-beautiful-dnd"; -import { dynamicPages } from "../../../extensions/register-page"; +import { pageStore } from "../../../extensions/page-store"; interface Props { className?: IClassName; @@ -156,7 +156,7 @@ export class ClustersMenu extends React.Component { )}
- {dynamicPages.globalPages.map(({ path, components: { MenuIcon } }) => { + {pageStore.globalPages.map(({ path, components: { MenuIcon } }) => { return navigate(path)}/> })}
diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 68c82f8676..ab934d2170 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -28,7 +28,7 @@ import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resourc import { CustomResources } from "../+custom-resources/custom-resources"; import { navigation } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac" -import { dynamicPages } from "../../../extensions/register-page"; +import { pageStore } from "../../../extensions/page-store"; const SidebarContext = React.createContext({ pinned: false }); type SidebarContextValue = { @@ -184,14 +184,14 @@ export class Sidebar extends React.Component { > {this.renderCustomResources()} - {dynamicPages.clusterPages.map(({ path, menuTitle, components: { MenuIcon } }) => { + {pageStore.clusterPages.map(({ path, title, components: { MenuIcon } }) => { return ( } /> ) diff --git a/src/renderer/components/layout/tab-layout.tsx b/src/renderer/components/layout/tab-layout.tsx index 82c0cac6cf..597cb6444e 100644 --- a/src/renderer/components/layout/tab-layout.tsx +++ b/src/renderer/components/layout/tab-layout.tsx @@ -1,5 +1,4 @@ import "./tab-layout.scss"; - import React, { ReactNode } from "react"; import { matchPath, RouteProps } from "react-router-dom"; import { observer } from "mobx-react"; @@ -7,7 +6,6 @@ import { cssNames } from "../../utils"; import { Tab, Tabs } from "../tabs"; import { ErrorBoundary } from "../error-boundary"; import { navigate, navigation } from "../../navigation"; -import { getHostedCluster } from "../../../common/cluster-store"; export interface TabRoute extends RouteProps { title: React.ReactNode; @@ -23,17 +21,13 @@ interface Props { export const TabLayout = observer(({ className, contentClass, tabs, children }: Props) => { const routePath = navigation.location.pathname; - const cluster = getHostedCluster(); - if (!cluster) { - return null; // fix: skip render when removing active (visible) cluster - } return (
{tabs && ( navigate(url)}> {tabs.map(({ title, path, url, ...routeProps }) => { const isActive = !!matchPath(routePath, { path, ...routeProps }); - return ; + return ; })} )}