Navigation refactoring, handling extension page params (#1651)

* decentralizing page url-params management -- PoC / tsc 4.1 random fixes

Signed-off-by: Roman <ixrock@gmail.com>

* fixes, tweak example-extension for demo

Signed-off-by: Roman <ixrock@gmail.com>

* lint fixes, revert tests

Signed-off-by: Roman <ixrock@gmail.com>

* removed occasional changes related to typescript 4.1

Signed-off-by: Roman <ixrock@gmail.com>

* updated example with 2 menu-items targeting same page with different params

Signed-off-by: Roman <ixrock@gmail.com>

* fix: merge page url chunks with native URL()-api, simplified default page-params registration

Signed-off-by: Roman <ixrock@gmail.com>

* fix: make lint happy

Signed-off-by: Roman <ixrock@gmail.com>

* fix: unit-tests

Signed-off-by: Roman <ixrock@gmail.com>

* renaming by jim's request: UrlParam => PageParam (type), createUrlParam => createPageParam (helper)

Signed-off-by: Roman <ixrock@gmail.com>

* fix: reverting NamespaceStore public-api breaking changes

Signed-off-by: Roman <ixrock@gmail.com>

* lint fix

Signed-off-by: Roman <ixrock@gmail.com>

* fine-tuning

Signed-off-by: Roman <ixrock@gmail.com>

* yes, lint always unhappy

Signed-off-by: Roman <ixrock@gmail.com>

* fix build

Signed-off-by: Roman <ixrock@gmail.com>

* small fixes

Signed-off-by: Roman <ixrock@gmail.com>

* fix merge-conflicts

Signed-off-by: Roman <ixrock@gmail.com>

* removed `isSystem` page-param's init field exposed to extensions-api

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman authored and GitHub committed 2020-12-22 15:29:25 +02:00
1 parent 11c611dabe
commit be4e1aa15c
64 files changed
+751 -518

No files matched your search

+49 -15
View File
@@ -1,30 +1,64 @@
import { LensRendererExtension, Component } from "@k8slens/extensions";
import { CoffeeDoodle } from "react-open-doodles";
import path from "path";
import React from "react";
import { observer } from "mobx-react";
import { CoffeeDoodle } from "react-open-doodles";
import { Component, Interface, K8sApi, LensRendererExtension } from "@k8slens/extensions";
export function ExampleIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="pages" tooltip={path.basename(__filename)}/>;
export interface ExamplePageProps extends Interface.PageComponentProps<ExamplePageParams> {
extension: LensRendererExtension; // provided in "./renderer.tsx"
}
export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> {
export interface ExamplePageParams {
exampleId: string;
selectedNamespaces: K8sApi.Namespace[];
}
export const namespaceStore = K8sApi.apiManager.getStore<K8sApi.NamespaceStore>(K8sApi.namespacesApi);
@observer
export class ExamplePage extends React.Component<ExamplePageProps> {
async componentDidMount() {
await namespaceStore.loadAll();
}
deactivate = () => {
const { extension } = this.props;
extension.disable();
};
render() {
const doodleStyle = {
width: "200px"
};
renderSelectedNamespaces() {
const { selectedNamespaces } = this.props.params;
return (
<div className="flex column gaps align-flex-start">
<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}/>
<div className="flex gaps inline">
{selectedNamespaces.get().map(ns => {
const name = ns.getName();
return <Component.Badge key={name} label={name} tooltip={`Created: ${ns.getAge()}`}/>;
})}
</div>
);
}
render() {
const { exampleId } = this.props.params;
return (
<div className="flex column gaps align-flex-start" style={{ padding: 24 }}>
<div style={{ width: 200 }}>
<CoffeeDoodle accent="#3d90ce"/>
</div>
<div>Hello from Example extension!</div>
<div>Location: <i>{location.href}</i></div>
<div>Namespaces: {this.renderSelectedNamespaces()}</div>
<p className="url-params-demo flex column gaps">
<a onClick={() => exampleId.set("secret")}>Show secret button</a>
{exampleId.get() === "secret" && (
<Component.Button accent label="Deactivate" onClick={this.deactivate}/>
)}
</p>
</div>
);
}
+31 -11
View File
@@ -1,25 +1,45 @@
import { LensRendererExtension } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page";
import { Component, Interface, K8sApi, LensRendererExtension } from "@k8slens/extensions";
import { ExamplePage, ExamplePageParams, namespaceStore } from "./page";
import React from "react";
import path from "path";
export default class ExampleExtension extends LensRendererExtension {
clusterPages = [
clusterPages: Interface.PageRegistration[] = [
{
id: "example",
title: "Example Extension",
components: {
Page: () => <ExamplePage extension={this}/>,
Page: (props: Interface.PageComponentProps<ExamplePageParams>) => {
return <ExamplePage {...props} extension={this}/>;
},
},
params: {
// setup basic param "exampleId" with default value "demo"
exampleId: "demo",
// setup advanced multi-values param "selectedNamespaces" with custom parsing/stringification
selectedNamespaces: {
defaultValueStringified: ["default", "kube-system"],
multiValues: true,
parse(values: string[]) { // from URL
return values.map(name => namespaceStore.getByName(name)).filter(Boolean);
},
stringify(values: K8sApi.Namespace[]) { // to URL
return values.map(namespace => namespace.getName());
},
}
}
}
];
clusterPageMenus = [
clusterPageMenus: Interface.ClusterPageMenuRegistration[] = [
{
target: { pageId: "example", params: {} },
title: "Example Extension",
title: "Example extension",
components: {
Icon: ExampleIcon,
}
}
},
},
];
}
export function ExampleIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="pages" tooltip={path.basename(__filename)}/>;
}