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

fixes, tweak example-extension for demo

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-12-03 19:41:53 +02:00
parent b7be386e6b
commit cd7f906afc
9 changed files with 70 additions and 47 deletions

View File

@ -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<string>({
name: "name",
defaultValue: "demo",
});
export function ExampleIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="pages" tooltip={path.basename(__filename)}/>;
}
@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 (
<div className="flex column gaps align-flex-start">
<div style={doodleStyle}><CoffeeDoodle accent="#3d90ce" /></div>
<div className="flex column gaps align-flex-start" style={{ padding: 24 }}>
<div style={doodleStyle}><CoffeeDoodle accent="#3d90ce"/></div>
<p>Hello from Example extension!</p>
<p>File: <i>{__filename}</i></p>
<Component.Button accent label="Deactivate" onClick={this.deactivate}/>
<p>Location: <i>{location.href}</i></p>
<p className="url-params-demo flex column gaps">
<a onClick={() => exampleNameUrlParam.set("secret")}>Show secret button</a>
{exampleName === "secret" && (
<Component.Button accent label="Deactivate" onClick={this.deactivate}/>
)}
</p>
</div>
);
}

View File

@ -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: () => <ExamplePage extension={this}/>,
}
},
params: [
exampleNameUrlParam,
]
}
];
clusterPageMenus = [
{
target: { pageId: "example", params: {} },
target: { pageId: "example" },
title: "Example Extension",
components: {
Icon: ExampleIcon,

View File

@ -29,7 +29,7 @@ export interface PageComponents {
export interface PageTarget<P = {}> {
extensionId?: string;
pageId?: string;
params?: Record<string, any | any[]> & P;
params?: Record<string, any | any[]> & P; // default target page params
}
export interface RegisteredPage extends PageRegistration {
@ -38,24 +38,21 @@ export interface RegisteredPage extends PageRegistration {
}
export function getExtensionPageUrl<P extends object>(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("&")}`;
}
}

View File

@ -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";

View File

@ -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,
});
}

View File

@ -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<Props> {
<div className="extensions">
{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 (
<Icon
key={pageUrl}
tooltip={title}
active={isActiveRoute(pageUrl)}
active={isActive}
onClick={() => navigate(pageUrl)}
/>
);

View File

@ -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);

View File

@ -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<SidebarContextValue>({ pinned: false });
@ -84,13 +84,14 @@ export class Sidebar extends React.Component<Props> {
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<Props> {
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));
}

View File

@ -54,7 +54,7 @@ export class UrlParam<V = any | any[]> {
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<V = any | any[]> {
}
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 : "");