From 140c6f7385375823e8f0d0308830ec3aad774890 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Thu, 19 Nov 2020 17:33:40 +0200 Subject: [PATCH] allow extension cluster menus to have a parent Signed-off-by: Jari Kolehmainen --- .../registries/page-menu-registry.ts | 40 +++++++++++-- src/renderer/components/app.tsx | 59 ++++++++++++++++++- src/renderer/components/layout/sidebar.tsx | 41 +++++++++++-- 3 files changed, 128 insertions(+), 12 deletions(-) diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index ebaaa42dbb..3644263319 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -1,9 +1,10 @@ // Extensions-api -> Register page menu items import type { IconProps } from "../../renderer/components/icon"; import type React from "react"; -import { action } from "mobx"; +import { action, computed } from "mobx"; import { BaseRegistry } from "./base-registry"; import { LensExtension } from "../lens-extension"; +import { RegisteredPage } from "./page-registry"; export interface PageMenuTarget

{ extensionId?: string; @@ -17,11 +18,16 @@ export interface PageMenuRegistration { components: PageMenuComponents; } +export interface ClusterPageMenuRegistration extends PageMenuRegistration { + id?: string; + parentId?: string; +} + export interface PageMenuComponents { Icon: React.ComponentType; } -export class PageMenuRegistry extends BaseRegistry> { +export class GlobalPageMenuRegistry extends BaseRegistry { @action add(items: PageMenuRegistration[], ext: LensExtension) { const normalizedItems = items.map(menuItem => { @@ -35,5 +41,31 @@ export class PageMenuRegistry extends BaseRegistry { + @action + add(items: PageMenuRegistration[], ext: LensExtension) { + const normalizedItems = items.map(menuItem => { + menuItem.target = { + extensionId: ext.name, + ...(menuItem.target || {}), + }; + return menuItem + }) + return super.add(normalizedItems); + } + + getRootItems() { + return this.getItems().filter((item) => !item.parentId) + } + + getSubItems(parentId: string) { + return this.getItems().filter((item) => item.parentId === parentId) + } + + getByPage(page: RegisteredPage) { + return this.getItems().find((item) => item.target?.pageId == page.id && item.target?.extensionId === page.extensionId) + } +} + +export const globalPageMenuRegistry = new GlobalPageMenuRegistry(); +export const clusterPageMenuRegistry = new ClusterPageMenuRegistry(); diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index f05ec8a7a8..8477aa972d 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -34,12 +34,15 @@ import { Terminal } from "./dock/terminal"; import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store"; import logger from "../../main/logger"; import { webFrame } from "electron"; -import { clusterPageRegistry } from "../../extensions/registries/page-registry"; +import { clusterPageRegistry, getExtensionPageUrl, PageRegistration, RegisteredPage } from "../../extensions/registries/page-registry"; import { extensionLoader } from "../../extensions/extension-loader"; import { appEventBus } from "../../common/event-bus" import { requestMain } from "../../common/ipc"; import whatInput from 'what-input'; import { clusterSetFrameIdHandler } from "../../common/cluster-ipc"; +import { clusterPageMenuRegistry } from "../../extensions/registries"; +import { TabLayoutRoute, TabLayout } from "./layout/tab-layout"; +import { Trans } from "@lingui/macro"; @observer export class App extends React.Component { @@ -72,9 +75,58 @@ export class App extends React.Component { return workloadsURL(); } + getTabLayoutRoutes(page: RegisteredPage) { + const menuItem = clusterPageMenuRegistry.getByPage(page); + const routes: TabLayoutRoute[] = []; + if (!menuItem.id) { + return routes; + } + clusterPageMenuRegistry.getSubItems(menuItem.id).forEach((item) => { + const page = clusterPageRegistry.getByPageMenuTarget(item.target); + if (page) { + routes.push({ + routePath: page.routePath, + url: getExtensionPageUrl({ extensionId: page.extensionId, pageId: page.id, params: item.target.params }), + title: item.title, + component: page.components.Page, + exact: page.exact + }); + } + }); + if (routes.length > 0) { + routes.unshift({ + routePath: page.routePath, + url: getExtensionPageUrl({ extensionId: page.extensionId, pageId: page.id, params: menuItem.target.params }), + title: Overview, + component: page.components.Page, + exact: page.exact + }) + } + return routes; + } + + renderExtensionTabLayoutRoutes() { + return clusterPageMenuRegistry.getRootItems().map((menu, index) => { + const page = clusterPageRegistry.getByPageMenuTarget(menu.target) + if (page) { + const tabRoutes = this.getTabLayoutRoutes(page) + if (tabRoutes.length > 0) { + const pageComponent = () => + return + } else { + const pageComponent = () => + return + } + } + }) + } + renderExtensionRoutes() { - return clusterPageRegistry.getItems().map(({ components: { Page }, exact, routePath }) => { - return + return clusterPageRegistry.getItems().map((page, index) => { + const menu = clusterPageMenuRegistry.getByPage(page) + if (!menu) { + return + } }) } @@ -96,6 +148,7 @@ export class App extends React.Component { + {this.renderExtensionTabLayoutRoutes()} {this.renderExtensionRoutes()} diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index b77847b4ef..dc2ab39f1b 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -29,7 +29,7 @@ import { CustomResources } from "../+custom-resources/custom-resources"; import { isActiveRoute, navigation } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac" import { Spinner } from "../spinner"; -import { clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries"; +import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl, RegisteredPage } from "../../../extensions/registries"; const SidebarContext = React.createContext({ pinned: false }); type SidebarContextValue = { @@ -76,6 +76,35 @@ export class Sidebar extends React.Component { }); } + getTabLayoutRoutes(menu: ClusterPageMenuRegistration, page: RegisteredPage): TabLayoutRoute[] { + if (!menu.id) { + return []; + } + const routes: TabLayoutRoute[] = []; + clusterPageMenuRegistry.getSubItems(menu.id).forEach((subItem) => { + const subPage = clusterPageRegistry.getByPageMenuTarget(subItem.target); + if (subPage) { + routes.push({ + routePath: subPage.id, + url: getExtensionPageUrl({ extensionId: subPage.extensionId, pageId: subPage.id, params: subItem.target.params }), + title: subItem.title, + component: subPage.components.Page, + exact: subPage.exact + }); + } + }); + if (routes.length > 0) { + routes.unshift({ + routePath: page.routePath, + url: getExtensionPageUrl({ extensionId: page.extensionId, pageId: page.id, params: menu.target.params }), + title: Overview, + component: page.components.Page, + exact: page.exact + }); + } + return routes; + } + render() { const { toggle, isPinned, className } = this.props; const query = namespaceStore.getContextParams(); @@ -191,17 +220,19 @@ export class Sidebar extends React.Component { > {this.renderCustomResources()} - {clusterPageMenuRegistry.getItems().map(({ title, target, components: { Icon } }) => { - const registeredPage = clusterPageRegistry.getByPageMenuTarget(target); + {clusterPageMenuRegistry.getRootItems().map((menuItem) => { + const registeredPage = clusterPageRegistry.getByPageMenuTarget(menuItem.target); if (!registeredPage) return; const { extensionId, id: pageId } = registeredPage; - const pageUrl = getExtensionPageUrl({ extensionId, pageId, params: target.params }); + const pageUrl = getExtensionPageUrl({ extensionId, pageId, params: menuItem.target.params }); const isActive = pageUrl === navigation.location.pathname; + const tabRoutes = this.getTabLayoutRoutes(menuItem, registeredPage) return ( } + text={menuItem.title} icon={} isActive={isActive} + subMenus={tabRoutes} /> ) })}