mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Replace catalog entity detail registry with reactive solution
Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
parent
1e2a2161f5
commit
ff1ab54e0f
@ -250,7 +250,6 @@ export class ExtensionLoader {
|
||||
return this.autoInitExtensions(async (extension: LensRendererExtension) => {
|
||||
const removeItems = [
|
||||
registries.EntitySettingRegistry.getInstance().add(extension.entitySettings),
|
||||
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
|
||||
];
|
||||
|
||||
this.events.on("remove", (removedExtension: LensRendererExtension) => {
|
||||
|
||||
@ -28,6 +28,9 @@ import extensionPageParametersInjectable from "../renderer/routes/extension-page
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getExtensionRoutePath } from "../renderer/routes/get-extension-route-path";
|
||||
import { navigateToRouteInjectionToken } from "../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import type {
|
||||
CatalogEntityDetailRegistration,
|
||||
} from "../renderer/components/+catalog/catalog-entity-detail-items/extension-registration";
|
||||
|
||||
export class LensRendererExtension extends LensExtension {
|
||||
globalPages: registries.PageRegistration[] = [];
|
||||
@ -43,7 +46,7 @@ export class LensRendererExtension extends LensExtension {
|
||||
commands: CommandRegistration[] = [];
|
||||
welcomeMenus: WelcomeMenuRegistration[] = [];
|
||||
welcomeBanners: WelcomeBannerRegistration[] = [];
|
||||
catalogEntityDetailItems: registries.CatalogEntityDetailRegistration<CatalogEntity>[] = [];
|
||||
catalogEntityDetailItems: CatalogEntityDetailRegistration<CatalogEntity>[] = [];
|
||||
topBarItems: TopBarRegistration[] = [];
|
||||
additionalCategoryColumns: AdditionalCategoryColumnRegistration[] = [];
|
||||
customCategoryViews: CustomCategoryViewRegistration[] = [];
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* 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 { CatalogEntity } from "../common-api/catalog";
|
||||
import { BaseRegistry } from "./base-registry";
|
||||
|
||||
export interface CatalogEntityDetailsProps<T extends CatalogEntity> {
|
||||
entity: T;
|
||||
}
|
||||
|
||||
export interface CatalogEntityDetailComponents<T extends CatalogEntity> {
|
||||
Details: React.ComponentType<CatalogEntityDetailsProps<T>>;
|
||||
}
|
||||
|
||||
export interface CatalogEntityDetailRegistration<T extends CatalogEntity> {
|
||||
kind: string;
|
||||
apiVersions: string[];
|
||||
components: CatalogEntityDetailComponents<T>;
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
export class CatalogEntityDetailRegistry extends BaseRegistry<CatalogEntityDetailRegistration<CatalogEntity>> {
|
||||
getItemsForKind(kind: string, apiVersion: string) {
|
||||
const items = this.getItems().filter((item) => {
|
||||
return item.kind === kind && item.apiVersions.includes(apiVersion);
|
||||
});
|
||||
|
||||
return items.sort((a, b) => (b.priority ?? 50) - (a.priority ?? 50));
|
||||
}
|
||||
}
|
||||
@ -9,5 +9,4 @@ export * from "./page-registry";
|
||||
export * from "./page-menu-registry";
|
||||
export * from "./kube-object-detail-registry";
|
||||
export * from "./entity-setting-registry";
|
||||
export * from "./catalog-entity-detail-registry";
|
||||
export * from "./protocol-handler";
|
||||
|
||||
@ -86,9 +86,6 @@ export async function bootstrap(di: DiContainer) {
|
||||
logger.info(`${logPrefix} initializing KubeObjectDetailRegistry`);
|
||||
initializers.initKubeObjectDetailRegistry();
|
||||
|
||||
logger.info(`${logPrefix} initializing CatalogEntityDetailRegistry`);
|
||||
initializers.initCatalogEntityDetailRegistry();
|
||||
|
||||
const navigateToAddCluster = di.inject(navigateToAddClusterInjectable);
|
||||
const addSyncEntries = di.inject(addSyncEntriesInjectable);
|
||||
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectionToken } from "@ogre-tools/injectable";
|
||||
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import type { CatalogEntity } from "../../../../common/catalog";
|
||||
import type { CatalogEntityDetailItemComponentProps } from "./extension-registration";
|
||||
|
||||
export interface CatalogEntityDetailItem<T extends CatalogEntity> {
|
||||
apiVersions: string[];
|
||||
kind: string;
|
||||
|
||||
components: {
|
||||
Details: React.ComponentType<CatalogEntityDetailItemComponentProps<T>>;
|
||||
};
|
||||
|
||||
orderNumber: number;
|
||||
|
||||
extension?: LensRendererExtension;
|
||||
}
|
||||
|
||||
export const catalogEntityDetailItemInjectionToken = getInjectionToken<CatalogEntityDetailItem<CatalogEntity>>({
|
||||
id: "catalog-entity-detail-item",
|
||||
});
|
||||
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
|
||||
import { CatalogEntityDetailItem, catalogEntityDetailItemInjectionToken } from "./catalog-entity-detail-item-injection-token";
|
||||
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import { conforms, eq, filter, includes, overSome, sortBy } from "lodash/fp";
|
||||
import type { CatalogEntity } from "../../../../common/catalog";
|
||||
|
||||
const catalogEntityDetailItemsInjectable = getInjectable({
|
||||
id: "catalog-entity-detail-items",
|
||||
|
||||
instantiate: (di, catalogEntity: CatalogEntity) => {
|
||||
const extensions = di.inject(rendererExtensionsInjectable);
|
||||
|
||||
return computed(() => {
|
||||
const enabledExtensions = extensions.get();
|
||||
|
||||
return pipeline(
|
||||
di.injectMany(catalogEntityDetailItemInjectionToken),
|
||||
|
||||
filter((item) =>
|
||||
overSome([
|
||||
isNonExtensionItem,
|
||||
isEnabledExtensionItemFor(enabledExtensions),
|
||||
])(item),
|
||||
),
|
||||
|
||||
filter(item =>
|
||||
conforms({
|
||||
kind: eq(catalogEntity.kind),
|
||||
apiVersions: includes(catalogEntity.apiVersion),
|
||||
})(item),
|
||||
),
|
||||
|
||||
items => sortBy("orderNumber", items),
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, catalogEntity: CatalogEntity) =>
|
||||
`${catalogEntity.kind}/${catalogEntity.apiVersion}`,
|
||||
}),
|
||||
});
|
||||
|
||||
const isNonExtensionItem = (item: CatalogEntityDetailItem<CatalogEntity>) =>
|
||||
!item.extension;
|
||||
|
||||
const isEnabledExtensionItemFor =
|
||||
(enabledExtensions: LensRendererExtension[]) =>
|
||||
(item: CatalogEntityDetailItem<CatalogEntity>) =>
|
||||
!!enabledExtensions.find((extension) => extension === item.extension);
|
||||
|
||||
export default catalogEntityDetailItemsInjectable;
|
||||
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { pipeline } from "@ogre-tools/fp";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { forEach } from "lodash/fp";
|
||||
import { extensionRegistratorInjectionToken } from "../../../../extensions/extension-loader/extension-registrator-injection-token";
|
||||
import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension";
|
||||
import { catalogEntityDetailItemInjectionToken } from "./catalog-entity-detail-item-injection-token";
|
||||
|
||||
const extensionCatalogEntityDetailItemsRegistratorInjectable = getInjectable({
|
||||
id: "extension-catalog-entity-detail-items-registrator",
|
||||
|
||||
instantiate:
|
||||
(di) => (extension: LensRendererExtension, installationCounter) => {
|
||||
pipeline(
|
||||
extension.catalogEntityDetailItems.map((registration, index) =>
|
||||
getInjectable({
|
||||
id: `catalog-entity-detail-item-${index}-from-${extension.sanitizedExtensionId}-instance-${installationCounter}`,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: registration.apiVersions,
|
||||
kind: registration.kind,
|
||||
|
||||
components: {
|
||||
Details: registration.components.Details,
|
||||
},
|
||||
|
||||
orderNumber: -registration.priority || -50,
|
||||
extension,
|
||||
}),
|
||||
|
||||
injectionToken: catalogEntityDetailItemInjectionToken,
|
||||
}),
|
||||
),
|
||||
|
||||
forEach(di.register),
|
||||
);
|
||||
},
|
||||
|
||||
injectionToken: extensionRegistratorInjectionToken,
|
||||
});
|
||||
|
||||
export default extensionCatalogEntityDetailItemsRegistratorInjectable;
|
||||
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { CatalogEntity } from "../../../../common/catalog";
|
||||
|
||||
export interface CatalogEntityDetailItemComponentProps<T extends CatalogEntity> {
|
||||
entity: T;
|
||||
}
|
||||
|
||||
export interface CatalogEntityDetailComponents<T extends CatalogEntity> {
|
||||
Details: React.ComponentType<CatalogEntityDetailItemComponentProps<T>>;
|
||||
}
|
||||
|
||||
export interface CatalogEntityDetailRegistration<T extends CatalogEntity> {
|
||||
kind: string;
|
||||
apiVersions: string[];
|
||||
components: CatalogEntityDetailComponents<T>;
|
||||
priority?: number;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { catalogEntityDetailItemInjectionToken } from "../catalog-entity-detail-item-injection-token";
|
||||
import { KubernetesCluster } from "../../../../../common/catalog-entities";
|
||||
import { DrawerItem, DrawerTitle } from "../../../drawer";
|
||||
import React from "react";
|
||||
import type { CatalogEntityDetailItemComponentProps } from "../extension-registration";
|
||||
|
||||
const Details = ({ entity }: CatalogEntityDetailItemComponentProps<KubernetesCluster>) => (
|
||||
<>
|
||||
<DrawerTitle>Kubernetes Information</DrawerTitle>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem name="Distribution">
|
||||
{entity.metadata.distro || "unknown"}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Kubelet Version">
|
||||
{entity.metadata.kubeVersion || "unknown"}
|
||||
</DrawerItem>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
const kubernetesInformationCatalogEntityDetailItemInjectable = getInjectable({
|
||||
id: "kubernetes-information-catalog-entity-detail-item",
|
||||
instantiate: () => ({
|
||||
apiVersions: [KubernetesCluster.apiVersion],
|
||||
kind: KubernetesCluster.kind,
|
||||
orderNumber: 10,
|
||||
|
||||
components: {
|
||||
Details,
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: catalogEntityDetailItemInjectionToken,
|
||||
});
|
||||
|
||||
export default kubernetesInformationCatalogEntityDetailItemInjectable;
|
||||
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { catalogEntityDetailItemInjectionToken } from "../catalog-entity-detail-item-injection-token";
|
||||
import { WebLink } from "../../../../../common/catalog-entities";
|
||||
import { DrawerItem, DrawerTitle } from "../../../drawer";
|
||||
import React from "react";
|
||||
import type { CatalogEntityDetailItemComponentProps } from "../extension-registration";
|
||||
|
||||
const Details = ({ entity }: CatalogEntityDetailItemComponentProps<WebLink>) => (
|
||||
<>
|
||||
<DrawerTitle>More Information</DrawerTitle>
|
||||
<DrawerItem name="URL">{entity.spec.url}</DrawerItem>
|
||||
</>
|
||||
);
|
||||
|
||||
const webLinkCatalogEntityDetailItemInjectable = getInjectable({
|
||||
id: "web-link-catalog-entity-detail-item",
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: [WebLink.apiVersion],
|
||||
kind: WebLink.kind,
|
||||
orderNumber: 20,
|
||||
|
||||
components: {
|
||||
Details,
|
||||
},
|
||||
}),
|
||||
|
||||
injectionToken: catalogEntityDetailItemInjectionToken,
|
||||
});
|
||||
|
||||
export default webLinkCatalogEntityDetailItemInjectable;
|
||||
@ -7,14 +7,17 @@ import styles from "./catalog-entity-details.module.scss";
|
||||
import React, { Component } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { Drawer, DrawerItem } from "../drawer";
|
||||
import type { CatalogCategory, CatalogEntity } from "../../../common/catalog";
|
||||
import type { CatalogEntity } from "../../../common/catalog";
|
||||
import { Icon } from "../icon";
|
||||
import { CatalogEntityDrawerMenu } from "./catalog-entity-drawer-menu";
|
||||
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||
import { isDevelopment } from "../../../common/vars";
|
||||
import { cssNames } from "../../utils";
|
||||
import { Avatar } from "../avatar";
|
||||
import { getLabelBadges } from "./helpers";
|
||||
import catalogEntityDetailItemsInjectable from "./catalog-entity-detail-items/catalog-entity-detail-items.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { CatalogEntityDetailItem } from "./catalog-entity-detail-items/catalog-entity-detail-item-injection-token";
|
||||
import type { IComputedValue } from "mobx";
|
||||
|
||||
export interface CatalogEntityDetailsProps<T extends CatalogEntity> {
|
||||
entity: T;
|
||||
@ -22,25 +25,17 @@ export interface CatalogEntityDetailsProps<T extends CatalogEntity> {
|
||||
onRun: () => void;
|
||||
}
|
||||
|
||||
@observer
|
||||
export class CatalogEntityDetails<T extends CatalogEntity> extends Component<CatalogEntityDetailsProps<T>> {
|
||||
categoryIcon(category: CatalogCategory) {
|
||||
if (Icon.isSvg(category.metadata.icon)) {
|
||||
return <Icon svg={category.metadata.icon} smallest />;
|
||||
} else {
|
||||
return <Icon material={category.metadata.icon} smallest />;
|
||||
}
|
||||
}
|
||||
interface Dependencies {
|
||||
detailItems: IComputedValue<CatalogEntityDetailItem<any>[]>;
|
||||
}
|
||||
|
||||
@observer
|
||||
class NonInjectedCatalogEntityDetails<T extends CatalogEntity> extends Component<CatalogEntityDetailsProps<T> & Dependencies> {
|
||||
renderContent(entity: T) {
|
||||
const { onRun, hideDetails } = this.props;
|
||||
const detailItems = CatalogEntityDetailRegistry.getInstance().getItemsForKind(entity.kind, entity.apiVersion);
|
||||
const details = detailItems.map(({ components }, index) => <components.Details entity={entity} key={index} />);
|
||||
const showDefaultDetails = detailItems.find((item) => item.priority > 999) === undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
{showDefaultDetails && (
|
||||
<div className="flex">
|
||||
<div className={styles.entityIcon}>
|
||||
<Avatar
|
||||
@ -84,9 +79,8 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Cat
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="box grow">
|
||||
{details}
|
||||
{this.props.detailItems.get().map(({ components: { Details }}, index) => <Details entity={entity} key={index} />)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
@ -109,3 +103,18 @@ export class CatalogEntityDetails<T extends CatalogEntity> extends Component<Cat
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const InjectedCatalogEntityDetails = withInjectables<Dependencies, CatalogEntityDetailsProps<CatalogEntity>>(
|
||||
NonInjectedCatalogEntityDetails,
|
||||
|
||||
{
|
||||
getProps: (di, props) => ({
|
||||
detailItems: di.inject(catalogEntityDetailItemsInjectable, props.entity),
|
||||
...props,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
export const CatalogEntityDetails = <T extends CatalogEntity>(
|
||||
props: CatalogEntityDetailsProps<T>,
|
||||
) => <InjectedCatalogEntityDetails {...props} />;
|
||||
|
||||
@ -10,7 +10,6 @@ import { Catalog } from "./catalog";
|
||||
import { mockWindow } from "../../../../__mocks__/windowMock";
|
||||
import { CatalogCategoryRegistry, CatalogEntity, CatalogEntityActionContext, CatalogEntityData } from "../../../common/catalog";
|
||||
import { CatalogEntityRegistry } from "../../api/catalog-entity-registry";
|
||||
import { CatalogEntityDetailRegistry } from "../../../extensions/registries";
|
||||
import type { CatalogEntityStore } from "./catalog-entity-store/catalog-entity.store";
|
||||
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
@ -101,7 +100,6 @@ describe("<Catalog />", () => {
|
||||
|
||||
UserStore.createInstance();
|
||||
ThemeStore.createInstance();
|
||||
CatalogEntityDetailRegistry.createInstance();
|
||||
|
||||
render = renderFor(di);
|
||||
|
||||
@ -123,7 +121,6 @@ describe("<Catalog />", () => {
|
||||
afterEach(() => {
|
||||
UserStore.resetInstance();
|
||||
ThemeStore.resetInstance();
|
||||
CatalogEntityDetailRegistry.resetInstance();
|
||||
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
|
||||
@ -1,48 +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 { KubernetesCluster, WebLink } from "../../common/catalog-entities";
|
||||
import { CatalogEntityDetailRegistry, CatalogEntityDetailsProps } from "../../extensions/registries";
|
||||
import { DrawerItem, DrawerTitle } from "../components/drawer";
|
||||
|
||||
export function initCatalogEntityDetailRegistry() {
|
||||
CatalogEntityDetailRegistry.getInstance()
|
||||
.add([
|
||||
{
|
||||
apiVersions: [KubernetesCluster.apiVersion],
|
||||
kind: KubernetesCluster.kind,
|
||||
components: {
|
||||
Details: ({ entity }: CatalogEntityDetailsProps<KubernetesCluster>) => (
|
||||
<>
|
||||
<DrawerTitle>Kubernetes Information</DrawerTitle>
|
||||
<div className="box grow EntityMetadata">
|
||||
<DrawerItem name="Distribution">
|
||||
{entity.metadata.distro || "unknown"}
|
||||
</DrawerItem>
|
||||
<DrawerItem name="Kubelet Version">
|
||||
{entity.metadata.kubeVersion || "unknown"}
|
||||
</DrawerItem>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
apiVersions: [WebLink.apiVersion],
|
||||
kind: WebLink.kind,
|
||||
components: {
|
||||
Details: ({ entity }: CatalogEntityDetailsProps<WebLink>) => (
|
||||
<>
|
||||
<DrawerTitle>More Information</DrawerTitle>
|
||||
<DrawerItem name="URL">
|
||||
{entity.spec.url}
|
||||
</DrawerItem>
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
export * from "./catalog-entity-detail-registry";
|
||||
export * from "./catalog";
|
||||
export * from "./entity-settings-registry";
|
||||
export * from "./ipc";
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
import * as registries from "../../extensions/registries";
|
||||
|
||||
export function initRegistries() {
|
||||
registries.CatalogEntityDetailRegistry.createInstance();
|
||||
registries.KubeObjectDetailRegistry.createInstance();
|
||||
registries.EntitySettingRegistry.createInstance();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user