1
0
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:
Sebastian Malton 2021-06-04 05:44:25 -04:00 committed by GitHub
parent a9761c4374
commit 0d0c67f13f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 395 additions and 251 deletions

View File

@ -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).
``` 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() {
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).
``` 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() {
console.log("bye bye")
}
@ -44,15 +44,15 @@ This extension can register custom app menus that will be displayed on OS native
Example:
```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 = [
{
parentId: "help",
label: "Example item",
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).
``` 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() {
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).
``` 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() {
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
import React from "react"
import { Component, LensRendererExtension } from "@k8slens/extensions"
import { Renderer } from "@k8slens/extensions"
import { ExamplePage } from "./src/example-page"
export default class ExampleRendererExtension extends LensRendererExtension {
const {
Component: {
Icon,
}
} = Renderer;
export default class ExampleRendererExtension extends Renderer.LensExtension {
globalPages = [
{
id: "example",
@ -117,7 +123,7 @@ export default class ExampleRendererExtension extends LensRendererExtension {
title: "Example page", // used in icon's tooltip
target: { pageId: "example" }
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
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions"
import { Renderer } from "@k8slens/extensions"
import { myCustomPreferencesStore } from "./src/my-custom-preferences-store"
import { MyCustomPreferenceHint, MyCustomPreferenceInput } from "./src/my-custom-preference"
export default class ExampleRendererExtension extends LensRendererExtension {
export default class ExampleRendererExtension extends Renderer.LensExtension {
appPreferences = [
{
title: "My Custom Preference",
@ -156,10 +162,10 @@ These pages are visible in a cluster menu when a cluster is opened.
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./src/page"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterPages = [
{
id: "extension-example", // optional
@ -190,10 +196,10 @@ These features are visible in the "Cluster Settings" page.
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions"
import { Renderer } from "@k8slens/extensions"
import { MyCustomFeature } from "./src/my-custom-feature"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterFeatures = [
{
title: "My Custom Feature",
@ -219,15 +225,21 @@ This extension can register custom icons and text to a status bar area.
```typescript
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 = [
{
components: {
Item: (
<div className="flex align-center gaps hover-highlight" onClick={() => this.navigate("/example-page")} >
<Component.Icon material="favorite" />
<Icon material="favorite" />
</div>
)
}
@ -243,10 +255,10 @@ This extension can register custom menu items (actions) for specified Kubernetes
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { CustomMenuItem, CustomMenuItemProps } from "./src/custom-menu-item"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
kubeObjectMenuItems = [
{
kind: "Node",
@ -266,10 +278,10 @@ This extension can register custom details (content) for specified Kubernetes ki
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { CustomKindDetails, CustomKindDetailsProps } from "./src/custom-kind-details"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
kubeObjectDetailItems = [
{
kind: "CustomKind",

View File

@ -114,14 +114,14 @@ There is a way of detect active theme and its changes in JS. [MobX observer func
```js
import React from "react"
import { observer } from "mobx-react"
import { App, Component, Theme } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
@observer
export class SupportPage extends React.Component {
render() {
return (
<div className="SupportPage">
<h1>Active theme is {Theme.getActiveTheme().name}</h1>
<h1>Active theme is {Renderer.Theme.getActiveTheme().name}</h1>
</div>
);
}

View File

@ -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.
``` typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page"
import React from "react"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterPages = [
{
id: "extension-example",

View File

@ -30,9 +30,8 @@ Each guide or code sample includes the following:
| Sample | APIs |
| ----- | ----- |
[hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-sample) | LensMainExtension <br> LensRendererExtension <br> Component.Icon <br> 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> Component.Icon <br> 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> Component.Icon <br> 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 |
[hello-world](https://github.com/lensapp/lens-extension-samples/tree/master/helloworld-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> 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> 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> Renderer.Component.Icon <br> Renderer.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 |

View File

@ -43,10 +43,10 @@ To register either a handler or a listener, you should do something like the fol
`main.ts`:
```typescript
import { LensMainExtension } from "@k8slens/extensions";
import { Main } from "@k8slens/extensions";
import { IpcMain } from "./helpers/main";
export class ExampleExtensionMain extends LensMainExtension {
export class ExampleExtensionMain extends Main.LensExtension {
onActivate() {
IpcMain.createInstance(this);
}
@ -60,10 +60,10 @@ Lens will automatically clean up that store and all the handlers on deactivation
`helpers/main.ts`:
```typescript
import { Ipc, Types } from "@k8slens/extensions";
import { Main } from "@k8slens/extensions";
export class IpcMain extends Ipc.Main {
constructor(extension: LensMainExtension) {
export class IpcMain extends Main.Ipc {
constructor(extension: Main.LensExtension) {
super(extension);
this.listen("initialize", onInitialize);
@ -82,10 +82,10 @@ You should be able to just call `IpcMain.getInstance()` anywhere it is needed in
`renderer.ts`:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { IpcRenderer } from "./helpers/renderer";
export class ExampleExtensionRenderer extends LensRendererExtension {
export class ExampleExtensionRenderer extends Renderer.LensExtension {
onActivate() {
const ipc = IpcRenderer.createInstance(this);
@ -100,9 +100,9 @@ It is also needed to create an instance to broadcast messages too.
`helpers/renderer.ts`:
```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.
@ -116,7 +116,7 @@ There is no behind the scenes transfer of these functions.
To register a "handler" call `IpcMain.getInstance().handle(...)`.
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.
Calling either `IpcRenderer.getInstance().broadcast(...)` or `IpcMain.getInstance().broadcast(...)` sends an event to all `renderer` frames and to `main`.

View File

@ -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:
```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.
```typescript
export function CertificateIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="security" tooltip="Certificates"/>
import { Renderer } from "@k8slens/extensions";
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 = [
{
@ -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.
```typescript
export default class CrdSampleExtension extends LensRendererExtension {
export default class CrdSampleExtension extends Renderer.LensExtension {
...
clusterPages = [{
@ -65,18 +75,29 @@ export default class CrdSampleExtension extends LensRendererExtension {
In the previous step we defined `CertificatePage` component to render certificates.
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
In order to list CRD objects, we need first fetch those from Kubernetes API.
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:
```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 namespaced = true
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:
```typescript
export class CertificatesApi extends K8sApi.KubeApi<Certificate> {
}
export class CertificatesApi extends KubeApi<Certificate> {}
export const certificatesApi = new CertificatesApi({
objectConstructor: Certificate
});
@ -131,7 +152,7 @@ export const certificatesApi = new CertificatesApi({
`CertificateStore` defines storage for `Certificate` objects
```typescript
export class CertificatesStore extends K8sApi.KubeObjectStore<Certificate> {
export class CertificatesStore extends KubeObjectStore<Certificate> {
api = certificatesApi
}
@ -141,7 +162,7 @@ export const certificatesStore = new CertificatesStore();
And, finally, we register this store to Lens's API manager.
```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`.
```typescript
import { Component, LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react";
import { certificatesStore } from "../certificate-store";
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.
To do that, we just need to add `Component.KubeObjectListLayout` component inside `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.
`Component.KubeObjectListLayout` will fetch automatically items from the given store when component is mounted.
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 `Renderer.Component.KubeObjectListLayout` in `store` property.
`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:
```typescript
import { Renderer } from "@k8slens/extensions";
const {
Component: {
TabLayout,
KubeObjectListLayout,
},
} = Renderer;
enum sortBy {
name = "name",
namespace = "namespace",
@ -181,8 +211,8 @@ export class CertificatePage extends React.Component<{ extension: LensRendererEx
render() {
return (
<Component.TabLayout>
<Component.KubeObjectListLayout
<TabLayout>
<KubeObjectListLayout
className="Certicates" store={certificatesStore}
sortingCallbacks={{
[sortBy.name]: (certificate: Certificate) => certificate.getName(),
@ -204,7 +234,7 @@ export class CertificatePage extends React.Component<{ extension: LensRendererEx
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:
```typescript
export default class CrdSampleExtension extends LensRendererExtension {
export default class CrdSampleExtension extends Renderer.LensExtension {
//...
kubeObjectDetailItems = [{
@ -235,14 +265,22 @@ export default class CrdSampleExtension extends LensRendererExtension {
Here we defined that `CertificateDetails` component will render the resource details.
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.
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
import { Component, K8sApi } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react";
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> {
@ -252,29 +290,29 @@ export class CertificateDetails extends React.Component<CertificateDetailsProps>
if (!certificate) return null;
return (
<div className="Certificate">
<Component.DrawerItem name="Created">
<DrawerItem name="Created">
{certificate.getAge(true, false)} ago ({certificate.metadata.creationTimestamp })
</Component.DrawerItem>
<Component.DrawerItem name="DNS Names">
</DrawerItem>
<DrawerItem name="DNS Names">
{certificate.spec.dnsNames.join(",")}
</Component.DrawerItem>
<Component.DrawerItem name="Secret">
</DrawerItem>
<DrawerItem name="Secret">
{certificate.spec.secretName}
</Component.DrawerItem>
<Component.DrawerItem name="Status" className="status" labelsOnly>
</DrawerItem>
<DrawerItem name="Status" className="status" labelsOnly>
{certificate.status.conditions.map((condition, index) => {
const { type, reason, message, status } = condition;
const kind = type || reason;
if (!kind) return null;
return (
<Component.Badge
<Badge
key={kind + index} label={kind}
className={"success "+kind.toLowerCase()}
tooltip={message}
/>
);
})}
</Component.DrawerItem>
</DrawerItem>
</div>
)
}

View File

@ -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:
```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() {
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.
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.
### `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.
``` 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 = [
{
parentId: "help",
@ -102,4 +74,4 @@ Valid values include: `"file"`, `"edit"`, `"view"`, and `"help"`.
* `click()` is called when the menu item is selected.
In this example, we simply log a message.
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.

View File

@ -18,13 +18,13 @@ In other words, which handler is selected in either process is independent from
Example of registering a handler:
```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);
}
export default class ExampleExtensionMain extends LensMainExtension {
export default class ExampleExtensionMain extends Main.LensExtension {
protocolHandlers = [
pathSchema: "/",
handler: rootHandler,

View File

@ -24,9 +24,9 @@ All UI elements are based on React components.
To create a renderer extension, extend the `LensRendererExtension` class:
```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() {
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:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page"
import React from "react"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterPages = [
{
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`:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react"
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:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page"
import React from "react"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterPages = [
{
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:
```typescript
import { LensRendererExtension, Component } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react"
export function ExampleIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="pages" tooltip={"Hi!"}/>
type IconProps = Renderer.Component.IconProps;
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() {
return (
<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.
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).
The properties that `Component.Icon` uses are defined as follows:
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 `Renderer.Component.Icon` uses are defined as follows:
* `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.
@ -187,11 +193,11 @@ The following example groups two sub menu items under one parent menu item:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExampleIcon, ExamplePage } from "./page"
import React from "react"
export default class ExampleExtension extends LensRendererExtension {
export default class ExampleExtension extends Renderer.LensExtension {
clusterPages = [
{
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:
```typescript
import { LensRendererExtension } from '@k8slens/extensions';
import { Renderer } from '@k8slens/extensions';
import { HelpPage } from './page';
import React from 'react';
export default class HelpExtension extends LensRendererExtension {
export default class HelpExtension extends Renderer.LensExtension {
globalPages = [
{
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`:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react"
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:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { HelpIcon, HelpPage } from "./page"
import React from "react"
export default class HelpExtension extends LensRendererExtension {
export default class HelpExtension extends Renderer.LensExtension {
globalPages = [
{
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:
```typescript
import { LensRendererExtension, Component } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import React from "react"
export function HelpIcon(props: Component.IconProps) {
return <Component.Icon {...props} material="help"/>
type IconProps = Renderer.Component.IconProps;
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() {
return (
<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.
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).
The property that `Component.Icon` uses is defined as follows:
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 `Renderer.Component.Icon` uses is defined as follows:
* `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`:
```typescript
import { LensRendererExtension } from "@k8slens/extensions"
import { Renderer } from "@k8slens/extensions"
import { ExampleFeature } from "./src/example-feature"
import React from "react"
export default class ExampleFeatureExtension extends LensRendererExtension {
export default class ExampleFeatureExtension extends Renderer.LensExtension {
clusterFeatures = [
{
title: "Example Feature",
@ -462,45 +474,69 @@ Consider using the following properties with `updateStatus()`:
The following shows a very simple implementation of a `ClusterFeature`:
```typescript
import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions";
import { Renderer, Common } from "@k8slens/extensions";
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;
}
export class ExampleFeature {
protected stack: ResourceStack;
constructor(protected cluster: KubernetesCluster) {
this.stack = new ResourceStack(cluster, this.name);
}
async upgrade(cluster: Store.Cluster): Promise<void> {
return this.install(cluster);
install(): Promise<string> {
return this.stack.kubectlApplyFolder(path.join(__dirname, "../resources/"));
}
async updateStatus(cluster: Store.Cluster): Promise<ClusterFeature.FeatureStatus> {
upgrade(): Promise<string> {
return this.install(config);
}
async getStatus(): Promise<MetricsStatus> {
const status: MetricsStatus = { installed: false, canUpgrade: false};
try {
const pod = K8sApi.forCluster(cluster, K8sApi.Pod);
const pod = forCluster(cluster, Pod);
const examplePod = await pod.get({name: "example-pod", namespace: "default"});
if (examplePod?.kind) {
this.status.installed = true;
this.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.installed = true;
status.currentVersion = examplePod.spec.containers[0].image.split(":")[1];
status.canUpgrade = true; // a real implementation would perform a check here that is relevant to the specific feature
} else {
this.status.installed = false;
this.status.canUpgrade = false;
status.installed = false;
status.canUpgrade = false;
}
} catch(e) {
if (e?.error?.code === 404) {
this.status.installed = false;
this.status.canUpgrade = false;
status.installed = false;
status.canUpgrade = false;
}
}
return this.status;
return status;
}
async uninstall(cluster: Store.Cluster): Promise<void> {
const podApi = K8sApi.forCluster(cluster, K8sApi.Pod);
await podApi.delete({name: "example-pod", namespace: "default"});
async uninstall(): Promise<string> {
return this.stack.kubectlDeleteFolder(this.resourceFolder);
}
}
```
@ -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:
```typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
import { observable } from "mobx";
import React from "react";
export default class ExampleRendererExtension extends LensRendererExtension {
export default class ExampleRendererExtension extends Renderer.LensExtension {
@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:
```typescript
import { Component } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { observer } from "mobx-react";
import React from "react";
const {
Component: {
Checkbox,
},
} = Renderer;
export class ExamplePreferenceProps {
preference: {
enabled: boolean;
@ -594,7 +636,7 @@ export class ExamplePreferenceInput extends React.Component<ExamplePreferencePro
render() {
const { preference } = this.props;
return (
<Component.Checkbox
<Checkbox
label="I understand appPreferences"
value={preference.enabled}
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.
* `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):
```typescript
import { LensRendererExtension } from '@k8slens/extensions';
import { Renderer } from '@k8slens/extensions';
import { HelpIcon, HelpPage } from "./page"
import React from 'react';
export default class HelpExtension extends LensRendererExtension {
export default class HelpExtension extends Renderer.LensExtension {
globalPages = [
{
id: "help",
@ -703,16 +745,19 @@ The following example shows how to add a `kubeObjectMenuItems` for namespace res
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
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 = [
{
kind: "Namespace",
apiVersions: ["v1"],
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
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;
if (!namespace) return null;
const namespaceName = namespace.getName();
const sendToTerminal = (command: string) => {
Component.terminalStore.sendCommand(command, {
terminalStore.sendCommand(command, {
enter: true,
newTab: true,
});
@ -755,21 +812,21 @@ export function NamespaceMenuItem(props: Component.KubeObjectMenuProps<K8sApi.Na
};
return (
<Component.MenuItem onClick={getPods}>
<Component.Icon material="speaker_group" interactive={toolbar} title="Get pods in terminal"/>
<span className="title">Get Pods</span>
</Component.MenuItem>
<MenuItem onClick={getPods}>
<Icon material="speaker_group" interactive={toolbar} title="Get pods in terminal"/>
<span className="title">Get Pods</span>
</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.
The name of the namespace is retrieved from `props` passed into `NamespaceMenuItem()`.
`namespace` is the `props.object`, which is of type `K8sApi.Namespace`.
`K8sApi.Namespace` is the API for accessing namespaces.
`namespace` is the `props.object`, which is of type `Renderer.K8sApi.Namespace`.
`Renderer.K8sApi.Namespace` is the API for accessing namespaces.
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.
@ -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:
```typescript
import React from "react"
import { LensRendererExtension } from "@k8slens/extensions";
import { NamespaceDetailsItem } from "./src/namespace-details-item"
import React from "react";
import { Renderer } from "@k8slens/extensions";
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 = [
{
kind: "Namespace",
apiVersions: ["v1"],
priority: 10,
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`:
``` typescript
import { Component, K8sApi } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { PodsDetailsList } from "./pods-details-list";
import React from "react";
import { observable } from "mobx";
import { observer } from "mobx-react";
@observer
export class NamespaceDetailsItem extends React.Component<Component.KubeObjectDetailsProps<K8sApi.Namespace>> {
const {
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() {
this.pods = await K8sApi.podsApi.list({namespace: this.props.object.getName()});
const namespace = this.props.object.getName();
this.pods = await podsApi.list({ namespace });
}
render() {
return (
<div>
<Component.DrawerTitle title="Pods" />
<DrawerTitle title="Pods" />
<PodsDetailsList pods={this.pods}/>
</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.
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.
To get this list of pods, this example uses the Kubernetes pods API `K8sApi.podsApi.list()` method.
The `K8sApi.podsApi` is automatically configured for the active cluster.
To get this list of pods, this example uses the Kubernetes pods API `podsApi.list()` method.
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`.
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()`.
@ -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`.
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.
Multiple details in a drawer can be placed in `<Component.DrawerItem>` elements for further separation, if desired.
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 `<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`:
``` typescript
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 {
pods: K8sApi.Pod[];
pods?: Pod[];
}
export class PodsDetailsList extends React.Component<Props> {
getTableRow(index: number) {
const {pods} = this.props;
return (
<Component.TableRow key={index} nowrap>
<Component.TableCell className="podName">{pods[index].getName()}</Component.TableCell>
<Component.TableCell className="podAge">{pods[index].getAge()}</Component.TableCell>
<Component.TableCell className="podStatus">{pods[index].getStatus()}</Component.TableCell>
</Component.TableRow>
)
}
getTableRow = (pod: Pod) => {
return (
<TableRow key={index} nowrap>
<TableCell className="podName">{pods[index].getName()}</TableCell>
<TableCell className="podAge">{pods[index].getAge()}</TableCell>
<TableCell className="podStatus">{pods[index].getStatus()}</TableCell>
</TableRow>
)
};
render() {
const {pods} = this.props
if (!pods?.length) {
return null;
}
const { pods } = this.props
return (
<div >
<Component.Table>
<Component.TableHead>
<Component.TableCell className="podName">Name</Component.TableCell>
<Component.TableCell className="podAge">Age</Component.TableCell>
<Component.TableCell className="podStatus">Status</Component.TableCell>
</Component.TableHead>
{
pods.map((pod, index) => this.getTableRow(index))
}
</Component.Table>
</div>
)
if (!pods?.length) {
return null;
}
return (
<div>
<Table>
<TableHead>
<TableCell className="podName">Name</TableCell>
<TableCell className="podAge">Age</TableCell>
<TableCell className="podStatus">Status</TableCell>
</TableHead>
{ pods.map(this.getTableRow) }
</Table>
</div>
);
}
}
```
@ -909,9 +992,9 @@ export class PodsDetailsList extends React.Component<Props> {
![DetailsWithPods](images/kubeobjectdetailitemwithpods.png)
Obtain the name, age, and status for each pod using the `K8sApi.Pod` methods.
Construct the table using the `Component.Table` and related elements.
Obtain the name, age, and status for each pod using the `Renderer.K8sApi.Pod` methods.
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.
The table is constructed using the `Component.Table` and related elements.
For each pod the name, age, and status are obtained using the `Renderer.K8sApi.Pod` methods.
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.

View File

@ -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:
``` typescript
import { Store } from "@k8slens/extensions";
import { Common } from "@k8slens/extensions";
import { observable, makeObservable } from "mobx";
export type ExamplePreferencesModel = {
enabled: boolean;
};
export class ExamplePreferencesStore extends Store.ExtensionStore<ExamplePreferencesModel> {
export class ExamplePreferencesStore extends Common.Store.ExtensionStore<ExamplePreferencesModel> {
@observable enabled = false;
@ -87,10 +87,10 @@ The following example code, modified from the [`appPreferences`](../renderer-ext
This can be done in `./main.ts`:
``` typescript
import { LensMainExtension } from "@k8slens/extensions";
import { Main } from "@k8slens/extensions";
import { ExamplePreferencesStore } from "./src/example-preference-store";
export default class ExampleMainExtension extends LensMainExtension {
export default class ExampleMainExtension extends Main.LensExtension {
async onActivate() {
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`:
``` typescript
import { LensRendererExtension } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
import { ExamplePreferencesStore } from "./src/example-preference-store";
import React from "react";
export default class ExampleRendererExtension extends LensRendererExtension {
export default class ExampleRendererExtension extends Renderer.LensExtension {
async onActivate() {
await ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this);
@ -130,17 +130,23 @@ Again, `ExamplePreferencesStore.getInstanceOrCreate().loadExtension(this)` is ca
`ExamplePreferenceInput` is defined in `./src/example-preference.tsx`:
``` typescript
import { Component } from "@k8slens/extensions";
import { Renderer } from "@k8slens/extensions";
import { observer } from "mobx-react";
import React from "react";
import { ExamplePreferencesStore } from "./example-preference-store";
const {
Component: {
Checkbox,
},
} = Renderer;
@observer
export class ExamplePreferenceInput extends React.Component {
render() {
return (
<Component.Checkbox
<Checkbox
label="I understand appPreferences"
value={ExamplePreferencesStore.getInstace().enabled}
onChange={v => { ExamplePreferencesStore.getInstace().enabled = v; }}

View File

@ -14,7 +14,13 @@ My component `GlobalPageMenuIcon`
```typescript
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 => (
<Icon

View File

@ -37,7 +37,7 @@ export const isPublishConfigured = Object.keys(packageInfo.build).includes("publ
export const productName = packageInfo.productName;
export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`;
export const publicPath = "/build/";
export const publicPath = "/build/" as string;
// Webpack build paths
export const contextDir = process.cwd();
@ -60,13 +60,13 @@ defineGlobal("__static", {
});
// Apis
export const apiPrefix = "/api"; // local router apis
export const apiKubePrefix = "/api-kube"; // k8s cluster apis
export const apiPrefix = "/api" as string; // local router apis
export const apiKubePrefix = "/api-kube" as string; // k8s cluster apis
// Links
export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues";
export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI";
export const supportUrl = "https://docs.k8slens.dev/latest/support/";
export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues" as string;
export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI" as string;
export const supportUrl = "https://docs.k8slens.dev/latest/support/" as string;
// This explicitly ignores the prerelease info on the package version
const { major, minor, patch } = new SemVer(packageInfo.version);

View File

@ -20,11 +20,13 @@
*/
import * as Catalog from "./catalog";
import * as Navigation from "./navigation";
import { IpcMain as Ipc } from "../ipc/ipc-main";
import { LensMainExtension as LensExtension } from "../lens-main-extension";
export {
Catalog,
Navigation,
Ipc,
LensExtension,
};

View 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);
}