mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fixes
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
f97fbdf9ed
commit
ffa6a982b5
@ -1,24 +0,0 @@
|
||||
import { DynamicPageType, LensRendererExtension, PageStore } from "@lens/ui-extensions";
|
||||
import { examplePage, ExtensionIcon } from "./page"
|
||||
|
||||
export default class ExampleExtension extends LensRendererExtension {
|
||||
onActivate() {
|
||||
console.log('EXAMPLE EXTENSION RENDERER: ACTIVATED', this.getMeta());
|
||||
}
|
||||
|
||||
registerPages(pageStore: PageStore) {
|
||||
this.registerPage(pageStore, {
|
||||
type: DynamicPageType.CLUSTER,
|
||||
path: "/extension-example",
|
||||
title: "Example Extension",
|
||||
components: {
|
||||
Page: examplePage(this),
|
||||
MenuIcon: ExtensionIcon,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
console.log('EXAMPLE EXTENSION RENDERER: DEACTIVATED', this.getMeta());
|
||||
}
|
||||
}
|
||||
@ -5,10 +5,6 @@ export default class ExampleExtensionMain extends LensMainExtension {
|
||||
console.log('EXAMPLE EXTENSION MAIN: ACTIVATED', this.getMeta());
|
||||
}
|
||||
|
||||
onEvent(evt: any) {
|
||||
//
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
console.log('EXAMPLE EXTENSION MAIN: DEACTIVATED', this.getMeta());
|
||||
}
|
||||
|
||||
@ -28,5 +28,5 @@ export class ExtensionPage extends React.Component<{ extension: LensRendererExte
|
||||
}
|
||||
|
||||
export function examplePage(ext: LensRendererExtension) {
|
||||
return () => <ExtensionPage extension={ext}/>
|
||||
return () => <ExtensionPage extension={ext} />
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ export default class ExampleExtension extends LensRendererExtension {
|
||||
}
|
||||
|
||||
registerPages(pageStore: PageStore) {
|
||||
this.registerPage(pageStore, {
|
||||
this.disposers.push(pageStore.register({
|
||||
type: DynamicPageType.CLUSTER,
|
||||
path: "/extension-example",
|
||||
title: "Example Extension",
|
||||
@ -15,7 +15,7 @@ export default class ExampleExtension extends LensRendererExtension {
|
||||
Page: examplePage(this),
|
||||
MenuIcon: ExtensionIcon,
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
onDeactivate() {
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"experimentalDecorators": true,
|
||||
"jsx": "react"
|
||||
},
|
||||
"include": [
|
||||
|
||||
@ -12,15 +12,18 @@
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "concurrently -k \"yarn dev-run -C\" yarn:dev:*",
|
||||
"dev-build": "concurrently yarn:compile:*",
|
||||
"dev-run": "nodemon --watch static/build/main.js --exec \"electron --inspect .\"",
|
||||
"dev:main": "yarn compile:main --watch",
|
||||
"dev:renderer": "yarn compile:renderer --watch",
|
||||
"dev:extension-rollup": "yarn compile:extension-rollup --watch",
|
||||
"dev:extension-api": "yarn compile:extension-api --watch",
|
||||
"compile": "env NODE_ENV=production concurrently yarn:compile:*",
|
||||
"compile:main": "webpack --config webpack.main.ts",
|
||||
"compile:renderer": "webpack --config webpack.renderer.ts",
|
||||
"compile:i18n": "lingui compile",
|
||||
"compile:extension-api": "rollup --config src/extensions/rollup.config.js",
|
||||
"compile:extension-rollup": "rollup --config src/extensions/rollup.config.js",
|
||||
"compile:extension-api": "webpack --config webpack.extensions.ts",
|
||||
"build:linux": "yarn compile && electron-builder --linux --dir -c.productName=Lens",
|
||||
"build:mac": "yarn compile && electron-builder --mac --dir -c.productName=Lens",
|
||||
"build:win": "yarn compile && electron-builder --win --dir -c.productName=Lens",
|
||||
|
||||
@ -66,14 +66,13 @@ export class ExtensionLoader {
|
||||
}
|
||||
|
||||
protected autoloadExtensions(getLensRuntimeEnv: () => LensExtensionRuntimeEnv, callback: (instance: LensExtension) => void) {
|
||||
return reaction(() => this.extensions.toJS(), installedExtensions => {
|
||||
installedExtensions.forEach((ext) => {
|
||||
return reaction(() => this.extensions.toJS(), (installedExtensions) => {
|
||||
for(const [id, ext] of installedExtensions) {
|
||||
let instance = this.instances.get(ext.manifestPath)
|
||||
if (!instance) {
|
||||
const extensionModule = this.requireExtension(ext)
|
||||
if (!extensionModule) {
|
||||
logger.error("[EXTENSION-LOADER] failed to load extension " + ext.manifestPath)
|
||||
return
|
||||
continue
|
||||
}
|
||||
const LensExtensionClass = extensionModule.default;
|
||||
instance = new LensExtensionClass({ ...ext.manifest, manifestPath: ext.manifestPath, id: ext.manifestPath }, ext.manifest);
|
||||
@ -81,7 +80,7 @@ export class ExtensionLoader {
|
||||
callback(instance)
|
||||
this.instances.set(ext.id, instance)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, {
|
||||
fireImmediately: true,
|
||||
delay: 0,
|
||||
@ -92,17 +91,17 @@ export class ExtensionLoader {
|
||||
let extEntrypoint = ""
|
||||
return withExtensionPackagesRoot(() => {
|
||||
try {
|
||||
if (ipcRenderer) {
|
||||
extEntrypoint = path.join(path.dirname(extension.manifestPath), extension.manifest.renderer)
|
||||
} else {
|
||||
extEntrypoint = path.join(path.dirname(extension.manifestPath), extension.manifest.main)
|
||||
if (ipcRenderer && extension.manifest.renderer) {
|
||||
extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.renderer))
|
||||
} else if (extension.manifest.main) {
|
||||
extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.main))
|
||||
}
|
||||
if (extEntrypoint !== "") {
|
||||
return __non_webpack_require__(extEntrypoint)
|
||||
}
|
||||
} catch (err) {
|
||||
console.trace(err)
|
||||
console.error(`[EXTENSION-LOADER]: can't load extension main at ${extEntrypoint}: ${err}`, { extension });
|
||||
console.trace(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,10 +2,23 @@ import type { ExtensionManifest } from "./lens-extension"
|
||||
import path from "path"
|
||||
import fs from "fs-extra"
|
||||
import logger from "../main/logger"
|
||||
import { withExtensionPackagesRoot, extensionPackagesRoot, InstalledExtension } from "./extension-loader"
|
||||
import npm from "npm"
|
||||
import { extensionPackagesRoot, InstalledExtension } from "./extension-loader"
|
||||
import * as child_process from 'child_process';
|
||||
|
||||
type Dependencies = {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
type PackageJson = {
|
||||
dependencies: Dependencies;
|
||||
}
|
||||
|
||||
export class ExtensionManager {
|
||||
|
||||
protected packagesJson: PackageJson = {
|
||||
dependencies: {}
|
||||
}
|
||||
|
||||
get extensionPackagesRoot() {
|
||||
return extensionPackagesRoot()
|
||||
}
|
||||
@ -14,11 +27,13 @@ export class ExtensionManager {
|
||||
return path.resolve(__static, "../extensions");
|
||||
}
|
||||
|
||||
get npmPath() {
|
||||
return __non_webpack_require__.resolve('npm/bin/npm-cli')
|
||||
}
|
||||
|
||||
async load() {
|
||||
logger.info("[EXTENSION-MANAGER] loading extensions from " + this.extensionPackagesRoot)
|
||||
|
||||
await fs.ensureDir(path.join(this.extensionPackagesRoot, "node_modules"))
|
||||
await fs.writeFile(path.join(this.extensionPackagesRoot, "package.json"), `{"dependencies": []}`, {mode: 0o600})
|
||||
|
||||
return await this.loadExtensions();
|
||||
}
|
||||
@ -27,9 +42,7 @@ export class ExtensionManager {
|
||||
let manifestJson: ExtensionManifest;
|
||||
try {
|
||||
manifestJson = __non_webpack_require__(manifestPath)
|
||||
withExtensionPackagesRoot(() => {
|
||||
this.installPackageFromPath(path.dirname(manifestPath))
|
||||
})
|
||||
this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath)
|
||||
|
||||
logger.info("[EXTENSION-MANAGER] installed extension " + manifestJson.name)
|
||||
return {
|
||||
@ -44,31 +57,17 @@ export class ExtensionManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected installPackageFromPath(path: string): Promise<void> {
|
||||
const origLogger = console.log
|
||||
protected installPackages(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
npm.load({
|
||||
production: true,
|
||||
global: false,
|
||||
prefix: this.extensionPackagesRoot,
|
||||
dev: false,
|
||||
spin: false,
|
||||
"ignore-scripts": true,
|
||||
loglevel: "silent"
|
||||
}, (err) => {
|
||||
console.log = function() {
|
||||
// just to ignore ts empty function error
|
||||
}
|
||||
npm.commands.install([
|
||||
path
|
||||
], (err) => {
|
||||
console.log = origLogger
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
const child = child_process.fork(this.npmPath, ["install", "--silent"], {
|
||||
cwd: extensionPackagesRoot(),
|
||||
silent: true
|
||||
})
|
||||
child.on("close", () => {
|
||||
resolve()
|
||||
})
|
||||
child.on("error", (err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -80,15 +79,19 @@ export class ExtensionManager {
|
||||
|
||||
async loadFromFolder(folderPath: string): Promise<InstalledExtension[]> {
|
||||
const paths = await fs.readdir(folderPath);
|
||||
const manifestsLoading = paths.map(fileName => {
|
||||
const extensions: InstalledExtension[] = []
|
||||
for (const fileName of paths) {
|
||||
const absPath = path.resolve(folderPath, fileName);
|
||||
const manifestPath = path.resolve(absPath, "package.json");
|
||||
return fs.access(manifestPath, fs.constants.F_OK)
|
||||
.then(async () => await this.getExtensionByManifest(manifestPath))
|
||||
.catch(() => null)
|
||||
});
|
||||
let extensions = await Promise.all(manifestsLoading);
|
||||
extensions = extensions.filter(v => !!v); // filter out files and invalid folders (without manifest.json)
|
||||
await fs.access(manifestPath, fs.constants.F_OK)
|
||||
const ext = await this.getExtensionByManifest(manifestPath).catch(() => null)
|
||||
if (ext) {
|
||||
extensions.push(ext)
|
||||
}
|
||||
}
|
||||
await fs.writeFile(path.join(this.extensionPackagesRoot, "package.json"), JSON.stringify(this.packagesJson), {mode: 0o600})
|
||||
await this.installPackages()
|
||||
|
||||
logger.debug(`[EXTENSION-MANAGER]: ${extensions.length} extensions loaded`, { folderPath, extensions });
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// Lens-extensions api developer's kit
|
||||
export type { LensExtensionRuntimeEnv, PageStore } from "./lens-renderer-runtime";
|
||||
export type { LensExtensionRuntimeEnv } from "./lens-renderer-runtime"
|
||||
export type { PageStore } from "./page-store"
|
||||
|
||||
// APIs
|
||||
export * from "./lens-renderer-extension"
|
||||
export { DynamicPageType } from "./page-store";
|
||||
export { DynamicPageType } from "./page-store"
|
||||
|
||||
// TODO: add more common re-usable UI components + refactor interfaces (Props -> ComponentProps)
|
||||
export { default as React } from "react"
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import type { PageStore } from "./lens-renderer-runtime"
|
||||
import type { PageStore } from "./extension-renderer-api"
|
||||
import type { PageRegistration } from "./page-store"
|
||||
import { LensExtension } from "./lens-extension"
|
||||
|
||||
export class LensRendererExtension extends LensExtension {
|
||||
export abstract class LensRendererExtension extends LensExtension {
|
||||
registerPages(pageStore: PageStore) {
|
||||
// mock
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Runtime helpers
|
||||
protected registerPage(pageStore: PageStore, params: PageRegistration) {
|
||||
const dispose = pageStore.register(params);
|
||||
|
||||
@ -2,11 +2,6 @@
|
||||
|
||||
import logger from "../main/logger";
|
||||
import { navigate } from "../renderer/navigation";
|
||||
import { PageRegistration } from "./page-store";
|
||||
|
||||
export interface PageStore {
|
||||
register(params: PageRegistration): () => void
|
||||
}
|
||||
|
||||
export interface LensExtensionRuntimeEnv {
|
||||
logger: typeof logger;
|
||||
|
||||
@ -81,6 +81,7 @@ async function main() {
|
||||
|
||||
extensionLoader.loadOnMain(getLensRuntime)
|
||||
extensionLoader.extensions.replace(await extensionManager.load())
|
||||
extensionLoader.broadcastExtensions()
|
||||
}
|
||||
|
||||
app.on("ready", main);
|
||||
|
||||
@ -4,6 +4,7 @@ import { BrowserWindow, dialog, ipcMain, shell, webContents } from "electron"
|
||||
import windowStateKeeper from "electron-window-state"
|
||||
import { observable } from "mobx";
|
||||
import { initMenu } from "./menu";
|
||||
import { extensionLoader } from "../extensions/extension-loader";
|
||||
|
||||
export class WindowManager {
|
||||
protected mainView: BrowserWindow;
|
||||
@ -40,6 +41,9 @@ export class WindowManager {
|
||||
event.preventDefault();
|
||||
shell.openExternal(url);
|
||||
});
|
||||
this.mainView.webContents.on("dom-ready", () => {
|
||||
extensionLoader.broadcastExtensions()
|
||||
})
|
||||
|
||||
// track visible cluster from ui
|
||||
ipcMain.on("cluster-view:current-id", (event, clusterId: ClusterId) => {
|
||||
@ -72,8 +76,8 @@ export class WindowManager {
|
||||
try {
|
||||
await this.showSplash();
|
||||
await this.mainView.loadURL(`http://localhost:${this.proxyPort}`)
|
||||
this.mainView.show();
|
||||
this.splashWindow.close();
|
||||
this.mainView.show()
|
||||
this.splashWindow.close()
|
||||
} catch (err) {
|
||||
dialog.showErrorBox("ERROR!", err.toString())
|
||||
}
|
||||
|
||||
50
webpack.extensions.ts
Executable file
50
webpack.extensions.ts
Executable file
@ -0,0 +1,50 @@
|
||||
import { extensionsDir, extensionsLibName, extensionsRendererLibName } from "./src/common/vars";
|
||||
import path from "path";
|
||||
import webpack from "webpack";
|
||||
import nodeExternals from "webpack-node-externals";
|
||||
import { webpackLensRenderer } from "./webpack.renderer";
|
||||
import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin";
|
||||
import ProgressBarPlugin from "progress-bar-webpack-plugin";
|
||||
import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
||||
|
||||
export default [
|
||||
webpackExtensionsApi,
|
||||
webpackExtensionsRendererApi
|
||||
]
|
||||
|
||||
// todo: use common chunks/externals for "react", "react-dom", etc.
|
||||
export function webpackExtensionsApi(): webpack.Configuration {
|
||||
const config = webpackLensRenderer({ showVars: false })
|
||||
config.name = "extensions-api"
|
||||
config.entry = {
|
||||
[extensionsLibName]: path.resolve(extensionsDir, "extension-api.ts")
|
||||
}
|
||||
config.externals = [
|
||||
nodeExternals()
|
||||
]
|
||||
config.plugins = [
|
||||
new ProgressBarPlugin(),
|
||||
new ForkTsCheckerPlugin(),
|
||||
]
|
||||
config.output.libraryTarget = "commonjs2"
|
||||
config.devtool = "nosources-source-map"
|
||||
return config
|
||||
}
|
||||
|
||||
export function webpackExtensionsRendererApi(): webpack.Configuration {
|
||||
const config = webpackLensRenderer({ showVars: false })
|
||||
config.name = "extensions-renderer-api"
|
||||
config.entry = {
|
||||
[extensionsRendererLibName]: path.resolve(extensionsDir, "extension-renderer-api.ts")
|
||||
}
|
||||
config.plugins = [
|
||||
new ProgressBarPlugin(),
|
||||
new ForkTsCheckerPlugin(),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
})
|
||||
]
|
||||
config.output.libraryTarget = "commonjs2"
|
||||
config.devtool = "nosources-source-map"
|
||||
return config
|
||||
}
|
||||
@ -8,34 +8,9 @@ import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin"
|
||||
import ProgressBarPlugin from "progress-bar-webpack-plugin";
|
||||
|
||||
export default [
|
||||
webpackLensRenderer,
|
||||
webpackExtensionsApi,
|
||||
webpackExtensionsRendererApi
|
||||
webpackLensRenderer
|
||||
]
|
||||
|
||||
// todo: use common chunks/externals for "react", "react-dom", etc.
|
||||
export function webpackExtensionsApi(): webpack.Configuration {
|
||||
const config = webpackLensRenderer({ showVars: false });
|
||||
config.name = "extensions-api"
|
||||
config.entry = {
|
||||
[extensionsLibName]: path.resolve(extensionsDir, "extension-api.ts")
|
||||
};
|
||||
config.output.libraryTarget = "commonjs2"
|
||||
config.devtool = "nosources-source-map";
|
||||
return config;
|
||||
}
|
||||
|
||||
export function webpackExtensionsRendererApi(): webpack.Configuration {
|
||||
const config = webpackLensRenderer({ showVars: false });
|
||||
config.name = "extensions-renderer-api"
|
||||
config.entry = {
|
||||
[extensionsRendererLibName]: path.resolve(extensionsDir, "extension-renderer-api.ts")
|
||||
};
|
||||
config.output.libraryTarget = "commonjs2"
|
||||
config.devtool = "nosources-source-map";
|
||||
return config;
|
||||
}
|
||||
|
||||
export function webpackLensRenderer({ showVars = true } = {}): webpack.Configuration {
|
||||
if (showVars) {
|
||||
console.info('WEBPACK:renderer', require("./src/common/vars"));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user