1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

extensions-api -- provide lens-runtime params on extension.enable

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-09-06 17:52:05 +03:00
parent 01d5989894
commit eca3cadd80
6 changed files with 58 additions and 44 deletions

View File

@ -3,6 +3,9 @@
"version": "1.0.0", "version": "1.0.0",
"description": "Example extension", "description": "Example extension",
"main": "example-extension.ts", "main": "example-extension.ts",
"lens": {
"metadata": {}
},
"dependencies": { "dependencies": {
} }
} }

View File

@ -1,5 +1,5 @@
// Lens-extensions api developer's kit // Lens-extensions api developer's kit
export type { LensRendererRuntimeEnv } from "./extension-api.runtime"; export type { LensRuntimeRendererEnv } from "./lens-runtime";
// APIs // APIs
export * from "./extension" export * from "./extension"

View File

@ -1,9 +1,11 @@
import type { LensRuntimeRendererEnv } from "./lens-runtime";
import path from "path"; import path from "path";
import fs from "fs-extra"; import fs from "fs-extra";
import { action, comparer, observable, toJS } from "mobx"; import { action, observable, reaction, toJS } from "mobx";
import { BaseStore } from "../common/base-store"; import { BaseStore } from "../common/base-store";
import { ExtensionId, ExtensionManifest, ExtensionVersion, LensExtension } from "./extension"; import { ExtensionId, ExtensionManifest, ExtensionVersion, LensExtension } from "./extension";
import { isDevelopment } from "../common/vars"; import { isDevelopment } from "../common/vars";
import logger from "../main/logger";
export interface ExtensionStoreModel { export interface ExtensionStoreModel {
version: ExtensionVersion; version: ExtensionVersion;
@ -11,7 +13,7 @@ export interface ExtensionStoreModel {
} }
export interface ExtensionModel { export interface ExtensionModel {
id: ExtensionId; id?: ExtensionId; // available in lens-extension instance
version: ExtensionVersion; version: ExtensionVersion;
name: string; name: string;
manifestPath: string; manifestPath: string;
@ -39,7 +41,7 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
@observable version: ExtensionVersion = "0.0.0"; @observable version: ExtensionVersion = "0.0.0";
@observable extensions = observable.map<ExtensionId, LensExtension>(); @observable extensions = observable.map<ExtensionId, LensExtension>();
@observable removed = observable.map<ExtensionId, LensExtension>(); @observable removed = observable.map<ExtensionId, LensExtension>();
@observable installed = observable.map<string, InstalledExtension>([], { equals: comparer.shallow }); @observable.shallow installed = observable.map<string, InstalledExtension>([]);
get folderPath(): string { get folderPath(): string {
if (isDevelopment) { if (isDevelopment) {
@ -49,10 +51,28 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
} }
async load() { async load() {
await this.loadInstalledExtensions(); await this.loadExtensions();
return super.load(); return super.load();
} }
enableAutoInitOnLoad(getLensRuntimeEnv: () => LensRuntimeRendererEnv, { delay = 0 } = {}) {
logger.info('[EXTENSIONS-STORE]: enabled: auto-init loaded extensions');
return reaction(() => Array.from(this.installed.values()), installedExtensions => {
installedExtensions.forEach(({ extensionModule, manifest, manifestPath }) => {
let instance = this.getById(manifestPath);
if (!instance) {
const LensExtension = extensionModule.default;
instance = new LensExtension({ ...manifest }, manifest);
this.extensions.set(manifestPath, instance); // fixme: mobx error
instance.enable(getLensRuntimeEnv());
}
})
}, {
fireImmediately: true,
delay: delay,
})
}
getExtensionByManifest(manifestPath: string): InstalledExtension { getExtensionByManifest(manifestPath: string): InstalledExtension {
let manifestJson: ExtensionManifest; let manifestJson: ExtensionManifest;
let mainJs: string; let mainJs: string;
@ -72,21 +92,13 @@ export class ExtensionStore extends BaseStore<ExtensionStoreModel> {
} }
@action @action
async loadInstalledExtensions() { async loadExtensions() {
const extensions = await this.loadExtensions(this.folderPath); const extensions = await this.loadFromFolder(this.folderPath);
this.installed.replace(extensions.map(ext => [ext.manifestPath, ext])); const extManifestMap = new Map(extensions.map(ext => [ext.manifestPath, ext]));
this.installed.replace(extManifestMap);
// todo: remove
if (process.isMainFrame) {
extensions.forEach(({ extensionModule, manifest }) => {
const LensExtension = extensionModule.default;
const instance = new LensExtension({ ...manifest }, manifest);
instance.activate();
})
}
} }
async loadExtensions(folderPath: string): Promise<InstalledExtension[]> { async loadFromFolder(folderPath: string): Promise<InstalledExtension[]> {
const paths = await fs.readdir(folderPath); const paths = await fs.readdir(folderPath);
const manifestsLoading = paths.map(fileName => { const manifestsLoading = paths.map(fileName => {
const absPath = path.resolve(folderPath, fileName); const absPath = path.resolve(folderPath, fileName);

View File

@ -1,11 +1,11 @@
import type { ExtensionModel } from "./extension-store"; import type { ExtensionModel } from "./extension-store";
import type { LensRendererRuntimeEnv } from "./extension-api.runtime"; import type { LensRuntimeRendererEnv } from "./lens-runtime";
import { readJsonSync } from "fs-extra"; import { readJsonSync } from "fs-extra";
import { action, observable } from "mobx"; import { action, observable } from "mobx";
import extensionManifest from "./example-extension/package.json" import extensionManifest from "./example-extension/package.json"
import logger from "../main/logger"; import logger from "../main/logger";
export type ExtensionId = string; export type ExtensionId = string; // id or path to "%lens-extension/manifest.json"
export type ExtensionVersion = string | number; export type ExtensionVersion = string | number;
export type ExtensionManifest = typeof extensionManifest & ExtensionModel; export type ExtensionManifest = typeof extensionManifest & ExtensionModel;
@ -19,7 +19,7 @@ export class LensExtension implements ExtensionModel {
@observable manifest: ExtensionManifest; @observable manifest: ExtensionManifest;
@observable manifestPath: string; @observable manifestPath: string;
@observable isEnabled = false; @observable isEnabled = false;
@observable.ref runtime: LensRendererRuntimeEnv; @observable.ref runtime: Partial<LensRuntimeRendererEnv> = {};
constructor(model: ExtensionModel, manifest: ExtensionManifest) { constructor(model: ExtensionModel, manifest: ExtensionManifest) {
this.importModel(model, manifest); this.importModel(model, manifest);
@ -38,38 +38,30 @@ export class LensExtension implements ExtensionModel {
} }
} }
async activate() { async enable(runtime: LensRuntimeRendererEnv) {
logger.info(`[EXTENSION]: activate ${this.name}@${this.version}`, this.getMeta());
}
async deactivate() {
logger.info(`[EXTENSION]: deactivate ${this.name}@${this.version}`, this.getMeta());
}
async enable() {
logger.info(`[EXTENSION]: enable ${this.name}@${this.version}`, this.getMeta());
this.isEnabled = true; this.isEnabled = true;
this.runtime = runtime;
logger.info(`[EXTENSION]: enable ${this.name}@${this.version}`, this.getMeta());
} }
async disable() { async disable() {
logger.info(`[EXTENSION]: disable ${this.name}@${this.version}`, this.getMeta());
this.isEnabled = false; this.isEnabled = false;
this.runtime = {};
logger.info(`[EXTENSION]: disable ${this.name}@${this.version}`, this.getMeta());
} }
async install() { // todo
// todo async install(downloadUrl?: string) {
return;
} }
// todo
async uninstall() { async uninstall() {
// todo return;
} }
async upgrade() { async hasNewVersion(): Promise<Partial<ExtensionModel>> {
// todo return;
}
async checkNewVersion() {
// todo
} }
getMeta() { getMeta() {
@ -78,6 +70,7 @@ export class LensExtension implements ExtensionModel {
manifest: this.manifest, manifest: this.manifest,
manifestPath: this.manifestPath, manifestPath: this.manifestPath,
enabled: this.isEnabled, enabled: this.isEnabled,
runtime: Object.keys(this.runtime),
} }
} }

View File

@ -1,12 +1,12 @@
// Lens runtime params provider to hook up into extensions // Lens runtime for injecting to extension on activation
import { apiManager, ApiManager } from "../renderer/api/api-manager"; import { apiManager, ApiManager } from "../renderer/api/api-manager";
export interface LensRendererRuntimeEnv { export interface LensRuntimeRendererEnv {
apiManager: ApiManager; apiManager: ApiManager;
} }
// todo: expose more public runtime apis: stores, managers, etc. // todo: expose more public runtime apis: stores, managers, etc.
export function getExtensionRuntime(): LensRendererRuntimeEnv { export function getLensRuntime(): LensRuntimeRendererEnv {
return { return {
apiManager, apiManager,
} }

View File

@ -11,9 +11,15 @@ import { ErrorBoundary } from "./components/error-boundary";
import { WhatsNew, whatsNewRoute } from "./components/+whats-new"; import { WhatsNew, whatsNewRoute } from "./components/+whats-new";
import { Notifications } from "./components/notifications"; import { Notifications } from "./components/notifications";
import { ConfirmDialog } from "./components/confirm-dialog"; import { ConfirmDialog } from "./components/confirm-dialog";
import { extensionStore } from "../extensions/extension-store";
import { getLensRuntime } from "../extensions/lens-runtime";
@observer @observer
export class LensApp extends React.Component { export class LensApp extends React.Component {
componentDidMount() {
extensionStore.enableAutoInitOnLoad(getLensRuntime);
}
render() { render() {
return ( return (
<I18nProvider i18n={_i18n}> <I18nProvider i18n={_i18n}>