mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
more DRY, remove DrawerSection, DrawerSubSection, and DrawerSubTitle
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
2b2395d4dd
commit
3c530ab0ed
@ -6,29 +6,29 @@ The Renderer Extension API allows you to access, configure, and customize Lens d
|
||||
|
||||
The custom Lens UI elements that you can add include:
|
||||
|
||||
* [Cluster pages](#clusterpages)
|
||||
* [Cluster page menus](#clusterpagemenus)
|
||||
* [Global pages](#globalpages)
|
||||
* [Welcome menus](#welcomemenus)
|
||||
* [App preferences](#apppreferences)
|
||||
* [Top bar items](#topbaritems)
|
||||
* [Status bar items](#statusbaritems)
|
||||
* [KubeObject menu items](#kubeobjectmenuitems)
|
||||
* [KubeObject detail items](#kubeobjectdetailitems)
|
||||
* [KubeObject status texts](#kubeobjectstatustexts)
|
||||
* [Kube workloads overview items](#kubeworkloadsoverviewitems)
|
||||
- [Cluster pages](#clusterpages)
|
||||
- [Cluster page menus](#clusterpagemenus)
|
||||
- [Global pages](#globalpages)
|
||||
- [Welcome menus](#welcomemenus)
|
||||
- [App preferences](#apppreferences)
|
||||
- [Top bar items](#topbaritems)
|
||||
- [Status bar items](#statusbaritems)
|
||||
- [KubeObject menu items](#kubeobjectmenuitems)
|
||||
- [KubeObject detail items](#kubeobjectdetailitems)
|
||||
- [KubeObject status texts](#kubeobjectstatustexts)
|
||||
- [Kube workloads overview items](#kubeworkloadsoverviewitems)
|
||||
|
||||
as well as catalog-related UI elements:
|
||||
|
||||
* [Entity settings](#entitysettings)
|
||||
* [Catalog entity detail items](#catalogentitydetailitems)
|
||||
- [Entity settings](#entitysettings)
|
||||
- [Catalog entity detail items](#catalogentitydetailitems)
|
||||
|
||||
All UI elements are based on React components.
|
||||
|
||||
Finally, you can also add commands and protocol handlers:
|
||||
|
||||
* [Command palette commands](#commandpalettecommands)
|
||||
* [protocol handlers](protocol-handlers.md)
|
||||
- [Command palette commands](#commandpalettecommands)
|
||||
- [protocol handlers](protocol-handlers.md)
|
||||
|
||||
## `Renderer.LensExtension` Class
|
||||
|
||||
@ -41,11 +41,11 @@ import { Renderer } from "@k8slens/extensions";
|
||||
|
||||
export default class ExampleExtensionMain extends Renderer.LensExtension {
|
||||
onActivate() {
|
||||
console.log('custom renderer process extension code started');
|
||||
console.log("custom renderer process extension code started");
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
console.log('custom renderer process extension de-activated');
|
||||
console.log("custom renderer process extension de-activated");
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -56,7 +56,7 @@ You can initiate custom code by implementing `onActivate()`.
|
||||
Implementing `onDeactivate()` gives you the opportunity to clean up after your extension.
|
||||
|
||||
!!! info
|
||||
Disable extensions from the Lens Extensions page:
|
||||
Disable extensions from the Lens Extensions page:
|
||||
|
||||
1. Navigate to **File** > **Extensions** in the top menu bar.
|
||||
(On Mac, it is **Lens** > **Extensions**.)
|
||||
@ -75,17 +75,17 @@ Add a cluster page definition to a `Renderer.LensExtension` subclass with the fo
|
||||
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { ExampleIcon, ExamplePage } from "./page"
|
||||
import React from "react"
|
||||
import { ExampleIcon, ExamplePage } from "./page";
|
||||
import React from "react";
|
||||
|
||||
export default class ExampleExtension extends Renderer.LensExtension {
|
||||
clusterPages = [
|
||||
{
|
||||
id: "hello",
|
||||
components: {
|
||||
Page: () => <ExamplePage extension={this}/>,
|
||||
}
|
||||
}
|
||||
Page: () => <ExamplePage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -93,24 +93,26 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
`clusterPages` is an array of objects that satisfy the `PageRegistration` interface.
|
||||
The properties of the `clusterPages` array objects are defined as follows:
|
||||
|
||||
* `id` is a string that identifies the page.
|
||||
* `components` matches the `PageComponents` interface for which there is one field, `Page`.
|
||||
* `Page` is of type ` React.ComponentType<any>`.
|
||||
It offers flexibility in defining the appearance and behavior of your page.
|
||||
- `id` is a string that identifies the page.
|
||||
- `components` matches the `PageComponents` interface for which there is one field, `Page`.
|
||||
- `Page` is of type ` React.ComponentType<any>`.
|
||||
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 { 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;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p>Hello world!</p>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -130,17 +132,17 @@ By expanding on the above example, you can add a cluster page menu item to the `
|
||||
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { ExampleIcon, ExamplePage } from "./page"
|
||||
import React from "react"
|
||||
import { ExampleIcon, ExamplePage } from "./page";
|
||||
import React from "react";
|
||||
|
||||
export default class ExampleExtension extends Renderer.LensExtension {
|
||||
clusterPages = [
|
||||
{
|
||||
id: "hello",
|
||||
components: {
|
||||
Page: () => <ExamplePage extension={this}/>,
|
||||
}
|
||||
}
|
||||
Page: () => <ExamplePage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
clusterPageMenus = [
|
||||
@ -149,7 +151,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
title: "Hello World",
|
||||
components: {
|
||||
Icon: ExampleIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@ -159,10 +161,10 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
This element defines how the cluster page menu item will appear and what it will do when you click it.
|
||||
The properties of the `clusterPageMenus` array objects are defined as follows:
|
||||
|
||||
* `target` links to the relevant cluster page using `pageId`.
|
||||
* `pageId` takes the value of the relevant cluster page's `id` property.
|
||||
* `title` sets the name of the cluster page menu item that will appear in the left side menu.
|
||||
* `components` is used to set an icon that appears to the left of the `title` text in the left side menu.
|
||||
- `target` links to the relevant cluster page using `pageId`.
|
||||
- `pageId` takes the value of the relevant cluster page's `id` property.
|
||||
- `title` sets the name of the cluster page menu item that will appear in the left side menu.
|
||||
- `components` is used to set an icon that appears to the left of the `title` text in the left side menu.
|
||||
|
||||
The above example creates a menu item that reads **Hello World**.
|
||||
When users click **Hello World**, the cluster dashboard will show the contents of `Example Page`.
|
||||
@ -171,7 +173,7 @@ This example requires the definition of another React-based component, `ExampleI
|
||||
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import React from "react"
|
||||
import React from "react";
|
||||
|
||||
type IconProps = Renderer.Component.IconProps;
|
||||
|
||||
@ -180,16 +182,18 @@ const {
|
||||
} = Renderer;
|
||||
|
||||
export function ExampleIcon(props: IconProps) {
|
||||
return <Icon {...props} material="pages" tooltip={"Hi!"}/>
|
||||
return <Icon {...props} material="pages" tooltip={"Hi!"} />;
|
||||
}
|
||||
|
||||
export class ExamplePage extends React.Component<{ extension: Renderer.LensExtension }> {
|
||||
export class ExamplePage extends React.Component<{
|
||||
extension: Renderer.LensExtension;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p>Hello world!</p>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -198,32 +202,31 @@ Lens includes various built-in components available for extension developers to
|
||||
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.
|
||||
- `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.
|
||||
|
||||
`clusterPageMenus` can also be used to define sub menu items, so that you can create groups of cluster pages.
|
||||
The following example groups two sub menu items under one parent menu item:
|
||||
|
||||
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { ExampleIcon, ExamplePage } from "./page"
|
||||
import React from "react"
|
||||
import { ExampleIcon, ExamplePage } from "./page";
|
||||
import React from "react";
|
||||
|
||||
export default class ExampleExtension extends Renderer.LensExtension {
|
||||
clusterPages = [
|
||||
{
|
||||
id: "hello",
|
||||
components: {
|
||||
Page: () => <ExamplePage extension={this}/>,
|
||||
}
|
||||
Page: () => <ExamplePage extension={this} />,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "bonjour",
|
||||
components: {
|
||||
Page: () => <ExemplePage extension={this}/>,
|
||||
}
|
||||
}
|
||||
Page: () => <ExemplePage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
clusterPageMenus = [
|
||||
@ -232,7 +235,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
title: "Greetings",
|
||||
components: {
|
||||
Icon: ExampleIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: "example",
|
||||
@ -240,7 +243,7 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
title: "Hello World",
|
||||
components: {
|
||||
Icon: ExampleIcon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
parentId: "example",
|
||||
@ -248,8 +251,8 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
title: "Bonjour le monde",
|
||||
components: {
|
||||
Icon: ExempleIcon,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -280,18 +283,18 @@ Unlike cluster pages, users can trigger global pages even when there is no activ
|
||||
The following example defines a `Renderer.LensExtension` subclass with a single global page definition:
|
||||
|
||||
```typescript
|
||||
import { Renderer } from '@k8slens/extensions';
|
||||
import { HelpPage } from './page';
|
||||
import React from 'react';
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { HelpPage } from "./page";
|
||||
import React from "react";
|
||||
|
||||
export default class HelpExtension extends Renderer.LensExtension {
|
||||
globalPages = [
|
||||
{
|
||||
id: "help",
|
||||
components: {
|
||||
Page: () => <HelpPage extension={this}/>,
|
||||
}
|
||||
}
|
||||
Page: () => <HelpPage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -299,24 +302,26 @@ export default class HelpExtension extends Renderer.LensExtension {
|
||||
`globalPages` is an array of objects that satisfy the `PageRegistration` interface.
|
||||
The properties of the `globalPages` array objects are defined as follows:
|
||||
|
||||
* `id` is a string that identifies the page.
|
||||
* `components` matches the `PageComponents` interface for which there is one field, `Page`.
|
||||
* `Page` is of type `React.ComponentType<any>`.
|
||||
It offers flexibility in defining the appearance and behavior of your page.
|
||||
- `id` is a string that identifies the page.
|
||||
- `components` matches the `PageComponents` interface for which there is one field, `Page`.
|
||||
- `Page` is of type `React.ComponentType<any>`.
|
||||
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 { 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;
|
||||
}> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<p>Help yourself</p>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -328,11 +333,12 @@ This way, `HelpPage` can access all `HelpExtension` subclass data.
|
||||
This example code shows how to create a global page, but not how to make that page available to the Lens user.
|
||||
Global pages are typically made available in the following ways:
|
||||
|
||||
* To add global pages to the top menu bar, see [`appMenus`](../main-extension#appmenus) in the Main Extension guide.
|
||||
* To add global pages as an interactive element in the blue status bar along the bottom of the Lens UI, see [`statusBarItems`](#statusbaritems).
|
||||
* To add global pages to the Welcome Page, see [`welcomeMenus`](#welcomemenus).
|
||||
- To add global pages to the top menu bar, see [`appMenus`](../main-extension#appmenus) in the Main Extension guide.
|
||||
- To add global pages as an interactive element in the blue status bar along the bottom of the Lens UI, see [`statusBarItems`](#statusbaritems).
|
||||
- To add global pages to the Welcome Page, see [`welcomeMenus`](#welcomemenus).
|
||||
|
||||
### `welcomeMenus`
|
||||
|
||||
### `appPreferences`
|
||||
|
||||
The Lens **Preferences** page is a built-in global page.
|
||||
@ -342,22 +348,24 @@ The following example demonstrates adding a custom preference:
|
||||
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { ExamplePreferenceHint, ExamplePreferenceInput } from "./src/example-preference";
|
||||
import {
|
||||
ExamplePreferenceHint,
|
||||
ExamplePreferenceInput,
|
||||
} from "./src/example-preference";
|
||||
import { observable } from "mobx";
|
||||
import React from "react";
|
||||
|
||||
export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||
|
||||
@observable preference = { enabled: false };
|
||||
|
||||
appPreferences = [
|
||||
{
|
||||
title: "Example Preferences",
|
||||
components: {
|
||||
Input: () => <ExamplePreferenceInput preference={this.preference}/>,
|
||||
Hint: () => <ExamplePreferenceHint/>
|
||||
}
|
||||
}
|
||||
Input: () => <ExamplePreferenceInput preference={this.preference} />,
|
||||
Hint: () => <ExamplePreferenceHint />,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -365,13 +373,13 @@ export default class ExampleRendererExtension extends Renderer.LensExtension {
|
||||
`appPreferences` is an array of objects that satisfies the `AppPreferenceRegistration` interface.
|
||||
The properties of the `appPreferences` array objects are defined as follows:
|
||||
|
||||
* `title` sets the heading text displayed on the Preferences page.
|
||||
* `components` specifies two `React.Component` objects that define the interface for the preference.
|
||||
* `Input` specifies an interactive input element for the preference.
|
||||
* `Hint` provides descriptive information for the preference, shown below the `Input` element.
|
||||
- `title` sets the heading text displayed on the Preferences page.
|
||||
- `components` specifies two `React.Component` objects that define the interface for the preference.
|
||||
- `Input` specifies an interactive input element for the preference.
|
||||
- `Hint` provides descriptive information for the preference, shown below the `Input` element.
|
||||
|
||||
!!! note
|
||||
Note that the input and the hint can be comprised of more sophisticated elements, according to the needs of the extension.
|
||||
Note that the input and the hint can be comprised of more sophisticated elements, according to the needs of the extension.
|
||||
|
||||
`ExamplePreferenceInput` expects its React props to be set to an `ExamplePreferenceProps` instance.
|
||||
This is how `ExampleRendererExtension` handles the state of the preference input.
|
||||
@ -386,22 +394,19 @@ import { observer } from "mobx-react";
|
||||
import React from "react";
|
||||
|
||||
const {
|
||||
Component: {
|
||||
Checkbox,
|
||||
},
|
||||
Component: { Checkbox },
|
||||
} = Renderer;
|
||||
|
||||
export class ExamplePreferenceProps {
|
||||
preference: {
|
||||
enabled: boolean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@observer
|
||||
export class ExamplePreferenceInput extends React.Component<ExamplePreferenceProps> {
|
||||
|
||||
public constructor() {
|
||||
super({preference: { enabled: false}});
|
||||
super({ preference: { enabled: false } });
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
@ -411,7 +416,9 @@ export class ExamplePreferenceInput extends React.Component<ExamplePreferencePro
|
||||
<Checkbox
|
||||
label="I understand appPreferences"
|
||||
value={preference.enabled}
|
||||
onChange={v => { preference.enabled = v; }}
|
||||
onChange={(v) => {
|
||||
preference.enabled = v;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -419,18 +426,16 @@ export class ExamplePreferenceInput extends React.Component<ExamplePreferencePro
|
||||
|
||||
export class ExamplePreferenceHint extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<span>This is an example of an appPreference for extensions.</span>
|
||||
);
|
||||
return <span>This is an example of an appPreference for extensions.</span>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`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`.
|
||||
* `onChange` is a function that responds when the state of the checkbox changes.
|
||||
- `label` sets the text that displays next to the checkbox.
|
||||
- `value` is initially set to `preference.enabled`.
|
||||
- `onChange` is a function that responds when the state of the checkbox changes.
|
||||
|
||||
`ExamplePreferenceInput` is defined with the `ExamplePreferenceProps` React props.
|
||||
This is an object with the single `enabled` property.
|
||||
@ -461,18 +466,18 @@ 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 { Renderer } from '@k8slens/extensions';
|
||||
import { HelpIcon, HelpPage } from "./page"
|
||||
import React from 'react';
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { HelpIcon, HelpPage } from "./page";
|
||||
import React from "react";
|
||||
|
||||
export default class HelpExtension extends Renderer.LensExtension {
|
||||
globalPages = [
|
||||
{
|
||||
id: "help",
|
||||
components: {
|
||||
Page: () => <HelpPage extension={this}/>,
|
||||
}
|
||||
}
|
||||
Page: () => <HelpPage extension={this} />,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
statusBarItems = [
|
||||
@ -486,7 +491,7 @@ export default class HelpExtension extends Renderer.LensExtension {
|
||||
<HelpIcon />
|
||||
My Status Bar Item
|
||||
</div>
|
||||
)
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -495,14 +500,14 @@ export default class HelpExtension extends Renderer.LensExtension {
|
||||
|
||||
The properties of the `statusBarItems` array objects are defined as follows:
|
||||
|
||||
* `Item` specifies the `React.Component` that will be shown on the status bar.
|
||||
By default, items are added starting from the right side of the status bar.
|
||||
Due to limited space in the status bar, `Item` will typically specify only an icon or a short string of text.
|
||||
The example above reuses the `HelpIcon` from the [`globalPageMenus` guide](#globalpagemenus).
|
||||
* `onClick` determines what the `statusBarItem` does when it is clicked.
|
||||
In the example, `onClick` is set to a function that calls the `LensRendererExtension` `navigate()` method.
|
||||
`navigate` takes the `id` of the associated global page as a parameter.
|
||||
Thus, clicking the status bar item activates the associated global pages.
|
||||
- `Item` specifies the `React.Component` that will be shown on the status bar.
|
||||
By default, items are added starting from the right side of the status bar.
|
||||
Due to limited space in the status bar, `Item` will typically specify only an icon or a short string of text.
|
||||
The example above reuses the `HelpIcon` from the [`globalPageMenus` guide](#globalpagemenus).
|
||||
- `onClick` determines what the `statusBarItem` does when it is clicked.
|
||||
In the example, `onClick` is set to a function that calls the `LensRendererExtension` `navigate()` method.
|
||||
`navigate` takes the `id` of the associated global page as a parameter.
|
||||
Thus, clicking the status bar item activates the associated global pages.
|
||||
|
||||
### `kubeObjectMenuItems`
|
||||
|
||||
@ -518,9 +523,9 @@ They also appear on the title bar of the details page for specific resources:
|
||||
The following example shows how to add a `kubeObjectMenuItems` for namespace resources with an associated action:
|
||||
|
||||
```typescript
|
||||
import React from "react"
|
||||
import React from "react";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { NamespaceMenuItem } from "./src/namespace-menu-item"
|
||||
import { NamespaceMenuItem } from "./src/namespace-menu-item";
|
||||
|
||||
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||
type Namespace = Renderer.K8sApi.Namespace;
|
||||
@ -531,23 +536,24 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
kind: "Namespace",
|
||||
apiVersions: ["v1"],
|
||||
components: {
|
||||
MenuItem: (props: KubeObjectMenuProps<Namespace>) => <NamespaceMenuItem {...props} />
|
||||
}
|
||||
}
|
||||
MenuItem: (props: KubeObjectMenuProps<Namespace>) => (
|
||||
<NamespaceMenuItem {...props} />
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
`kubeObjectMenuItems` is an array of objects matching the `KubeObjectMenuRegistration` interface.
|
||||
The example above adds a menu item for namespaces in the cluster dashboard.
|
||||
The properties of the `kubeObjectMenuItems` array objects are defined as follows:
|
||||
|
||||
* `kind` specifies the Kubernetes resource type the menu item will apply to.
|
||||
* `apiVersion` specifies the Kubernetes API version number to use with the resource type.
|
||||
* `components` defines the menu item's appearance and behavior.
|
||||
* `MenuItem` provides a function that returns a `React.Component` given a set of menu item properties.
|
||||
In this example a `NamespaceMenuItem` object is returned.
|
||||
- `kind` specifies the Kubernetes resource type the menu item will apply to.
|
||||
- `apiVersion` specifies the Kubernetes API version number to use with the resource type.
|
||||
- `components` defines the menu item's appearance and behavior.
|
||||
- `MenuItem` provides a function that returns a `React.Component` given a set of menu item properties.
|
||||
In this example a `NamespaceMenuItem` object is returned.
|
||||
|
||||
`NamespaceMenuItem` is defined in `./src/namespace-menu-item.tsx`:
|
||||
|
||||
@ -556,11 +562,7 @@ import React from "react";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
|
||||
const {
|
||||
Component: {
|
||||
terminalStore,
|
||||
MenuItem,
|
||||
Icon,
|
||||
},
|
||||
Component: { terminalStore, MenuItem, Icon },
|
||||
Navigation,
|
||||
} = Renderer;
|
||||
|
||||
@ -587,12 +589,15 @@ export function NamespaceMenuItem(props: KubeObjectMenuProps<Namespace>) {
|
||||
|
||||
return (
|
||||
<MenuItem onClick={getPods}>
|
||||
<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>
|
||||
</MenuItem>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
`NamespaceMenuItem` returns a `Renderer.Component.MenuItem` which defines the menu item's appearance and its behavior when activated via the `onClick` property.
|
||||
@ -629,9 +634,11 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
apiVersions: ["v1"],
|
||||
priority: 10,
|
||||
components: {
|
||||
Details: (props: KubeObjectDetailsProps<Namespace>) => <NamespaceDetailsItem {...props} />
|
||||
}
|
||||
}
|
||||
Details: (props: KubeObjectDetailsProps<Namespace>) => (
|
||||
<NamespaceDetailsItem {...props} />
|
||||
),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
@ -640,15 +647,15 @@ export default class ExampleExtension extends Renderer.LensExtension {
|
||||
This example above adds a detail item for namespaces in the cluster dashboard.
|
||||
The properties of the `kubeObjectDetailItems` array objects are defined as follows:
|
||||
|
||||
* `kind` specifies the Kubernetes resource type the detail item will apply to.
|
||||
* `apiVersion` specifies the Kubernetes API version number to use with the resource type.
|
||||
* `components` defines the detail item's appearance and behavior.
|
||||
* `Details` provides a function that returns a `React.Component` given a set of detail item properties.
|
||||
In this example a `NamespaceDetailsItem` object is returned.
|
||||
- `kind` specifies the Kubernetes resource type the detail item will apply to.
|
||||
- `apiVersion` specifies the Kubernetes API version number to use with the resource type.
|
||||
- `components` defines the detail item's appearance and behavior.
|
||||
- `Details` provides a function that returns a `React.Component` given a set of detail item properties.
|
||||
In this example a `NamespaceDetailsItem` object is returned.
|
||||
|
||||
`NamespaceDetailsItem` is defined in `./src/namespace-details-item.tsx`:
|
||||
|
||||
``` typescript
|
||||
```typescript
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
import { PodsDetailsList } from "./pods-details-list";
|
||||
import React from "react";
|
||||
@ -656,12 +663,8 @@ import { observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
const {
|
||||
K8sApi: {
|
||||
podsApi,
|
||||
},
|
||||
Component: {
|
||||
DrawerTitle,
|
||||
},
|
||||
K8sApi: { podsApi },
|
||||
Component: { DrawerTitle },
|
||||
} = Renderer;
|
||||
|
||||
type KubeObjectMenuProps = Renderer.Component.KubeObjectMenuProps;
|
||||
@ -669,7 +672,9 @@ type Namespace = Renderer.K8sApi.Namespace;
|
||||
type Pod = Renderer.K8sApi.Pod;
|
||||
|
||||
@observer
|
||||
export class NamespaceDetailsItem extends React.Component<KubeObjectDetailsProps<Namespace>> {
|
||||
export class NamespaceDetailsItem extends React.Component<
|
||||
KubeObjectDetailsProps<Namespace>
|
||||
> {
|
||||
@observable private pods: Pod[];
|
||||
|
||||
async componentDidMount() {
|
||||
@ -681,10 +686,10 @@ export class NamespaceDetailsItem extends React.Component<KubeObjectDetailsProps
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<DrawerTitle title="Pods" />
|
||||
<PodsDetailsList pods={this.pods}/>
|
||||
<DrawerTitle>Pods</DrawerTitle>
|
||||
<PodsDetailsList pods={this.pods} />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -709,17 +714,12 @@ Details are placed in drawers, and using `Renderer.Component.DrawerTitle` provid
|
||||
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
|
||||
```typescript
|
||||
import React from "react";
|
||||
import { Renderer } from "@k8slens/extensions";
|
||||
|
||||
const {
|
||||
Component: {
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
Table,
|
||||
},
|
||||
Component: { TableHead, TableRow, TableCell, Table },
|
||||
} = Renderer;
|
||||
|
||||
type Pod = Renderer.K8sApi.Pod;
|
||||
@ -736,11 +736,11 @@ export class PodsDetailsList extends React.Component<PodsDetailsListProps> {
|
||||
<TableCell className="podAge">{pods[index].getAge()}</TableCell>
|
||||
<TableCell className="podStatus">{pods[index].getStatus()}</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { pods } = this.props
|
||||
const { pods } = this.props;
|
||||
|
||||
if (!pods?.length) {
|
||||
return null;
|
||||
@ -754,7 +754,7 @@ export class PodsDetailsList extends React.Component<PodsDetailsListProps> {
|
||||
<TableCell className="podAge">Age</TableCell>
|
||||
<TableCell className="podStatus">Status</TableCell>
|
||||
</TableHead>
|
||||
{ pods.map(this.getTableRow) }
|
||||
{pods.map(this.getTableRow)}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -134,7 +134,7 @@ export class HpaDetails extends React.Component<HpaDetailsProps> {
|
||||
})}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle title="Metrics"/>
|
||||
<DrawerTitle>Metrics</DrawerTitle>
|
||||
<div className="metrics">
|
||||
{this.renderMetrics()}
|
||||
</div>
|
||||
|
||||
@ -85,7 +85,7 @@ export class ConfigMapDetails extends React.Component<ConfigMapDetailsProps> {
|
||||
{
|
||||
data.length > 0 && (
|
||||
<>
|
||||
<DrawerTitle title="Data"/>
|
||||
<DrawerTitle>Data</DrawerTitle>
|
||||
{
|
||||
data.map(([name, value]) => (
|
||||
<div key={name} className="data">
|
||||
|
||||
@ -82,7 +82,7 @@ export class ResourceQuotaDetails extends React.Component<ResourceQuotaDetailsPr
|
||||
|
||||
{quota.getScopeSelector().length > 0 && (
|
||||
<>
|
||||
<DrawerTitle title="Scope Selector"/>
|
||||
<DrawerTitle>Scope Selector</DrawerTitle>
|
||||
<Table className="paths">
|
||||
<TableHead>
|
||||
<TableCell>Operator</TableCell>
|
||||
|
||||
@ -116,7 +116,7 @@ export class SecretDetails extends React.Component<SecretDetailsProps> {
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerTitle title="Data" />
|
||||
<DrawerTitle>Data</DrawerTitle>
|
||||
{secrets.map(this.renderSecret)}
|
||||
<Button
|
||||
primary
|
||||
|
||||
@ -92,7 +92,7 @@ export class CRDDetails extends React.Component<CRDDetailsProps> {
|
||||
})
|
||||
}
|
||||
</DrawerItem>
|
||||
<DrawerTitle title="Names"/>
|
||||
<DrawerTitle>Names</DrawerTitle>
|
||||
<Table selectable className="names box grow">
|
||||
<TableHead>
|
||||
<TableCell>plural</TableCell>
|
||||
@ -109,7 +109,7 @@ export class CRDDetails extends React.Component<CRDDetailsProps> {
|
||||
</Table>
|
||||
{printerColumns.length > 0 &&
|
||||
<>
|
||||
<DrawerTitle title="Additional Printer Columns"/>
|
||||
<DrawerTitle>Additional Printer Columns</DrawerTitle>
|
||||
<Table selectable className="printer-columns box grow">
|
||||
<TableHead>
|
||||
<TableCell className="name">Name</TableCell>
|
||||
@ -136,7 +136,7 @@ export class CRDDetails extends React.Component<CRDDetailsProps> {
|
||||
}
|
||||
{validation &&
|
||||
<>
|
||||
<DrawerTitle title="Validation"/>
|
||||
<DrawerTitle>Validation</DrawerTitle>
|
||||
<MonacoEditor
|
||||
readOnly
|
||||
value={validation}
|
||||
|
||||
@ -71,7 +71,7 @@ export class EventDetails extends React.Component<EventDetailsProps> {
|
||||
<span className={kebabCase(type)}>{type}</span>
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle title="Involved object"/>
|
||||
<DrawerTitle>Involved object</DrawerTitle>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableCell>Name</TableCell>
|
||||
|
||||
@ -113,7 +113,7 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
|
||||
|
||||
return (
|
||||
<div className="values">
|
||||
<DrawerTitle title="Values" />
|
||||
<DrawerTitle>Values</DrawerTitle>
|
||||
<div className="flex column gaps">
|
||||
<Checkbox
|
||||
label="User-supplied values only"
|
||||
@ -238,9 +238,9 @@ class NonInjectedReleaseDetails extends Component<ReleaseDetailsProps & Dependen
|
||||
/>
|
||||
</DrawerItem>
|
||||
{this.renderValues()}
|
||||
<DrawerTitle title="Notes"/>
|
||||
<DrawerTitle>Notes</DrawerTitle>
|
||||
{this.renderNotes()}
|
||||
<DrawerTitle title="Resources"/>
|
||||
<DrawerTitle>Resources</DrawerTitle>
|
||||
{resources && this.renderResources(resources)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -35,7 +35,7 @@ export class EndpointDetails extends React.Component<EndpointDetailsProps> {
|
||||
return (
|
||||
<div className="EndpointDetails">
|
||||
<KubeObjectMeta object={endpoint}/>
|
||||
<DrawerTitle title="Subsets"/>
|
||||
<DrawerTitle>Subsets</DrawerTitle>
|
||||
{
|
||||
endpoint.getEndpointSubsets().map((subset) => (
|
||||
<EndpointSubsetList key={subset.toString()} subset={subset} endpoint={endpoint} />
|
||||
|
||||
@ -160,10 +160,10 @@ export class IngressDetails extends React.Component<IngressDetailsProps> {
|
||||
{serviceName}:{servicePort}
|
||||
</DrawerItem>
|
||||
}
|
||||
<DrawerTitle title="Rules"/>
|
||||
<DrawerTitle>Rules</DrawerTitle>
|
||||
{this.renderPaths(ingress)}
|
||||
|
||||
<DrawerTitle title="Load-Balancer Ingress Points"/>
|
||||
<DrawerTitle>Load-Balancer Ingress Points</DrawerTitle>
|
||||
{this.renderIngressPoints(ingressPoints)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -170,7 +170,7 @@ export class NetworkPolicyDetails extends React.Component<NetworkPolicyDetailsPr
|
||||
|
||||
{ingress && (
|
||||
<>
|
||||
<DrawerTitle title="Ingress"/>
|
||||
<DrawerTitle>Ingress</DrawerTitle>
|
||||
{ingress.map((ingress, i) => (
|
||||
<div key={i} data-testid={`ingress-${i}`}>
|
||||
{this.renderNetworkPolicyPorts(ingress.ports)}
|
||||
@ -182,7 +182,7 @@ export class NetworkPolicyDetails extends React.Component<NetworkPolicyDetailsPr
|
||||
|
||||
{egress && (
|
||||
<>
|
||||
<DrawerTitle title="Egress"/>
|
||||
<DrawerTitle>Egress</DrawerTitle>
|
||||
{egress.map((egress, i) => (
|
||||
<div key={i} data-testid={`egress-${i}`}>
|
||||
{this.renderNetworkPolicyPorts(egress.ports)}
|
||||
|
||||
@ -86,7 +86,7 @@ class NonInjectedServiceDetails extends React.Component<ServiceDetailsProps & De
|
||||
{spec.sessionAffinity}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle title="Connection"/>
|
||||
<DrawerTitle>Connection</DrawerTitle>
|
||||
|
||||
<DrawerItem name="Cluster IP">
|
||||
{spec.clusterIP}
|
||||
@ -129,7 +129,7 @@ class NonInjectedServiceDetails extends React.Component<ServiceDetailsProps & De
|
||||
{spec.loadBalancerIP}
|
||||
</DrawerItem>
|
||||
)}
|
||||
<DrawerTitle title="Endpoint"/>
|
||||
<DrawerTitle>Endpoint</DrawerTitle>
|
||||
|
||||
<ServiceDetailsEndpoint endpoint={endpoint}/>
|
||||
</div>
|
||||
|
||||
@ -169,9 +169,9 @@ class NonInjectedNodeDetails extends React.Component<NodeDetailsProps & Dependen
|
||||
}
|
||||
</DrawerItem>
|
||||
}
|
||||
<DrawerTitle title="Capacity"/>
|
||||
<DrawerTitle>Capacity</DrawerTitle>
|
||||
<NodeDetailsResources node={node} type={"capacity"}/>
|
||||
<DrawerTitle title="Allocatable"/>
|
||||
<DrawerTitle>Allocatable</DrawerTitle>
|
||||
<NodeDetailsResources node={node} type={"allocatable"}/>
|
||||
<PodDetailsList
|
||||
pods={childPods}
|
||||
|
||||
@ -161,7 +161,7 @@ export class PodSecurityPolicyDetails extends React.Component<PodSecurityPolicyD
|
||||
|
||||
{allowedHostPaths && (
|
||||
<>
|
||||
<DrawerTitle title="Allowed Host Paths"/>
|
||||
<DrawerTitle>Allowed Host Paths</DrawerTitle>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableCell>Path Prefix</TableCell>
|
||||
@ -186,7 +186,7 @@ export class PodSecurityPolicyDetails extends React.Component<PodSecurityPolicyD
|
||||
|
||||
{runtimeClass && (
|
||||
<>
|
||||
<DrawerTitle title="Runtime Class"/>
|
||||
<DrawerTitle>Runtime Class</DrawerTitle>
|
||||
<DrawerItem name="Allowed Runtime Class Names">
|
||||
{runtimeClass.allowedRuntimeClassNames?.join(", ") || "-"}
|
||||
</DrawerItem>
|
||||
@ -198,7 +198,7 @@ export class PodSecurityPolicyDetails extends React.Component<PodSecurityPolicyD
|
||||
|
||||
{seLinux && (
|
||||
<>
|
||||
<DrawerTitle title="Se Linux"/>
|
||||
<DrawerTitle>Se Linux</DrawerTitle>
|
||||
<DrawerItem name="Rule">
|
||||
{seLinux.rule}
|
||||
</DrawerItem>
|
||||
|
||||
@ -80,7 +80,7 @@ class NonInjectedStorageClassDetails extends React.Component<StorageClassDetails
|
||||
)}
|
||||
{parameters && (
|
||||
<>
|
||||
<DrawerTitle title="Parameters"/>
|
||||
<DrawerTitle>Parameters</DrawerTitle>
|
||||
{
|
||||
Object.entries(parameters).map(([name, value]) => (
|
||||
<DrawerItem key={name + value} name={startCase(name)}>
|
||||
|
||||
@ -102,7 +102,7 @@ export class PersistentVolumeClaimDetails extends React.Component<PersistentVolu
|
||||
{volumeClaim.getStatus()}
|
||||
</DrawerItem>
|
||||
|
||||
<DrawerTitle title="Selector"/>
|
||||
<DrawerTitle>Selector</DrawerTitle>
|
||||
|
||||
<DrawerItem name="Match Labels" labelsOnly>
|
||||
{volumeClaim.getMatchLabels().map(label => <Badge key={label} label={label}/>)}
|
||||
|
||||
@ -67,7 +67,7 @@ export class VolumeDetailsList extends React.Component<VolumeDetailsListProps> {
|
||||
|
||||
return (
|
||||
<div className="VolumeDetailsList flex column">
|
||||
<DrawerTitle title="Persistent Volumes"/>
|
||||
<DrawerTitle>Persistent Volumes</DrawerTitle>
|
||||
<Table
|
||||
tableId="storage_volume_details_list"
|
||||
items={persistentVolumes}
|
||||
|
||||
@ -65,7 +65,7 @@ export class PersistentVolumeDetails extends React.Component<PersistentVolumeDet
|
||||
|
||||
{nfs && (
|
||||
<>
|
||||
<DrawerTitle title="Network File System"/>
|
||||
<DrawerTitle>Network File System</DrawerTitle>
|
||||
{
|
||||
Object.entries(nfs).map(([name, value]) => (
|
||||
<DrawerItem key={name} name={startCase(name)}>
|
||||
@ -78,7 +78,7 @@ export class PersistentVolumeDetails extends React.Component<PersistentVolumeDet
|
||||
|
||||
{flexVolume && (
|
||||
<>
|
||||
<DrawerTitle title="FlexVolume"/>
|
||||
<DrawerTitle>FlexVolume</DrawerTitle>
|
||||
<DrawerItem name="Driver">
|
||||
{flexVolume.driver}
|
||||
</DrawerItem>
|
||||
@ -94,7 +94,7 @@ export class PersistentVolumeDetails extends React.Component<PersistentVolumeDet
|
||||
|
||||
{claimRef && (
|
||||
<>
|
||||
<DrawerTitle title="Claim"/>
|
||||
<DrawerTitle>Claim</DrawerTitle>
|
||||
<DrawerItem name="Type">
|
||||
{claimRef.kind}
|
||||
</DrawerItem>
|
||||
|
||||
@ -68,7 +68,7 @@ export class ClusterRoleBindingDetails extends React.Component<ClusterRoleBindin
|
||||
<div className="ClusterRoleBindingDetails">
|
||||
<KubeObjectMeta object={clusterRoleBinding} />
|
||||
|
||||
<DrawerTitle title="Reference" />
|
||||
<DrawerTitle>Reference</DrawerTitle>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableCell>Kind</TableCell>
|
||||
@ -82,7 +82,7 @@ export class ClusterRoleBindingDetails extends React.Component<ClusterRoleBindin
|
||||
</TableRow>
|
||||
</Table>
|
||||
|
||||
<DrawerTitle title="Bindings" />
|
||||
<DrawerTitle>Bindings</DrawerTitle>
|
||||
{subjects.length > 0 && (
|
||||
<Table selectable className="bindings box grow">
|
||||
<TableHead>
|
||||
|
||||
@ -28,7 +28,7 @@ export class ClusterRoleDetails extends React.Component<ClusterRoleDetailsProps>
|
||||
<div className="ClusterRoleDetails">
|
||||
<KubeObjectMeta object={clusterRole}/>
|
||||
|
||||
<DrawerTitle title="Rules"/>
|
||||
<DrawerTitle>Rules</DrawerTitle>
|
||||
{rules.map(({ resourceNames, apiGroups, resources, verbs }, index) => {
|
||||
return (
|
||||
<div className="rule" key={index}>
|
||||
|
||||
@ -64,7 +64,7 @@ export class RoleBindingDetails extends React.Component<RoleBindingDetailsProps>
|
||||
<div className="RoleBindingDetails">
|
||||
<KubeObjectMeta object={roleBinding} />
|
||||
|
||||
<DrawerTitle title="Reference" />
|
||||
<DrawerTitle>Reference</DrawerTitle>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableCell>Kind</TableCell>
|
||||
@ -78,7 +78,7 @@ export class RoleBindingDetails extends React.Component<RoleBindingDetailsProps>
|
||||
</TableRow>
|
||||
</Table>
|
||||
|
||||
<DrawerTitle title="Bindings" />
|
||||
<DrawerTitle>Bindings</DrawerTitle>
|
||||
{subjects.length > 0 && (
|
||||
<Table selectable className="bindings box grow">
|
||||
<TableHead>
|
||||
|
||||
@ -27,7 +27,7 @@ export class RoleDetails extends React.Component<RoleDetailsProps> {
|
||||
return (
|
||||
<div className="RoleDetails">
|
||||
<KubeObjectMeta object={role}/>
|
||||
<DrawerTitle title="Rules"/>
|
||||
<DrawerTitle>Rules</DrawerTitle>
|
||||
{rules.map(({ resourceNames, apiGroups, resources, verbs }, index) => {
|
||||
return (
|
||||
<div className="rule" key={index}>
|
||||
|
||||
@ -143,7 +143,7 @@ export class ServiceAccountsDetails extends React.Component<ServiceAccountsDetai
|
||||
</DrawerItem>
|
||||
}
|
||||
|
||||
<DrawerTitle title="Mountable secrets"/>
|
||||
<DrawerTitle>Mountable secrets</DrawerTitle>
|
||||
<div className="secrets">
|
||||
{this.renderSecrets()}
|
||||
</div>
|
||||
|
||||
@ -78,7 +78,7 @@ class NonInjectedCronJobDetails extends React.Component<CronJobDetailsProps & De
|
||||
</DrawerItem>
|
||||
{childJobs.length > 0 &&
|
||||
<>
|
||||
<DrawerTitle title="Jobs"/>
|
||||
<DrawerTitle>Jobs</DrawerTitle>
|
||||
{childJobs.map((job: Job) => {
|
||||
const selectors = job.getSelectors();
|
||||
const condition = job.getCondition();
|
||||
|
||||
@ -53,7 +53,7 @@ export class DeploymentReplicaSets extends React.Component<DeploymentReplicaSets
|
||||
|
||||
return (
|
||||
<div className="ReplicaSets flex column">
|
||||
<DrawerTitle title="Deploy Revisions"/>
|
||||
<DrawerTitle>Deploy Revisions</DrawerTitle>
|
||||
<Table
|
||||
selectable
|
||||
tableId="deployment_replica_sets_view"
|
||||
|
||||
@ -131,7 +131,7 @@ export class PodDetailsList extends React.Component<PodDetailsListProps> {
|
||||
|
||||
return (
|
||||
<div className="PodDetailsList flex column">
|
||||
<DrawerTitle title="Pods" />
|
||||
<DrawerTitle>Pods</DrawerTitle>
|
||||
<Table
|
||||
tableId="workloads_pod_details_list"
|
||||
items={pods}
|
||||
|
||||
@ -10,7 +10,7 @@ import { Link } from "react-router-dom";
|
||||
import { configMapApi, Pod, PodVolume, PodVolumeKind, PodVolumeVariants, pvcApi, SecretReference, secretsApi } from "../../../common/k8s-api/endpoints";
|
||||
import type { KubeApi } from "../../../common/k8s-api/kube-api";
|
||||
import type { KubeObject, LocalObjectReference } from "../../../common/k8s-api/kube-object";
|
||||
import { DrawerItem, DrawerItemLabels, DrawerSection, DrawerSubSection } from "../drawer";
|
||||
import { DrawerItem, DrawerItemLabels, DrawerTitle } from "../drawer";
|
||||
import { Icon } from "../icon";
|
||||
import { getDetailsUrl } from "../kube-detail-params";
|
||||
|
||||
@ -341,7 +341,8 @@ const volumeRenderers: PodVolumeVariantRenderers = {
|
||||
sources.map(({ secret, downwardAPI, configMap, serviceAccountToken }, index) => (
|
||||
<React.Fragment key={index}>
|
||||
{secret && (
|
||||
<DrawerSubSection title="Secret">
|
||||
<>
|
||||
<DrawerTitle size="sub-title">Secret</DrawerTitle>
|
||||
<DrawerItem name="Name">
|
||||
{secret.name}
|
||||
</DrawerItem>
|
||||
@ -352,10 +353,11 @@ const volumeRenderers: PodVolumeVariantRenderers = {
|
||||
</ul>
|
||||
</DrawerItem>
|
||||
)}
|
||||
</DrawerSubSection>
|
||||
</>
|
||||
)}
|
||||
{downwardAPI && (
|
||||
<DrawerSubSection title="Downward API">
|
||||
<>
|
||||
<DrawerTitle size="sub-title">Downward API</DrawerTitle>
|
||||
{downwardAPI.items && (
|
||||
<DrawerItem name="Items">
|
||||
<ul>
|
||||
@ -363,10 +365,11 @@ const volumeRenderers: PodVolumeVariantRenderers = {
|
||||
</ul>
|
||||
</DrawerItem>
|
||||
)}
|
||||
</DrawerSubSection>
|
||||
</>
|
||||
)}
|
||||
{configMap && (
|
||||
<DrawerSubSection title="Config Map">
|
||||
<>
|
||||
<DrawerTitle size="sub-title">Config Map</DrawerTitle>
|
||||
<DrawerItem name="Name">
|
||||
{configMap.name}
|
||||
</DrawerItem>
|
||||
@ -377,10 +380,11 @@ const volumeRenderers: PodVolumeVariantRenderers = {
|
||||
</ul>
|
||||
</DrawerItem>
|
||||
)}
|
||||
</DrawerSubSection>
|
||||
</>
|
||||
)}
|
||||
{serviceAccountToken && (
|
||||
<DrawerSubSection title="Service Account Token">
|
||||
<>
|
||||
<DrawerTitle size="sub-title">Service Account Token</DrawerTitle>
|
||||
<DrawerItem name="Audience" hidden={!serviceAccountToken.audience}>
|
||||
{serviceAccountToken.audience}
|
||||
</DrawerItem>
|
||||
@ -390,7 +394,7 @@ const volumeRenderers: PodVolumeVariantRenderers = {
|
||||
<DrawerItem name="Path">
|
||||
{serviceAccountToken.path}
|
||||
</DrawerItem>
|
||||
</DrawerSubSection>
|
||||
</>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))
|
||||
@ -639,9 +643,14 @@ export const PodVolumes = observer(({ pod }: PodVolumesProps) => {
|
||||
|
||||
const volumes = pod.getVolumes();
|
||||
|
||||
if (volumes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<DrawerSection title="Volumes" hidden={volumes.length === 0}>
|
||||
<>
|
||||
<DrawerTitle>Volumes</DrawerTitle>
|
||||
{volumes.map(renderVolume)}
|
||||
</DrawerSection>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { DrawerTitle, DrawerSubTitle } from "./drawer-title";
|
||||
|
||||
export interface DrawerSectionProps {
|
||||
className?: string;
|
||||
title?: React.ReactNode;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export class DrawerSection extends React.Component<DrawerSectionProps> {
|
||||
render() {
|
||||
const { title, children, className, hidden } = this.props;
|
||||
|
||||
if (hidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerTitle className={className} title={title} />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class DrawerSubSection extends React.Component<DrawerSectionProps> {
|
||||
render() {
|
||||
const { title, children, className, hidden } = this.props;
|
||||
|
||||
if (hidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrawerSubTitle className={className} title={title} />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,14 @@
|
||||
*/
|
||||
|
||||
.DrawerTitle {
|
||||
padding: $padding * 1.5 $padding * 3;
|
||||
margin: $margin * 3 (-$margin * 3);
|
||||
background: var(--drawerSubtitleBackground);
|
||||
}
|
||||
|
||||
.DrawerSubTitle {
|
||||
padding: $padding $padding * 2;
|
||||
background: var(--drawerSubtitleBackground);
|
||||
.DrawerTitle.title {
|
||||
padding: $padding * 1.5 $padding * 3;
|
||||
}
|
||||
|
||||
.DrawerTitle.sub-title {
|
||||
padding: $padding $padding * 2;
|
||||
}
|
||||
@ -3,34 +3,29 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./drawer-title.scss";
|
||||
import styles from "./drawer-title.module.css";
|
||||
import React from "react";
|
||||
import { cssNames } from "../../utils";
|
||||
|
||||
export interface DrawerTitleProps {
|
||||
className?: string;
|
||||
title?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
|
||||
/**
|
||||
* Specifies how large this title is
|
||||
*
|
||||
* @default "title"
|
||||
*/
|
||||
size?: "sub-title" | "title";
|
||||
}
|
||||
|
||||
export class DrawerTitle extends React.Component<DrawerTitleProps> {
|
||||
render() {
|
||||
const { title, children, className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={cssNames("DrawerTitle", className)}>
|
||||
{title || children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export class DrawerSubTitle extends React.Component<DrawerTitleProps> {
|
||||
render() {
|
||||
const { title, children, className } = this.props;
|
||||
|
||||
return (
|
||||
<div className={cssNames("DrawerSubTitle", className)}>
|
||||
{title || children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export function DrawerTitle({ className, children, size = "title" }: DrawerTitleProps) {
|
||||
return (
|
||||
<div className={cssNames(styles.DrawerTitle, className, {
|
||||
[styles.title]: size === "title",
|
||||
[styles["sub-title"]]: size === "sub-title",
|
||||
})}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ export function initCatalogEntityDetailRegistry() {
|
||||
components: {
|
||||
Details: ({ entity }: CatalogEntityDetailsProps<KubernetesCluster>) => (
|
||||
<>
|
||||
<DrawerTitle title="Kubernetes Information" />
|
||||
<DrawerTitle>Kubernetes Information</DrawerTitle>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem name="Distribution">
|
||||
{entity.metadata.distro || "unknown"}
|
||||
@ -36,7 +36,7 @@ export function initCatalogEntityDetailRegistry() {
|
||||
components: {
|
||||
Details: ({ entity }: CatalogEntityDetailsProps<WebLink>) => (
|
||||
<>
|
||||
<DrawerTitle title="More Information" />
|
||||
<DrawerTitle>More Information</DrawerTitle>
|
||||
<DrawerItem name="URL">
|
||||
{entity.spec.url}
|
||||
</DrawerItem>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user