diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index 3224b08fd3..1772694137 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -2,7 +2,7 @@ import React from "react"; import { observer } from "mobx-react"; import { Redirect, Route, Switch } from "react-router"; import { TabLayout, TabLayoutRoute } from "../layout/tab-layout"; -import { crdResourcesRoute, crdRoute, crdURL, crdDefinitionsRoute } from "./crd.route"; +import { crdDefinitionsRoute, crdResourcesRoute, crdURL } from "./crd.route"; import { CrdList } from "./crd-list"; import { CrdResources } from "./crd-resources"; @@ -14,7 +14,7 @@ export class CustomResources extends React.Component { title: "Definitions", component: CustomResources, url: crdURL(), - routePath: crdRoute.path.toString(), + routePath: String(crdDefinitionsRoute.path), } ]; } diff --git a/src/renderer/components/layout/sidebar-item.tsx b/src/renderer/components/layout/sidebar-item.tsx index e2eb942db4..3dd1302d85 100644 --- a/src/renderer/components/layout/sidebar-item.tsx +++ b/src/renderer/components/layout/sidebar-item.tsx @@ -6,19 +6,18 @@ import { cssNames, prevDefault } from "../../utils"; import { observer } from "mobx-react"; import { NavLink } from "react-router-dom"; import { Icon } from "../icon"; -import { TabLayoutRoute } from "./tab-layout"; import { sidebarStorage } from "./sidebar-storage"; import { isActiveRoute } from "../../navigation"; interface SidebarItemProps { - id: string; // Used to save nav item collapse/expand state in local storage + id: string; // unique id, used in storage and integration tests url: string; - text: React.ReactNode | string; className?: string; + title: React.ReactNode; icon?: React.ReactNode; isHidden?: boolean; - isActive?: boolean; - subMenus?: TabLayoutRoute[]; + isActive?: boolean; // marks a link, by default checks `props.url` to identify active state + subMenu?: React.ReactNode | React.ComponentType[]; // props.children could be used too } @observer @@ -26,22 +25,30 @@ export class SidebarItem extends React.Component { static displayName = "SidebarItem"; get id(): string { - return this.props.id; // unique id, used in storage and integration tests + return this.props.id; } - get compact(): boolean { + @computed get compact(): boolean { return Boolean(sidebarStorage.get().compact); } - get expanded(): boolean { + @computed get expanded(): boolean { return Boolean(sidebarStorage.get().expanded[this.id]); } - @computed get isExpandable(): boolean { - const { subMenus, children } = this.props; - const hasContent = subMenus?.length > 0 || children; + @computed get isActive(): boolean { + return this.props.isActive ?? isActiveRoute({ + path: this.props.url, + exact: true, + }); + } - return Boolean(hasContent && !this.compact) /*not available in compact-mode*/; + @computed get isExpandable(): boolean { + if (this.compact) { + return false; // not available currently + } + + return Boolean(this.props.subMenu || this.props.children); } toggleExpand = () => { @@ -51,11 +58,11 @@ export class SidebarItem extends React.Component { }; render() { - const { isHidden, isActive, subMenus = [], icon, text, children, url, className } = this.props; + const { isHidden, icon, title, children, url, className, subMenu } = this.props; if (isHidden) return null; - const { id, compact, expanded, isExpandable, toggleExpand } = this; + const { isActive, id, compact, expanded, isExpandable, toggleExpand } = this; const classNames = cssNames(SidebarItem.displayName, className, { compact, }); @@ -68,7 +75,7 @@ export class SidebarItem extends React.Component { className={cssNames("nav-item flex gaps align-center", { expandable: isExpandable })} onClick={isExpandable ? prevDefault(toggleExpand) : undefined}> {icon} - {text} + {title} {isExpandable && { {isExpandable && expanded && (
    - {subMenus.map(({ title, routePath, url = routePath }) => { - const subItemId = `${id}${routePath}`; - - return ( - - ); - })} + {subMenu} {children}
)} diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 7f0ddd818f..7db46d903b 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -1,7 +1,8 @@ import "./sidebar.scss"; +import type { TabLayoutRoute } from "./tab-layout"; import React from "react"; -import type { TabLayoutRoute } from "./tab-layout"; +import { computed } from "mobx"; import { observer } from "mobx-react"; import { NavLink } from "react-router-dom"; import { cssNames } from "../../utils"; @@ -22,7 +23,7 @@ import { UserManagement } from "../+user-management"; import { Storage } from "../+storage"; import { Network } from "../+network"; import { crdStore } from "../+custom-resources/crd.store"; -import { CrdList, crdResourcesRoute, crdRoute, crdURL } from "../+custom-resources"; +import { crdRoute, crdURL } from "../+custom-resources"; import { CustomResources } from "../+custom-resources/custom-resources"; import { isActiveRoute } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac"; @@ -44,29 +45,50 @@ export class Sidebar extends React.Component { crdStore.reloadAll(); } - renderCustomResources() { - if (crdStore.isLoading) { + @computed get crdSubMenu(): React.ReactNode { + if (!crdStore.isLoaded) { return ; } return Object.entries(crdStore.groups).map(([group, crds]) => { - const submenus: TabLayoutRoute[] = crds.map((crd) => { - return { - title: crd.getResourceKind(), - component: CrdList, - url: crd.getResourceUrl(), - routePath: String(crdResourcesRoute.path), - }; + const crdGroupSubMenu: React.ReactNode = crds.map((crd) => { + return ( + + ); }); return ( + ); + }); + } + + renderTreeFromTabRoutes(tabRoutes: TabLayoutRoute[] = []): React.ReactNode { + if (!tabRoutes.length) { + return null; + } + + return tabRoutes.map(({ title, routePath, url = routePath, exact = true }) => { + const subMenuItemId = `tab-route-item-${url}`; + + return ( + ); }); @@ -122,10 +144,10 @@ export class Sidebar extends React.Component { key={id} id={id} url={pageUrl} - text={menuItem.title} - icon={} isActive={isActive} - subMenus={tabRoutes} + title={menuItem.title} + icon={} + subMenu={this.renderTreeFromTabRoutes(tabRoutes)} /> ); }); @@ -153,98 +175,98 @@ export class Sidebar extends React.Component {
} /> } /> } + subMenu={this.renderTreeFromTabRoutes(Workloads.tabRoutes)} /> } + subMenu={this.renderTreeFromTabRoutes(Config.tabRoutes)} /> } + subMenu={this.renderTreeFromTabRoutes(Network.tabRoutes)} /> } - text="Storage" + subMenu={this.renderTreeFromTabRoutes(Storage.tabRoutes)} /> } - text="Namespaces" /> } - text="Events" /> } - text="Apps" /> } - text="Access Control" + subMenu={this.renderTreeFromTabRoutes(UserManagement.tabRoutes)} /> } - text="Custom Resources" > - {this.renderCustomResources()} + {this.renderTreeFromTabRoutes(CustomResources.tabRoutes)} + {this.crdSubMenu} {this.renderRegisteredMenus()}