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

register status-bar element, base class for extension's registry

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2020-10-22 14:24:37 +03:00
parent 59ca12ff31
commit 6572fad1c8
11 changed files with 85 additions and 77 deletions

View File

@ -1,6 +1,7 @@
import { LensRendererExtension, Registry } from "@k8slens/extensions"; import React from "react";
import { Support } from "./src/support"; import { Component, LensRendererExtension, Navigation, Registry } from "@k8slens/extensions";
import { supportPageRoute, supportPageURL } from "./src/support.route"; import { supportPageRoute, supportPageURL } from "./src/support.route";
import { Support } from "./src/support";
export default class SupportPageRendererExtension extends LensRendererExtension { export default class SupportPageRendererExtension extends LensRendererExtension {
async onActivate() { async onActivate() {
@ -19,4 +20,18 @@ export default class SupportPageRendererExtension extends LensRendererExtension
}) })
) )
} }
registerStatusBarIcon(registry: Registry.StatusBarRegistry) {
this.disposers.push(
registry.add({
icon: (
<Component.Icon
material="support"
tooltip="Support"
onClick={() => Navigation.navigate(supportPageURL())}
/>
)
})
)
}
} }

View File

@ -34,33 +34,33 @@ export class ExtensionLoader {
} }
} }
loadOnClusterRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on cluster renderer')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
})
}
loadOnMainRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on main renderer')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
instance.registerAppPreferences(appPreferenceRegistry)
})
}
loadOnMain() { loadOnMain() {
logger.info('[EXTENSIONS-LOADER]: load on main') logger.info('[EXTENSIONS-LOADER]: load on main')
this.autoloadExtensions((instance: LensMainExtension) => { this.autoloadExtensions((instance: LensMainExtension) => {
instance.registerAppMenus(menuRegistry); instance.registerAppMenus(menuRegistry);
instance.registerStatusBarIcon(statusBarRegistry); })
}
loadOnClusterManagerRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on main renderer (cluster manager)')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
instance.registerAppPreferences(appPreferenceRegistry)
instance.registerStatusBarIcon(statusBarRegistry)
})
}
loadOnClusterRenderer() {
logger.info('[EXTENSIONS-LOADER]: load on cluster renderer (dashboard)')
this.autoloadExtensions((instance: LensRendererExtension) => {
instance.registerPages(pageRegistry)
}) })
} }
protected autoloadExtensions(callback: (instance: LensExtension) => void) { protected autoloadExtensions(callback: (instance: LensExtension) => void) {
return reaction(() => this.extensions.toJS(), (installedExtensions) => { return reaction(() => this.extensions.toJS(), (installedExtensions) => {
for (const [id, ext] of installedExtensions) { for (const [id, ext] of installedExtensions) {
let instance = this.instances.get(ext.manifestPath) let instance = this.instances.get(ext.name)
if (!instance) { if (!instance) {
const extensionModule = this.requireExtension(ext) const extensionModule = this.requireExtension(ext)
if (!extensionModule) { if (!extensionModule) {
@ -70,7 +70,7 @@ export class ExtensionLoader {
instance = new LensExtensionClass({ ...ext.manifest, manifestPath: ext.manifestPath, id: ext.manifestPath }, ext.manifest); instance = new LensExtensionClass({ ...ext.manifest, manifestPath: ext.manifestPath, id: ext.manifestPath }, ext.manifest);
instance.enable(); instance.enable();
callback(instance) callback(instance)
this.instances.set(ext.id, instance) this.instances.set(ext.name, instance)
} }
} }
}, { }, {

View File

@ -1,6 +1,7 @@
import { LensExtension } from "./lens-extension" import { LensExtension } from "./lens-extension"
import type { PageRegistry } from "./registries/page-registry" import type { PageRegistry } from "./registries/page-registry"
import type { AppPreferenceRegistry } from "./registries/app-preference-registry"; import type { AppPreferenceRegistry } from "./registries/app-preference-registry";
import type { StatusBarRegistry } from "./registries";
export class LensRendererExtension extends LensExtension { export class LensRendererExtension extends LensExtension {
registerPages(registry: PageRegistry) { registerPages(registry: PageRegistry) {
@ -10,4 +11,8 @@ export class LensRendererExtension extends LensExtension {
registerAppPreferences(registry: AppPreferenceRegistry) { registerAppPreferences(registry: AppPreferenceRegistry) {
return return
} }
registerStatusBarIcon(registry: StatusBarRegistry) {
return
}
} }

View File

@ -1,5 +1,5 @@
import { observable } from "mobx" import type React from "react"
import React from "react" import { BaseRegistry } from "./base-registry";
export interface AppPreferenceComponents { export interface AppPreferenceComponents {
Hint: React.ComponentType<any>; Hint: React.ComponentType<any>;
@ -11,17 +11,7 @@ export interface AppPreferenceRegistration {
components: AppPreferenceComponents; components: AppPreferenceComponents;
} }
export class AppPreferenceRegistry { export class AppPreferenceRegistry extends BaseRegistry<AppPreferenceRegistration> {
preferences = observable.array<AppPreferenceRegistration>([], { deep: false });
add(preference: AppPreferenceRegistration) {
this.preferences.push(preference)
return () => {
this.preferences.replace(
this.preferences.filter(c => c !== preference)
)
};
}
} }
export const appPreferenceRegistry = new AppPreferenceRegistry() export const appPreferenceRegistry = new AppPreferenceRegistry()

View File

@ -0,0 +1,17 @@
// Base class for extensions-api registries
import { observable } from "mobx";
export class BaseRegistry<T = any> {
protected items = observable<T>([], { deep: false });
getItems(): T[] {
return this.items.toJS();
}
add(item: T) {
this.items.push(item);
return () => {
this.items.remove(item); // works because of {deep: false};
}
}
}

View File

@ -1,24 +1,14 @@
// Extensions API -> Global menu customize // Extensions API -> Global menu customizations
import { observable } from "mobx";
import { MenuItemConstructorOptions } from "electron";
import type { MenuTopId } from "../../main/menu"; import type { MenuTopId } from "../../main/menu";
import type { MenuItemConstructorOptions } from "electron";
import { BaseRegistry } from "./base-registry";
export interface MenuRegistration extends MenuItemConstructorOptions { export interface MenuRegistration extends MenuItemConstructorOptions {
parentId?: MenuTopId; parentId?: MenuTopId;
} }
export class MenuRegistry { export class MenuRegistry extends BaseRegistry<MenuRegistration> {
protected items = observable.array([], { deep: false });
getItems(): MenuRegistration[] {
return this.items.toJS();
}
add(item: MenuRegistration) {
this.items.push(item);
return () => this.items.remove(item)
}
} }
export const menuRegistry = new MenuRegistry(); export const menuRegistry = new MenuRegistry();

View File

@ -5,7 +5,8 @@ import type { RouteProps } from "react-router";
import type { IconProps } from "../../renderer/components/icon"; import type { IconProps } from "../../renderer/components/icon";
import type { IClassName } from "../../renderer/utils"; import type { IClassName } from "../../renderer/utils";
import type { TabRoute } from "../../renderer/components/layout/tab-layout"; import type { TabRoute } from "../../renderer/components/layout/tab-layout";
import { computed, observable } from "mobx"; import { BaseRegistry } from "./base-registry";
import { computed } from "mobx";
export enum PageRegistryType { export enum PageRegistryType {
GLOBAL = "lens-scope", GLOBAL = "lens-scope",
@ -26,21 +27,13 @@ export interface PageComponents {
MenuIcon?: React.ComponentType<IconProps>; MenuIcon?: React.ComponentType<IconProps>;
} }
export class PageRegistry { export class PageRegistry extends BaseRegistry<PageRegistration> {
protected pages = observable.array<PageRegistration>([], { deep: false });
@computed get globalPages() { @computed get globalPages() {
return this.pages.filter(page => page.type === PageRegistryType.GLOBAL); return this.items.filter(page => page.type === PageRegistryType.GLOBAL);
} }
@computed get clusterPages() { @computed get clusterPages() {
return this.pages.filter(page => page.type === PageRegistryType.CLUSTER); return this.items.filter(page => page.type === PageRegistryType.CLUSTER);
}
// fixme: validate route paths to avoid collisions
add(pageInit: PageRegistration) {
this.pages.push(pageInit);
return () => this.pages.remove(pageInit); // works because of {deep: false};
} }
} }

View File

@ -1,15 +1,13 @@
// Extensions API -> Status bar customizations // Extensions API -> Status bar customizations
import { observable } from "mobx"; import React from "react";
import { BaseRegistry } from "./base-registry";
export interface StatusBarRegistration { export interface StatusBarRegistration {
icon?: React.ReactNode;
} }
export class StatusBarRegistry { export class StatusBarRegistry extends BaseRegistry<StatusBarRegistration> {
items = observable<StatusBarRegistration>([], { deep: false });
add(item: StatusBarRegistration) {
}
} }
export const statusBarRegistry = new StatusBarRegistry(); export const statusBarRegistry = new StatusBarRegistry();

View File

@ -103,7 +103,6 @@ export class Preferences extends React.Component {
render() { render() {
const { preferences } = userStore; const { preferences } = userStore;
const extensionPreferences = appPreferenceRegistry.preferences;
const header = <h2><Trans>Preferences</Trans></h2>; const header = <h2><Trans>Preferences</Trans></h2>;
return ( return (
<PageLayout showOnTop className="Preferences" header={header}> <PageLayout showOnTop className="Preferences" header={header}>
@ -170,7 +169,7 @@ export class Preferences extends React.Component {
</small> </small>
<div className="extensions flex column gaps"> <div className="extensions flex column gaps">
{extensionPreferences.map(({ title, components: { Hint, Input } }, index) => { {appPreferenceRegistry.getItems().map(({ title, components: { Hint, Input } }, index) => {
return ( return (
<div key={index} className="preference"> <div key={index} className="preference">
<h2>{title}</h2> <h2>{title}</h2>

View File

@ -5,7 +5,7 @@ import { observer } from "mobx-react";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { WorkspaceMenu } from "../+workspaces/workspace-menu"; import { WorkspaceMenu } from "../+workspaces/workspace-menu";
import { workspaceStore } from "../../../common/workspace-store"; import { workspaceStore } from "../../../common/workspace-store";
import { navigate } from "../../navigation"; import { statusBarRegistry } from "../../../extensions/registries";
@observer @observer
export class BottomBar extends React.Component { export class BottomBar extends React.Component {
@ -13,18 +13,19 @@ export class BottomBar extends React.Component {
const { currentWorkspace } = workspaceStore; const { currentWorkspace } = workspaceStore;
return ( return (
<div className="BottomBar flex gaps"> <div className="BottomBar flex gaps">
<div id="current-workspace" className="flex gaps align-center box"> <div id="current-workspace" className="flex gaps align-center">
<Icon small material="layers"/> <Icon small material="layers"/>
<span className="workspace-name">{currentWorkspace.name}</span> <span className="workspace-name">{currentWorkspace.name}</span>
</div> </div>
<WorkspaceMenu htmlFor="current-workspace"/> <WorkspaceMenu
<Icon htmlFor="current-workspace"
small
material="support"
tooltip="Support"
className="support-icon box right"
onClick={() => navigate("/support")}
/> />
<div className="extensions box grow flex gaps justify-flex-end">
{statusBarRegistry.getItems().map(({ icon }, index) => {
if (!icon) return;
return <React.Fragment key={index}>{icon}</React.Fragment>
})}
</div>
</div> </div>
) )
} }

View File

@ -16,7 +16,7 @@ import { extensionLoader } from "../extensions/extension-loader";
@observer @observer
export class LensApp extends React.Component { export class LensApp extends React.Component {
static async init() { static async init() {
extensionLoader.loadOnMainRenderer(); extensionLoader.loadOnClusterManagerRenderer();
} }
render() { render() {