Skip to content

Commit

Permalink
Replace CatalogEntityDetailRegistry with an injectable solution (#6605)
Browse files Browse the repository at this point in the history
* Replace EntityDetailRegistry with an injectable solution

- Add some behavioural tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshots

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix import error

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Simplify loading extensions

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix lint

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshot

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove the last reminents of BaseRegistry

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix import errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix TypeError when loading extensions

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Update snapshots

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Cleanup LensExtensions

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Remove bad comment

Signed-off-by: Sebastian Malton <sebastian@malton.name>

* Fix type errors

Signed-off-by: Sebastian Malton <sebastian@malton.name>

Signed-off-by: Sebastian Malton <sebastian@malton.name>
  • Loading branch information
Nokel81 authored Dec 2, 2022
1 parent 1acacbb commit 9ba92cb
Show file tree
Hide file tree
Showing 78 changed files with 15,163 additions and 585 deletions.
4 changes: 2 additions & 2 deletions __mocks__/react-beautiful-dnd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ import type {
} from "react-beautiful-dnd";

export const DragDropContext = ({ children }: DragDropContextProps) => <>{ children }</>;
export const Draggable = ({ children }: DraggableProps) => <>{ children }</>;
export const Droppable = ({ children }: DroppableProps) => <>{ children }</>;
export const Draggable = ({ children }: DraggableProps) => <>{ children({} as any, {} as any, {} as any) }</>;
export const Droppable = ({ children }: DroppableProps) => <>{ children({} as any, {} as any) }</>;
9 changes: 5 additions & 4 deletions src/common/catalog-entities/web-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import { getLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
import productNameInjectable from "../vars/product-name.injectable";
import { WeblinkStore } from "../weblink-store";
import weblinkStoreInjectable from "../weblink-store.injectable";

export type WebLinkStatusPhase = "available" | "unavailable";

Expand All @@ -31,14 +31,15 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
}

onContextMenuOpen(context: CatalogEntityContextMenuContext) {
const di = getLegacyGlobalDiForExtensionApi();
// NOTE: this is safe because `onContextMenuOpen` is only supposed to be called in the renderer
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.renderer);
const productName = di.inject(productNameInjectable);

if (this.metadata.source === "local") {
context.menuItems.push({
title: "Delete",
icon: "delete",
onClick: async () => WeblinkStore.getInstance().removeById(this.getId()),
onClick: async () => di.inject(weblinkStoreInjectable).removeById(this.getId()),
confirm: {
message: `Remove Web Link "${this.getName()}" from ${productName}?`,
},
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/common/protocol-handler/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { RoutingError, RoutingErrorType } from "./error";
import type { ExtensionsStore } from "../../extensions/extensions-store/extensions-store";
import type { ExtensionLoader } from "../../extensions/extension-loader";
import type { LensExtension } from "../../extensions/lens-extension";
import type { RouteHandler, RouteParams } from "../../extensions/registries/protocol-handler";
import type { RouteHandler, RouteParams } from "./registration";
import { when } from "mobx";
import { ipcRenderer } from "electron";
import type { Logger } from "../logger";
Expand Down
6 changes: 3 additions & 3 deletions src/extensions/common-api/registrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../..
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../features/preferences/renderer/compliance-for-legacy-extension-api/app-preference-registration";
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../../renderer/components/kube-object-details/kube-object-detail-registration";
export type { KubeObjectStatusRegistration } from "../../renderer/components/kube-object-status-icon/kube-object-status-registration";
export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../registries/page-registry";
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../registries/page-menu-registry";
export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../registries/protocol-handler";
export type { PageRegistration, RegisteredPage, PageParams, PageComponentProps, PageComponents, PageTarget } from "../../renderer/routes/page-registration";
export type { ClusterPageMenuRegistration, ClusterPageMenuComponents } from "../../renderer/components/layout/cluster-page-menu";
export type { ProtocolHandlerRegistration, RouteParams as ProtocolRouteParams, RouteHandler as ProtocolRouteHandler } from "../../common/protocol-handler/registration";
export type { CustomCategoryViewProps, CustomCategoryViewComponents, CustomCategoryViewRegistration } from "../../renderer/components/+catalog/custom-views";
export type { ShellEnvModifier, ShellEnvContext } from "../../main/shell-session/shell-env-modifier/shell-env-modifier-registration";
export type { KubeObjectContextMenuItem, KubeObjectOnContextMenuOpenContext, KubeObjectOnContextMenuOpen, KubeObjectHandlers, KubeObjectHandlerRegistration } from "../../renderer/kube-object/handler";
Expand Down
48 changes: 8 additions & 40 deletions src/extensions/extension-loader/extension-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@ import { isEqual } from "lodash";
import type { ObservableMap } from "mobx";
import { action, computed, makeObservable, observable, observe, reaction, when } from "mobx";
import { broadcastMessage, ipcMainOn, ipcRendererOn, ipcMainHandle } from "../../common/ipc";
import type { Disposer } from "../../common/utils";
import { isDefined, toJS } from "../../common/utils";
import type { InstalledExtension } from "../extension-discovery/extension-discovery";
import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "../lens-extension";
import type { LensRendererExtension } from "../lens-renderer-extension";
import * as registries from "../registries";
import type { LensExtensionState } from "../extensions-store/extensions-store";
import { extensionLoaderFromMainChannel, extensionLoaderFromRendererChannel } from "../../common/ipc/extension-handling";
import { requestExtensionLoaderInitialState } from "../../renderer/ipc";
Expand Down Expand Up @@ -203,7 +200,7 @@ export class ExtensionLoader {

protected async initMain() {
this.isLoaded = true;
this.loadOnMain();
await this.autoInitExtensions();

ipcMainHandle(extensionLoaderFromMainChannel, () => {
return Array.from(this.toJSON());
Expand Down Expand Up @@ -251,38 +248,7 @@ export class ExtensionLoader {
});
}

loadOnMain() {
this.autoInitExtensions(() => Promise.resolve([]));
}

loadOnClusterManagerRenderer = () => {
this.dependencies.logger.debug(`${logModule}: load on main renderer (cluster manager)`);

return this.autoInitExtensions(async (ext) => {
const extension = ext as LensRendererExtension;
const removeItems = [
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
];

this.onRemoveExtensionId.addListener((removedExtensionId) => {
if (removedExtensionId === extension.id) {
removeItems.forEach(remove => {
remove();
});
}
});

return removeItems;
});
};

loadOnClusterRenderer = () => {
this.dependencies.logger.debug(`${logModule}: load on cluster renderer (dashboard)`);

this.autoInitExtensions(async () => []);
};

protected async loadExtensions(installedExtensions: Map<string, InstalledExtension>, register: (ext: LensExtension) => Promise<Disposer[]>) {
protected async loadExtensions(installedExtensions: Map<string, InstalledExtension>) {
// Steps of the function:
// 1. require and call .activate for each Extension
// 2. Wait until every extension's onActivate has been resolved
Expand Down Expand Up @@ -346,7 +312,7 @@ export class ExtensionLoader {

// Return ExtensionLoading[]
return extensions.map(extension => {
const loaded = extension.instance.enable(register).catch((err) => {
const loaded = extension.instance.enable().catch((err) => {
this.dependencies.logger.error(`${logModule}: failed to enable`, { ext: extension, err });
});

Expand All @@ -357,12 +323,14 @@ export class ExtensionLoader {
});
}

protected autoInitExtensions(register: (ext: LensExtension) => Promise<Disposer[]>) {
autoInitExtensions() {
this.dependencies.logger.info(`${logModule}: auto initializing extensions`);

// Setup reaction to load extensions on JSON changes
reaction(() => this.toJSON(), installedExtensions => this.loadExtensions(installedExtensions, register));
reaction(() => this.toJSON(), installedExtensions => this.loadExtensions(installedExtensions));

// Load initial extensions
return this.loadExtensions(this.toJSON(), register);
return this.loadExtensions(this.toJSON());
}

protected requireExtension(extension: InstalledExtension): LensExtensionConstructor | null {
Expand Down
2 changes: 2 additions & 0 deletions src/extensions/lens-extension-set-dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import type { CatalogEntityRegistry as RendererCatalogEntityRegistry } from "../
import type { GetExtensionPageParameters } from "../renderer/routes/get-extension-page-parameters.injectable";
import type { FileSystemProvisionerStore } from "./extension-loader/file-system-provisioner-store/file-system-provisioner-store";
import type { NavigateForExtension } from "../main/start-main-application/lens-window/navigate-for-extension.injectable";
import type { Logger } from "../common/logger";

export interface LensExtensionDependencies {
readonly fileSystemProvisionerStore: FileSystemProvisionerStore;
readonly logger: Logger;
}

export interface LensMainExtensionDependencies extends LensExtensionDependencies {
Expand Down
21 changes: 6 additions & 15 deletions src/extensions/lens-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@

import type { InstalledExtension } from "./extension-discovery/extension-discovery";
import { action, computed, makeObservable, observable } from "mobx";
import logger from "../main/logger";
import type { ProtocolHandlerRegistration } from "./registries";
import type { PackageJson } from "type-fest";
import type { Disposer } from "../common/utils";
import { disposer } from "../common/utils";
import type { LensExtensionDependencies } from "./lens-extension-set-dependencies";
import type { ProtocolHandlerRegistration } from "./common-api/registrations";

export type LensExtensionId = string; // path to manifest (package.json)
export type LensExtensionConstructor = new (...args: ConstructorParameters<typeof LensExtension>) => LensExtension;
Expand Down Expand Up @@ -88,20 +86,13 @@ export class LensExtension<Dependencies extends LensExtensionDependencies = Lens
}

@action
async enable(register: (ext: this) => Promise<Disposer[]>) {
async enable() {
if (this._isEnabled) {
return;
}

try {
this._isEnabled = true;

this[Disposers].push(...await register(this));
logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`);

} catch (error) {
logger.error(`[EXTENSION]: failed to activate ${this.name}@${this.version}: ${error}`);
}
this._isEnabled = true;
this[lensExtensionDependencies].logger.info(`[EXTENSION]: enabled ${this.name}@${this.version}`);
}

@action
Expand All @@ -115,9 +106,9 @@ export class LensExtension<Dependencies extends LensExtensionDependencies = Lens
try {
await this.onDeactivate();
this[Disposers]();
logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`);
this[lensExtensionDependencies].logger.info(`[EXTENSION]: disabled ${this.name}@${this.version}`);
} catch (error) {
logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`);
this[lensExtensionDependencies].logger.error(`[EXTENSION]: disabling ${this.name}@${this.version} threw an error: ${error}`);
}
}

Expand Down
11 changes: 6 additions & 5 deletions src/extensions/lens-renderer-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import type * as registries from "./registries";
import { Disposers, LensExtension, lensExtensionDependencies } from "./lens-extension";
import type { CatalogEntity } from "../common/catalog";
import type { Disposer } from "../common/utils";
Expand All @@ -30,11 +29,13 @@ import type { AppPreferenceTabRegistration } from "../features/preferences/rende
import type { KubeObjectDetailRegistration } from "../renderer/components/kube-object-details/kube-object-detail-registration";
import type { ClusterFrameChildComponent } from "../renderer/frames/cluster-frame/cluster-frame-child-component-injection-token";
import type { EntitySettingRegistration } from "../renderer/components/+entity-settings/extension-registrator.injectable";
import type { CatalogEntityDetailRegistration } from "../renderer/components/+catalog/entity-details/token";
import type { ClusterPageMenuRegistration, PageRegistration } from "./common-api/registrations";

export class LensRendererExtension extends LensExtension<LensRendererExtensionDependencies> {
globalPages: registries.PageRegistration[] = [];
clusterPages: registries.PageRegistration[] = [];
clusterPageMenus: registries.ClusterPageMenuRegistration[] = [];
globalPages: PageRegistration[] = [];
clusterPages: PageRegistration[] = [];
clusterPageMenus: ClusterPageMenuRegistration[] = [];
clusterFrameComponents: ClusterFrameChildComponent[] = [];
kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [];
appPreferences: AppPreferenceRegistration[] = [];
Expand All @@ -47,7 +48,7 @@ export class LensRendererExtension extends LensExtension<LensRendererExtensionDe
commands: CommandRegistration[] = [];
welcomeMenus: WelcomeMenuRegistration[] = [];
welcomeBanners: WelcomeBannerRegistration[] = [];
catalogEntityDetailItems: registries.CatalogEntityDetailRegistration<CatalogEntity>[] = [];
catalogEntityDetailItems: CatalogEntityDetailRegistration<CatalogEntity>[] = [];
topBarItems: TopBarRegistration[] = [];
additionalCategoryColumns: AdditionalCategoryColumnRegistration[] = [];
customCategoryViews: CustomCategoryViewRegistration[] = [];
Expand Down
46 changes: 0 additions & 46 deletions src/extensions/registries/base-registry.ts

This file was deleted.

38 changes: 0 additions & 38 deletions src/extensions/registries/catalog-entity-detail-registry.ts

This file was deleted.

11 changes: 0 additions & 11 deletions src/extensions/registries/index.ts

This file was deleted.

Loading

0 comments on commit 9ba92cb

Please sign in to comment.