Unverified Commit f3a00593 authored by Roman's avatar Roman Committed by GitHub
Browse files

Extension support page (#1112)

Signed-off-by: default avatarRoman <ixrock@gmail.com>
Co-authored-by: default avatarJim Ehrismann <40840436+jim-docker@users.noreply.github.com>
parent ce995f3d
Showing with 3901 additions and 61 deletions
+3901 -61
......@@ -12,6 +12,6 @@ binaries/client/
binaries/server/
src/extensions/*/*.js
src/extensions/*/*.d.ts
src/extensions/example-extension/src/**
types/extension-api.d.ts
types/extension-renderer-api.d.ts
extensions/*/dist
......@@ -10,7 +10,7 @@ export default class ExampleExtension extends LensRendererExtension {
registerPages(registry: Registry.PageRegistry) {
this.disposers.push(
registry.add({
type: Registry.DynamicPageType.CLUSTER,
type: Registry.PageRegistryType.CLUSTER,
path: "/extension-example",
title: "Example Extension",
components: {
......
import { LensMainExtension, Registry, windowManager } from "@k8slens/extensions";
import { supportPageURL } from "./src/support.route";
export default class SupportPageMainExtension extends LensMainExtension {
async onActivate() {
console.log("support page extension activated")
}
async registerAppMenus(registry: Registry.MenuRegistry) {
this.disposers.push(
registry.add({
parentId: "help",
label: "Support",
click() {
windowManager.navigate({
channel: "menu:navigate", // fixme: use windowManager.ensureMainWindow from Tray's PR
url: supportPageURL(),
});
}
})
)
}
}
This diff is collapsed.
{
"name": "lens-support-page",
"version": "0.1.0",
"description": "Lens support page",
"main": "dist/main.js",
"renderer": "dist/renderer.js",
"scripts": {
"build": "webpack -p",
"dev": "webpack --watch"
},
"dependencies": {},
"devDependencies": {
"@types/node": "^14.11.11",
"@types/react": "^16.9.53",
"@types/react-router": "^5.1.8",
"@types/webpack": "^4.41.17",
"mobx": "^5.15.5",
"react": "^16.13.1",
"ts-loader": "^8.0.4",
"ts-node": "^9.0.0",
"typescript": "^4.0.3",
"webpack": "^4.44.2"
}
}
import React from "react";
import { Component, LensRendererExtension, Navigation, Registry } from "@k8slens/extensions";
import { supportPageRoute, supportPageURL } from "./src/support.route";
import { Support } from "./src/support";
export default class SupportPageRendererExtension extends LensRendererExtension {
async onActivate() {
console.log("support page extension activated")
}
registerPages(registry: Registry.PageRegistry) {
this.disposers.push(
registry.add({
...supportPageRoute,
type: Registry.PageRegistryType.GLOBAL,
url: supportPageURL(),
components: {
Page: Support,
}
})
)
}
registerStatusBarIcon(registry: Registry.StatusBarRegistry) {
this.disposers.push(
registry.add({
icon: (
<Component.Icon
material="support"
tooltip="Support"
onClick={() => Navigation.navigate(supportPageURL())}
/>
)
})
)
}
}
import type { RouteProps } from "react-router";
export const supportPageRoute: RouteProps = {
path: "/support"
}
export const supportPageURL = () => supportPageRoute.path.toString();
// TODO: figure out how to consume styles / handle import "./support.scss"
// TODO: support localization / figure out how to extract / consume i18n strings
import React from "react"
import { observer } from "mobx-react"
import { CommonVars, Component } from "@k8slens/extensions";
@observer
export class Support extends React.Component {
render() {
const { PageLayout } = Component;
const { slackUrl, issuesTrackerUrl } = CommonVars;
return (
<PageLayout showOnTop className="Support" header={<h2>Support</h2>}>
<h2>Community Slack Channel</h2>
<p>
Ask a question, see what's being discussed, join the conversation <a href={slackUrl} target="_blank">here</a>
</p>
<h2>Report an Issue</h2>
<p>
Review existing issues or open a new one <a href={issuesTrackerUrl} target="_blank">here</a>
</p>
{/*<h2><Trans>Commercial Support</Trans></h2>*/}
</PageLayout>
);
}
}
{
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"module": "CommonJS",
"target": "ES2017",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"moduleResolution": "Node",
"sourceMap": false,
"declaration": false,
"strict": false,
"noImplicitAny": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"jsx": "react",
"paths": {
"*": [
"node_modules/*",
"../../types/*"
]
}
},
"include": [
"renderer.ts",
"../../src/extensions/npm/**/*.d.ts",
"src/**/*"
]
}
import path from "path"
const outputPath = path.resolve(__dirname, 'dist');
// TODO: figure out how to share base TS and Webpack configs from Lens (npm, filesystem, etc?)
const lensExternals = {
"@k8slens/extensions": "var global.LensExtensions",
"react": "var global.React",
"mobx": "var global.Mobx",
"mobx-react": "var global.MobxReact",
};
export default [
{
entry: './main.ts',
context: __dirname,
target: "electron-main",
mode: "production",
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
externals: [
lensExternals,
],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
libraryTarget: "commonjs2",
globalObject: "this",
filename: 'main.js',
path: outputPath,
},
},
{
entry: './renderer.tsx',
context: __dirname,
target: "electron-renderer",
mode: "production",
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
externals: [
lensExternals,
],
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
libraryTarget: "commonjs2",
globalObject: "this",
filename: 'renderer.js',
path: outputPath,
},
},
];
......@@ -9,8 +9,8 @@
"styles": []
},
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "npm run build --watch"
"build": "webpack -p",
"dev": "webpack --watch"
},
"dependencies": {},
"devDependencies": {
......
......@@ -26,5 +26,5 @@
"renderer.ts",
"../../src/extensions/npm/**/*.d.ts",
"src/**/*"
],
]
}
......@@ -176,7 +176,8 @@
"extensions": [
"telemetry",
"pod-menu",
"node-menu"
"node-menu",
"support-page"
]
},
"dependencies": {
......@@ -314,7 +315,6 @@
"jest": "^26.0.1",
"jest-mock-extended": "^1.0.10",
"make-plural": "^6.2.1",
"material-design-icons": "^3.0.1",
"mini-css-extract-plugin": "^0.9.0",
"mobx-react": "^6.2.2",
"moment": "^2.26.0",
......
......@@ -21,11 +21,6 @@ export const rendererDir = path.join(contextDir, "src/renderer");
export const htmlTemplate = path.resolve(rendererDir, "template.html");
export const sassCommonVars = path.resolve(rendererDir, "components/vars.scss");
// Extensions
export const extensionsLibName = `${appName}-extensions.api`
export const extensionsRendererLibName = `${appName}-extensions-renderer.api`
export const extensionsDir = path.join(contextDir, "src/extensions");
// Special runtime paths
defineGlobal("__static", {
get() {
......
// Lens-extensions api developer's kit
export * from "../lens-main-extension"
export * from "../lens-renderer-extension"
import type { WindowManager } from "../../main/window-manager";
// APIs
import * as EventBus from "./event-bus"
import * as Store from "./stores"
import * as Util from "./utils"
import * as Registry from "../registries"
import * as CommonVars from "../../common/vars";
export let windowManager: WindowManager;
export {
EventBus,
Store,
Util,
Registry,
CommonVars,
}
export type { DynamicPageType, PageRegistry } from "../page-registry"
export type { AppPreferenceRegistry } from "../app-preference-registry"
export type { KubeObjectMenuRegistry } from "../../renderer/api/kube-object-menu-registry"
export type { KubeObjectDetailRegistry } from "../../renderer/api/kube-object-detail-registry"
// Lens-extensions api developer's kit
export type { LensExtensionRuntimeEnv } from "./lens-runtime";
export * from "./lens-main-extension"
export * from "./lens-renderer-extension"
// APIs
import * as EventBus from "./core-api/event-bus"
import * as Store from "./core-api/stores"
import * as Util from "./core-api/utils"
import * as Registry from "./core-api/registries"
export {
EventBus,
Registry,
Store,
Util
}
import React from "react";
import { cssNames } from "../renderer/utils";
import { TabLayout } from "../renderer/components/layout/tab-layout";
import { PageRegistration } from "./page-registry"
import { PageRegistration } from "./registries/page-registry"
export class DynamicPage extends React.Component<{ page: PageRegistration }> {
render() {
......
export * from "./core-extension-api"
export * from "./renderer-extension-api"
// Extension-api types generation bundle (used by rollup.js)
export * from "./core-api"
export * from "./renderer-api"
import type { ExtensionId, LensExtension, ExtensionManifest, ExtensionModel } from "./lens-extension"
import type { ExtensionId, ExtensionManifest, ExtensionModel, LensExtension } from "./lens-extension"
import type { LensMainExtension } from "./lens-main-extension"
import type { LensRendererExtension } from "./lens-renderer-extension"
import { broadcastIpc } from "../common/ipc"
import type { LensExtensionRuntimeEnv } from "./lens-runtime"
import path from "path"
import { broadcastIpc } from "../common/ipc"
import { observable, reaction, toJS, } from "mobx"
import logger from "../main/logger"
import { app, remote, ipcRenderer } from "electron"
import { pageRegistry } from "./page-registry";
import { appPreferenceRegistry } from "./app-preference-registry"
import { kubeObjectMenuRegistry } from "../renderer/api/kube-object-menu-registry"
import { app, ipcRenderer, remote } from "electron"
import { appPreferenceRegistry, kubeObjectMenuRegistry, menuRegistry, pageRegistry, statusBarRegistry } from "./registries";
export interface InstalledExtension extends ExtensionModel {
manifestPath: string;
......@@ -36,33 +34,34 @@ export class ExtensionLoader {
}
}
loadOnClusterRenderer(getLensRuntimeEnv: () => LensExtensionRuntimeEnv) {
logger.info('[EXTENSIONS-LOADER]: load on cluster renderer')
this.autoloadExtensions(getLensRuntimeEnv, (instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
instance.registerKubeObjectMenus(kubeObjectMenuRegistry)
loadOnMain() {
logger.info('[EXTENSIONS-LOADER]: load on main')
this.autoloadExtensions((instance: LensMainExtension) => {
instance.registerAppMenus(menuRegistry);
})
}
loadOnMainRenderer(getLensRuntimeEnv: () => LensExtensionRuntimeEnv) {
logger.info('[EXTENSIONS-LOADER]: load on main renderer')
this.autoloadExtensions(getLensRuntimeEnv, (instance: LensRendererExtension) => {
loadOnClusterManagerRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on main renderer (cluster manager)')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
instance.registerAppPreferences(appPreferenceRegistry)
instance.registerStatusBarIcon(statusBarRegistry)
})
}
loadOnMain(getLensRuntimeEnv: () => LensExtensionRuntimeEnv) {
logger.info('[EXTENSIONS-LOADER]: load on main')
this.autoloadExtensions(getLensRuntimeEnv, (instance: LensExtension) => {
// todo
loadOnClusterRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on cluster renderer (dashboard)')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
instance.registerKubeObjectMenus(kubeObjectMenuRegistry)
})
}
protected autoloadExtensions(getLensRuntimeEnv: () => LensExtensionRuntimeEnv, callback: (instance: LensExtension) => void) {
protected autoloadExtensions(callback: (instance: LensExtension) => void) {
return reaction(() => this.extensions.toJS(), (installedExtensions) => {
for(const [id, ext] of installedExtensions) {
let instance = this.instances.get(ext.manifestPath)
for (const [id, ext] of installedExtensions) {
let instance = this.instances.get(ext.name)
if (!instance) {
const extensionModule = this.requireExtension(ext)
if (!extensionModule) {
......@@ -70,9 +69,9 @@ export class ExtensionLoader {
}
const LensExtensionClass = extensionModule.default;
instance = new LensExtensionClass({ ...ext.manifest, manifestPath: ext.manifestPath, id: ext.manifestPath }, ext.manifest);
instance.enable(getLensRuntimeEnv())
instance.enable();
callback(instance)
this.instances.set(ext.id, instance)
this.instances.set(ext.name, instance)
}
}
}, {
......@@ -106,7 +105,9 @@ export class ExtensionLoader {
const extension = this.getById(id);
if (extension) {
const instance = this.instances.get(extension.id)
if (instance) { await instance.disable() }
if (instance) {
await instance.disable()
}
this.extensions.delete(id);
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment