mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Update docs to be correct with the new api changes (#2916)
* Update docs to be correct with the new api changes Signed-off-by: Sebastian Malton <sebastian@malton.name> * Fix renderer-extension.md Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
a9761c4374
commit
0d0c67f13f
@ -14,9 +14,9 @@ In order to see logs from this extension, you need to start Lens from the comman
|
|||||||
This extension can register a custom callback that is executed when an extension is activated (started).
|
This extension can register a custom callback that is executed when an extension is activated (started).
|
||||||
|
|
||||||
``` javascript
|
``` javascript
|
||||||
import { LensMainExtension } from "@k8slens/extensions"
|
import { Main } from "@k8slens/extensions"
|
||||||
|
|
||||||
export default class ExampleMainExtension extends LensMainExtension {
|
export default class ExampleMainExtension extends Main.LensExtension {
|
||||||
async onActivate() {
|
async onActivate() {
|
||||||
console.log("hello world")
|
console.log("hello world")
|
||||||
}
|
}
|
||||||
@ -28,9 +28,9 @@ export default class ExampleMainExtension extends LensMainExtension {
|
|||||||
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
|
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
|
||||||
|
|
||||||
``` javascript
|
``` javascript
|
||||||
import { LensMainExtension } from "@k8slens/extensions"
|
import { Main } from "@k8slens/extensions"
|
||||||
|
|
||||||
export default class ExampleMainExtension extends LensMainExtension {
|
export default class ExampleMainExtension extends Main.LensExtension {
|
||||||
async onDeactivate() {
|
async onDeactivate() {
|
||||||
console.log("bye bye")
|
console.log("bye bye")
|
||||||
}
|
}
|
||||||
@ -44,15 +44,15 @@ This extension can register custom app menus that will be displayed on OS native
|
|||||||
Example:
|
Example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensMainExtension, windowManager } from "@k8slens/extensions"
|
import { Main } from "@k8slens/extensions"
|
||||||
|
|
||||||
export default class ExampleMainExtension extends LensMainExtension {
|
export default class ExampleMainExtension extends Main.LensExtension {
|
||||||
appMenus = [
|
appMenus = [
|
||||||
{
|
{
|
||||||
parentId: "help",
|
parentId: "help",
|
||||||
label: "Example item",
|
label: "Example item",
|
||||||
click() {
|
click() {
|
||||||
windowManager.navigate("https://k8slens.dev");
|
Main.Navigation.navigate("https://k8slens.dev");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -69,9 +69,9 @@ In order to see logs from this extension you need to check them via **View** > *
|
|||||||
This extension can register a custom callback that is executed when an extension is activated (started).
|
This extension can register a custom callback that is executed when an extension is activated (started).
|
||||||
|
|
||||||
``` javascript
|
``` javascript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
async onActivate() {
|
async onActivate() {
|
||||||
console.log("hello world")
|
console.log("hello world")
|
||||||
}
|
}
|
||||||
@ -83,9 +83,9 @@ export default class ExampleExtension extends LensRendererExtension {
|
|||||||
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
|
This extension can register a custom callback that is executed when an extension is deactivated (stopped).
|
||||||
|
|
||||||
``` javascript
|
``` javascript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
|
|
||||||
export default class ExampleMainExtension extends LensRendererExtension {
|
export default class ExampleMainExtension extends Renderer.LensExtension {
|
||||||
async onDeactivate() {
|
async onDeactivate() {
|
||||||
console.log("bye bye")
|
console.log("bye bye")
|
||||||
}
|
}
|
||||||
@ -99,10 +99,16 @@ The global page is a full-screen page that hides all other content from a window
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { Component, LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
import { ExamplePage } from "./src/example-page"
|
import { ExamplePage } from "./src/example-page"
|
||||||
|
|
||||||
export default class ExampleRendererExtension extends LensRendererExtension {
|
const {
|
||||||
|
Component: {
|
||||||
|
Icon,
|
||||||
|
}
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||||
globalPages = [
|
globalPages = [
|
||||||
{
|
{
|
||||||
id: "example",
|
id: "example",
|
||||||
@ -117,7 +123,7 @@ export default class ExampleRendererExtension extends LensRendererExtension {
|
|||||||
title: "Example page", // used in icon's tooltip
|
title: "Example page", // used in icon's tooltip
|
||||||
target: { pageId: "example" }
|
target: { pageId: "example" }
|
||||||
components: {
|
components: {
|
||||||
Icon: () => <Component.Icon material="arrow"/>,
|
Icon: () => <Icon material="arrow"/>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -131,12 +137,12 @@ It is responsible for storing a state for custom preferences.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
import { myCustomPreferencesStore } from "./src/my-custom-preferences-store"
|
import { myCustomPreferencesStore } from "./src/my-custom-preferences-store"
|
||||||
import { MyCustomPreferenceHint, MyCustomPreferenceInput } from "./src/my-custom-preference"
|
import { MyCustomPreferenceHint, MyCustomPreferenceInput } from "./src/my-custom-preference"
|
||||||
|
|
||||||
|
|
||||||
export default class ExampleRendererExtension extends LensRendererExtension {
|
export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||||
appPreferences = [
|
appPreferences = [
|
||||||
{
|
{
|
||||||
title: "My Custom Preference",
|
title: "My Custom Preference",
|
||||||
@ -156,10 +162,10 @@ These pages are visible in a cluster menu when a cluster is opened.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExampleIcon, ExamplePage } from "./src/page"
|
import { ExampleIcon, ExamplePage } from "./src/page"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterPages = [
|
clusterPages = [
|
||||||
{
|
{
|
||||||
id: "extension-example", // optional
|
id: "extension-example", // optional
|
||||||
@ -190,10 +196,10 @@ These features are visible in the "Cluster Settings" page.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
import { MyCustomFeature } from "./src/my-custom-feature"
|
import { MyCustomFeature } from "./src/my-custom-feature"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterFeatures = [
|
clusterFeatures = [
|
||||||
{
|
{
|
||||||
title: "My Custom Feature",
|
title: "My Custom Feature",
|
||||||
@ -219,15 +225,21 @@ This extension can register custom icons and text to a status bar area.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Component, LensRendererExtension, Navigation } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
const {
|
||||||
|
Component: {
|
||||||
|
Icon,
|
||||||
|
}
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
statusBarItems = [
|
statusBarItems = [
|
||||||
{
|
{
|
||||||
components: {
|
components: {
|
||||||
Item: (
|
Item: (
|
||||||
<div className="flex align-center gaps hover-highlight" onClick={() => this.navigate("/example-page")} >
|
<div className="flex align-center gaps hover-highlight" onClick={() => this.navigate("/example-page")} >
|
||||||
<Component.Icon material="favorite" />
|
<Icon material="favorite" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -243,10 +255,10 @@ This extension can register custom menu items (actions) for specified Kubernetes
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { CustomMenuItem, CustomMenuItemProps } from "./src/custom-menu-item"
|
import { CustomMenuItem, CustomMenuItemProps } from "./src/custom-menu-item"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
kubeObjectMenuItems = [
|
kubeObjectMenuItems = [
|
||||||
{
|
{
|
||||||
kind: "Node",
|
kind: "Node",
|
||||||
@ -266,10 +278,10 @@ This extension can register custom details (content) for specified Kubernetes ki
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { CustomKindDetails, CustomKindDetailsProps } from "./src/custom-kind-details"
|
import { CustomKindDetails, CustomKindDetailsProps } from "./src/custom-kind-details"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
kubeObjectDetailItems = [
|
kubeObjectDetailItems = [
|
||||||
{
|
{
|
||||||
kind: "CustomKind",
|
kind: "CustomKind",
|
||||||
|
|||||||
@ -114,14 +114,14 @@ There is a way of detect active theme and its changes in JS. [MobX observer func
|
|||||||
```js
|
```js
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { observer } from "mobx-react"
|
import { observer } from "mobx-react"
|
||||||
import { App, Component, Theme } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class SupportPage extends React.Component {
|
export class SupportPage extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="SupportPage">
|
<div className="SupportPage">
|
||||||
<h1>Active theme is {Theme.getActiveTheme().name}</h1>
|
<h1>Active theme is {Renderer.Theme.getActiveTheme().name}</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,11 +96,11 @@ It also registers the `MenuItem` component that displays the `ExampleIcon` React
|
|||||||
These React components are defined in the additional `./src/page.tsx` file.
|
These React components are defined in the additional `./src/page.tsx` file.
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExampleIcon, ExamplePage } from "./page"
|
import { ExampleIcon, ExamplePage } from "./page"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterPages = [
|
clusterPages = [
|
||||||
{
|
{
|
||||||
id: "extension-example",
|
id: "extension-example",
|
||||||
|
|||||||
@ -30,9 +30,8 @@ Each guide or code sample includes the following:
|
|||||||
|
|
||||||
| Sample | APIs |
|
| Sample | APIs |
|
||||||
| ----- | ----- |
|
| ----- | ----- |
|
||||||
[hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> Component.IconProps |
|
[hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
|
||||||
[minikube](https://github.com/lensapp/lens-extension-samples/tree/master/minikube-sample) | LensMainExtension <br> Store.ClusterStore <br> Store.workspaceStore |
|
[styling-css-modules-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-css-modules-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
|
||||||
[styling-css-modules-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-css-modules-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> Component.IconProps |
|
[styling-emotion-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-emotion-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
|
||||||
[styling-emotion-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-emotion-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> Component.IconProps |
|
[styling-sass-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-sass-sample) | LensMainExtension <br> LensRendererExtension <br> Renderer.Component.Icon <br> Renderer.Component.IconProps |
|
||||||
[styling-sass-sample](https://github.com/lensapp/lens-extension-samples/tree/master/styling-sass-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> Component.IconProps |
|
[custom-resource-page](https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page) | LensRendererExtension <br> Renderer.K8sApi.KubeApi <br> Renderer.K8sApi.KubeObjectStore <br> Renderer.Component.KubeObjectListLayout <br> Renderer.Component.KubeObjectDetailsProps <br> Renderer.Component.IconProps |
|
||||||
[custom-resource-page](https://github.com/lensapp/lens-extension-samples/tree/master/custom-resource-page) | LensRendererExtension <br> K8sApi.KubeApi <br> K8sApi.KubeObjectStore <br> Component.KubeObjectListLayout <br> Component.KubeObjectDetailsProps <br> Component.IconProps |
|
|
||||||
|
|||||||
@ -43,10 +43,10 @@ To register either a handler or a listener, you should do something like the fol
|
|||||||
|
|
||||||
`main.ts`:
|
`main.ts`:
|
||||||
```typescript
|
```typescript
|
||||||
import { LensMainExtension } from "@k8slens/extensions";
|
import { Main } from "@k8slens/extensions";
|
||||||
import { IpcMain } from "./helpers/main";
|
import { IpcMain } from "./helpers/main";
|
||||||
|
|
||||||
export class ExampleExtensionMain extends LensMainExtension {
|
export class ExampleExtensionMain extends Main.LensExtension {
|
||||||
onActivate() {
|
onActivate() {
|
||||||
IpcMain.createInstance(this);
|
IpcMain.createInstance(this);
|
||||||
}
|
}
|
||||||
@ -60,10 +60,10 @@ Lens will automatically clean up that store and all the handlers on deactivation
|
|||||||
|
|
||||||
`helpers/main.ts`:
|
`helpers/main.ts`:
|
||||||
```typescript
|
```typescript
|
||||||
import { Ipc, Types } from "@k8slens/extensions";
|
import { Main } from "@k8slens/extensions";
|
||||||
|
|
||||||
export class IpcMain extends Ipc.Main {
|
export class IpcMain extends Main.Ipc {
|
||||||
constructor(extension: LensMainExtension) {
|
constructor(extension: Main.LensExtension) {
|
||||||
super(extension);
|
super(extension);
|
||||||
|
|
||||||
this.listen("initialize", onInitialize);
|
this.listen("initialize", onInitialize);
|
||||||
@ -82,10 +82,10 @@ You should be able to just call `IpcMain.getInstance()` anywhere it is needed in
|
|||||||
|
|
||||||
`renderer.ts`:
|
`renderer.ts`:
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { IpcRenderer } from "./helpers/renderer";
|
import { IpcRenderer } from "./helpers/renderer";
|
||||||
|
|
||||||
export class ExampleExtensionRenderer extends LensRendererExtension {
|
export class ExampleExtensionRenderer extends Renderer.LensExtension {
|
||||||
onActivate() {
|
onActivate() {
|
||||||
const ipc = IpcRenderer.createInstance(this);
|
const ipc = IpcRenderer.createInstance(this);
|
||||||
|
|
||||||
@ -100,9 +100,9 @@ It is also needed to create an instance to broadcast messages too.
|
|||||||
|
|
||||||
`helpers/renderer.ts`:
|
`helpers/renderer.ts`:
|
||||||
```typescript
|
```typescript
|
||||||
import { Ipc } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
export class IpcRenderer extends Ipc.Renderer {}
|
export class IpcRenderer extends Renderer.Ipc {}
|
||||||
```
|
```
|
||||||
|
|
||||||
It is necessary to create child classes of these `abstract class`'s in your extension before you can use them.
|
It is necessary to create child classes of these `abstract class`'s in your extension before you can use them.
|
||||||
@ -116,7 +116,7 @@ There is no behind the scenes transfer of these functions.
|
|||||||
To register a "handler" call `IpcMain.getInstance().handle(...)`.
|
To register a "handler" call `IpcMain.getInstance().handle(...)`.
|
||||||
The cleanup of these handlers is handled by Lens itself.
|
The cleanup of these handlers is handled by Lens itself.
|
||||||
|
|
||||||
The `listen()` methods on `Ipc.Main` and `Ipc.Renderer` return a `Disposer`, or more specifically, a `() => void`.
|
The `listen()` methods on `Main.Ipc` and `Renderer.Ipc` return a `Disposer`, or more specifically, a `() => void`.
|
||||||
This can be optionally called to remove the listener early.
|
This can be optionally called to remove the listener early.
|
||||||
|
|
||||||
Calling either `IpcRenderer.getInstance().broadcast(...)` or `IpcMain.getInstance().broadcast(...)` sends an event to all `renderer` frames and to `main`.
|
Calling either `IpcRenderer.getInstance().broadcast(...)` or `IpcMain.getInstance().broadcast(...)` sends an event to all `renderer` frames and to `main`.
|
||||||
|
|||||||
@ -18,7 +18,7 @@ First thing we need to do with our extension is to register new menu item in the
|
|||||||
We will do this in our extension class `CrdSampleExtension` that is derived `LensRendererExtension` class:
|
We will do this in our extension class `CrdSampleExtension` that is derived `LensRendererExtension` class:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export default class CrdSampleExtension extends LensRendererExtension {
|
export default class CrdSampleExtension extends Renderer.LensExtension {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -27,11 +27,21 @@ This object will register a menu item with "Certificates" text.
|
|||||||
It will also use `CertificateIcon` component to render an icon and navigate to cluster page that is having `certificates` page id.
|
It will also use `CertificateIcon` component to render an icon and navigate to cluster page that is having `certificates` page id.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export function CertificateIcon(props: Component.IconProps) {
|
import { Renderer } from "@k8slens/extensions";
|
||||||
return <Component.Icon {...props} material="security" tooltip="Certificates"/>
|
|
||||||
|
type IconProps = Renderer.Component.IconProps;
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export function CertificateIcon(props: IconProps) {
|
||||||
|
return <Icon {...props} material="security" tooltip="Certificates"/>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class CrdSampleExtension extends LensRendererExtension {
|
export default class CrdSampleExtension extends Renderer.LensExtension {
|
||||||
|
|
||||||
clusterPageMenus = [
|
clusterPageMenus = [
|
||||||
{
|
{
|
||||||
@ -48,7 +58,7 @@ export default class CrdSampleExtension extends LensRendererExtension {
|
|||||||
Then we need to register `PageRegistration` object with `certificates` id and define `CertificatePage` component to render certificates.
|
Then we need to register `PageRegistration` object with `certificates` id and define `CertificatePage` component to render certificates.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export default class CrdSampleExtension extends LensRendererExtension {
|
export default class CrdSampleExtension extends Renderer.LensExtension {
|
||||||
...
|
...
|
||||||
|
|
||||||
clusterPages = [{
|
clusterPages = [{
|
||||||
@ -65,18 +75,29 @@ export default class CrdSampleExtension extends LensRendererExtension {
|
|||||||
|
|
||||||
In the previous step we defined `CertificatePage` component to render certificates.
|
In the previous step we defined `CertificatePage` component to render certificates.
|
||||||
In this step we will actually implement that.
|
In this step we will actually implement that.
|
||||||
`CertificatePage` is a React component that will render `Component.KubeObjectListLayout` component to list `Certificate` CRD objects.
|
`CertificatePage` is a React component that will render `Renderer.Component.KubeObjectListLayout` component to list `Certificate` CRD objects.
|
||||||
|
|
||||||
### Get CRD objects
|
### Get CRD objects
|
||||||
|
|
||||||
In order to list CRD objects, we need first fetch those from Kubernetes API.
|
In order to list CRD objects, we need first fetch those from Kubernetes API.
|
||||||
Lens Extensions API provides easy mechanism to do this.
|
Lens Extensions API provides easy mechanism to do this.
|
||||||
We just need to define `Certificate` class derived from `K8sApi.KubeObject`, `CertificatesApi`derived from `K8sApi.KubeApi` and `CertificatesStore` derived from `K8sApi.KubeObjectStore`.
|
We just need to define `Certificate` class derived from `Renderer.K8sApi.KubeObject`, `CertificatesApi`derived from `Renderer.K8sApi.KubeApi` and `CertificatesStore` derived from `Renderer.K8sApi.KubeObjectStore`.
|
||||||
|
|
||||||
`Certificate` class defines properties found in the CRD object:
|
`Certificate` class defines properties found in the CRD object:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export class Certificate extends K8sApi.KubeObject {
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
|
const {
|
||||||
|
K8sApi: {
|
||||||
|
KubeObject,
|
||||||
|
KubeObjectStore,
|
||||||
|
KubeApi,
|
||||||
|
apiManager,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export class Certificate extends KubeObject {
|
||||||
static kind = "Certificate"
|
static kind = "Certificate"
|
||||||
static namespaced = true
|
static namespaced = true
|
||||||
static apiBase = "/apis/cert-manager.io/v1alpha2/certificates"
|
static apiBase = "/apis/cert-manager.io/v1alpha2/certificates"
|
||||||
@ -121,8 +142,8 @@ export class Certificate extends K8sApi.KubeObject {
|
|||||||
With `CertificatesApi` class we are able to manage `Certificate` objects in Kubernetes API:
|
With `CertificatesApi` class we are able to manage `Certificate` objects in Kubernetes API:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export class CertificatesApi extends K8sApi.KubeApi<Certificate> {
|
export class CertificatesApi extends KubeApi<Certificate> {}
|
||||||
}
|
|
||||||
export const certificatesApi = new CertificatesApi({
|
export const certificatesApi = new CertificatesApi({
|
||||||
objectConstructor: Certificate
|
objectConstructor: Certificate
|
||||||
});
|
});
|
||||||
@ -131,7 +152,7 @@ export const certificatesApi = new CertificatesApi({
|
|||||||
`CertificateStore` defines storage for `Certificate` objects
|
`CertificateStore` defines storage for `Certificate` objects
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export class CertificatesStore extends K8sApi.KubeObjectStore<Certificate> {
|
export class CertificatesStore extends KubeObjectStore<Certificate> {
|
||||||
api = certificatesApi
|
api = certificatesApi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +162,7 @@ export const certificatesStore = new CertificatesStore();
|
|||||||
And, finally, we register this store to Lens's API manager.
|
And, finally, we register this store to Lens's API manager.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
K8sApi.apiManager.registerStore(certificatesStore);
|
apiManager.registerStore(certificatesStore);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
@ -153,23 +174,32 @@ Then we need to fetch those and render them in the UI.
|
|||||||
First we define `CertificatePage` class that extends `React.Component`.
|
First we define `CertificatePage` class that extends `React.Component`.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Component, LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { certificatesStore } from "../certificate-store";
|
import { certificatesStore } from "../certificate-store";
|
||||||
import { Certificate } from "../certificate"
|
import { Certificate } from "../certificate"
|
||||||
|
|
||||||
export class CertificatePage extends React.Component<{ extension: LensRendererExtension }> {
|
export class CertificatePage extends React.Component<{ extension: Renderer.LensExtension }> {
|
||||||
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Next we will implement `render` method that will display certificates in a list.
|
Next we will implement `render` method that will display certificates in a list.
|
||||||
To do that, we just need to add `Component.KubeObjectListLayout` component inside `Component.TabLayout` component in render method.
|
To do that, we just need to add `Renderer.Component.KubeObjectListLayout` component inside `Renderer.Component.TabLayout` component in render method.
|
||||||
To define which objects the list is showing, we need to pass `certificateStore` object to `Component.KubeObjectListLayout` in `store` property.
|
To define which objects the list is showing, we need to pass `certificateStore` object to `Renderer.Component.KubeObjectListLayout` in `store` property.
|
||||||
`Component.KubeObjectListLayout` will fetch automatically items from the given store when component is mounted.
|
`Renderer.Component.KubeObjectListLayout` will fetch automatically items from the given store when component is mounted.
|
||||||
Also, we can define needed sorting callbacks and search filters for the list:
|
Also, we can define needed sorting callbacks and search filters for the list:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
TabLayout,
|
||||||
|
KubeObjectListLayout,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
enum sortBy {
|
enum sortBy {
|
||||||
name = "name",
|
name = "name",
|
||||||
namespace = "namespace",
|
namespace = "namespace",
|
||||||
@ -181,8 +211,8 @@ export class CertificatePage extends React.Component<{ extension: LensRendererEx
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Component.TabLayout>
|
<TabLayout>
|
||||||
<Component.KubeObjectListLayout
|
<KubeObjectListLayout
|
||||||
className="Certicates" store={certificatesStore}
|
className="Certicates" store={certificatesStore}
|
||||||
sortingCallbacks={{
|
sortingCallbacks={{
|
||||||
[sortBy.name]: (certificate: Certificate) => certificate.getName(),
|
[sortBy.name]: (certificate: Certificate) => certificate.getName(),
|
||||||
@ -204,7 +234,7 @@ export class CertificatePage extends React.Component<{ extension: LensRendererEx
|
|||||||
certificate.spec.issuerRef.name
|
certificate.spec.issuerRef.name
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Component.TabLayout>
|
</TabLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +249,7 @@ First, we need to register our custom component to render details for the specif
|
|||||||
We will do this again in `CrdSampleExtension` class:
|
We will do this again in `CrdSampleExtension` class:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export default class CrdSampleExtension extends LensRendererExtension {
|
export default class CrdSampleExtension extends Renderer.LensExtension {
|
||||||
//...
|
//...
|
||||||
|
|
||||||
kubeObjectDetailItems = [{
|
kubeObjectDetailItems = [{
|
||||||
@ -235,14 +265,22 @@ export default class CrdSampleExtension extends LensRendererExtension {
|
|||||||
Here we defined that `CertificateDetails` component will render the resource details.
|
Here we defined that `CertificateDetails` component will render the resource details.
|
||||||
So, next we need to implement that component.
|
So, next we need to implement that component.
|
||||||
Lens will inject `Certificate` object into our component so we just need to render some information out of it.
|
Lens will inject `Certificate` object into our component so we just need to render some information out of it.
|
||||||
We can use `Component.DrawerItem` component from Lens Extensions API to give the same look and feel as Lens is using elsewhere:
|
We can use `Renderer.Component.DrawerItem` component from Lens Extensions API to give the same look and feel as Lens is using elsewhere:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Component, K8sApi } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Certificate } from "../certificate";
|
import { Certificate } from "../certificate";
|
||||||
|
|
||||||
export interface CertificateDetailsProps extends Component.KubeObjectDetailsProps<Certificate>{
|
const {
|
||||||
|
Component: {
|
||||||
|
KubeObjectDetailsProps,
|
||||||
|
DrawerItem,
|
||||||
|
Badge,
|
||||||
|
}
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export interface CertificateDetailsProps extends KubeObjectDetailsProps<Certificate>{
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CertificateDetails extends React.Component<CertificateDetailsProps> {
|
export class CertificateDetails extends React.Component<CertificateDetailsProps> {
|
||||||
@ -252,29 +290,29 @@ export class CertificateDetails extends React.Component<CertificateDetailsProps>
|
|||||||
if (!certificate) return null;
|
if (!certificate) return null;
|
||||||
return (
|
return (
|
||||||
<div className="Certificate">
|
<div className="Certificate">
|
||||||
<Component.DrawerItem name="Created">
|
<DrawerItem name="Created">
|
||||||
{certificate.getAge(true, false)} ago ({certificate.metadata.creationTimestamp })
|
{certificate.getAge(true, false)} ago ({certificate.metadata.creationTimestamp })
|
||||||
</Component.DrawerItem>
|
</DrawerItem>
|
||||||
<Component.DrawerItem name="DNS Names">
|
<DrawerItem name="DNS Names">
|
||||||
{certificate.spec.dnsNames.join(",")}
|
{certificate.spec.dnsNames.join(",")}
|
||||||
</Component.DrawerItem>
|
</DrawerItem>
|
||||||
<Component.DrawerItem name="Secret">
|
<DrawerItem name="Secret">
|
||||||
{certificate.spec.secretName}
|
{certificate.spec.secretName}
|
||||||
</Component.DrawerItem>
|
</DrawerItem>
|
||||||
<Component.DrawerItem name="Status" className="status" labelsOnly>
|
<DrawerItem name="Status" className="status" labelsOnly>
|
||||||
{certificate.status.conditions.map((condition, index) => {
|
{certificate.status.conditions.map((condition, index) => {
|
||||||
const { type, reason, message, status } = condition;
|
const { type, reason, message, status } = condition;
|
||||||
const kind = type || reason;
|
const kind = type || reason;
|
||||||
if (!kind) return null;
|
if (!kind) return null;
|
||||||
return (
|
return (
|
||||||
<Component.Badge
|
<Badge
|
||||||
key={kind + index} label={kind}
|
key={kind + index} label={kind}
|
||||||
className={"success "+kind.toLowerCase()}
|
className={"success "+kind.toLowerCase()}
|
||||||
tooltip={message}
|
tooltip={message}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Component.DrawerItem>
|
</DrawerItem>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,9 +11,9 @@ The Main Extension API allows you to access, configure, and customize Lens data,
|
|||||||
To create a main extension simply extend the `LensMainExtension` class:
|
To create a main extension simply extend the `LensMainExtension` class:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensMainExtension } from "@k8slens/extensions";
|
import { Main } from "@k8slens/extensions";
|
||||||
|
|
||||||
export default class ExampleExtensionMain extends LensMainExtension {
|
export default class ExampleExtensionMain extends Main.LensExtension {
|
||||||
onActivate() {
|
onActivate() {
|
||||||
console.log('custom main process extension code started');
|
console.log('custom main process extension code started');
|
||||||
}
|
}
|
||||||
@ -39,34 +39,6 @@ The example above logs messages when the extension is enabled and disabled.
|
|||||||
To see standard output from the main process there must be a console connected to it.
|
To see standard output from the main process there must be a console connected to it.
|
||||||
Achieve this by starting Lens from the command prompt.
|
Achieve this by starting Lens from the command prompt.
|
||||||
|
|
||||||
The following example is a little more interesting.
|
|
||||||
It accesses some Lens state data, and it periodically logs the name of the cluster that is currently active in Lens.
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { LensMainExtension, Store } from "@k8slens/extensions";
|
|
||||||
|
|
||||||
export default class ActiveClusterExtensionMain extends LensMainExtension {
|
|
||||||
|
|
||||||
timer: NodeJS.Timeout
|
|
||||||
|
|
||||||
onActivate() {
|
|
||||||
console.log("Cluster logger activated");
|
|
||||||
this.timer = setInterval(() => {
|
|
||||||
if (!Store.ClusterStore.getInstance().active) {
|
|
||||||
console.log("No active cluster");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("active cluster is", Store.ClusterStore.getInstance().active.contextName)
|
|
||||||
}, 5000)
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeactivate() {
|
|
||||||
clearInterval(this.timer)
|
|
||||||
console.log("Cluster logger deactivated");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more details on accessing Lens state data, please see the [Stores](../stores) guide.
|
For more details on accessing Lens state data, please see the [Stores](../stores) guide.
|
||||||
|
|
||||||
### `appMenus`
|
### `appMenus`
|
||||||
@ -76,9 +48,9 @@ Note that this is the only UI feature that the Main Extension API allows you to
|
|||||||
The following example demonstrates adding an item to the **Help** menu.
|
The following example demonstrates adding an item to the **Help** menu.
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { LensMainExtension } from "@k8slens/extensions";
|
import { Main } from "@k8slens/extensions";
|
||||||
|
|
||||||
export default class SamplePageMainExtension extends LensMainExtension {
|
export default class SamplePageMainExtension extends Main.LensExtension {
|
||||||
appMenus = [
|
appMenus = [
|
||||||
{
|
{
|
||||||
parentId: "help",
|
parentId: "help",
|
||||||
@ -102,4 +74,4 @@ Valid values include: `"file"`, `"edit"`, `"view"`, and `"help"`.
|
|||||||
* `click()` is called when the menu item is selected.
|
* `click()` is called when the menu item is selected.
|
||||||
In this example, we simply log a message.
|
In this example, we simply log a message.
|
||||||
However, you would typically have this navigate to a specific page or perform another operation.
|
However, you would typically have this navigate to a specific page or perform another operation.
|
||||||
Note that pages are associated with the [`LensRendererExtension`](renderer-extension.md) class and can be defined in the process of extending it.
|
Note that pages are associated with the [`Renderer.LensExtension`](renderer-extension.md) class and can be defined in the process of extending it.
|
||||||
|
|||||||
@ -18,13 +18,13 @@ In other words, which handler is selected in either process is independent from
|
|||||||
Example of registering a handler:
|
Example of registering a handler:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensMainExtension, Interface } from "@k8slens/extensions";
|
import { Main, Common } from "@k8slens/extensions";
|
||||||
|
|
||||||
function rootHandler(params: Iterface.ProtocolRouteParams) {
|
function rootHandler(params: Common.Types.ProtocolRouteParams) {
|
||||||
console.log("routed to ExampleExtension", params);
|
console.log("routed to ExampleExtension", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ExampleExtensionMain extends LensMainExtension {
|
export default class ExampleExtensionMain extends Main.LensExtension {
|
||||||
protocolHandlers = [
|
protocolHandlers = [
|
||||||
pathSchema: "/",
|
pathSchema: "/",
|
||||||
handler: rootHandler,
|
handler: rootHandler,
|
||||||
|
|||||||
@ -24,9 +24,9 @@ All UI elements are based on React components.
|
|||||||
To create a renderer extension, extend the `LensRendererExtension` class:
|
To create a renderer extension, extend the `LensRendererExtension` class:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
export default class ExampleExtensionMain extends LensRendererExtension {
|
export default class ExampleExtensionMain extends Renderer.LensExtension {
|
||||||
onActivate() {
|
onActivate() {
|
||||||
console.log('custom renderer process extension code started');
|
console.log('custom renderer process extension code started');
|
||||||
}
|
}
|
||||||
@ -61,11 +61,11 @@ Use your extension to access Kubernetes resources in the active cluster with [`C
|
|||||||
Add a cluster page definition to a `LensRendererExtension` subclass with the following example:
|
Add a cluster page definition to a `LensRendererExtension` subclass with the following example:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExampleIcon, ExamplePage } from "./page"
|
import { ExampleIcon, ExamplePage } from "./page"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterPages = [
|
clusterPages = [
|
||||||
{
|
{
|
||||||
id: "hello",
|
id: "hello",
|
||||||
@ -88,7 +88,7 @@ It offers flexibility in defining the appearance and behavior of your page.
|
|||||||
`ExamplePage` in the example above can be defined in `page.tsx`:
|
`ExamplePage` in the example above can be defined in `page.tsx`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> {
|
export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> {
|
||||||
@ -116,11 +116,11 @@ Use `clusterPageMenus`, covered in the next section, to add cluster pages to the
|
|||||||
By expanding on the above example, you can add a cluster page menu item to the `ExampleExtension` definition:
|
By expanding on the above example, you can add a cluster page menu item to the `ExampleExtension` definition:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExampleIcon, ExamplePage } from "./page"
|
import { ExampleIcon, ExamplePage } from "./page"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterPages = [
|
clusterPages = [
|
||||||
{
|
{
|
||||||
id: "hello",
|
id: "hello",
|
||||||
@ -157,14 +157,20 @@ When users click **Hello World**, the cluster dashboard will show the contents o
|
|||||||
This example requires the definition of another React-based component, `ExampleIcon`, which has been added to `page.tsx`, as follows:
|
This example requires the definition of another React-based component, `ExampleIcon`, which has been added to `page.tsx`, as follows:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension, Component } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export function ExampleIcon(props: Component.IconProps) {
|
type IconProps = Renderer.Component.IconProps;
|
||||||
return <Component.Icon {...props} material="pages" tooltip={"Hi!"}/>
|
|
||||||
|
const {
|
||||||
|
Component: { Icon },
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export function ExampleIcon(props: IconProps) {
|
||||||
|
return <Icon {...props} material="pages" tooltip={"Hi!"}/>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> {
|
export class ExamplePage extends React.Component<{ extension: Renderer.LensExtension }> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -176,8 +182,8 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens
|
|||||||
```
|
```
|
||||||
|
|
||||||
Lens includes various built-in components available for extension developers to use.
|
Lens includes various built-in components available for extension developers to use.
|
||||||
One of these is the `Component.Icon`, introduced in `ExampleIcon`, which you can use to access any of the [icons](https://material.io/resources/icons/) available at [Material Design](https://material.io).
|
One of these is the `Renderer.Component.Icon`, introduced in `ExampleIcon`, which you can use to access any of the [icons](https://material.io/resources/icons/) available at [Material Design](https://material.io).
|
||||||
The properties that `Component.Icon` uses are defined as follows:
|
The properties that `Renderer.Component.Icon` uses are defined as follows:
|
||||||
|
|
||||||
* `material` takes the name of the icon you want to use.
|
* `material` takes the name of the icon you want to use.
|
||||||
* `tooltip` sets the text you want to appear when a user hovers over the icon.
|
* `tooltip` sets the text you want to appear when a user hovers over the icon.
|
||||||
@ -187,11 +193,11 @@ The following example groups two sub menu items under one parent menu item:
|
|||||||
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExampleIcon, ExamplePage } from "./page"
|
import { ExampleIcon, ExamplePage } from "./page"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
clusterPages = [
|
clusterPages = [
|
||||||
{
|
{
|
||||||
id: "hello",
|
id: "hello",
|
||||||
@ -261,11 +267,11 @@ Unlike cluster pages, users can trigger global pages even when there is no activ
|
|||||||
The following example defines a `LensRendererExtension` subclass with a single global page definition:
|
The following example defines a `LensRendererExtension` subclass with a single global page definition:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from '@k8slens/extensions';
|
import { Renderer } from '@k8slens/extensions';
|
||||||
import { HelpPage } from './page';
|
import { HelpPage } from './page';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default class HelpExtension extends LensRendererExtension {
|
export default class HelpExtension extends Renderer.LensExtension {
|
||||||
globalPages = [
|
globalPages = [
|
||||||
{
|
{
|
||||||
id: "help",
|
id: "help",
|
||||||
@ -288,7 +294,7 @@ It offers flexibility in defining the appearance and behavior of your page.
|
|||||||
`HelpPage` in the example above can be defined in `page.tsx`:
|
`HelpPage` in the example above can be defined in `page.tsx`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export class HelpPage extends React.Component<{ extension: LensRendererExtension }> {
|
export class HelpPage extends React.Component<{ extension: LensRendererExtension }> {
|
||||||
@ -320,11 +326,11 @@ Global pages can be made available in the following ways:
|
|||||||
By expanding on the above example, you can add a global page menu item to the `HelpExtension` definition:
|
By expanding on the above example, you can add a global page menu item to the `HelpExtension` definition:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { HelpIcon, HelpPage } from "./page"
|
import { HelpIcon, HelpPage } from "./page"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class HelpExtension extends LensRendererExtension {
|
export default class HelpExtension extends Renderer.LensExtension {
|
||||||
globalPages = [
|
globalPages = [
|
||||||
{
|
{
|
||||||
id: "help",
|
id: "help",
|
||||||
@ -362,14 +368,20 @@ This example requires the definition of another React-based component, `HelpIcon
|
|||||||
Update `page.tsx` from the example above with the `HelpIcon` definition, as follows:
|
Update `page.tsx` from the example above with the `HelpIcon` definition, as follows:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension, Component } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export function HelpIcon(props: Component.IconProps) {
|
type IconProps = Renderer.Component.IconProps;
|
||||||
return <Component.Icon {...props} material="help"/>
|
|
||||||
|
const {
|
||||||
|
Component: { Icon },
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
export function HelpIcon(props: IconProps) {
|
||||||
|
return <Icon {...props} material="help"/>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class HelpPage extends React.Component<{ extension: LensRendererExtension }> {
|
export class HelpPage extends React.Component<{ extension: Renderer.LensExtension }> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -381,8 +393,8 @@ export class HelpPage extends React.Component<{ extension: LensRendererExtension
|
|||||||
```
|
```
|
||||||
|
|
||||||
Lens includes various built-in components available for extension developers to use.
|
Lens includes various built-in components available for extension developers to use.
|
||||||
One of these is the `Component.Icon`, introduced in `HelpIcon`, which you can use to access any of the [icons](https://material.io/resources/icons/) available at [Material Design](https://material.io).
|
One of these is the `Renderer.Component.Icon`, introduced in `HelpIcon`, which you can use to access any of the [icons](https://material.io/resources/icons/) available at [Material Design](https://material.io).
|
||||||
The property that `Component.Icon` uses is defined as follows:
|
The property that `Renderer.Component.Icon` uses is defined as follows:
|
||||||
|
|
||||||
* `material` takes the name of the icon you want to use.
|
* `material` takes the name of the icon you want to use.
|
||||||
|
|
||||||
@ -401,11 +413,11 @@ They can be installed and uninstalled by the Lens user from the cluster **Settin
|
|||||||
The following example shows how to add a cluster feature as part of a `LensRendererExtension`:
|
The following example shows how to add a cluster feature as part of a `LensRendererExtension`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions"
|
import { Renderer } from "@k8slens/extensions"
|
||||||
import { ExampleFeature } from "./src/example-feature"
|
import { ExampleFeature } from "./src/example-feature"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default class ExampleFeatureExtension extends LensRendererExtension {
|
export default class ExampleFeatureExtension extends Renderer.LensExtension {
|
||||||
clusterFeatures = [
|
clusterFeatures = [
|
||||||
{
|
{
|
||||||
title: "Example Feature",
|
title: "Example Feature",
|
||||||
@ -462,45 +474,69 @@ Consider using the following properties with `updateStatus()`:
|
|||||||
The following shows a very simple implementation of a `ClusterFeature`:
|
The following shows a very simple implementation of a `ClusterFeature`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions";
|
import { Renderer, Common } from "@k8slens/extensions";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
export class ExampleFeature extends ClusterFeature.Feature {
|
const {
|
||||||
|
K8sApi: {
|
||||||
|
ResourceStack,
|
||||||
|
forCluster,
|
||||||
|
StorageClass,
|
||||||
|
Namespace,
|
||||||
|
}
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
async install(cluster: Store.Cluster): Promise<void> {
|
type ResourceStack = Renderer.K8sApi.ResourceStack;
|
||||||
|
type Pod = Renderer.K8sApi.Pod;
|
||||||
|
type KubernetesCluster = Common.Catalog.KubernetesCluster;
|
||||||
|
|
||||||
super.applyResources(cluster, path.join(__dirname, "../resources/"));
|
export interface MetricsStatus {
|
||||||
|
installed: boolean;
|
||||||
|
canUpgrade: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async upgrade(cluster: Store.Cluster): Promise<void> {
|
export class ExampleFeature {
|
||||||
return this.install(cluster);
|
protected stack: ResourceStack;
|
||||||
|
|
||||||
|
constructor(protected cluster: KubernetesCluster) {
|
||||||
|
this.stack = new ResourceStack(cluster, this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateStatus(cluster: Store.Cluster): Promise<ClusterFeature.FeatureStatus> {
|
install(): Promise<string> {
|
||||||
|
return this.stack.kubectlApplyFolder(path.join(__dirname, "../resources/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
upgrade(): Promise<string> {
|
||||||
|
return this.install(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStatus(): Promise<MetricsStatus> {
|
||||||
|
const status: MetricsStatus = { installed: false, canUpgrade: false};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pod = K8sApi.forCluster(cluster, K8sApi.Pod);
|
const pod = forCluster(cluster, Pod);
|
||||||
const examplePod = await pod.get({name: "example-pod", namespace: "default"});
|
const examplePod = await pod.get({name: "example-pod", namespace: "default"});
|
||||||
|
|
||||||
if (examplePod?.kind) {
|
if (examplePod?.kind) {
|
||||||
this.status.installed = true;
|
status.installed = true;
|
||||||
this.status.currentVersion = examplePod.spec.containers[0].image.split(":")[1];
|
status.currentVersion = examplePod.spec.containers[0].image.split(":")[1];
|
||||||
this.status.canUpgrade = true; // a real implementation would perform a check here that is relevant to the specific feature
|
status.canUpgrade = true; // a real implementation would perform a check here that is relevant to the specific feature
|
||||||
} else {
|
} else {
|
||||||
this.status.installed = false;
|
status.installed = false;
|
||||||
this.status.canUpgrade = false;
|
status.canUpgrade = false;
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (e?.error?.code === 404) {
|
if (e?.error?.code === 404) {
|
||||||
this.status.installed = false;
|
status.installed = false;
|
||||||
this.status.canUpgrade = false;
|
status.canUpgrade = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
async uninstall(cluster: Store.Cluster): Promise<void> {
|
async uninstall(): Promise<string> {
|
||||||
const podApi = K8sApi.forCluster(cluster, K8sApi.Pod);
|
return this.stack.kubectlDeleteFolder(this.resourceFolder);
|
||||||
await podApi.delete({name: "example-pod", namespace: "default"});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -539,12 +575,12 @@ You can use Lens extensions to add custom preferences to the Preferences page, p
|
|||||||
The following example demonstrates adding a custom preference:
|
The following example demonstrates adding a custom preference:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
|
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export default class ExampleRendererExtension extends LensRendererExtension {
|
export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||||
|
|
||||||
@observable preference = { enabled: false };
|
@observable preference = { enabled: false };
|
||||||
|
|
||||||
@ -578,10 +614,16 @@ This is how `ExampleRendererExtension` handles the state of the preference input
|
|||||||
In this example `ExamplePreferenceInput`, `ExamplePreferenceHint`, and `ExamplePreferenceProps` are defined in `./src/example-preference.tsx` as follows:
|
In this example `ExamplePreferenceInput`, `ExamplePreferenceHint`, and `ExamplePreferenceProps` are defined in `./src/example-preference.tsx` as follows:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Component } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
Checkbox,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
export class ExamplePreferenceProps {
|
export class ExamplePreferenceProps {
|
||||||
preference: {
|
preference: {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@ -594,7 +636,7 @@ export class ExamplePreferenceInput extends React.Component<ExamplePreferencePro
|
|||||||
render() {
|
render() {
|
||||||
const { preference } = this.props;
|
const { preference } = this.props;
|
||||||
return (
|
return (
|
||||||
<Component.Checkbox
|
<Checkbox
|
||||||
label="I understand appPreferences"
|
label="I understand appPreferences"
|
||||||
value={preference.enabled}
|
value={preference.enabled}
|
||||||
onChange={v => { preference.enabled = v; }}
|
onChange={v => { preference.enabled = v; }}
|
||||||
@ -612,7 +654,7 @@ export class ExamplePreferenceHint extends React.Component {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`ExamplePreferenceInput` implements a simple checkbox using Lens's `Component.Checkbox` using the following properties:
|
`ExamplePreferenceInput` implements a simple checkbox using Lens's `Renderer.Component.Checkbox` using the following properties:
|
||||||
|
|
||||||
* `label` sets the text that displays next to the checkbox.
|
* `label` sets the text that displays next to the checkbox.
|
||||||
* `value` is initially set to `preference.enabled`.
|
* `value` is initially set to `preference.enabled`.
|
||||||
@ -645,11 +687,11 @@ The following example adds a `statusBarItems` definition and a `globalPages` def
|
|||||||
It configures the status bar item to navigate to the global page upon activation (normally a mouse click):
|
It configures the status bar item to navigate to the global page upon activation (normally a mouse click):
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { LensRendererExtension } from '@k8slens/extensions';
|
import { Renderer } from '@k8slens/extensions';
|
||||||
import { HelpIcon, HelpPage } from "./page"
|
import { HelpIcon, HelpPage } from "./page"
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export default class HelpExtension extends LensRendererExtension {
|
export default class HelpExtension extends Renderer.LensExtension {
|
||||||
globalPages = [
|
globalPages = [
|
||||||
{
|
{
|
||||||
id: "help",
|
id: "help",
|
||||||
@ -703,16 +745,19 @@ The following example shows how to add a `kubeObjectMenuItems` for namespace res
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { NamespaceMenuItem } from "./src/namespace-menu-item"
|
import { NamespaceMenuItem } from "./src/namespace-menu-item"
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||||
|
type Namespace = Renderer.K8sApi.Namespace;
|
||||||
|
|
||||||
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
kubeObjectMenuItems = [
|
kubeObjectMenuItems = [
|
||||||
{
|
{
|
||||||
kind: "Namespace",
|
kind: "Namespace",
|
||||||
apiVersions: ["v1"],
|
apiVersions: ["v1"],
|
||||||
components: {
|
components: {
|
||||||
MenuItem: (props: Component.KubeObjectMenuProps<K8sApi.Namespace>) => <NamespaceMenuItem {...props} />
|
MenuItem: (props: KubeObjectMenuProps<Namespace>) => <NamespaceMenuItem {...props} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -734,16 +779,28 @@ In this example a `NamespaceMenuItem` object is returned.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Component, K8sApi, Navigation} from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
export function NamespaceMenuItem(props: Component.KubeObjectMenuProps<K8sApi.Namespace>) {
|
const {
|
||||||
|
Component: {
|
||||||
|
terminalStore,
|
||||||
|
MenuItem,
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
Navigation,
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||||
|
type Namespace = Renderer.K8sApi.Namespace;
|
||||||
|
|
||||||
|
export function NamespaceMenuItem(props: KubeObjectMenuProps<Namespace>) {
|
||||||
const { object: namespace, toolbar } = props;
|
const { object: namespace, toolbar } = props;
|
||||||
if (!namespace) return null;
|
if (!namespace) return null;
|
||||||
|
|
||||||
const namespaceName = namespace.getName();
|
const namespaceName = namespace.getName();
|
||||||
|
|
||||||
const sendToTerminal = (command: string) => {
|
const sendToTerminal = (command: string) => {
|
||||||
Component.terminalStore.sendCommand(command, {
|
terminalStore.sendCommand(command, {
|
||||||
enter: true,
|
enter: true,
|
||||||
newTab: true,
|
newTab: true,
|
||||||
});
|
});
|
||||||
@ -755,21 +812,21 @@ export function NamespaceMenuItem(props: Component.KubeObjectMenuProps<K8sApi.Na
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component.MenuItem onClick={getPods}>
|
<MenuItem onClick={getPods}>
|
||||||
<Component.Icon material="speaker_group" interactive={toolbar} title="Get pods in terminal"/>
|
<Icon material="speaker_group" interactive={toolbar} title="Get pods in terminal"/>
|
||||||
<span className="title">Get Pods</span>
|
<span className="title">Get Pods</span>
|
||||||
</Component.MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`NamespaceMenuItem` returns a `Component.MenuItem` which defines the menu item's appearance and its behavior when activated via the `onClick` property.
|
`NamespaceMenuItem` returns a `Renderer.Component.MenuItem` which defines the menu item's appearance and its behavior when activated via the `onClick` property.
|
||||||
In the example, `getPods()` opens a terminal tab and runs `kubectl` to get a list of pods running in the current namespace.
|
In the example, `getPods()` opens a terminal tab and runs `kubectl` to get a list of pods running in the current namespace.
|
||||||
|
|
||||||
The name of the namespace is retrieved from `props` passed into `NamespaceMenuItem()`.
|
The name of the namespace is retrieved from `props` passed into `NamespaceMenuItem()`.
|
||||||
`namespace` is the `props.object`, which is of type `K8sApi.Namespace`.
|
`namespace` is the `props.object`, which is of type `Renderer.K8sApi.Namespace`.
|
||||||
`K8sApi.Namespace` is the API for accessing namespaces.
|
`Renderer.K8sApi.Namespace` is the API for accessing namespaces.
|
||||||
The current namespace in this example is simply given by `namespace.getName()`.
|
The current namespace in this example is simply given by `namespace.getName()`.
|
||||||
Thus, `kubeObjectMenuItems` afford convenient access to the specific resource selected by the user.
|
Thus, `kubeObjectMenuItems` afford convenient access to the specific resource selected by the user.
|
||||||
|
|
||||||
@ -783,18 +840,22 @@ These custom details appear on the details page for a specific resource, such as
|
|||||||
The following example shows how to use `kubeObjectDetailItems` to add a tabulated list of pods to the Namespace resource details page:
|
The following example shows how to use `kubeObjectDetailItems` to add a tabulated list of pods to the Namespace resource details page:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react";
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { NamespaceDetailsItem } from "./src/namespace-details-item"
|
import { NamespaceDetailsItem } from "./src/namespace-details-item";
|
||||||
|
|
||||||
export default class ExampleExtension extends LensRendererExtension {
|
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||||
|
type KubeObjectDetailsProps = Renderer.Component.KubeObjectDetailsProps;
|
||||||
|
type Namespace = Renderer.K8sApi.Namespace;
|
||||||
|
|
||||||
|
export default class ExampleExtension extends Renderer.LensExtension {
|
||||||
kubeObjectDetailItems = [
|
kubeObjectDetailItems = [
|
||||||
{
|
{
|
||||||
kind: "Namespace",
|
kind: "Namespace",
|
||||||
apiVersions: ["v1"],
|
apiVersions: ["v1"],
|
||||||
priority: 10,
|
priority: 10,
|
||||||
components: {
|
components: {
|
||||||
Details: (props: Component.KubeObjectDetailsProps<K8sApi.Namespace>) => <NamespaceDetailsItem {...props} />
|
Details: (props: KubeObjectDetailsProps<Namespace>) => <NamespaceDetailsItem {...props} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@ -814,25 +875,39 @@ In this example a `NamespaceDetailsItem` object is returned.
|
|||||||
`NamespaceDetailsItem` is defined in `./src/namespace-details-item.tsx`:
|
`NamespaceDetailsItem` is defined in `./src/namespace-details-item.tsx`:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { Component, K8sApi } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { PodsDetailsList } from "./pods-details-list";
|
import { PodsDetailsList } from "./pods-details-list";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { observable } from "mobx";
|
import { observable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
|
|
||||||
@observer
|
const {
|
||||||
export class NamespaceDetailsItem extends React.Component<Component.KubeObjectDetailsProps<K8sApi.Namespace>> {
|
K8sApi: {
|
||||||
|
podsApi,
|
||||||
|
},
|
||||||
|
Component: {
|
||||||
|
DrawerTitle,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
@observable private pods: K8sApi.Pod[];
|
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||||
|
type Namespace = Renderer.K8sApi.Namespace;
|
||||||
|
type Pod = Renderer.K8sApi.Pod;
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export class NamespaceDetailsItem extends React.Component<KubeObjectDetailsProps<Namespace>> {
|
||||||
|
@observable private pods: Pod[];
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
this.pods = await K8sApi.podsApi.list({namespace: this.props.object.getName()});
|
const namespace = this.props.object.getName();
|
||||||
|
|
||||||
|
this.pods = await podsApi.list({ namespace });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Component.DrawerTitle title="Pods" />
|
<DrawerTitle title="Pods" />
|
||||||
<PodsDetailsList pods={this.pods}/>
|
<PodsDetailsList pods={this.pods}/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -840,14 +915,14 @@ export class NamespaceDetailsItem extends React.Component<Component.KubeObjectDe
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Since `NamespaceDetailsItem` extends `React.Component<Component.KubeObjectDetailsProps<K8sApi.Namespace>>`, it can access the current namespace object (type `K8sApi.Namespace`) through `this.props.object`.
|
Since `NamespaceDetailsItem` extends `React.Component<KubeObjectDetailsProps<Namespace>>`, it can access the current namespace object (type `Namespace`) through `this.props.object`.
|
||||||
You can query this object for many details about the current namespace.
|
You can query this object for many details about the current namespace.
|
||||||
In the example above, `componentDidMount()` gets the namespace's name using the `K8sApi.Namespace` `getName()` method.
|
In the example above, `componentDidMount()` gets the namespace's name using the `Namespace` `getName()` method.
|
||||||
Use the namespace's name to limit the list of pods only to those in the relevant namespace.
|
Use the namespace's name to limit the list of pods only to those in the relevant namespace.
|
||||||
To get this list of pods, this example uses the Kubernetes pods API `K8sApi.podsApi.list()` method.
|
To get this list of pods, this example uses the Kubernetes pods API `podsApi.list()` method.
|
||||||
The `K8sApi.podsApi` is automatically configured for the active cluster.
|
The `podsApi` is automatically configured for the active cluster.
|
||||||
|
|
||||||
Note that `K8sApi.podsApi.list()` is an asynchronous method.
|
Note that `podsApi.list()` is an asynchronous method.
|
||||||
Getting the pods list should occur prior to rendering the `NamespaceDetailsItem`.
|
Getting the pods list should occur prior to rendering the `NamespaceDetailsItem`.
|
||||||
It is a common technique in React development to await async calls in `componentDidMount()`.
|
It is a common technique in React development to await async calls in `componentDidMount()`.
|
||||||
However, `componentDidMount()` is called right after the first call to `render()`.
|
However, `componentDidMount()` is called right after the first call to `render()`.
|
||||||
@ -856,51 +931,59 @@ Like in the [`appPreferences` guide](#apppreferences), [`mobx`](https://mobx.js.
|
|||||||
This is done simply by marking the `pods` field as an `observable` and the `NamespaceDetailsItem` class itself as an `observer`.
|
This is done simply by marking the `pods` field as an `observable` and the `NamespaceDetailsItem` class itself as an `observer`.
|
||||||
|
|
||||||
Finally, the `NamespaceDetailsItem` renders using the `render()` method.
|
Finally, the `NamespaceDetailsItem` renders using the `render()` method.
|
||||||
Details are placed in drawers, and using `Component.DrawerTitle` provides a separator from details above this one.
|
Details are placed in drawers, and using `Renderer.Component.DrawerTitle` provides a separator from details above this one.
|
||||||
Multiple details in a drawer can be placed in `<Component.DrawerItem>` elements for further separation, if desired.
|
Multiple details in a drawer can be placed in `<Renderer.Component.DrawerItem>` elements for further separation, if desired.
|
||||||
The rest of this example's details are defined in `PodsDetailsList`, found in `./pods-details-list.tsx`:
|
The rest of this example's details are defined in `PodsDetailsList`, found in `./pods-details-list.tsx`:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Component, K8sApi } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
Table,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
|
type Pod = Renderer.K8sApi.Pod;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
pods: K8sApi.Pod[];
|
pods?: Pod[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PodsDetailsList extends React.Component<Props> {
|
export class PodsDetailsList extends React.Component<Props> {
|
||||||
|
getTableRow = (pod: Pod) => {
|
||||||
getTableRow(index: number) {
|
|
||||||
const {pods} = this.props;
|
|
||||||
return (
|
return (
|
||||||
<Component.TableRow key={index} nowrap>
|
<TableRow key={index} nowrap>
|
||||||
<Component.TableCell className="podName">{pods[index].getName()}</Component.TableCell>
|
<TableCell className="podName">{pods[index].getName()}</TableCell>
|
||||||
<Component.TableCell className="podAge">{pods[index].getAge()}</Component.TableCell>
|
<TableCell className="podAge">{pods[index].getAge()}</TableCell>
|
||||||
<Component.TableCell className="podStatus">{pods[index].getStatus()}</Component.TableCell>
|
<TableCell className="podStatus">{pods[index].getStatus()}</TableCell>
|
||||||
</Component.TableRow>
|
</TableRow>
|
||||||
)
|
)
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { pods } = this.props
|
const { pods } = this.props
|
||||||
|
|
||||||
if (!pods?.length) {
|
if (!pods?.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Component.Table>
|
<Table>
|
||||||
<Component.TableHead>
|
<TableHead>
|
||||||
<Component.TableCell className="podName">Name</Component.TableCell>
|
<TableCell className="podName">Name</TableCell>
|
||||||
<Component.TableCell className="podAge">Age</Component.TableCell>
|
<TableCell className="podAge">Age</TableCell>
|
||||||
<Component.TableCell className="podStatus">Status</Component.TableCell>
|
<TableCell className="podStatus">Status</TableCell>
|
||||||
</Component.TableHead>
|
</TableHead>
|
||||||
{
|
{ pods.map(this.getTableRow) }
|
||||||
pods.map((pod, index) => this.getTableRow(index))
|
</Table>
|
||||||
}
|
|
||||||
</Component.Table>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -909,9 +992,9 @@ export class PodsDetailsList extends React.Component<Props> {
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Obtain the name, age, and status for each pod using the `K8sApi.Pod` methods.
|
Obtain the name, age, and status for each pod using the `Renderer.K8sApi.Pod` methods.
|
||||||
Construct the table using the `Component.Table` and related elements.
|
Construct the table using the `Renderer.Component.Table` and related elements.
|
||||||
|
|
||||||
For each pod the name, age, and status are obtained using the `K8sApi.Pod` methods.
|
For each pod the name, age, and status are obtained using the `Renderer.K8sApi.Pod` methods.
|
||||||
The table is constructed using the `Component.Table` and related elements.
|
The table is constructed using the `Renderer.Component.Table` and related elements.
|
||||||
See [Component documentation](https://docs.k8slens.dev/latest/extensions/api/modules/_renderer_api_components_/) for further details.
|
See [Component documentation](https://docs.k8slens.dev/latest/extensions/api/modules/_renderer_api_components_/) for further details.
|
||||||
|
|||||||
@ -24,14 +24,14 @@ This is so that your data is kept up to date and not persisted longer than expec
|
|||||||
The following example code creates a store for the `appPreferences` guide example:
|
The following example code creates a store for the `appPreferences` guide example:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { Store } from "@k8slens/extensions";
|
import { Common } from "@k8slens/extensions";
|
||||||
import { observable, makeObservable } from "mobx";
|
import { observable, makeObservable } from "mobx";
|
||||||
|
|
||||||
export type ExamplePreferencesModel = {
|
export type ExamplePreferencesModel = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ExamplePreferencesStore extends Store.ExtensionStore<ExamplePreferencesModel> {
|
export class ExamplePreferencesStore extends Common.Store.ExtensionStore<ExamplePreferencesModel> {
|
||||||
|
|
||||||
@observable enabled = false;
|
@observable enabled = false;
|
||||||
|
|
||||||
@ -87,10 +87,10 @@ The following example code, modified from the [`appPreferences`](../renderer-ext
|
|||||||
This can be done in `./main.ts`:
|
This can be done in `./main.ts`:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { LensMainExtension } from "@k8slens/extensions";
|
import { Main } from "@k8slens/extensions";
|
||||||
import { ExamplePreferencesStore } from "./src/example-preference-store";
|
import { ExamplePreferencesStore } from "./src/example-preference-store";
|
||||||
|
|
||||||
export default class ExampleMainExtension extends LensMainExtension {
|
export default class ExampleMainExtension extends Main.LensExtension {
|
||||||
async onActivate() {
|
async onActivate() {
|
||||||
await ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this);
|
await ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this);
|
||||||
}
|
}
|
||||||
@ -102,12 +102,12 @@ Similarly, `ExamplePreferencesStore` must load in the renderer process where the
|
|||||||
This can be done in `./renderer.ts`:
|
This can be done in `./renderer.ts`:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { LensRendererExtension } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
|
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
|
||||||
import { ExamplePreferencesStore } from "./src/example-preference-store";
|
import { ExamplePreferencesStore } from "./src/example-preference-store";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export default class ExampleRendererExtension extends LensRendererExtension {
|
export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||||
|
|
||||||
async onActivate() {
|
async onActivate() {
|
||||||
await ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this);
|
await ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this);
|
||||||
@ -130,17 +130,23 @@ Again, `ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this)` is ca
|
|||||||
`ExamplePreferenceInput` is defined in `./src/example-preference.tsx`:
|
`ExamplePreferenceInput` is defined in `./src/example-preference.tsx`:
|
||||||
|
|
||||||
``` typescript
|
``` typescript
|
||||||
import { Component } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ExamplePreferencesStore } from "./example-preference-store";
|
import { ExamplePreferencesStore } from "./example-preference-store";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
Checkbox,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ExamplePreferenceInput extends React.Component {
|
export class ExamplePreferenceInput extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Component.Checkbox
|
<Checkbox
|
||||||
label="I understand appPreferences"
|
label="I understand appPreferences"
|
||||||
value={ExamplePreferencesStore.getInstace().enabled}
|
value={ExamplePreferencesStore.getInstace().enabled}
|
||||||
onChange={v => { ExamplePreferencesStore.getInstace().enabled = v; }}
|
onChange={v => { ExamplePreferencesStore.getInstace().enabled = v; }}
|
||||||
|
|||||||
@ -14,7 +14,13 @@ My component `GlobalPageMenuIcon`
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import { Component: { Icon } } from "@k8slens/extensions";
|
import { Renderer } from "@k8slens/extensions";
|
||||||
|
|
||||||
|
const {
|
||||||
|
Component: {
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
} = Renderer;
|
||||||
|
|
||||||
const GlobalPageMenuIcon = ({ navigate }: { navigate?: () => void }): JSX.Element => (
|
const GlobalPageMenuIcon = ({ navigate }: { navigate?: () => void }): JSX.Element => (
|
||||||
<Icon
|
<Icon
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export const isPublishConfigured = Object.keys(packageInfo.build).includes("publ
|
|||||||
|
|
||||||
export const productName = packageInfo.productName;
|
export const productName = packageInfo.productName;
|
||||||
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
|
||||||
export const publicPath = "/build/";
|
export const publicPath = "/build/" as string;
|
||||||
|
|
||||||
// Webpack build paths
|
// Webpack build paths
|
||||||
export const contextDir = process.cwd();
|
export const contextDir = process.cwd();
|
||||||
@ -60,13 +60,13 @@ defineGlobal("__static", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Apis
|
// Apis
|
||||||
export const apiPrefix = "/api"; // local router apis
|
export const apiPrefix = "/api" as string; // local router apis
|
||||||
export const apiKubePrefix = "/api-kube"; // k8s cluster apis
|
export const apiKubePrefix = "/api-kube" as string; // k8s cluster apis
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues";
|
export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues" as string;
|
||||||
export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI";
|
export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI" as string;
|
||||||
export const supportUrl = "https://docs.k8slens.dev/latest/support/";
|
export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string;
|
||||||
|
|
||||||
// This explicitly ignores the prerelease info on the package version
|
// This explicitly ignores the prerelease info on the package version
|
||||||
const { major, minor, patch } = new SemVer(packageInfo.version);
|
const { major, minor, patch } = new SemVer(packageInfo.version);
|
||||||
|
|||||||
@ -20,11 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import * as Catalog from "./catalog";
|
import * as Catalog from "./catalog";
|
||||||
|
import * as Navigation from "./navigation";
|
||||||
import { IpcMain as Ipc } from "../ipc/ipc-main";
|
import { IpcMain as Ipc } from "../ipc/ipc-main";
|
||||||
import { LensMainExtension as LensExtension } from "../lens-main-extension";
|
import { LensMainExtension as LensExtension } from "../lens-main-extension";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Catalog,
|
Catalog,
|
||||||
|
Navigation,
|
||||||
Ipc,
|
Ipc,
|
||||||
LensExtension,
|
LensExtension,
|
||||||
};
|
};
|
||||||
|
|||||||
26
src/extensions/main-api/navigation.ts
Normal file
26
src/extensions/main-api/navigation.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2021 OpenLens Authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { WindowManager } from "../../main/window-manager";
|
||||||
|
|
||||||
|
export function navigate(url: string) {
|
||||||
|
return WindowManager.getInstance().navigate(url);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user