284 lines
8.4 KiB
TypeScript
284 lines
8.4 KiB
TypeScript
import { boot } from 'quasar/wrappers';
|
|
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.permissions !== undefined) {
|
|
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) => {
|
|
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(
|
|
loadedPlugins: FG_Plugin.Flaschengeist,
|
|
modules: string[],
|
|
backendpromise: Promise<Backend | null>,
|
|
plugins: FG_Plugin.Plugin[],
|
|
router: Router
|
|
): 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);
|
|
}
|
|
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);
|
|
}
|
|
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.warn(e);
|
|
return null;
|
|
} finally {
|
|
return backend;
|
|
}
|
|
}
|
|
|
|
export default boot(({ router, app }) => {
|
|
const plugins: FG_Plugin.Plugin[] = [];
|
|
|
|
const backendPromise = getBackend();
|
|
|
|
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) => {
|
|
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,
|
|
router
|
|
);
|
|
loadedPlugins = loadPlugin(loadedPlugins, config.loadModules, backendPromise, plugins, router);
|
|
|
|
loadedPlugins.widgets.sort((a, b) => b.priority - a.priority);
|
|
|
|
loadedPlugins.routes.forEach((route) => router.addRoute(route));
|
|
|
|
// save plugins in VM-variable
|
|
app.provide('flaschengeist', loadedPlugins);
|
|
});
|