release v2.0.0 #4

Merged
crimsen merged 481 commits from develop into master 2024-01-18 15:15:08 +00:00
13 changed files with 574 additions and 128 deletions
Showing only changes of commit ef3fcc48a7 - Show all commits

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -2,22 +2,29 @@ import { boot } from 'quasar/wrappers';
import { RouteConfig } from 'vue-router'; import { RouteConfig } from 'vue-router';
import { Module } from 'vuex'; import { Module } from 'vuex';
interface PluginRouteConfig extends RouteConfig { const config = {
example?: unknown; // Do not change required Modules !!
} requiredModules: ['user'],
// here you can import plugins.
loadModules: ['plugin1', 'user-plugin']
};
interface EssentialLink { // do not change anything here !!
title: string;
interface ShortCutLink {
link: string; link: string;
icon?: string; icon: string;
} }
interface Plugin { interface Plugin {
name: string; name: string;
routes: PluginRouteConfig[] | RouteConfig[]; routes: RouteConfig[];
store?: Module<never, never>[]; store?: Module<never, never>[];
mainLink: PluginMainLink; mainLink: PluginMainLink;
requiredModules: string[]; requiredModules: string[];
shortcuts: ShortCutLink[];
shortcutsOut: ShortCutLink[];
version: string;
} }
interface PluginMainLink extends PluginChildLink { interface PluginMainLink extends PluginChildLink {
@ -31,15 +38,29 @@ interface PluginChildLink {
icon: string; icon: string;
} }
const config = { interface LoadedPlugin {
// Do not change required Modules !! name: string;
requiredModules: ['user'], version: string;
// here you can import plugins. }
loadModules: ['plugin1', 'user-plugin']
interface LoadedPlugins {
plugins: LoadedPlugin[];
routes: RouteConfig[];
mainLinks: PluginMainLink[];
shortcuts: ShortCutLink[];
shortcutsOut: ShortCutLink[];
}
export {
Plugin,
PluginChildLink,
PluginMainLink,
ShortCutLink,
LoadedPlugins,
LoadedPlugin
}; };
export { PluginRouteConfig, Plugin, PluginChildLink, PluginMainLink }; // combine routes from source to target
function combineRoutes( function combineRoutes(
target: RouteConfig[], target: RouteConfig[],
source: RouteConfig[] source: RouteConfig[]
@ -52,6 +73,7 @@ function combineRoutes(
} }
); );
if (targetRouteConfig) { if (targetRouteConfig) {
// if exists first layer in target exist iterate through 2nd layer e.g. /main/user, /main/about
sourceRouteConfig.children?.forEach( sourceRouteConfig.children?.forEach(
(sourcePluginChildRouteConfig: RouteConfig) => { (sourcePluginChildRouteConfig: RouteConfig) => {
const targetPluginRouteConfig: const targetPluginRouteConfig:
@ -62,16 +84,20 @@ function combineRoutes(
} }
); );
if (targetPluginRouteConfig) { if (targetPluginRouteConfig) {
// if 2nd layer in target exist check if target has children path.
if (targetPluginRouteConfig.children) { if (targetPluginRouteConfig.children) {
// if target has children path, add children from source.
targetPluginRouteConfig.children = Object.assign( targetPluginRouteConfig.children = Object.assign(
targetPluginRouteConfig.children, targetPluginRouteConfig.children,
sourcePluginChildRouteConfig.children sourcePluginChildRouteConfig.children
); );
} else { } else {
// if not set children of targen from children of source
targetPluginRouteConfig.children = targetPluginRouteConfig.children =
sourcePluginChildRouteConfig.children; sourcePluginChildRouteConfig.children;
} }
} else { } else {
// if target not exists in 2nd layer, add source to children of first targen
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
targetRouteConfig.children.push(sourcePluginChildRouteConfig); targetRouteConfig.children.push(sourcePluginChildRouteConfig);
@ -79,90 +105,110 @@ function combineRoutes(
} }
); );
} else { } else {
// if target not exists in first layer, add source
target.push(sourceRouteConfig); target.push(sourceRouteConfig);
} }
}); });
return target; return target;
} }
// combine Links of Plugins from source to target
function combineMainLinks( function combineMainLinks(
target: PluginMainLink[], target: PluginMainLink[],
source: PluginMainLink source: PluginMainLink
): PluginMainLink[] { ): PluginMainLink[] {
console.log('target', target);
console.log('source', source);
const targetPluginMainLink: PluginMainLink | undefined = target.find( const targetPluginMainLink: PluginMainLink | undefined = target.find(
(targetPluginMainLink: PluginMainLink) => { (targetPluginMainLink: PluginMainLink) => {
console.log(targetPluginMainLink.title, source.title); console.log(targetPluginMainLink.title, source.title);
return targetPluginMainLink.title == source.title; return targetPluginMainLink.title == source.title;
} }
); );
console.log('targetPluginMainLink', targetPluginMainLink);
if (targetPluginMainLink) { if (targetPluginMainLink) {
source.children.forEach((sourcePluginChildLink: PluginChildLink) => { source.children.forEach((sourcePluginChildLink: PluginChildLink) => {
targetPluginMainLink.children.push(sourcePluginChildLink); targetPluginMainLink.children.push(sourcePluginChildLink);
}); });
} else { } else {
console.log('push source', source);
target.push(source); target.push(source);
} }
console.log('merged', target);
return target; return target;
} }
// loade plugins
function loadPlugin(
loadedPlugins: LoadedPlugins,
modules: string[],
plugins: Plugin[],
store: any
): LoadedPlugins {
modules.forEach(requiredModule => {
const plugin = plugins.find(plugin => {
return plugin.name == requiredModule;
});
if (plugin) {
loadedPlugins.routes = combineRoutes(loadedPlugins.routes, plugin.routes);
if (plugin.store) {
plugin.store.forEach(store_module => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
store.registerModule(store_module);
});
}
loadedPlugins.mainLinks = combineMainLinks(
loadedPlugins.mainLinks,
plugin.mainLink
);
loadedPlugins.shortcuts = loadedPlugins.shortcuts.concat(
plugin.shortcuts
);
loadedPlugins.shortcutsOut = loadedPlugins.shortcutsOut.concat(
plugin.shortcutsOut
);
loadedPlugins.plugins.push({
name: plugin.name,
version: plugin.version
});
} else {
console.exception(`Don't find required Plugin ${requiredModule}`);
}
});
return loadedPlugins;
}
// "async" is optional; // "async" is optional;
// more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file // more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
export default boot(({ Vue, router, store }) => { export default boot(({ Vue, router, store }) => {
const pluginsContext = require.context('src/plugins', true, /.+\/plugin.ts$/);
let pluginMainLinks: PluginMainLink[] = [];
const plugins: Plugin[] = []; const plugins: Plugin[] = [];
let loadedPlugins: LoadedPlugins = {
routes: [],
plugins: [],
mainLinks: [],
shortcuts: [],
shortcutsOut: []
};
// get all plugins
const pluginsContext = require.context('src/plugins', true, /.+\/plugin.ts$/);
pluginsContext.keys().forEach((fileName: string) => { pluginsContext.keys().forEach((fileName: string) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
plugins.push(pluginsContext(fileName).default); plugins.push(pluginsContext(fileName).default);
}); });
let routes: RouteConfig[] = []; // load plugins
loadedPlugins = loadPlugin(
loadedPlugins,
config.requiredModules,
plugins,
store
);
loadedPlugins = loadPlugin(loadedPlugins, config.loadModules, plugins, store);
config.requiredModules.forEach(requiredModule => { console.log(loadedPlugins.routes);
const plugin = plugins.find(plugin => {
return plugin.name == requiredModule;
});
if (plugin) {
routes = combineRoutes(routes, plugin.routes);
if (plugin.store) {
plugin.store.forEach(store_module => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
store.registerModule(store_module);
});
}
pluginMainLinks = combineMainLinks(pluginMainLinks, plugin.mainLink);
} else {
console.exception(`Don't find required Plugin ${requiredModule}`);
}
});
config.loadModules.forEach(loadModule => { // add new routes for plugins
const plugin = plugins.find(plugin => { router.addRoutes(loadedPlugins.routes);
return plugin.name == loadModule;
}); // save plugins in VM-variable
if (plugin) {
routes = combineRoutes(routes, plugin.routes);
if (plugin.store) {
plugin.store.forEach(store_module => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
store.registerModule(store_module);
});
}
pluginMainLinks = combineMainLinks(pluginMainLinks, plugin.mainLink);
} else {
console.exception(`Don't find Plugin ${loadModule}`);
}
});
console.log(routes);
router.addRoutes(routes);
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
Vue.prototype.$flaschengeistPluginsMainLinks = pluginMainLinks; Vue.prototype.$flaschengeistPlugins = loadedPlugins;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access console.log(loadedPlugins);
Vue.prototype.$flaschengeistPlugins = plugins; console.log(Vue.prototype.$flaschengeistPlugins);
console.log(pluginMainLinks);
}); });

View File

@ -1,27 +0,0 @@
<template>
<div>
<essential-link
v-for="(link, index) in links"
:key="index"
:title="link.title"
:link="link.link"
:icon="link.icon"
/>
</div>
</template>
<script lang="ts">
const links = [
{ title: 'Neues Home', link: 'newHome', icon: 'mdi-google-home' },
{ title: 'Altes Home', link: 'oldHome', icon: 'mdi-home-modern' }
];
import { defineComponent } from '@vue/composition-api';
import EssentialLink from 'components/navigation/EssentialLink.vue';
export default defineComponent({
// name: 'ComponentName'
components: { EssentialLink },
setup() {
return { links };
}
});
</script>

View File

@ -0,0 +1,20 @@
<template>
<q-btn flat dense :icon="icon" :to="{ name: link }" />
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
name: 'ShortCutLink',
props: {
link: {
required: true,
type: String
},
icon: {
required: true,
type: String
}
}
});
</script>

View File

@ -26,17 +26,11 @@
<!-- Hier kommen die Shortlinks hin --> <!-- Hier kommen die Shortlinks hin -->
<div> <div>
<q-btn <short-cut-link
flat v-for="(shortcut, index) in $flaschengeistPlugins.shortcuts"
round :key="'shortcut' + index"
dense :link="shortcut.link"
icon="sim_card" :icon="shortcut.icon"
/>
<q-btn
flat
round
dense
icon="gamepad"
/> />
</div> </div>
<q-btn <q-btn
@ -60,7 +54,7 @@
<!-- Plugins --> <!-- Plugins -->
<q-list> <q-list>
<essential-link <essential-link
v-for="(link, index) in $flaschengeistPluginsMainLinks" v-for="(link, index) in $flaschengeistPlugins.mainLinks"
:key="'plugin' + index" :key="'plugin' + index"
:title="link.title" :title="link.title"
:link="link.link" :link="link.link"
@ -115,8 +109,9 @@
<script lang="ts"> <script lang="ts">
import EssentialLink from 'components/navigation/EssentialLink.vue'; import EssentialLink from 'components/navigation/EssentialLink.vue';
import ShortCutLink from 'components/navigation/ShortCutLink.vue';
import { Screen } from 'quasar'; import { Screen } from 'quasar';
import { PluginMainLink } from 'boot/plugins'; import { LoadedPlugins, PluginMainLink } from 'boot/plugins';
import { defineComponent, ref, computed } from '@vue/composition-api'; import { defineComponent, ref, computed } from '@vue/composition-api';
const links = [ const links = [
@ -128,15 +123,30 @@ const links = [
}, },
]; ];
const shortcuts = [
{
link: 'about',
icon: 'mdi-information',
},
{
link: 'user',
icon: 'mdi-account',
},
{
link: 'user-plugin1',
icon: 'mdi-account-plus',
},
];
declare module 'vue/types/vue' { declare module 'vue/types/vue' {
interface Vue { interface Vue {
$flaschengeistPluginsMainLinks: PluginMainLink[]; $flaschengeistPlugins: LoadedPlugins;
} }
} }
export default defineComponent({ export default defineComponent({
name: 'MainLayout', name: 'MainLayout',
components: { EssentialLink }, components: { EssentialLink, ShortCutLink },
setup(_, ctx) { setup(_, ctx) {
const leftDrawer = ref(false); const leftDrawer = ref(false);
@ -156,7 +166,7 @@ export default defineComponent({
const pluginChildLinks = computed(() => { const pluginChildLinks = computed(() => {
const link: const link:
| PluginMainLink | PluginMainLink
| undefined = ctx.root.$flaschengeistPluginsMainLinks.find( | undefined = ctx.root.$flaschengeistPlugins.mainLinks.find(
(plugin: PluginMainLink) => { (plugin: PluginMainLink) => {
if (ctx.root.$route.matched.length > 1) { if (ctx.root.$route.matched.length > 1) {
return plugin.name == ctx.root.$route.matched[1].name; return plugin.name == ctx.root.$route.matched[1].name;
@ -177,6 +187,7 @@ export default defineComponent({
leftDrawerClicker, leftDrawerClicker,
links, links,
pluginChildLinks, pluginChildLinks,
shortcuts,
}; };
}, },
}); });

View File

@ -13,6 +13,14 @@
Flaschengeist Flaschengeist
</span> </span>
</q-toolbar-title> </q-toolbar-title>
<div>
<short-cut-link
v-for="(shortcut, index) in $flaschengeistPlugins.shortcutsOut"
:key="'shortcut' + index"
:link="shortcut.link"
:icon="shortcut.icon"
/>
</div>
<q-btn <q-btn
flat flat
round round
@ -45,7 +53,9 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from '@vue/composition-api'; import { defineComponent } from '@vue/composition-api';
import ShortCutLink from 'components/navigation/ShortCutLink.vue';
export default defineComponent({ export default defineComponent({
name: 'OutLayout' name: 'OutLayout',
components: { ShortCutLink }
}); });
</script> </script>

View File

@ -4,7 +4,7 @@
class="fit row justify-center content-center items-center" class="fit row justify-center content-center items-center"
v-if="$route.name == 'about' || $route.name == 'about_out'" v-if="$route.name == 'about' || $route.name == 'about_out'"
> >
<q-card flat class="col-6"> <q-card flat class="col-xs-12 col-sm-10 col-md-6">
<q-card-section <q-card-section
class="row fit justify-center items-center content-center" class="row fit justify-center items-center content-center"
> >
@ -36,12 +36,12 @@
</q-card-section> </q-card-section>
<q-card-section v-if="$route.name == 'about'"> <q-card-section v-if="$route.name == 'about'">
<q-chip <q-chip
v-for="(plugin, index) in $flaschengeistPlugins" v-for="(plugin, index) in $flaschengeistPlugins.plugins"
:key="'plugin' + index" :key="'plugin' + index"
> >
{{ plugin.name }} {{ plugin.name }}
<q-separator vertical color="black" class="q-ma-xs" /> <q-separator vertical color="black" class="q-ma-xs" />
Version {{ plugin.version }}
</q-chip> </q-chip>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
@ -54,8 +54,8 @@
class="fit row inline wrap justify-around items-start content-start q-gutter-sm" class="fit row inline wrap justify-around items-start content-start q-gutter-sm"
> >
<developer <developer
v-for="developer in developers" v-for="(developer, index) in developers"
:key="i" :key="'dev' + index"
class="col-xs-12 col-md-5 col-lg-3" class="col-xs-12 col-md-5 col-lg-3"
:firstname="developer.firstname" :firstname="developer.firstname"
:lastname="developer.lastname" :lastname="developer.lastname"

View File

@ -15,7 +15,7 @@ import { mainLink } from '../plugin';
export default defineComponent({ export default defineComponent({
// name: 'PageName' // name: 'PageName'
setup(_, ctx) { setup(_, ctx) {
const a = ctx.root.$flaschengeistPluginsMainLinks; const a = ctx.root.$flaschengeistPlugins.mainLinks;
return { a, mainLink }; return { a, mainLink };
} }
}); });

View File

@ -1,4 +1,4 @@
import { Plugin, PluginMainLink } from 'boot/plugins'; import { Plugin, PluginMainLink, ShortCutLink } from 'boot/plugins';
import routes from 'src/plugins/plugin-example/routes'; import routes from 'src/plugins/plugin-example/routes';
const mainLink: PluginMainLink = { const mainLink: PluginMainLink = {
@ -26,7 +26,10 @@ const plugin: Plugin = {
routes, routes,
mainLink, mainLink,
name: mainLink.name, name: mainLink.name,
requiredModules: [] requiredModules: [],
shortcuts: [],
shortcutsOut: [],
version: '1.0.2'
}; };
export { mainLink }; export { mainLink };

View File

@ -15,7 +15,7 @@ import { mainLink } from '../plugin';
export default defineComponent({ export default defineComponent({
// name: 'PageName' // name: 'PageName'
setup(_, ctx) { setup(_, ctx) {
const a = ctx.root.$flaschengeistPluginsMainLinks; const a = ctx.root.$flaschengeistPlugins.mainLinks;
return { a, mainLink }; return { a, mainLink };
} }
}); });

View File

@ -1,4 +1,4 @@
import { Plugin, PluginMainLink } from 'boot/plugins'; import { Plugin, PluginMainLink, ShortCutLink } from 'boot/plugins';
import routes from './routes'; import routes from './routes';
const mainLink: PluginMainLink = { const mainLink: PluginMainLink = {
@ -22,11 +22,21 @@ const mainLink: PluginMainLink = {
] ]
}; };
const shortcuts: ShortCutLink[] = [
{
link: 'user-plugin2',
icon: 'mdi-account-minus'
}
];
const plugin: Plugin = { const plugin: Plugin = {
routes, routes,
mainLink, mainLink,
name: mainLink.name, name: mainLink.name,
requiredModules: ['user'] requiredModules: ['user'],
shortcuts,
shortcutsOut: [],
version: '0.1.0'
}; };
export { mainLink }; export { mainLink };

View File

@ -36,7 +36,7 @@ export default defineComponent({
const userState = computed( const userState = computed(
() => <UserStateInterface>root.$store.state.user () => <UserStateInterface>root.$store.state.user
); );
const a = root.$flaschengeistPluginsMainLinks; const a = ctx.root.$flaschengeistPlugins.mainLinks;
return { a, userState }; return { a, userState };
}, },
}); });

View File

@ -13,7 +13,10 @@ const plugin: Plugin = {
routes, routes,
mainLink, mainLink,
name: mainLink.name, name: mainLink.name,
requiredModules: [] requiredModules: [],
shortcutsOut: [],
shortcuts: [],
version: '0.0.1'
}; };
export { mainLink }; export { mainLink };