mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add extension API for registering custom category views (#4733)
This commit is contained in:
parent
4f5a2988cb
commit
53ffc62391
@ -21,6 +21,42 @@ The categories provided by Lens itself have the following names:
|
|||||||
|
|
||||||
To register a category, call the `Main.Catalog.catalogCategories.add()` and `Renderer.Catalog.catalogCategories.add()` with instances of your class.
|
To register a category, call the `Main.Catalog.catalogCategories.add()` and `Renderer.Catalog.catalogCategories.add()` with instances of your class.
|
||||||
|
|
||||||
|
### Custom Category Views
|
||||||
|
|
||||||
|
By default when a specific category is selected in the catalog page a list of entities of the group and kind that the category has registered.
|
||||||
|
It is possible to register custom views for specific categories by registering them on your `Renderer.LensExtension` class.
|
||||||
|
|
||||||
|
A registration takes the form of a [Common.Types.CustomCategoryViewRegistration](../api/interfaces/Common.Types.CustomCategoryViewRegistration.md)
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Renderer, Common } from "@k8slens/extensions";
|
||||||
|
|
||||||
|
function MyKubernetesClusterView({
|
||||||
|
category,
|
||||||
|
}: Common.Types.CustomCategoryViewProps) {
|
||||||
|
return <div>My view: {category.getId()}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class extends Renderer.LensExtension {
|
||||||
|
customCategoryViews = [
|
||||||
|
{
|
||||||
|
group: "entity.k8slens.dev",
|
||||||
|
kind: "KubernetesCluster",
|
||||||
|
priority: 10,
|
||||||
|
components: {
|
||||||
|
View: MyKubernetesClusterView,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will register a new view for the KubernetesCluster category, and because the priority is < 50 it will be displayed above the default list view.
|
||||||
|
|
||||||
|
The default list view has a priority of 50 and and custom views with priority (defaulting to 50) >= 50 will be displayed afterwards.
|
||||||
|
|
||||||
## Entities
|
## Entities
|
||||||
|
|
||||||
An entity is the data within the catalog.
|
An entity is the data within the catalog.
|
||||||
|
|||||||
@ -17,3 +17,11 @@ export function getOrInsert<K, V>(map: Map<K, V>, key: K, value: V): V {
|
|||||||
|
|
||||||
return map.get(key);
|
return map.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like `getOrInsert` but specifically for when `V` is `Map<any, any>` so that
|
||||||
|
* the typings are inferred.
|
||||||
|
*/
|
||||||
|
export function getOrInsertMap<K, MK, MV>(map: Map<K, Map<MK, MV>>, key: K): Map<MK, MV> {
|
||||||
|
return getOrInsert(map, key, new Map<MK, MV>());
|
||||||
|
}
|
||||||
|
|||||||
@ -11,3 +11,4 @@ export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps,
|
|||||||
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
|
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
|
||||||
export type { StatusBarRegistration } from "../registries/status-bar-registry";
|
export type { StatusBarRegistration } from "../registries/status-bar-registry";
|
||||||
export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler";
|
export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler";
|
||||||
|
export type { CustomCategoryViewProps, CustomCategoryViewComponents, CustomCategoryViewRegistration } from "../../renderer/components/+catalog/custom-views";
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import type { WelcomeBannerRegistration } from "../renderer/components/+welcome/
|
|||||||
import type { CommandRegistration } from "../renderer/components/command-palette/registered-commands/commands";
|
import type { CommandRegistration } from "../renderer/components/command-palette/registered-commands/commands";
|
||||||
import type { AppPreferenceRegistration } from "../renderer/components/+preferences/app-preferences/app-preference-registration";
|
import type { AppPreferenceRegistration } from "../renderer/components/+preferences/app-preferences/app-preference-registration";
|
||||||
import type { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns";
|
import type { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns";
|
||||||
|
import type { CustomCategoryViewRegistration } from "../renderer/components/+catalog/custom-views";
|
||||||
|
|
||||||
export class LensRendererExtension extends LensExtension {
|
export class LensRendererExtension extends LensExtension {
|
||||||
globalPages: registries.PageRegistration[] = [];
|
globalPages: registries.PageRegistration[] = [];
|
||||||
@ -35,6 +36,7 @@ export class LensRendererExtension extends LensExtension {
|
|||||||
catalogEntityDetailItems: registries.CatalogEntityDetailRegistration<CatalogEntity>[] = [];
|
catalogEntityDetailItems: registries.CatalogEntityDetailRegistration<CatalogEntity>[] = [];
|
||||||
topBarItems: TopBarRegistration[] = [];
|
topBarItems: TopBarRegistration[] = [];
|
||||||
additionalCategoryColumns: AdditionalCategoryColumnRegistration[] = [];
|
additionalCategoryColumns: AdditionalCategoryColumnRegistration[] = [];
|
||||||
|
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
||||||
|
|
||||||
async navigate<P extends object>(pageId?: string, params?: P) {
|
async navigate<P extends object>(pageId?: string, params?: P) {
|
||||||
const { navigate } = await import("../renderer/navigation");
|
const { navigate } = await import("../renderer/navigation");
|
||||||
|
|||||||
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ConfigurableDependencyInjectionContainer } from "@ogre-tools/injectable";
|
||||||
|
import { computed } from "mobx";
|
||||||
|
import type React from "react";
|
||||||
|
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||||
|
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
|
||||||
|
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||||
|
import type { CustomCategoryViewRegistration } from "../custom-views";
|
||||||
|
import customCategoryViewsInjectable from "../custom-views.injectable";
|
||||||
|
|
||||||
|
describe("Custom Category Views", () => {
|
||||||
|
let di: ConfigurableDependencyInjectionContainer;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
di = getDiForUnitTesting();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should order items correctly over all extensions", () => {
|
||||||
|
const component1 = (): React.ReactElement => null;
|
||||||
|
const component2 = (): React.ReactElement => null;
|
||||||
|
|
||||||
|
di.override(rendererExtensionsInjectable, () => computed(() => [
|
||||||
|
{
|
||||||
|
customCategoryViews: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
View: component1,
|
||||||
|
},
|
||||||
|
group: "foo",
|
||||||
|
kind: "bar",
|
||||||
|
priority: 100,
|
||||||
|
} as CustomCategoryViewRegistration,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
customCategoryViews: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
View: component2,
|
||||||
|
},
|
||||||
|
group: "foo",
|
||||||
|
kind: "bar",
|
||||||
|
priority: 95,
|
||||||
|
} as CustomCategoryViewRegistration,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as LensRendererExtension[]));
|
||||||
|
|
||||||
|
const customCategoryViews = di.inject(customCategoryViewsInjectable);
|
||||||
|
const { after } = customCategoryViews.get().get("foo").get("bar");
|
||||||
|
|
||||||
|
expect(after[0].View).toBe(component2);
|
||||||
|
expect(after[1].View).toBe(component1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should put put priority < 50 items in before", () => {
|
||||||
|
const component1 = (): React.ReactElement => null;
|
||||||
|
const component2 = (): React.ReactElement => null;
|
||||||
|
|
||||||
|
di.override(rendererExtensionsInjectable, () => computed(() => [
|
||||||
|
{
|
||||||
|
customCategoryViews: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
View: component1,
|
||||||
|
},
|
||||||
|
group: "foo",
|
||||||
|
kind: "bar",
|
||||||
|
priority: 40,
|
||||||
|
} as CustomCategoryViewRegistration,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
customCategoryViews: [
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
View: component2,
|
||||||
|
},
|
||||||
|
group: "foo",
|
||||||
|
kind: "bar",
|
||||||
|
priority: 95,
|
||||||
|
} as CustomCategoryViewRegistration,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as LensRendererExtension[]));
|
||||||
|
|
||||||
|
const customCategoryViews = di.inject(customCategoryViewsInjectable);
|
||||||
|
const { before } = customCategoryViews.get().get("foo").get("bar");
|
||||||
|
|
||||||
|
expect(before[0].View).toBe(component1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -8,7 +8,7 @@ import styles from "./catalog.module.scss";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-react";
|
import { disposeOnUnmount, observer } from "mobx-react";
|
||||||
import { ItemListLayout } from "../item-object-list";
|
import { ItemListLayout } from "../item-object-list";
|
||||||
import { action, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
import { action, IComputedValue, makeObservable, observable, reaction, runInAction, when } from "mobx";
|
||||||
import type { CatalogEntityStore } from "./catalog-entity-store/catalog-entity.store";
|
import type { CatalogEntityStore } from "./catalog-entity-store/catalog-entity.store";
|
||||||
import { navigate } from "../../navigation";
|
import { navigate } from "../../navigation";
|
||||||
import { MenuItem, MenuActions } from "../menu";
|
import { MenuItem, MenuActions } from "../menu";
|
||||||
@ -33,6 +33,9 @@ import catalogPreviousActiveTabStorageInjectable from "./catalog-previous-active
|
|||||||
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
import catalogEntityStoreInjectable from "./catalog-entity-store/catalog-entity-store.injectable";
|
||||||
import type { GetCategoryColumnsParams, CategoryColumns } from "./get-category-columns.injectable";
|
import type { GetCategoryColumnsParams, CategoryColumns } from "./get-category-columns.injectable";
|
||||||
import getCategoryColumnsInjectable from "./get-category-columns.injectable";
|
import getCategoryColumnsInjectable from "./get-category-columns.injectable";
|
||||||
|
import type { RegisteredCustomCategoryViewDecl } from "./custom-views.injectable";
|
||||||
|
import customCategoryViewsInjectable from "./custom-views.injectable";
|
||||||
|
import type { CustomCategoryViewComponents } from "./custom-views";
|
||||||
|
|
||||||
interface Props extends RouteComponentProps<CatalogViewRouteParam> {}
|
interface Props extends RouteComponentProps<CatalogViewRouteParam> {}
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ interface Dependencies {
|
|||||||
catalogPreviousActiveTabStorage: { set: (value: string ) => void };
|
catalogPreviousActiveTabStorage: { set: (value: string ) => void };
|
||||||
catalogEntityStore: CatalogEntityStore;
|
catalogEntityStore: CatalogEntityStore;
|
||||||
getCategoryColumns: (params: GetCategoryColumnsParams) => CategoryColumns;
|
getCategoryColumns: (params: GetCategoryColumnsParams) => CategoryColumns;
|
||||||
|
customCategoryViews: IComputedValue<Map<string, Map<string, RegisteredCustomCategoryViewDecl>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
@ -213,16 +217,44 @@ class NonInjectedCatalog extends React.Component<Props & Dependencies> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderViews = () => {
|
||||||
|
const { catalogEntityStore, customCategoryViews } = this.props;
|
||||||
|
const { activeCategory } = catalogEntityStore;
|
||||||
|
|
||||||
|
if (!activeCategory) {
|
||||||
|
return this.renderList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const customViews = customCategoryViews.get()
|
||||||
|
.get(activeCategory.spec.group)
|
||||||
|
?.get(activeCategory.spec.names.kind);
|
||||||
|
const renderView = ({ View }: CustomCategoryViewComponents, index: number) => (
|
||||||
|
<View
|
||||||
|
key={index}
|
||||||
|
category={activeCategory}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{customViews?.before.map(renderView)}
|
||||||
|
{this.renderList()}
|
||||||
|
{customViews?.after.map(renderView)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
renderList() {
|
renderList() {
|
||||||
const { activeCategory } = this.props.catalogEntityStore;
|
const { catalogEntityStore, getCategoryColumns } = this.props;
|
||||||
const tableId = activeCategory ? `catalog-items-${activeCategory.metadata.name.replace(" ", "")}` : "catalog-items";
|
const { activeCategory } = catalogEntityStore;
|
||||||
|
const tableId = activeCategory
|
||||||
|
? `catalog-items-${activeCategory.metadata.name.replace(" ", "")}`
|
||||||
|
: "catalog-items";
|
||||||
|
|
||||||
if (this.activeTab === undefined) {
|
if (this.activeTab === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { sortingCallbacks, searchFilters, renderTableContents, renderTableHeader } = this.props.getCategoryColumns({ activeCategory });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListLayout
|
<ItemListLayout
|
||||||
className={styles.Catalog}
|
className={styles.Catalog}
|
||||||
@ -230,14 +262,11 @@ class NonInjectedCatalog extends React.Component<Props & Dependencies> {
|
|||||||
renderHeaderTitle={activeCategory?.metadata.name ?? "Browse All"}
|
renderHeaderTitle={activeCategory?.metadata.name ?? "Browse All"}
|
||||||
isSelectable={false}
|
isSelectable={false}
|
||||||
isConfigurable={true}
|
isConfigurable={true}
|
||||||
store={this.props.catalogEntityStore}
|
store={catalogEntityStore}
|
||||||
sortingCallbacks={sortingCallbacks}
|
|
||||||
searchFilters={searchFilters}
|
|
||||||
renderTableHeader={renderTableHeader}
|
|
||||||
customizeTableRowProps={entity => ({
|
customizeTableRowProps={entity => ({
|
||||||
disabled: !entity.isEnabled(),
|
disabled: !entity.isEnabled(),
|
||||||
})}
|
})}
|
||||||
renderTableContents={renderTableContents}
|
{...getCategoryColumns({ activeCategory })}
|
||||||
onDetails={this.onDetails}
|
onDetails={this.onDetails}
|
||||||
renderItemMenu={this.renderItemMenu}
|
renderItemMenu={this.renderItemMenu}
|
||||||
/>
|
/>
|
||||||
@ -254,7 +283,7 @@ class NonInjectedCatalog extends React.Component<Props & Dependencies> {
|
|||||||
return (
|
return (
|
||||||
<MainLayout sidebar={this.renderNavigation()}>
|
<MainLayout sidebar={this.renderNavigation()}>
|
||||||
<div className="p-6 h-full">
|
<div className="p-6 h-full">
|
||||||
{this.renderList()}
|
{this.renderViews()}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
selectedEntity
|
selectedEntity
|
||||||
@ -281,6 +310,7 @@ export const Catalog = withInjectables<Dependencies, Props>( NonInjectedCatalog,
|
|||||||
catalogEntityStore: di.inject(catalogEntityStoreInjectable),
|
catalogEntityStore: di.inject(catalogEntityStoreInjectable),
|
||||||
catalogPreviousActiveTabStorage: di.inject(catalogPreviousActiveTabStorageInjectable),
|
catalogPreviousActiveTabStorage: di.inject(catalogPreviousActiveTabStorageInjectable),
|
||||||
getCategoryColumns: di.inject(getCategoryColumnsInjectable),
|
getCategoryColumns: di.inject(getCategoryColumnsInjectable),
|
||||||
|
customCategoryViews: di.inject(customCategoryViewsInjectable),
|
||||||
...props,
|
...props,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
|||||||
import { computed, IComputedValue } from "mobx";
|
import { computed, IComputedValue } from "mobx";
|
||||||
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||||
import { getOrInsert } from "../../utils";
|
import { getOrInsert, getOrInsertMap } from "../../utils";
|
||||||
import type { RegisteredAdditionalCategoryColumn } from "./custom-category-columns";
|
import type { RegisteredAdditionalCategoryColumn } from "./custom-category-columns";
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
@ -19,7 +19,7 @@ function getAdditionCategoryColumns({ extensions }: Dependencies): IComputedValu
|
|||||||
|
|
||||||
for (const ext of extensions.get()) {
|
for (const ext of extensions.get()) {
|
||||||
for (const { renderCell, titleProps, priority = 50, searchFilter, sortCallback, ...registration } of ext.additionalCategoryColumns) {
|
for (const { renderCell, titleProps, priority = 50, searchFilter, sortCallback, ...registration } of ext.additionalCategoryColumns) {
|
||||||
const byGroup = getOrInsert(res, registration.group, new Map<string, RegisteredAdditionalCategoryColumn[]>());
|
const byGroup = getOrInsertMap(res, registration.group);
|
||||||
const byKind = getOrInsert(byGroup, registration.kind, []);
|
const byKind = getOrInsert(byGroup, registration.kind, []);
|
||||||
const id = `${ext.name}:${registration.id}`;
|
const id = `${ext.name}:${registration.id}`;
|
||||||
|
|
||||||
|
|||||||
58
src/renderer/components/+catalog/custom-views.injectable.ts
Normal file
58
src/renderer/components/+catalog/custom-views.injectable.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||||
|
import { orderBy } from "lodash";
|
||||||
|
import { computed, IComputedValue } from "mobx";
|
||||||
|
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
|
||||||
|
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||||
|
import { getOrInsert, getOrInsertMap } from "../../utils";
|
||||||
|
import type { CustomCategoryViewComponents } from "./custom-views";
|
||||||
|
|
||||||
|
interface Dependencies {
|
||||||
|
extensions: IComputedValue<LensRendererExtension[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisteredCustomCategoryViewDecl {
|
||||||
|
/**
|
||||||
|
* The asc sorted list of items with priority set to < 50
|
||||||
|
*/
|
||||||
|
before: CustomCategoryViewComponents[];
|
||||||
|
/**
|
||||||
|
* The asc sorted list of items with priority not set or set to >= 50
|
||||||
|
*/
|
||||||
|
after: CustomCategoryViewComponents[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCustomCategoryViews({ extensions }: Dependencies): IComputedValue<Map<string, Map<string, RegisteredCustomCategoryViewDecl>>> {
|
||||||
|
return computed(() => {
|
||||||
|
const res = new Map<string, Map<string, RegisteredCustomCategoryViewDecl>>();
|
||||||
|
const registrations = extensions.get()
|
||||||
|
.flatMap(ext => ext.customCategoryViews)
|
||||||
|
.map(({ priority = 50, ...rest }) => ({ priority, ...rest }));
|
||||||
|
const sortedRegistrations = orderBy(registrations, "priority", "asc");
|
||||||
|
|
||||||
|
for (const { priority, group, kind, components } of sortedRegistrations) {
|
||||||
|
const byGroup = getOrInsertMap(res, group);
|
||||||
|
const { before, after } = getOrInsert(byGroup, kind, { before: [], after: [] });
|
||||||
|
|
||||||
|
if (priority < 50) {
|
||||||
|
before.push(components);
|
||||||
|
} else {
|
||||||
|
after.push(components);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const customCategoryViewsInjectable = getInjectable({
|
||||||
|
instantiate: (di) => getCustomCategoryViews({
|
||||||
|
extensions: di.inject(rendererExtensionsInjectable),
|
||||||
|
}),
|
||||||
|
lifecycle: lifecycleEnum.singleton,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default customCategoryViewsInjectable;
|
||||||
57
src/renderer/components/+catalog/custom-views.ts
Normal file
57
src/renderer/components/+catalog/custom-views.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type React from "react";
|
||||||
|
import type { CatalogCategory } from "../../api/catalog-entity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The props for CustomCategoryViewComponents.View
|
||||||
|
*/
|
||||||
|
export interface CustomCategoryViewProps {
|
||||||
|
/**
|
||||||
|
* The category instance itself
|
||||||
|
*/
|
||||||
|
category: CatalogCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components for the category view.
|
||||||
|
*/
|
||||||
|
export interface CustomCategoryViewComponents {
|
||||||
|
View: React.ComponentType<CustomCategoryViewProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the type used to declare additional views for a specific category
|
||||||
|
*/
|
||||||
|
export interface CustomCategoryViewRegistration {
|
||||||
|
/**
|
||||||
|
* The catalog entity kind that is declared by the category for this registration
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* - `"KubernetesCluster"`
|
||||||
|
*/
|
||||||
|
kind: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The catalog entity group that is declared by the category for this registration
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* - `"entity.k8slens.dev"`
|
||||||
|
*/
|
||||||
|
group: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sorting order value. Used to determine the total order of the views.
|
||||||
|
*
|
||||||
|
* @default 50
|
||||||
|
*/
|
||||||
|
priority?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The components for this registration
|
||||||
|
*/
|
||||||
|
components: CustomCategoryViewComponents;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user