flaschengeist-frontend/src/boot/plugins.ts

302 lines
8.9 KiB
TypeScript
Raw Normal View History

import { boot } from 'quasar/wrappers';
import { Store } from 'vuex';
import { FG_Plugin } from 'src/plugins';
import routes from 'src/router/routes';
import { api } from 'boot/axios';
import { AxiosResponse } from 'axios';
import { Router, RouteRecordRaw } from 'vue-router';
const config: { [key: string]: Array<string> } = {
// Do not change required Modules !!
requiredModules: ['User'],
// here you can import plugins.
loadModules: ['Balance', 'Schedule', 'Pricelist'],
};
// do not change anything here !!
// combine routes from source to target
interface BackendPlugin {
permissions: string[];
version: string;
}
interface BackendPlugins {
[key: string]: BackendPlugin | null;
}
interface Backend {
plugins: BackendPlugins[];
version: string;
}
export { Backend };
function setPermissions(object: FG_Plugin.PluginRouteConfig) {
if (object.route.meta === undefined) object.route.meta = {};
object.route.meta['permissions'] = object.permissions;
}
function convertRoutes(parent: RouteRecordRaw, children?: FG_Plugin.PluginRouteConfig[]) {
if (children === undefined) return;
children.forEach((child) => {
setPermissions(child);
convertRoutes(child.route, child.children);
if (parent.children === undefined) parent.children = [];
parent.children.push(child.route);
});
}
function combineRoutes(
target: RouteRecordRaw[],
source: FG_Plugin.PluginRouteConfig[],
mainPath: '/' | '/main' = '/'
): RouteRecordRaw[] {
// Search parent
target.forEach((target) => {
if (target.path === mainPath) {
// Parent found = target
source.forEach((sourceMainConfig: FG_Plugin.PluginRouteConfig) => {
// Check if source is already in target
const targetMainConfig = target.children?.find((targetMainConfig: RouteRecordRaw) => {
return sourceMainConfig.route.path === targetMainConfig.path;
});
// Already in target routes, add only children
if (targetMainConfig) {
convertRoutes(targetMainConfig, sourceMainConfig.children);
} else {
// Append to target
if (target.children === undefined) {
target.children = [];
}
convertRoutes(sourceMainConfig.route, sourceMainConfig.children);
if (
sourceMainConfig.children &&
sourceMainConfig.children.length > 0 &&
!sourceMainConfig.route.component
)
Object.assign(sourceMainConfig.route, {
component: () => import('src/components/navigation/EmptyParent.vue'),
});
target.children.push(sourceMainConfig.route);
}
});
}
});
return target;
}
// combine Links of Plugins from source to target
function combineMainLinks(
target: FG_Plugin.PluginMainLink[],
source: FG_Plugin.PluginRouteConfig
): FG_Plugin.PluginMainLink[] {
const targetPluginMainLink: FG_Plugin.PluginMainLink | undefined = target.find(
(targetPluginMainLink: FG_Plugin.PluginMainLink) => {
console.log(targetPluginMainLink.title, source.title);
return targetPluginMainLink.title == source.title;
}
);
if (targetPluginMainLink) {
source.children?.forEach((sourcePluginChildLink: FG_Plugin.PluginRouteConfig) => {
targetPluginMainLink.children.push(<FG_Plugin.PluginChildLink>{
title: sourcePluginChildLink.title,
icon: sourcePluginChildLink.icon,
link: sourcePluginChildLink.route.name,
name: sourcePluginChildLink.route.name,
permissions: sourcePluginChildLink.permissions,
});
});
} else {
const mainLink: FG_Plugin.PluginMainLink = <FG_Plugin.PluginMainLink>{
title: source.title,
icon: source.icon,
link: source.route.name,
name: source.route.name,
permissions: source.permissions,
};
source.children?.forEach((child) => {
if (mainLink.children === undefined) {
mainLink.children = [];
}
mainLink.children.push(<FG_Plugin.PluginChildLink>{
title: child.title,
icon: child.icon,
link: child.route.name,
name: child.route.name,
permissions: child.permissions,
});
});
target.push(mainLink);
}
return target;
}
function loadShortCuts(
target: FG_Plugin.ShortCutLink[],
source: FG_Plugin.PluginRouteConfig[]
): FG_Plugin.ShortCutLink[] {
source.forEach((route) => {
if (route.shortcut) {
target.push(<FG_Plugin.ShortCutLink>{
link: route.route.name,
icon: route.icon,
permissions: route.permissions,
});
}
if (route.children) {
target = loadShortCuts(target, route.children);
}
});
return target;
}
// loade plugins
function loadPlugin(
2021-02-04 01:42:49 +00:00
loadedPlugins: FG_Plugin.Flaschengeist,
modules: string[],
backendpromise: Promise<Backend | null>,
plugins: FG_Plugin.Plugin[],
store: Store<unknown>,
router: Router
2021-02-04 01:42:49 +00:00
): FG_Plugin.Flaschengeist {
modules.forEach((requiredModule) => {
const plugin = plugins.find((plugin) => {
return plugin.name == requiredModule;
});
if (plugin) {
if (plugin.mainRoutes) {
loadedPlugins.routes = combineRoutes(loadedPlugins.routes, plugin.mainRoutes, '/main');
plugin.mainRoutes.forEach((route) => {
loadedPlugins.mainLinks = combineMainLinks(loadedPlugins.mainLinks, route);
});
loadedPlugins.shortcuts = loadShortCuts(loadedPlugins.shortcuts, plugin.mainRoutes);
console.log(loadedPlugins);
}
if (plugin.outRoutes) {
loadedPlugins.routes = combineRoutes(loadedPlugins.routes, plugin.outRoutes);
loadedPlugins.shortcutsOut = loadShortCuts(loadedPlugins.shortcutsOut, plugin.outRoutes);
}
if (plugin.widgets.length > 0) {
plugin.widgets.forEach((widget) => (widget.name = plugin.name + '_' + widget.name));
Array.prototype.push.apply(loadedPlugins.widgets, plugin.widgets);
}
if (plugin.store) {
2020-10-16 06:45:40 +00:00
plugin.store.forEach((store_plugin, store_namespace) => {
store.registerModule(store_namespace, store_plugin);
});
}
loadedPlugins.plugins.push({
name: plugin.name,
version: plugin.version,
});
} else {
console.exception(`Could not find required Plugin ${requiredModule}`);
router.push({ name: 'error' }).catch((e) => {
console.warn(e);
});
}
});
return loadedPlugins;
}
async function getBackend(): Promise<Backend | null> {
let backend: Backend | null = null;
try {
const response: AxiosResponse<Backend> = await api.get('/');
backend = response.data;
} catch (e) {
console.log(e);
return null;
} finally {
return backend;
}
}
// "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
export default boot(({ router, app, store }) => {
const plugins: FG_Plugin.Plugin[] = [];
const backendPromise = getBackend();
2021-02-04 01:42:49 +00:00
let loadedPlugins: FG_Plugin.Flaschengeist = {
routes,
plugins: [],
mainLinks: [],
shortcuts: [],
shortcutsOut: [],
widgets: [],
};
// get all plugins
const pluginsContext = require.context('src/plugins', true, /.+\/plugin.ts$/);
pluginsContext.keys().forEach((fileName: string) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
plugins.push(pluginsContext(fileName).default);
});
// check dependencies
backendPromise
.then((backend) => {
console.log(backend);
if (backend) {
plugins.forEach((plugin: FG_Plugin.Plugin) => {
plugin.requiredModules.forEach((requiredModule: string) => {
if (
!(
config.requiredModules.includes(requiredModule) ||
config.loadModules.includes(requiredModule)
)
) {
console.error(`Plugin ${plugin.name} need Plugin ${requiredModule}`);
router.push({ name: 'error' }).catch((e) => {
console.warn(e);
});
}
});
plugin.requiredBackendModules.forEach((requiredBackendModule: string) => {
if (!(requiredBackendModule in backend.plugins)) {
console.error(
`Plugin ${plugin.name} need Plugin ${requiredBackendModule} in backend.`
);
router.push({ name: 'error' }).catch((err) => {
console.warn(err);
});
}
});
});
}
})
.catch((e) => {
console.error(e);
});
// load plugins
loadedPlugins = loadPlugin(
loadedPlugins,
config.requiredModules,
backendPromise,
plugins,
store,
router
);
loadedPlugins = loadPlugin(
loadedPlugins,
config.loadModules,
backendPromise,
plugins,
store,
router
);
loadedPlugins.widgets.sort((a, b) => b.priority - a.priority);
loadedPlugins.routes.forEach((route) => router.addRoute(route));
// save plugins in VM-variable
2021-02-04 01:42:49 +00:00
app.provide('flaschengeist', loadedPlugins);
});