mirror of https://github.com/rancher/dashboard.git
202 lines
5.3 KiB
TypeScript
202 lines
5.3 KiB
TypeScript
import { RouteConfig } from 'vue-router';
|
|
import { DSL as STORE_DSL } from '@shell/store/type-map';
|
|
import { IPlugin } from './types';
|
|
import coreStore, { coreStoreModule, coreStoreState } from '@shell/plugins/dashboard-store';
|
|
import {
|
|
PluginRouteConfig, RegisterStore, UnregisterStore, CoreStoreSpecifics, CoreStoreConfig, OnNavToPackage, OnNavAwayFromPackage, OnLogOut
|
|
} from '@shell/core/types';
|
|
|
|
export class Plugin implements IPlugin {
|
|
public id: string;
|
|
public name: string;
|
|
public types: any = {};
|
|
public l10n: { [key: string]: Function[] } = {};
|
|
public locales: { locale: string, label: string}[] = [];
|
|
public products: Function[] = [];
|
|
public productNames: string[] = [];
|
|
public routes: { parent?: string, route: RouteConfig }[] = [];
|
|
public stores: { storeName: string, register: RegisterStore, unregister: UnregisterStore }[] = [];
|
|
public onEnter: OnNavToPackage = () => Promise.resolve();
|
|
public onLeave: OnNavAwayFromPackage = () => Promise.resolve();
|
|
public _onLogOut: OnLogOut = () => Promise.resolve();
|
|
|
|
// Plugin metadata (plugin package.json)
|
|
public _metadata: any = {};
|
|
|
|
public _validators: {[key:string]: Function } = {}
|
|
|
|
// Is this a built-in plugin (bundled with the application)
|
|
public builtin = false;
|
|
|
|
// Uninstall hooks
|
|
public uninstallHooks: Function[] = [];
|
|
|
|
constructor(id: string) {
|
|
this.id = id;
|
|
this.name = id;
|
|
}
|
|
|
|
get metadata() {
|
|
return this._metadata;
|
|
}
|
|
|
|
set metadata(value) {
|
|
this._metadata = value;
|
|
this.name = this._metadata.name || this.id;
|
|
}
|
|
|
|
get validators() {
|
|
return this._validators;
|
|
}
|
|
|
|
set validators(vals: {[key:string]: Function }) {
|
|
this._validators = vals;
|
|
}
|
|
|
|
// Track which products the plugin creates
|
|
DSL(store: any, productName: string) {
|
|
const storeDSL = STORE_DSL(store, productName);
|
|
|
|
this.productNames.push(productName);
|
|
|
|
return storeDSL;
|
|
}
|
|
|
|
addProduct(product: Function): void {
|
|
this.products.push(product);
|
|
}
|
|
|
|
addLocale(locale: string, label: string): void {
|
|
this.locales.push({ locale, label });
|
|
}
|
|
|
|
addL10n(locale: string, fn: Function) {
|
|
this.register('l10n', locale, fn);
|
|
}
|
|
|
|
addRoutes(routes: PluginRouteConfig[] | RouteConfig[]) {
|
|
routes.forEach((r: PluginRouteConfig | RouteConfig) => {
|
|
if (Object.keys(r).includes('parent')) {
|
|
const pConfig = r as PluginRouteConfig;
|
|
|
|
if (pConfig.parent) {
|
|
this.addRoute(pConfig.parent, pConfig.route);
|
|
} else {
|
|
this.addRoute(pConfig.route);
|
|
}
|
|
} else {
|
|
this.addRoute(r as RouteConfig);
|
|
}
|
|
});
|
|
}
|
|
|
|
addRoute(parentOrRoute: RouteConfig | string, optionalRoute?: RouteConfig): void {
|
|
// Always add the pkg name to the route metadata
|
|
const hasParent = typeof (parentOrRoute) === 'string';
|
|
const parent: string | undefined = hasParent ? parentOrRoute as string : undefined;
|
|
const route: RouteConfig = hasParent ? optionalRoute as RouteConfig : parentOrRoute as RouteConfig;
|
|
|
|
route.meta = {
|
|
...route?.meta,
|
|
pkg: this.name,
|
|
};
|
|
|
|
this.routes.push({ parent, route });
|
|
}
|
|
|
|
addUninstallHook(hook: Function) {
|
|
this.uninstallHooks.push(hook);
|
|
}
|
|
|
|
addStore(storeName: string, register: RegisterStore, unregister: UnregisterStore) {
|
|
this.stores.push({
|
|
storeName, register, unregister
|
|
});
|
|
}
|
|
|
|
addDashboardStore(storeName: string, storeSpecifics: CoreStoreSpecifics, config: CoreStoreConfig) {
|
|
this.stores.push({
|
|
storeName,
|
|
register: () => {
|
|
return coreStore(
|
|
this.storeFactory(storeSpecifics, config),
|
|
config,
|
|
);
|
|
},
|
|
unregister: (store: any) => {
|
|
store.unregisterModule(storeName);
|
|
}
|
|
});
|
|
}
|
|
|
|
private storeFactory(storeSpecifics: CoreStoreSpecifics, config: CoreStoreConfig) {
|
|
return {
|
|
...coreStoreModule,
|
|
|
|
state() {
|
|
return {
|
|
...coreStoreState(config.namespace, config.baseUrl, config.isClusterStore),
|
|
...storeSpecifics.state()
|
|
};
|
|
},
|
|
|
|
getters: {
|
|
...coreStoreModule.getters,
|
|
...storeSpecifics.getters
|
|
},
|
|
|
|
mutations: {
|
|
...coreStoreModule.mutations,
|
|
...storeSpecifics.mutations
|
|
},
|
|
|
|
actions: {
|
|
...coreStoreModule.actions,
|
|
...storeSpecifics.actions
|
|
},
|
|
};
|
|
}
|
|
|
|
public addNavHooks(
|
|
onEnter: OnNavToPackage = () => Promise.resolve(),
|
|
onLeave: OnNavAwayFromPackage = () => Promise.resolve(),
|
|
onLogOut: OnLogOut = () => Promise.resolve(),
|
|
): void {
|
|
this.onEnter = onEnter;
|
|
this.onLeave = onLeave;
|
|
this._onLogOut = onLogOut;
|
|
}
|
|
|
|
public async onLogOut(store: any) {
|
|
await Promise.all(this.stores.map((s: any) => store.dispatch(`${ s.storeName }/onLogout`)));
|
|
|
|
await this._onLogOut(store);
|
|
}
|
|
|
|
public register(type: string, name: string, fn: Function) {
|
|
const nparts = name.split('/');
|
|
|
|
// Support components in a sub-folder - component_name/index.vue (and ignore other componnets in that folder)
|
|
if (nparts.length === 2) {
|
|
if (nparts[1] !== 'index') {
|
|
return;
|
|
}
|
|
name = nparts[0];
|
|
}
|
|
|
|
// Accumulate l10n resources rather than replace
|
|
if (type === 'l10n') {
|
|
if (!this.l10n[name]) {
|
|
this.l10n[name] = [];
|
|
}
|
|
|
|
this.l10n[name].push(fn);
|
|
} else {
|
|
if (!this.types[type]) {
|
|
this.types[type] = {};
|
|
}
|
|
this.types[type][name] = fn;
|
|
}
|
|
}
|
|
}
|