mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fixes & refactoring
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
10570423fc
commit
5643e84401
@ -16,46 +16,34 @@ export function extensionPackagesRoot() {
|
||||
}
|
||||
|
||||
export class ExtensionLoader {
|
||||
@observable isLoaded = false;
|
||||
protected extensions = observable.map<LensExtensionId, InstalledExtension>();
|
||||
protected instances = observable.map<LensExtensionId, LensExtension>()
|
||||
protected instances = observable.map<LensExtensionId, LensExtension>();
|
||||
|
||||
@observable isLoaded = false;
|
||||
whenLoaded = when(() => this.isLoaded);
|
||||
|
||||
constructor() {
|
||||
if (ipcRenderer) {
|
||||
ipcRenderer.on("extensions:loaded", (event, extensions: InstalledExtension[]) => {
|
||||
ipcRenderer.on("extensions:loaded", (event, extensions: [LensExtensionId, InstalledExtension][]) => {
|
||||
this.isLoaded = true;
|
||||
extensions.forEach((ext) => {
|
||||
if (!this.extensions.has(ext.manifestPath)) {
|
||||
this.extensions.set(ext.manifestPath, ext)
|
||||
extensions.forEach(([extId, ext]) => {
|
||||
if (!this.extensions.has(extId)) {
|
||||
this.extensions.set(extId, ext)
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
this.manageExtensionsState();
|
||||
extensionsStore.manageState(this);
|
||||
}
|
||||
|
||||
@computed get userExtensions(): InstalledExtension[] {
|
||||
return Array.from(this.toJSON().values()).filter(ext => !ext.isBundled)
|
||||
}
|
||||
|
||||
protected async manageExtensionsState() {
|
||||
await extensionsStore.whenLoaded;
|
||||
await when(() => this.isLoaded);
|
||||
|
||||
// apply initial state
|
||||
this.extensions.forEach((ext, extId) => {
|
||||
ext.enabled = ext.isBundled || extensionsStore.isEnabled(extId);
|
||||
@computed get userExtensions(): Map<LensExtensionId, InstalledExtension> {
|
||||
const extensions = this.extensions.toJS();
|
||||
extensions.forEach((ext, extId) => {
|
||||
if (ext.isBundled) {
|
||||
extensions.delete(extId);
|
||||
}
|
||||
})
|
||||
|
||||
// handle updated state from store
|
||||
reaction(() => extensionsStore.extensions.toJS(), extensionsState => {
|
||||
extensionsState.forEach((state, extId) => {
|
||||
const ext = this.extensions.get(extId);
|
||||
if (ext && !ext.isBundled && ext.enabled !== state.enabled) {
|
||||
ext.enabled = state.enabled;
|
||||
}
|
||||
})
|
||||
});
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@action
|
||||
@ -93,14 +81,13 @@ export class ExtensionLoader {
|
||||
}
|
||||
|
||||
protected autoInitExtensions(register: (ext: LensExtension) => Function[]) {
|
||||
return reaction(() => this.toJSON(), (installedExtensions) => {
|
||||
return reaction(() => this.toJSON(), installedExtensions => {
|
||||
for (const [extId, ext] of installedExtensions) {
|
||||
let instance = this.instances.get(extId);
|
||||
if (ext.enabled && !instance) {
|
||||
if (ext.isEnabled && !instance) {
|
||||
try {
|
||||
const extensionModule = this.requireExtension(ext)
|
||||
if (!extensionModule) continue;
|
||||
const LensExtensionClass: LensExtensionConstructor = extensionModule.default;
|
||||
const LensExtensionClass: LensExtensionConstructor = this.requireExtension(ext)
|
||||
if (!LensExtensionClass) continue;
|
||||
instance = new LensExtensionClass(ext);
|
||||
instance.whenEnabled(() => register(instance));
|
||||
instance.enable();
|
||||
@ -108,7 +95,7 @@ export class ExtensionLoader {
|
||||
} catch (err) {
|
||||
logger.error(`[EXTENSION-LOADER]: activation extension error`, { ext, err })
|
||||
}
|
||||
} else if (!ext.enabled && instance) {
|
||||
} else if (!ext.isEnabled && instance) {
|
||||
try {
|
||||
instance.disable();
|
||||
this.instances.delete(extId);
|
||||
@ -131,7 +118,7 @@ export class ExtensionLoader {
|
||||
extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.main))
|
||||
}
|
||||
if (extEntrypoint !== "") {
|
||||
return __non_webpack_require__(extEntrypoint)
|
||||
return __non_webpack_require__(extEntrypoint).default;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[EXTENSION-LOADER]: can't load extension main at ${extEntrypoint}: ${err}`, { extension });
|
||||
@ -139,7 +126,11 @@ export class ExtensionLoader {
|
||||
}
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
getExtension(extId: LensExtensionId): InstalledExtension {
|
||||
return this.extensions.get(extId);
|
||||
}
|
||||
|
||||
toJSON(): Map<LensExtensionId, InstalledExtension> {
|
||||
return toJS(this.extensions, {
|
||||
exportMapsAsObjects: false,
|
||||
recurseEverything: true,
|
||||
@ -153,7 +144,7 @@ export class ExtensionLoader {
|
||||
frameId: frameId,
|
||||
frameOnly: !!frameId,
|
||||
args: [
|
||||
Array.from(this.toJSON().values()),
|
||||
Array.from(this.toJSON()),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,8 +10,8 @@ import { getBundledExtensions } from "../common/utils/app-version"
|
||||
export interface InstalledExtension {
|
||||
readonly manifest: LensExtensionManifest;
|
||||
readonly manifestPath: string;
|
||||
readonly isBundled?: boolean; // defined in package.json
|
||||
enabled?: boolean;
|
||||
readonly isBundled?: boolean; // defined in project root's package.json
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
type Dependencies = {
|
||||
@ -90,6 +90,7 @@ export class ExtensionManager {
|
||||
manifestPath: path.join(this.nodeModulesPath, manifestJson.name, "package.json"),
|
||||
manifest: manifestJson,
|
||||
isBundled: isBundled,
|
||||
isEnabled: isBundled,
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`[EXTENSION-MANAGER]: can't install extension at ${manifestPath}: ${err}`, { manifestJson });
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { LensExtensionId } from "./lens-extension";
|
||||
import type { ExtensionLoader } from "./extension-loader";
|
||||
import { BaseStore } from "../common/base-store"
|
||||
import { action, observable, toJS } from "mobx";
|
||||
import { action, observable, reaction, toJS } from "mobx";
|
||||
|
||||
export interface LensExtensionsStoreModel {
|
||||
extensions: Record<LensExtensionId, LensExtensionState>;
|
||||
@ -13,33 +14,60 @@ export interface LensExtensionState {
|
||||
export class ExtensionsStore extends BaseStore<LensExtensionsStoreModel> {
|
||||
constructor() {
|
||||
super({
|
||||
configName: "lens-extensions"
|
||||
configName: "lens-extensions",
|
||||
});
|
||||
}
|
||||
|
||||
@observable extensions = observable.map<LensExtensionId, LensExtensionState>();
|
||||
protected state = observable.map<LensExtensionId, LensExtensionState>();
|
||||
|
||||
@action
|
||||
setEnabled(extId: LensExtensionId, enabled: boolean) {
|
||||
const state = this.extensions.get(extId);
|
||||
this.extensions.set(extId, {
|
||||
...(state || {}),
|
||||
enabled: enabled,
|
||||
protected getState(extensionLoader: ExtensionLoader) {
|
||||
const state: Record<LensExtensionId, LensExtensionState> = {};
|
||||
return Array.from(extensionLoader.userExtensions).reduce((state, [extId, ext]) => {
|
||||
state[extId] = {
|
||||
enabled: ext.isEnabled,
|
||||
}
|
||||
return state;
|
||||
}, state)
|
||||
}
|
||||
|
||||
async manageState(extensionLoader: ExtensionLoader) {
|
||||
await extensionLoader.whenLoaded;
|
||||
await this.whenLoaded;
|
||||
|
||||
// activate user-extensions when state is ready
|
||||
extensionLoader.userExtensions.forEach((ext, extId) => {
|
||||
ext.isEnabled = this.isEnabled(extId);
|
||||
});
|
||||
|
||||
// apply state on changes from store
|
||||
reaction(() => this.state.toJS(), extensionsState => {
|
||||
extensionsState.forEach((state, extId) => {
|
||||
const ext = extensionLoader.getExtension(extId);
|
||||
if (ext && !ext.isBundled) {
|
||||
ext.isEnabled = state.enabled;
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// save state on change `extension.isEnabled`
|
||||
reaction(() => this.getState(extensionLoader), extensionsState => {
|
||||
this.state.merge(extensionsState)
|
||||
})
|
||||
}
|
||||
|
||||
isEnabled(extensionId: LensExtensionId) {
|
||||
const state = this.extensions.get(extensionId);
|
||||
isEnabled(extId: LensExtensionId) {
|
||||
const state = this.state.get(extId);
|
||||
return !state /* enabled by default */ || state.enabled;
|
||||
}
|
||||
|
||||
@action
|
||||
protected fromStore({ extensions }: LensExtensionsStoreModel) {
|
||||
this.extensions.merge(extensions);
|
||||
this.state.merge(extensions);
|
||||
}
|
||||
|
||||
toJSON(): LensExtensionsStoreModel {
|
||||
return toJS({
|
||||
extensions: this.extensions.toJSON(),
|
||||
extensions: this.state.toJSON(),
|
||||
}, {
|
||||
recurseEverything: true
|
||||
})
|
||||
|
||||
@ -4,6 +4,8 @@ import React from "react";
|
||||
import * as Mobx from "mobx"
|
||||
import * as MobxReact from "mobx-react"
|
||||
import * as LensExtensions from "../extensions/extension-api"
|
||||
import { App } from "./components/app";
|
||||
import { LensApp } from "./lens-app";
|
||||
import { render, unmountComponentAtNode } from "react-dom";
|
||||
import { isMac } from "../common/vars";
|
||||
import { userStore } from "../common/user-store";
|
||||
@ -11,8 +13,6 @@ import { workspaceStore } from "../common/workspace-store";
|
||||
import { clusterStore } from "../common/cluster-store";
|
||||
import { i18nStore } from "./i18n";
|
||||
import { themeStore } from "./theme.store";
|
||||
import { App } from "./components/app";
|
||||
import { LensApp } from "./lens-app";
|
||||
import { extensionsStore } from "../extensions/extensions-store";
|
||||
|
||||
type AppComponent = React.ComponentType & {
|
||||
|
||||
@ -12,7 +12,6 @@ import { Icon } from "../icon";
|
||||
import { PageLayout } from "../layout/page-layout";
|
||||
import { extensionLoader } from "../../../extensions/extension-loader";
|
||||
import { extensionManager } from "../../../extensions/extension-manager";
|
||||
import { extensionsStore } from "../../../extensions/extensions-store";
|
||||
|
||||
@observer
|
||||
export class Extensions extends React.Component {
|
||||
@ -20,7 +19,7 @@ export class Extensions extends React.Component {
|
||||
|
||||
@computed get extensions() {
|
||||
const searchText = this.search.toLowerCase();
|
||||
return extensionLoader.userExtensions.filter(ext => {
|
||||
return Array.from(extensionLoader.userExtensions.values()).filter(ext => {
|
||||
const { name, description } = ext.manifest;
|
||||
return [
|
||||
name.toLowerCase().includes(searchText),
|
||||
@ -70,7 +69,7 @@ export class Extensions extends React.Component {
|
||||
)
|
||||
}
|
||||
return extensions.map(ext => {
|
||||
const { manifestPath: extId, enabled, manifest } = ext;
|
||||
const { manifestPath: extId, isEnabled, manifest } = ext;
|
||||
const { name, description } = manifest;
|
||||
return (
|
||||
<div key={extId} className="extension flex gaps align-center">
|
||||
@ -82,11 +81,11 @@ export class Extensions extends React.Component {
|
||||
Description: <span className="text-secondary">{description}</span>
|
||||
</div>
|
||||
</div>
|
||||
{!enabled && (
|
||||
<Button plain active onClick={() => extensionsStore.setEnabled(extId, true)}>Enable</Button>
|
||||
{!isEnabled && (
|
||||
<Button plain active onClick={() => ext.isEnabled = true}>Enable</Button>
|
||||
)}
|
||||
{enabled && (
|
||||
<Button accent onClick={() => extensionsStore.setEnabled(extId, false)}>Disable</Button>
|
||||
{isEnabled && (
|
||||
<Button accent onClick={() => ext.isEnabled = false}>Disable</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user