diff --git a/src/extensions/example-extension/example-extension.tsx b/src/extensions/example-extension/example-extension.tsx index 5c1582057f..9a95f30f6e 100644 --- a/src/extensions/example-extension/example-extension.tsx +++ b/src/extensions/example-extension/example-extension.tsx @@ -1,4 +1,4 @@ -import { Icon, LensExtension } from "@lens/extensions"; // fixme: map to generated types from "extension-api.d.ts" +import { DynamicPageType, Icon, LensExtension } from "@lens/extensions"; // fixme: map to generated types from "extension-api.d.ts" import React from "react"; import path from "path"; @@ -8,10 +8,11 @@ export default class ExampleExtension extends LensExtension { onActivate() { console.log('EXAMPLE EXTENSION: ACTIVATE', this.getMeta()) this.unRegisterPage = this.runtime.dynamicPages.register({ - type: "cluster-view", + type: DynamicPageType.CLUSTER, path: "/extension-example", + menuTitle: "Example Extension", components: { - Main: ExtensionPage, + Page: ExtensionPage, MenuIcon: ExtensionIcon, } }) @@ -27,7 +28,7 @@ export function ExtensionIcon(props: {} /*IconProps |*/) { return } -// todo: provide extension instance and runtime params (via context or props) +// todo: provide extension-instance and lens-runtime (context/props/extension-js-scope) export class ExtensionPage extends React.Component { render() { return ( diff --git a/src/extensions/extension-api.ts b/src/extensions/extension-api.ts index 3dff72d00c..803698f71f 100644 --- a/src/extensions/extension-api.ts +++ b/src/extensions/extension-api.ts @@ -3,6 +3,7 @@ export type { LensRuntimeRendererEnv } from "./lens-runtime"; // APIs export * from "./extension" +export { DynamicPageType } from "./register-page"; // Common UI components export * from "../renderer/components/icon" diff --git a/src/extensions/lens-runtime.ts b/src/extensions/lens-runtime.ts index e456bb435f..333282a734 100644 --- a/src/extensions/lens-runtime.ts +++ b/src/extensions/lens-runtime.ts @@ -1,18 +1,14 @@ -// Lens runtime for injecting to extension on activation -import { apiManager } from "../renderer/api/api-manager"; +// Lens renderer runtime params available to the extension after activation import logger from "../main/logger"; -import { dynamicPages } from "../renderer/components/cluster-manager/register-page"; +import { dynamicPages } from "./register-page"; export interface LensRuntimeRendererEnv { - apiManager: typeof apiManager; logger: typeof logger; dynamicPages: typeof dynamicPages } -// todo: expose more public runtime apis: stores, managers, etc. export function getLensRuntime(): LensRuntimeRendererEnv { return { - apiManager, logger, dynamicPages, } diff --git a/src/renderer/components/cluster-manager/register-page.ts b/src/extensions/register-page.tsx similarity index 58% rename from src/renderer/components/cluster-manager/register-page.ts rename to src/extensions/register-page.tsx index 49d32dcb30..34317c1d93 100644 --- a/src/renderer/components/cluster-manager/register-page.ts +++ b/src/extensions/register-page.tsx @@ -1,12 +1,18 @@ -// Dynamic pages +// Extensions-api -> Dynamic pages -import React from "react"; import { computed, observable } from "mobx"; -import type { IconProps } from "../icon"; +import React from "react"; +import type { IconProps } from "../renderer/components/icon"; + +export enum DynamicPageType { + GLOBAL = "lens-scope", + CLUSTER = "cluster-view-scope", +} export interface PageRegistration { - path: string; - type: "global" | "cluster-view"; + path: string; // route-path + menuTitle: string; + type: DynamicPageType; components: PageComponents; } @@ -19,13 +25,14 @@ export class PagesStore { protected pages = observable.array([], { deep: false }); @computed get globalPages() { - return this.pages.filter(page => page.type === "global"); + return this.pages.filter(page => page.type === DynamicPageType.GLOBAL); } @computed get clusterPages() { - return this.pages.filter(page => page.type === "cluster-view"); + return this.pages.filter(page => page.type === DynamicPageType.CLUSTER); } + // todo: verify paths to avoid collision with existing pages register(params: PageRegistration) { this.pages.push(params); return () => { diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index e4b24c3035..ee4dd6dedf 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -10,6 +10,7 @@ import { i18nStore } from "./i18n"; import { themeStore } from "./theme.store"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; +import { getLensRuntime } from "../extensions/lens-runtime"; type AppComponent = React.ComponentType & { init?(): void; @@ -32,6 +33,7 @@ export async function bootstrap(App: AppComponent) { // init app's dependencies if any if (App.init) { await App.init(); + extensionStore.autoEnableOnLoad(getLensRuntime); } render(, rootElem); } diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 23e71e2be9..a878fd47b7 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -35,6 +35,7 @@ import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store import logger from "../../main/logger"; import { clusterIpc } from "../../common/cluster-ipc"; import { webFrame } from "electron"; +import { dynamicPages } from "../../extensions/register-page"; @observer export class App extends React.Component { @@ -71,6 +72,9 @@ export class App extends React.Component { + {dynamicPages.clusterPages.map(({ path, components: { Page } }) => { + return + })} diff --git a/src/renderer/components/cluster-manager/cluster-manager.tsx b/src/renderer/components/cluster-manager/cluster-manager.tsx index 9f46c88e19..10ee59f467 100644 --- a/src/renderer/components/cluster-manager/cluster-manager.tsx +++ b/src/renderer/components/cluster-manager/cluster-manager.tsx @@ -15,7 +15,7 @@ import { Extensions, extensionsRoute } from "../+extensions"; import { clusterViewRoute, clusterViewURL, getMatchedCluster, getMatchedClusterId } from "./cluster-view.route"; import { clusterStore } from "../../../common/cluster-store"; import { hasLoadedView, initView, lensViews, refreshViews } from "./lens-views"; -import { dynamicPages } from "./register-page"; +import { dynamicPages } from "../../../extensions/register-page"; @observer export class ClusterManager extends React.Component { diff --git a/src/renderer/components/cluster-manager/clusters-menu.tsx b/src/renderer/components/cluster-manager/clusters-menu.tsx index 64f69fb736..30edfc22c7 100644 --- a/src/renderer/components/cluster-manager/clusters-menu.tsx +++ b/src/renderer/components/cluster-manager/clusters-menu.tsx @@ -21,7 +21,7 @@ import { ConfirmDialog } from "../confirm-dialog"; import { clusterIpc } from "../../../common/cluster-ipc"; import { clusterViewURL, getMatchedClusterId } from "./cluster-view.route"; import { DragDropContext, Draggable, DraggableProvided, Droppable, DroppableProvided, DropResult } from "react-beautiful-dnd"; -import { dynamicPages } from "./register-page"; +import { dynamicPages } from "../../../extensions/register-page"; interface Props { className?: IClassName; @@ -150,9 +150,7 @@ export class ClustersMenu extends React.Component {
{dynamicPages.globalPages.map(({ path, components: { MenuIcon } }) => { - if (MenuIcon) { - return navigate(path)}/> - } + return navigate(path)}/> })}
diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index d46a1548cf..91cd4940a6 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -28,6 +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"; const SidebarContext = React.createContext({ pinned: false }); type SidebarContextValue = { @@ -183,6 +184,18 @@ export class Sidebar extends React.Component { > {this.renderCustomResources()} + {dynamicPages.clusterPages.map(({ path, menuTitle, components: { MenuIcon } }) => { + return ( + } + /> + ) + })} diff --git a/src/renderer/lens-app.tsx b/src/renderer/lens-app.tsx index 7c1f228fd3..9b4fffc6a1 100644 --- a/src/renderer/lens-app.tsx +++ b/src/renderer/lens-app.tsx @@ -11,15 +11,9 @@ import { ErrorBoundary } from "./components/error-boundary"; import { WhatsNew, whatsNewRoute } from "./components/+whats-new"; import { Notifications } from "./components/notifications"; import { ConfirmDialog } from "./components/confirm-dialog"; -import { extensionStore } from "../extensions/extension-store"; -import { getLensRuntime } from "../extensions/lens-runtime"; @observer export class LensApp extends React.Component { - componentDidMount() { - extensionStore.autoEnableOnLoad(getLensRuntime); - } - render() { return (