diff --git a/src/boot/plugins.ts b/src/boot/plugins.ts index a049a17..c9960ae 100644 --- a/src/boot/plugins.ts +++ b/src/boot/plugins.ts @@ -3,7 +3,7 @@ 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'; +import { RouteRecordRaw } from 'vue-router'; const config: { [key: string]: Array } = { // Do not change required Modules !! @@ -12,9 +12,33 @@ const config: { [key: string]: Array } = { loadModules: ['Balance', 'Schedule', 'Pricelist'], }; +/* Stop! + // do not change anything here !! -// combine routes from source to target +// You can not even read? I said stop! + +// Really are you stupid? Stop scrolling down here! + +// Every line you scroll down, an unicorn will die painfully! + +// Ok you must hate unicorns... But what if I say you I joked... Baby otters will die! + + .-"""-. + / o\ + | o 0).-. + | .-;(_/ .-. + \ / /)).---._| `\ , + '. ' /(( `'-./ _/| + \ .' ) .-.;` / + '. | `\-' + '._ -' / + ``""--`------` +*/ + +/**************************************************** + ******** Internal area for some magic ************** + ****************************************************/ interface BackendPlugin { permissions: string[]; @@ -22,44 +46,60 @@ interface BackendPlugin { } interface BackendPlugins { - [key: string]: BackendPlugin | null; + [key: string]: BackendPlugin; } interface Backend { - plugins: BackendPlugins[]; + plugins: BackendPlugins; version: string; } - export { Backend }; -function setPermissions(object: FG_Plugin.PluginRouteConfig) { +// Combine routes, shortcuts and widgets from plugins + +/** + * Helper function, set permissions from MenuRoute to meta from RouteRecordRaw + * @param object MenuRoute to set route meta + */ +function setPermissions(object: FG_Plugin.MenuRoute) { 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); - }); +/** + * Helper function to convert MenuRoute to the parents RouteRecordRaw + * @param parent Parent RouteRecordRaw + * @param children MenuRoute to convert + */ +function convertRoutes(parent: RouteRecordRaw, children?: FG_Plugin.MenuRoute[]) { + if (children !== undefined) { + children.forEach((child) => { + setPermissions(child); + convertRoutes(child.route, child.children); + if (parent.children === undefined) parent.children = []; + parent.children.push(child.route); + }); + } } -function combineRoutes( +/** + * Combines routes from plugin MenuRoute to Vue-Router RouteRecordRaw to get a clean route-tree + * @param target + * @param source + * @param mainPath + */ +function combineMenuRoutes( target: RouteRecordRaw[], - source: FG_Plugin.PluginRouteConfig[], - mainPath: '/' | '/main' = '/' + source: FG_Plugin.MenuRoute[], + mainPath: '/' | '/in' = '/' ): RouteRecordRaw[] { // Search parent target.forEach((target) => { if (target.path === mainPath) { // Parent found = target - source.forEach((sourceMainConfig: FG_Plugin.PluginRouteConfig) => { + source.forEach((sourceMainConfig: FG_Plugin.MenuRoute) => { // Check if source is already in target const targetMainConfig = target.children?.find((targetMainConfig: RouteRecordRaw) => { return sourceMainConfig.route.path === targetMainConfig.path; @@ -89,193 +129,229 @@ function combineRoutes( 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({ - title: sourcePluginChildLink.title, - icon: sourcePluginChildLink.icon, - link: sourcePluginChildLink.route.name, - name: sourcePluginChildLink.route.name, - permissions: sourcePluginChildLink.permissions, +function combineRoutes( + target: RouteRecordRaw[], + source: FG_Plugin.NamedRouteRecordRaw[], + mainPath: '/' | '/in' +) { + // Search parent + target.forEach((target) => { + if (target.path === mainPath) { + // Parent found = target + source.forEach((sourceRoute) => { + // Check if source is already in target + const targetRoot = target.children?.find( + (targetRoot) => sourceRoute.path === targetRoot.path + ); + // Already in target routes, add only children + if (targetRoot) { + if (targetRoot.children === undefined) targetRoot.children = []; + targetRoot.children.push(...(sourceRoute.children || [])); + } else { + // Append to target + if (target.children === undefined) target.children = []; + if ( + sourceRoute.children && + sourceRoute.children.length > 0 && + sourceRoute.component === undefined + ) + Object.assign(sourceRoute, { + component: () => import('src/components/navigation/EmptyParent.vue'), + }); + target.children.push(sourceRoute); + } }); - }); - } else { - const mainLink: FG_Plugin.PluginMainLink = { + } + }); +} + +/** + * Combine MenuRoutes into Flaschengeist MenuLinks for the main menu + * @param target Flaschengeist list of menu links + * @param source MenuRoutes to combine + */ +function combineMenuLinks(target: FG_Plugin.MenuLink[], source: FG_Plugin.MenuRoute) { + let idx = target.findIndex((link) => link.title == source.title); + // Link not found, add new one + if (idx === -1) { + idx += target.push({ 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({ - title: child.title, - icon: child.icon, - link: child.route.name, - name: child.route.name, - permissions: child.permissions, - }); }); - target.push(mainLink); } - return target; + if (target[idx].children === undefined) { + target[idx].children = []; + } + source.children?.forEach((sourceChild) => { + target[idx].children?.push({ + title: sourceChild.title, + icon: sourceChild.icon, + link: sourceChild.route.name, + permissions: sourceChild.permissions, + }); + }); } -function loadShortCuts( - target: FG_Plugin.ShortCutLink[], - source: FG_Plugin.PluginRouteConfig[] -): FG_Plugin.ShortCutLink[] { +/** + * Combine shortcuts from Plugin MenuRouts into the Flaschenbeist Shortcut list + * @param target Flaschengeist list of shortcuts + * @param source MenuRoutes to extract shortcuts from + */ +function combineShortcuts(target: FG_Plugin.Shortcut[], source: FG_Plugin.MenuRoute[]) { source.forEach((route) => { if (route.shortcut) { - target.push({ + target.push({ link: route.route.name, icon: route.icon, permissions: route.permissions, }); } if (route.children) { - target = loadShortCuts(target, route.children); + combineShortcuts(target, route.children); } }); - return target; } -// loade plugins +/** + * Load a Flaschengeist plugin + * @param loadedPlugins Flaschgeist object + * @param pluginName Plugin to load + * @param context RequireContext of plugins + * @param router VueRouter instance + */ function loadPlugin( loadedPlugins: FG_Plugin.Flaschengeist, - modules: string[], - backendpromise: Promise, - 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; -} + pluginName: string, + context: __WebpackModuleApi.RequireContext, + backend: Backend +) { + // Check if already loaded + if (loadedPlugins.plugins.findIndex((p) => p.name === pluginName) !== -1) return true; -async function getBackend(): Promise { - let backend: Backend | null = null; - try { - const response: AxiosResponse = await api.get('/'); - backend = response.data; - } catch (e) { - console.warn(e); - return null; - } finally { - return backend; + // Search if plugin is installed + const available = context.keys(); + const plugin = available.includes(`./${pluginName.toLowerCase()}/plugin.ts`) + ? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + context(`./${pluginName.toLowerCase()}/plugin.ts`).default + : undefined; + + if (!plugin) { + // Plugin is not found, results in an error + console.exception(`Could not find required Plugin ${pluginName}`); + return false; + } else { + // Plugin found. Check backend dependencies + if ( + !plugin.requiredBackendModules.every((required) => backend.plugins[required] !== undefined) + ) { + console.error(`Plugin ${pluginName}: Backend modules not satisfied`); + return false; + } + + // Check frontend dependencies + if ( + !plugin.requiredModules.every((required) => + loadPlugin(loadedPlugins, required, context, backend) + ) + ) { + console.error(`Plugin ${pluginName}: Backend modules not satisfied`); + return false; + } + + // Start combining and loading routes, shortcuts etc + if (plugin.internalRoutes) { + combineRoutes(loadedPlugins.routes, plugin.internalRoutes, '/in'); + } + + if (plugin.innerRoutes) { + // Routes for Vue Router + combineMenuRoutes(loadedPlugins.routes, plugin.innerRoutes, '/in'); + // Combine links for menu + plugin.innerRoutes.forEach((route) => combineMenuLinks(loadedPlugins.menuLinks, route)); + // Combine shortcuts + combineShortcuts(loadedPlugins.shortcuts, plugin.innerRoutes); + } + + if (plugin.outerRoutes) { + combineMenuRoutes(loadedPlugins.routes, plugin.outerRoutes); + combineShortcuts(loadedPlugins.outerShortcuts, plugin.outerRoutes); + } + + 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, + }); + + return plugin; } } -export default boot(({ router, app }) => { - const plugins: FG_Plugin.Plugin[] = []; +/** + * Loading backend information + * @returns Backend object or null + */ +async function getBackend() { + try { + const { data }: AxiosResponse = await api.get('/'); + return data; + } catch (e) { + console.warn(e); + return null; + } +} - const backendPromise = getBackend(); +/** + * Boot file, load all required plugins, check for dependencies + */ +export default boot(async ({ router, app }) => { + const backend = await getBackend(); + if (!backend) { + void router.push({ name: 'error' }); + return; + } - let loadedPlugins: FG_Plugin.Flaschengeist = { + const loadedPlugins: FG_Plugin.Flaschengeist = { routes, plugins: [], - mainLinks: [], + menuLinks: [], shortcuts: [], - shortcutsOut: [], + outerShortcuts: [], 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); + + // Start loading plugins + // Load required modules: + config.requiredModules.forEach((required) => { + const plugin = loadPlugin(loadedPlugins, required, pluginsContext, backend); + if (!plugin) { + void router.push({ name: 'error' }); + return; + } }); - // 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); + // Load user defined plugins + config.loadModules.forEach((required) => { + const plugin = loadPlugin(loadedPlugins, required, pluginsContext, backend); + if (!plugin) { + void router.push({ name: 'error' }); + return; + } + }); + // Sort widgets by priority loadedPlugins.widgets.sort((a, b) => b.priority - a.priority); + // Add loaded routes to router loadedPlugins.routes.forEach((route) => router.addRoute(route)); // save plugins in VM-variable diff --git a/src/components/navigation/EssentialLink.vue b/src/components/navigation/EssentialLink.vue index 0a2e95d..c70ac08 100644 --- a/src/components/navigation/EssentialLink.vue +++ b/src/components/navigation/EssentialLink.vue @@ -1,50 +1,35 @@ diff --git a/src/components/navigation/ShortCutLink.vue b/src/components/navigation/ShortCutLink.vue deleted file mode 100644 index ef80be6..0000000 --- a/src/components/navigation/ShortCutLink.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/src/components/navigation/ShortcutLink.vue b/src/components/navigation/ShortcutLink.vue new file mode 100644 index 0000000..1a00c44 --- /dev/null +++ b/src/components/navigation/ShortcutLink.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/components/utils/IsoDateInput.vue b/src/components/utils/IsoDateInput.vue index 2da0e0a..2fff921 100644 --- a/src/components/utils/IsoDateInput.vue +++ b/src/components/utils/IsoDateInput.vue @@ -39,7 +39,7 @@ diff --git a/src/plugins.d.ts b/src/plugins.d.ts index a30f64a..e30a1d3 100644 --- a/src/plugins.d.ts +++ b/src/plugins.d.ts @@ -1,66 +1,100 @@ -import { RouteRecordRaw } from 'vue-router'; +import { RouteRecordRaw, RouteRecordName } from 'vue-router'; import { Component, ComputedRef } from 'vue'; -declare global { - type Validator = (value: unknown) => boolean | string; -} - declare namespace FG_Plugin { - interface ShortCutLink { - link: string; + /** + * Interface defining a Flaschengeist plugin + */ + interface Plugin { + name: string; + version: string; + widgets: Widget[]; + /** Pther frontend modules needed for this plugin to work correctly */ + requiredModules: string[]; + /** Backend modules needed for this plugin to work correctly */ + requiredBackendModules: string[]; + /** Menu entries for authenticated users */ + innerRoutes?: MenuRoute[]; + /** Public menu entries (without authentification) */ + outerRoutes?: MenuRoute[]; + /** Routes without menu links, for internal usage */ + internalRoutes?: NamedRouteRecordRaw[]; + } + + /** + * Defines the loaded state of the Flaschengeist + */ + interface Flaschengeist { + /** All loaded plugins */ + plugins: LoadedPlugin[]; + /** All routes, combined from all plugins */ + routes: RouteRecordRaw[]; + /** All menu entries */ + menuLinks: MenuLink[]; + /** All inner shortcuts */ + shortcuts: Shortcut[]; + /** All outer shortcuts */ + outerShortcuts: Shortcut[]; + /** All widgets */ + widgets: Widget[]; + } + + /** + * Loaded Flaschengeist plugin + */ + interface LoadedPlugin { + name: string; + version: string; + } + + /** + * Defines a shortcut link + */ + interface Shortcut { + link: RouteRecordName; icon: string; permissions?: string[]; } - interface PluginRouteConfig { + /** + * Defines a main menu entry along with the route + * Used when defining a plugin + */ + interface MenuRoute extends MenuEntry { + route: NamedRouteRecordRaw; + shortcut?: boolean; + children?: this[]; + } + + type NamedRouteRecordRaw = RouteRecordRaw & { + name: RouteRecordName; + }; + + /** + * Defines a menu entry in the main menu + */ + interface MenuLink extends MenuEntry { + /** Name of the target route */ + link: RouteRecordName; + } + + /** + * Base interface for internal use + */ + interface MenuEntry { title: string | ComputedRef; icon: string; - route: RouteRecordRaw; - shortcut?: boolean; - children?: PluginRouteConfig[]; permissions?: string[]; + children?: this[]; } + /** + * Widget object for the dashboard + */ interface Widget { name: string; priority: number; permissions: FG.Permission[]; widget: Component; } - - interface Plugin { - name: string; - version: string; - widgets: Widget[]; - requiredModules: string[]; - requiredBackendModules: string[]; - mainRoutes?: PluginRouteConfig[]; - outRoutes?: PluginRouteConfig[]; - } - - interface PluginMainLink extends PluginChildLink { - children: PluginChildLink[]; - } - - interface PluginChildLink { - name: string; - title: string; - link: string; - icon: string; - permissions?: string[]; - } - - interface LoadedPlugin { - name: string; - version: string; - } - - interface Flaschengeist { - plugins: LoadedPlugin[]; - routes: RouteRecordRaw[]; - mainLinks: PluginMainLink[]; - shortcuts: ShortCutLink[]; - shortcutsOut: ShortCutLink[]; - widgets: Widget[]; - } } diff --git a/src/plugins/balance/plugin.ts b/src/plugins/balance/plugin.ts index 414cfc6..e6604a4 100644 --- a/src/plugins/balance/plugin.ts +++ b/src/plugins/balance/plugin.ts @@ -4,7 +4,7 @@ import { defineAsyncComponent } from 'vue'; const plugin: FG_Plugin.Plugin = { name: 'Balance', - mainRoutes: routes, + innerRoutes: routes, requiredModules: ['User'], requiredBackendModules: ['balance'], version: '0.0.2', diff --git a/src/plugins/balance/routes/index.ts b/src/plugins/balance/routes/index.ts index ae70140..5988b46 100644 --- a/src/plugins/balance/routes/index.ts +++ b/src/plugins/balance/routes/index.ts @@ -1,7 +1,7 @@ import { FG_Plugin } from 'src/plugins'; import permissions from '../permissions'; -const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ +const mainRoutes: FG_Plugin.MenuRoute[] = [ { title: 'Gerücht', icon: 'mdi-cash-100', diff --git a/src/plugins/pricelist/plugin.ts b/src/plugins/pricelist/plugin.ts index 1e742b7..c6f9d67 100644 --- a/src/plugins/pricelist/plugin.ts +++ b/src/plugins/pricelist/plugin.ts @@ -1,21 +1,13 @@ -import routes from './routes'; +import { innerRoutes } from './routes'; import { FG_Plugin } from 'src/plugins'; const plugin: FG_Plugin.Plugin = { name: 'Pricelist', - mainRoutes: routes, + innerRoutes, requiredModules: [], requiredBackendModules: ['pricelist'], version: '0.0.1', widgets: [], - // widgets: [ - // { - // priority: 1, - // name: 'greeting', - // permissions: [] - // widget: () => import('./components/Widget.vue') - // } - // ] }; export default plugin; diff --git a/src/plugins/pricelist/routes/index.ts b/src/plugins/pricelist/routes/index.ts index ebe7f4a..1ba6d56 100644 --- a/src/plugins/pricelist/routes/index.ts +++ b/src/plugins/pricelist/routes/index.ts @@ -1,12 +1,13 @@ import { FG_Plugin } from 'src/plugins'; -const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ + +export const innerRoutes: FG_Plugin.MenuRoute[] = [ { title: 'Getränke', icon: 'mdi-glass-mug-variant', route: { path: 'drinks', name: 'drinks', - redirect: { name: 'drinks-pricelist' } + redirect: { name: 'drinks-pricelist' }, }, permissions: ['user'], children: [ @@ -18,8 +19,8 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ route: { path: 'pricelist', name: 'drinks-pricelist', - component: () => import('../pages/PricelistP.vue') - } + component: () => import('../pages/PricelistP.vue'), + }, }, { title: 'Einstellungen', @@ -29,11 +30,9 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ route: { path: 'settings', name: 'drinks-settings', - component: () => import('../pages/Settings.vue') - } - } - ] - } + component: () => import('../pages/Settings.vue'), + }, + }, + ], + }, ]; - -export default mainRoutes; diff --git a/src/plugins/schedule/plugin.ts b/src/plugins/schedule/plugin.ts index 467a0be..0082363 100644 --- a/src/plugins/schedule/plugin.ts +++ b/src/plugins/schedule/plugin.ts @@ -1,10 +1,11 @@ import { defineAsyncComponent } from 'vue'; -import mainRoutes from './routes'; +import { innerRoutes, privateRoutes } from './routes'; import { FG_Plugin } from 'src/plugins'; const plugin: FG_Plugin.Plugin = { name: 'Schedule', - mainRoutes, + innerRoutes, + internalRoutes: privateRoutes, requiredModules: ['User'], requiredBackendModules: ['events'], version: '0.0.1', diff --git a/src/plugins/schedule/routes/index.ts b/src/plugins/schedule/routes/index.ts index 7c816a6..80f968a 100644 --- a/src/plugins/schedule/routes/index.ts +++ b/src/plugins/schedule/routes/index.ts @@ -1,7 +1,7 @@ import { FG_Plugin } from 'src/plugins'; import { PERMISSIONS } from '../permissions'; -const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ +export const innerRoutes: FG_Plugin.MenuRoute[] = [ { title: 'Dienste', icon: 'mdi-briefcase', @@ -47,4 +47,10 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ }, ]; -export default mainRoutes; +export const privateRoutes: FG_Plugin.NamedRouteRecordRaw[] = [ + { + name: 'events-edit', + path: 'schedule/edit/:id', + redirect: { name: 'schedule-overview' }, + }, +]; diff --git a/src/plugins/user/pages/MainPage.vue b/src/plugins/user/pages/MainPage.vue deleted file mode 100644 index edfce23..0000000 --- a/src/plugins/user/pages/MainPage.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/src/plugins/user/plugin.ts b/src/plugins/user/plugin.ts index d978b59..e447d87 100644 --- a/src/plugins/user/plugin.ts +++ b/src/plugins/user/plugin.ts @@ -4,7 +4,7 @@ import { defineAsyncComponent } from 'vue'; const plugin: FG_Plugin.Plugin = { name: 'User', - mainRoutes: routes, + innerRoutes: routes, requiredModules: [], requiredBackendModules: ['auth'], version: '0.0.1', diff --git a/src/plugins/user/routes/index.ts b/src/plugins/user/routes/index.ts index 795e265..45d29de 100644 --- a/src/plugins/user/routes/index.ts +++ b/src/plugins/user/routes/index.ts @@ -2,14 +2,14 @@ import { FG_Plugin } from 'src/plugins'; import { useMainStore } from 'src/store'; import { computed } from 'vue'; -const mainRoutes: FG_Plugin.PluginRouteConfig[] = [ +const mainRoutes: FG_Plugin.MenuRoute[] = [ { get title() { - return computed(() => useMainStore().user?.display_name || 'Not loaded'); + return computed(() => useMainStore().currentUser.display_name); }, icon: 'mdi-account', permissions: ['user'], - route: { path: 'user', name: 'user', component: () => import('../pages/MainPage.vue') }, + route: { path: 'user', name: 'user', redirect: { name: 'user-settings' } }, children: [ { title: 'Einstellungen', diff --git a/src/router/routes.ts b/src/router/routes.ts index b39533a..b7a0cd6 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -24,7 +24,7 @@ const routes: RouteRecordRaw[] = [ ], }, { - path: '/main', + path: '/in', redirect: 'dashboard', component: () => import('layouts/MainLayout.vue'), meta: { permissions: ['user'] }, diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts index a0bd87b..eab6529 100644 --- a/src/shims-vue.d.ts +++ b/src/shims-vue.d.ts @@ -4,11 +4,3 @@ declare module '*.vue' { const component: ComponentOptions; export default component; } - -/* -// Mocks all files ending in `.vue` showing them as plain Vue instances -declare module '*.vue' { - import Vue from 'vue'; - export default Vue; -} -*/ diff --git a/src/utils/validators.ts b/src/utils/validators.ts index c7d6431..16eb2a5 100644 --- a/src/utils/validators.ts +++ b/src/utils/validators.ts @@ -1,3 +1,5 @@ +export type Validator = (value: unknown) => boolean | string; + export function notEmpty(val: unknown) { return !!val || 'Feld darf nicht leer sein!'; }