1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

TabLayout should not be part of LensRuntimeRendererEnv (#1029)

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-10-06 14:38:28 +03:00 committed by GitHub
parent 2b6f283e1b
commit c78b071da3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 40 additions and 38 deletions

View File

@ -1,4 +1,4 @@
import { Button, DynamicPageType, Icon, IconProps, LensExtension, React } from "@lens/extensions"; import { Button, Icon, IconProps, LensExtension, React, DynamicPageType } from "@lens/extensions";
import { CoffeeDoodle } from "react-open-doodles"; import { CoffeeDoodle } from "react-open-doodles";
import path from "path"; import path from "path";
@ -8,7 +8,7 @@ export default class ExampleExtension extends LensExtension {
this.registerPage({ this.registerPage({
type: DynamicPageType.CLUSTER, type: DynamicPageType.CLUSTER,
path: "/extension-example", path: "/extension-example",
menuTitle: "Example Extension", title: "Example Extension",
components: { components: {
Page: () => <ExtensionPage extension={this}/>, Page: () => <ExtensionPage extension={this}/>,
MenuIcon: ExtensionIcon, MenuIcon: ExtensionIcon,
@ -33,19 +33,16 @@ export class ExtensionPage extends React.Component<{ extension: ExampleExtension
} }
render() { render() {
const { TabLayout } = this.props.extension.runtime.components;
const doodleStyle = { const doodleStyle = {
width: "200px" width: "200px"
} }
return ( return (
<TabLayout className="ExampleExtension"> <div className="ExampleExtension flex column gaps align-flex-start">
<div className="flex column gaps align-flex-start">
<div style={doodleStyle}><CoffeeDoodle accent="#3d90ce"/></div> <div style={doodleStyle}><CoffeeDoodle accent="#3d90ce"/></div>
<p>Hello from Example extension!</p> <p>Hello from Example extension!</p>
<p>File: <i>{__filename}</i></p> <p>File: <i>{__filename}</i></p>
<Button accent label="Deactivate" onClick={this.deactivate}/> <Button accent label="Deactivate" onClick={this.deactivate}/>
</div> </div>
</TabLayout>
) )
} }
} }

View File

@ -1,12 +1,13 @@
// Lens-extensions api developer's kit // Lens-extensions api developer's kit
export type { LensRuntimeRendererEnv } from "./lens-runtime"; // TODO: add more common re-usable UI components + refactor interfaces (Props -> ComponentProps)
// TODO: figure out how to import as normal npm-package
export { default as React } from "react"
// APIs
export * from "./lens-extension" export * from "./lens-extension"
export { LensRuntimeRendererEnv } from "./lens-runtime";
export { DynamicPageType } from "./register-page"; export { DynamicPageType } from "./register-page";
// TODO: add more common re-usable UI components + refactor interfaces (Props -> ComponentProps)
export { default as React } from "react"
export * from "../renderer/components/icon" export * from "../renderer/components/icon"
export * from "../renderer/components/tooltip" export * from "../renderer/components/tooltip"
export * from "../renderer/components/button" export * from "../renderer/components/button"

View File

@ -1,17 +1,13 @@
// Lens renderer runtime params available to extensions after activation // Lens renderer runtime apis exposed to extensions once activated
import logger from "../main/logger"; import logger from "../main/logger";
import { dynamicPages } from "./register-page"; import { dynamicPages } from "./register-page";
import { TabLayout } from "../renderer/components/layout/tab-layout";
import { navigate } from "../renderer/navigation"; import { navigate } from "../renderer/navigation";
export interface LensRuntimeRendererEnv { export interface LensRuntimeRendererEnv {
navigate: typeof navigate; navigate: typeof navigate;
logger: typeof logger; logger: typeof logger;
dynamicPages: typeof dynamicPages dynamicPages: typeof dynamicPages
components: {
TabLayout: typeof TabLayout
}
} }
export function getLensRuntime(): LensRuntimeRendererEnv { export function getLensRuntime(): LensRuntimeRendererEnv {
@ -19,8 +15,5 @@ export function getLensRuntime(): LensRuntimeRendererEnv {
logger, logger,
navigate, navigate,
dynamicPages, dynamicPages,
components: {
TabLayout // fixme: refactor, import as pure component from "@lens/extensions"
}
} }
} }

View File

@ -2,18 +2,24 @@
import { computed, observable } from "mobx"; import { computed, observable } from "mobx";
import React from "react"; import React from "react";
import type { IconProps } from "../renderer/components/icon"; import { RouteProps } from "react-router";
import { IconProps } from "../renderer/components/icon";
import { cssNames, IClassName } from "../renderer/utils";
import { TabLayout, TabRoute } from "../renderer/components/layout/tab-layout";
export enum DynamicPageType { export enum DynamicPageType {
GLOBAL = "lens-scope", GLOBAL = "lens-scope",
CLUSTER = "cluster-view-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 path: string; // route-path
menuTitle: string; title: React.ReactNode; // used in sidebar's & tabs-layout
type: DynamicPageType; type: DynamicPageType;
components: PageComponents; components: PageComponents;
subPages?: (PageRegistration & TabRoute)[];
} }
export interface PageComponents { export interface PageComponents {
@ -43,4 +49,15 @@ export class PagesStore {
} }
} }
export class DynamicPage extends React.Component<{ page: PageRegistration }> {
render() {
const { className, components: { Page }, subPages = [] } = this.props.page;
return (
<TabLayout className={cssNames("ExtensionPage", className)} tabs={subPages}>
<Page/>
</TabLayout>
)
}
}
export const dynamicPages = new PagesStore(); export const dynamicPages = new PagesStore();

View File

@ -36,7 +36,7 @@ import { getHostedCluster, getHostedClusterId } from "../../common/cluster-store
import logger from "../../main/logger"; import logger from "../../main/logger";
import { clusterIpc } from "../../common/cluster-ipc"; import { clusterIpc } from "../../common/cluster-ipc";
import { webFrame } from "electron"; import { webFrame } from "electron";
import { dynamicPages } from "../../extensions/register-page"; import { DynamicPage, dynamicPages } from "../../extensions/register-page";
@observer @observer
export class App extends React.Component { export class App extends React.Component {
@ -74,8 +74,8 @@ export class App extends React.Component {
<Route component={CustomResources} {...crdRoute}/> <Route component={CustomResources} {...crdRoute}/>
<Route component={UserManagement} {...usersManagementRoute}/> <Route component={UserManagement} {...usersManagementRoute}/>
<Route component={Apps} {...appsRoute}/> <Route component={Apps} {...appsRoute}/>
{dynamicPages.clusterPages.map(({ path, components: { Page } }) => { {dynamicPages.clusterPages.map(page => {
return <Route key={path} path={path} component={Page}/> return <Route {...page} key={page.path} render={() => <DynamicPage page={page}/>}/>
})} })}
<Redirect exact from="/" to={this.startURL}/> <Redirect exact from="/" to={this.startURL}/>
<Route component={NotFound}/> <Route component={NotFound}/>

View File

@ -184,14 +184,14 @@ export class Sidebar extends React.Component<Props> {
> >
{this.renderCustomResources()} {this.renderCustomResources()}
</SidebarNavItem> </SidebarNavItem>
{dynamicPages.clusterPages.map(({ path, menuTitle, components: { MenuIcon } }) => { {dynamicPages.clusterPages.map(({ path, title, components: { MenuIcon } }) => {
return ( return (
<SidebarNavItem <SidebarNavItem
key={path} key={path}
id={`extension-${path}`} id={`extension-${path}`}
url={path} url={path}
routePath={path} routePath={path}
text={menuTitle} text={title}
icon={<MenuIcon/>} icon={<MenuIcon/>}
/> />
) )

View File

@ -1,5 +1,4 @@
import "./tab-layout.scss"; import "./tab-layout.scss";
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { matchPath, RouteProps } from "react-router-dom"; import { matchPath, RouteProps } from "react-router-dom";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
@ -7,7 +6,6 @@ import { cssNames } from "../../utils";
import { Tab, Tabs } from "../tabs"; import { Tab, Tabs } from "../tabs";
import { ErrorBoundary } from "../error-boundary"; import { ErrorBoundary } from "../error-boundary";
import { navigate, navigation } from "../../navigation"; import { navigate, navigation } from "../../navigation";
import { getHostedCluster } from "../../../common/cluster-store";
export interface TabRoute extends RouteProps { export interface TabRoute extends RouteProps {
title: React.ReactNode; title: React.ReactNode;
@ -23,10 +21,6 @@ interface Props {
export const TabLayout = observer(({ className, contentClass, tabs, children }: Props) => { export const TabLayout = observer(({ className, contentClass, tabs, children }: Props) => {
const routePath = navigation.location.pathname; const routePath = navigation.location.pathname;
const cluster = getHostedCluster();
if (!cluster) {
return null; // fix: skip render when removing active (visible) cluster
}
return ( return (
<div className={cssNames("TabLayout", className)}> <div className={cssNames("TabLayout", className)}>
{tabs && ( {tabs && (