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:
parent
b7be386e6b
commit
cd7f906afc
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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("&")}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
@ -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)}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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 : "");
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user