From cd7f906afcbbc0bdc43402daab98da0e9c710220 Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 3 Dec 2020 19:41:53 +0200 Subject: [PATCH] fixes, tweak example-extension for demo Signed-off-by: Roman --- extensions/example-extension/page.tsx | 27 ++++++++++++++----- extensions/example-extension/renderer.tsx | 9 ++++--- src/extensions/registries/page-registry.ts | 27 +++++++++---------- src/extensions/renderer-api/navigation.ts | 2 +- src/renderer/components/app.tsx | 10 +++---- .../cluster-manager/clusters-menu.tsx | 11 +++++--- .../kube-object/kube-object-details.tsx | 2 +- src/renderer/components/layout/sidebar.tsx | 17 ++++++------ src/renderer/navigation/url-param.ts | 12 ++++++--- 9 files changed, 70 insertions(+), 47 deletions(-) diff --git a/extensions/example-extension/page.tsx b/extensions/example-extension/page.tsx index 3318cafc00..66e55e354b 100644 --- a/extensions/example-extension/page.tsx +++ b/extensions/example-extension/page.tsx @@ -1,12 +1,19 @@ -import { LensRendererExtension, Component } from "@k8slens/extensions"; +import { Component, LensRendererExtension, Navigation } from "@k8slens/extensions"; import { CoffeeDoodle } from "react-open-doodles"; -import path from "path"; import React from "react"; +import path from "path"; +import { observer } from "mobx-react"; + +export const exampleNameUrlParam = Navigation.createUrlParam({ + name: "name", + defaultValue: "demo", +}); export function ExampleIcon(props: Component.IconProps) { return ; } +@observer export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> { deactivate = () => { const { extension } = this.props; @@ -15,16 +22,24 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens }; render() { + const exampleName = exampleNameUrlParam.get(); const doodleStyle = { width: "200px" }; - return ( -
-
+
+
+

Hello from Example extension!

File: {__filename}

- +

Location: {location.href}

+ +

+ exampleNameUrlParam.set("secret")}>Show secret button + {exampleName === "secret" && ( + + )} +

); } diff --git a/extensions/example-extension/renderer.tsx b/extensions/example-extension/renderer.tsx index 1a7d473ecd..329ba7921b 100644 --- a/extensions/example-extension/renderer.tsx +++ b/extensions/example-extension/renderer.tsx @@ -1,5 +1,5 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import { ExampleIcon, ExamplePage } from "./page"; +import { ExampleIcon, ExamplePage, exampleNameUrlParam } from "./page"; import React from "react"; export default class ExampleExtension extends LensRendererExtension { @@ -9,13 +9,16 @@ export default class ExampleExtension extends LensRendererExtension { title: "Example Extension", components: { Page: () => , - } + }, + params: [ + exampleNameUrlParam, + ] } ]; clusterPageMenus = [ { - target: { pageId: "example", params: {} }, + target: { pageId: "example" }, title: "Example Extension", components: { Icon: ExampleIcon, diff --git a/src/extensions/registries/page-registry.ts b/src/extensions/registries/page-registry.ts index f59e6e4b9a..5e1ab3e811 100644 --- a/src/extensions/registries/page-registry.ts +++ b/src/extensions/registries/page-registry.ts @@ -29,7 +29,7 @@ export interface PageComponents { export interface PageTarget

{ extensionId?: string; pageId?: string; - params?: Record & P; + params?: Record & P; // default target page params } export interface RegisteredPage extends PageRegistration { @@ -38,24 +38,21 @@ export interface RegisteredPage extends PageRegistration { } export function getExtensionPageUrl

(target: PageTarget): string { - const { extensionId, pageId = "", params } = target; + const { extensionId, pageId = "", params: targetParams = {} } = target; let stringifiedParams = ""; // stringify params to matched target page - if (params) { - const page = globalPageRegistry.getByPageTarget(target) || clusterPageRegistry.getByPageTarget(target); - if (page?.params) { - const searchParams: string[] = []; - page.params.forEach(urlParam => { - const paramValue = params[urlParam.name]; - if (paramValue == undefined) return; - searchParams.push( - urlParam.toSearchString(paramValue, { mergeGlobals: false, withPrefix: false }) // e.g. "param=value" - ); + const page = globalPageRegistry.getByPageTarget(target) || clusterPageRegistry.getByPageTarget(target); + if (page?.params) { + const searchParams = page.params.map(urlParam => { + return urlParam.toSearchString({ + value: targetParams[urlParam.name] ?? urlParam.getDefaultValue(), + mergeGlobals: false, + withPrefix: false, }); - if (searchParams.length > 0) { - stringifiedParams = `?${searchParams.join("&")}`; - } + }); + if (searchParams.length > 0) { + stringifiedParams = `?${searchParams.join("&")}`; } } diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index 76623dd89f..4e281bc3de 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -1,3 +1,3 @@ -export { navigate, UrlParamInit, isActiveRoute, createUrlParam, UrlParam } from "../../renderer/navigation"; +export { createUrlParam, navigate, isActiveRoute, UrlParamInit, UrlParam } from "../../renderer/navigation"; export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/components/kube-object/kube-object-details"; export { IURLParams } from "../../common/utils/buildUrl"; diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index d8dacaa22a..f6c266f966 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -34,7 +34,7 @@ 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 } from "../../extensions/registries/page-registry"; import { extensionLoader } from "../../extensions/extension-loader"; import { appEventBus } from "../../common/event-bus"; import { broadcastMessage, requestMain } from "../../common/ipc"; @@ -126,14 +126,14 @@ export class App extends React.Component { if (!menuItem.id) { return routes; } - clusterPageMenuRegistry.getSubItems(menuItem).forEach((item) => { - const page = clusterPageRegistry.getByPageTarget(item.target); + clusterPageMenuRegistry.getSubItems(menuItem).forEach((subMenu) => { + const page = clusterPageRegistry.getByPageTarget(subMenu.target); if (page) { routes.push({ routePath: page.url, - url: page.url, - title: item.title, + url: getExtensionPageUrl(subMenu.target), + title: subMenu.title, component: page.components.Page, }); } diff --git a/src/renderer/components/cluster-manager/clusters-menu.tsx b/src/renderer/components/cluster-manager/clusters-menu.tsx index 21ed76b848..decea328de 100644 --- a/src/renderer/components/cluster-manager/clusters-menu.tsx +++ b/src/renderer/components/cluster-manager/clusters-menu.tsx @@ -22,7 +22,7 @@ import { landingURL } from "../+landing-page"; import { Tooltip } from "../tooltip"; import { ConfirmDialog } from "../confirm-dialog"; import { clusterViewURL } from "./cluster-view.route"; -import { globalPageMenuRegistry, globalPageRegistry } from "../../../extensions/registries"; +import { getExtensionPageUrl, globalPageMenuRegistry, globalPageRegistry } from "../../../extensions/registries"; import { clusterDisconnectHandler } from "../../../common/cluster-ipc"; interface Props { @@ -159,13 +159,16 @@ export class ClustersMenu extends React.Component {

{globalPageMenuRegistry.getItems().map(({ title, target, components: { Icon } }) => { const registeredPage = globalPageRegistry.getByPageTarget(target); - if (!registeredPage) return; - const { url: pageUrl } = registeredPage; + if (!registeredPage){ + return; + } + const pageUrl = getExtensionPageUrl(target); + const isActive = isActiveRoute(registeredPage.url); return ( navigate(pageUrl)} /> ); diff --git a/src/renderer/components/kube-object/kube-object-details.tsx b/src/renderer/components/kube-object/kube-object-details.tsx index 2652861227..24c716ec8f 100644 --- a/src/renderer/components/kube-object/kube-object-details.tsx +++ b/src/renderer/components/kube-object/kube-object-details.tsx @@ -37,7 +37,7 @@ export function hideDetails() { } export function getDetailsUrl(details: string, resetSelected = false) { - const detailsUrl = kubeDetailsUrlParam.toSearchString(details); + const detailsUrl = kubeDetailsUrlParam.toSearchString({ value: details }); if (resetSelected) { const params = new URLSearchParams(detailsUrl); params.delete(kubeSelectedUrlParam.name); diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index ff70384f97..a5fffe7d3c 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 } from "../../navigation"; import { isAllowedResource } from "../../../common/rbac"; import { Spinner } from "../spinner"; -import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry } from "../../../extensions/registries"; +import { ClusterPageMenuRegistration, clusterPageMenuRegistry, clusterPageRegistry, getExtensionPageUrl } from "../../../extensions/registries"; const SidebarContext = React.createContext({ pinned: false }); @@ -84,13 +84,14 @@ export class Sidebar extends React.Component { return routes; } - clusterPageMenuRegistry.getSubItems(menu).forEach((subItem) => { - const subPage = clusterPageRegistry.getByPageTarget(subItem.target); + clusterPageMenuRegistry.getSubItems(menu).forEach((subMenu) => { + const subPage = clusterPageRegistry.getByPageTarget(subMenu.target); if (subPage) { + const { extensionId, id: pageId } = subPage; routes.push({ routePath: subPage.url, - url: subPage.url, - title: subItem.title, + url: getExtensionPageUrl({ extensionId, pageId, params: subMenu.target.params }), + title: subMenu.title, component: subPage.components.Page, }); } @@ -106,12 +107,12 @@ export class Sidebar extends React.Component { return; } + let pageUrl = getExtensionPageUrl(menuItem.target); + let isActive = isActiveRoute(registeredPage.url); const tabRoutes = this.getTabLayoutRoutes(menuItem); - let pageUrl = registeredPage.url; - let isActive = isActiveRoute(pageUrl); if (tabRoutes.length > 0) { - pageUrl = (tabRoutes.find(tab => tab.default) || tabRoutes[0]).url; + pageUrl = tabRoutes[0].url; isActive = isActiveRoute(tabRoutes.map((tab) => tab.routePath)); } diff --git a/src/renderer/navigation/url-param.ts b/src/renderer/navigation/url-param.ts index 25f554c770..d138c46266 100644 --- a/src/renderer/navigation/url-param.ts +++ b/src/renderer/navigation/url-param.ts @@ -54,7 +54,7 @@ export class UrlParam { get(): V { const { history, urlName } = this; - const { multiValueSep, multiValues, defaultValue, skipEmpty } = this.init; + const { multiValueSep, defaultValue, skipEmpty } = this.init; const value = this.parse(history.searchParams.getAsArray(urlName, multiValueSep)); if (skipEmpty && this.isEmpty(value)) { @@ -64,19 +64,23 @@ export class UrlParam { } set(value: V, { mergeGlobals = true, replaceHistory = false } = {}) { - const search = this.toSearchString(value, { mergeGlobals }); + const search = this.toSearchString({ mergeGlobals, value }); this.history.merge({ search }, replaceHistory); } + getDefaultValue(){ + return this.init.defaultValue; + } + isDefault() { - return this.get() === this.init.defaultValue; + return this.get() === this.getDefaultValue(); } clear() { this.history.searchParams.delete(this.urlName); } - toSearchString(value = this.get(), { withPrefix = true, mergeGlobals = true } = {}): string { + toSearchString({ withPrefix = true, mergeGlobals = true, value = this.get() } = {}): string { const { history, urlName, init: { skipEmpty } } = this; const searchParams = new URLSearchParams(mergeGlobals ? history.location.search : "");