Merge branch 'master' into extension-auto-update

This commit is contained in:
Lauri Nevala authored and GitHub committed 2022-01-20 13:35:13 +02:00
commit d26322df1a
69 files changed
+1318 -806

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../registries/app-preference-registry";
export type { AppPreferenceRegistration, AppPreferenceComponents } from "../../renderer/components/+preferences/app-preferences/app-preference-registration";
export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry";
export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry";
export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry";
@@ -269,7 +269,6 @@ export class ExtensionLoader {
return this.autoInitExtensions(async (extension: LensRendererExtension) => {
const removeItems = [
registries.GlobalPageRegistry.getInstance().add(extension.globalPages, extension),
registries.AppPreferenceRegistry.getInstance().add(extension.appPreferences),
registries.EntitySettingRegistry.getInstance().add(extension.entitySettings),
registries.StatusBarRegistry.getInstance().add(extension.statusBarItems),
registries.CatalogEntityDetailRegistry.getInstance().add(extension.catalogEntityDetailItems),
@@ -291,11 +290,12 @@ export class ExtensionLoader {
});
};
loadOnClusterRenderer = (entity: KubernetesCluster) => {
loadOnClusterRenderer = (getCluster: () => KubernetesCluster) => {
logger.debug(`${logModule}: load on cluster renderer (dashboard)`);
this.autoInitExtensions(async (extension: LensRendererExtension) => {
if ((await extension.isEnabledForCluster(entity)) === false) {
// getCluster must be a callback, as the entity might be available only after an extension has been loaded
if ((await extension.isEnabledForCluster(getCluster())) === false) {
return [];
}
@@ -324,11 +324,15 @@ export class ExtensionLoader {
this.extensions.get(extension.id).availableUpdate = await extension.checkForUpdate();
}
protected autoInitExtensions(register: (ext: LensExtension) => Promise<Disposer[]>) {
const loadingExtensions: ExtensionLoading[] = [];
protected async loadExtensions(installedExtensions: Map<string, InstalledExtension>, register: (ext: LensExtension) => Promise<Disposer[]>) {
// Steps of the function:
// 1. require and call .activate for each Extension
// 2. Wait until every extension's onActivate has been resolved
// 3. Call .enable for each extension
// 4. Return ExtensionLoading[]
reaction(() => this.toJSON(), async installedExtensions => {
for (const [extId, extension] of installedExtensions) {
const extensions = [...installedExtensions.entries()]
.map(([extId, extension]) => {
const alreadyInit = this.instances.has(extId) || this.nonInstancesByName.has(extension.manifest.name);
if (extension.isCompatible && extension.isEnabled && !alreadyInit) {
@@ -337,7 +341,8 @@ export class ExtensionLoader {
if (!LensExtensionClass) {
this.nonInstancesByName.add(extension.manifest.name);
continue;
return null;
}
// const instance = new LensExtensionClass(extension, this.extensionUpdateChecker);
@@ -347,27 +352,49 @@ export class ExtensionLoader {
this.extensionUpdateChecker,
);
const loaded = instance.enable(register).catch((err) => {
logger.error(`${logModule}: failed to enable`, { ext: extension, err });
});
loadingExtensions.push({
isBundled: extension.isBundled,
loaded,
});
this.instances.set(extId, instance);
return {
extId,
instance,
isBundled: extension.isBundled,
activated: instance.activate(),
};
} catch (err) {
logger.error(`${logModule}: activation extension error`, { ext: extension, err });
}
} else if (!extension.isEnabled && alreadyInit) {
this.removeInstance(extId);
}
}
}, {
fireImmediately: true,
});
return loadingExtensions;
return null;
})
// Remove null values
.filter(extension => Boolean(extension));
// We first need to wait until each extension's `onActivate` is resolved,
// as this might register new catalog categories. Afterwards we can safely .enable the extension.
await Promise.all(extensions.map(extension => extension.activated));
// Return ExtensionLoading[]
return extensions.map(extension => {
const loaded = extension.instance.enable(register).catch((err) => {
logger.error(`${logModule}: failed to enable`, { ext: extension, err });
});
return {
isBundled: extension.isBundled,
loaded,
};
});
}
protected autoInitExtensions(register: (ext: LensExtension) => Promise<Disposer[]>) {
// Setup reaction to load extensions on JSON changes
reaction(() => this.toJSON(), installedExtensions => this.loadExtensions(installedExtensions, register));
// Load initial extensions
return this.loadExtensions(this.toJSON(), register);
}
protected requireExtension(extension: InstalledExtension): LensExtensionConstructor | null {
+6 -1
View File
@@ -91,7 +91,6 @@ export class LensExtension {
}
try {
await this.onActivate();
this._isEnabled = true;
this[Disposers].push(...await register(this));
@@ -118,6 +117,12 @@ export class LensExtension {
}
}
@action
activate() {
return this.onActivate();
}
public async checkForUpdate() {
return this.updateChecker?.run(this.manifest);
}
+4 -1
View File
@@ -15,13 +15,15 @@ import type { KubernetesCluster } from "../common/catalog-entities";
import type { WelcomeMenuRegistration } from "../renderer/components/+welcome/welcome-menu-items/welcome-menu-registration";
import type { WelcomeBannerRegistration } from "../renderer/components/+welcome/welcome-banner-items/welcome-banner-registration";
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 { AdditionalCategoryColumnRegistration } from "../renderer/components/+catalog/custom-category-columns";
export class LensRendererExtension extends LensExtension {
globalPages: registries.PageRegistration[] = [];
clusterPages: registries.PageRegistration[] = [];
clusterPageMenus: registries.ClusterPageMenuRegistration[] = [];
kubeObjectStatusTexts: registries.KubeObjectStatusRegistration[] = [];
appPreferences: registries.AppPreferenceRegistration[] = [];
appPreferences: AppPreferenceRegistration[] = [];
entitySettings: registries.EntitySettingRegistration[] = [];
statusBarItems: registries.StatusBarRegistration[] = [];
kubeObjectDetailItems: registries.KubeObjectDetailRegistration[] = [];
@@ -32,6 +34,7 @@ export class LensRendererExtension extends LensExtension {
welcomeBanners: WelcomeBannerRegistration[] = [];
catalogEntityDetailItems: registries.CatalogEntityDetailRegistration<CatalogEntity>[] = [];
topBarItems: TopBarRegistration[] = [];
additionalCategoryColumns: AdditionalCategoryColumnRegistration[] = [];
async navigate<P extends object>(pageId?: string, params?: P) {
const { navigate } = await import("../renderer/navigation");
@@ -1,32 +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 { BaseRegistry } from "./base-registry";
export interface AppPreferenceComponents {
Hint: React.ComponentType<any>;
Input: React.ComponentType<any>;
}
export interface AppPreferenceRegistration {
title: string;
id?: string;
showInPreferencesTab?: string;
components: AppPreferenceComponents;
}
export interface RegisteredAppPreference extends AppPreferenceRegistration {
id: string;
}
export class AppPreferenceRegistry extends BaseRegistry<AppPreferenceRegistration, RegisteredAppPreference> {
getRegisteredItem(item: AppPreferenceRegistration): RegisteredAppPreference {
return {
id: item.id || item.title.toLowerCase().replace(/[^0-9a-zA-Z]+/g, "-"),
...item,
};
}
}
-1
View File
@@ -7,7 +7,6 @@
export * from "./page-registry";
export * from "./page-menu-registry";
export * from "./app-preference-registry";
export * from "./status-bar-registry";
export * from "./kube-object-detail-registry";
export * from "./kube-object-menu-registry";
@@ -31,6 +31,11 @@ export * from "../../renderer/components/input/input";
// command-overlay
export const CommandOverlay = asLegacyGlobalObjectForExtensionApi(commandOverlayInjectable);
export type {
CategoryColumnRegistration,
AdditionalCategoryColumnRegistration,
} from "../../renderer/components/+catalog/custom-category-columns";
// other components
export * from "../../renderer/components/icon";
export * from "../../renderer/components/tooltip";
@@ -8,10 +8,8 @@ import extensionsInjectable from "./extensions.injectable";
import type { LensRendererExtension } from "./lens-renderer-extension";
const rendererExtensionsInjectable = getInjectable({
instantiate: (di) => di.inject(extensionsInjectable) as IComputedValue<LensRendererExtension[]>,
lifecycle: lifecycleEnum.singleton,
instantiate: (di) =>
di.inject(extensionsInjectable) as IComputedValue<LensRendererExtension[]>,
});
export default rendererExtensionsInjectable;