Added Dashboard as start page
* Plugins can register widgets on the dashboard * Added dummy widget for schedule and user ("greeting") * Added simple widget for balance
This commit is contained in:
parent
31620f9681
commit
cfc46dddd3
|
@ -1829,6 +1829,11 @@
|
||||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/crypto-js": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-6+OPzqhKX/cx5xh+yO8Cqg3u3alrkhoxhE5ZOdSEv0DOzJ13lwJ6laqGU0Kv6+XDMFmlnGId04LtY22PsFLQUw=="
|
||||||
|
},
|
||||||
"@types/electron-packager": {
|
"@types/electron-packager": {
|
||||||
"version": "14.0.0",
|
"version": "14.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/electron-packager/-/electron-packager-14.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/electron-packager/-/electron-packager-14.0.0.tgz",
|
||||||
|
@ -4402,6 +4407,11 @@
|
||||||
"randomfill": "^1.0.3"
|
"randomfill": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"crypto-js": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg=="
|
||||||
|
},
|
||||||
"css": {
|
"css": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
|
||||||
|
|
|
@ -11,9 +11,11 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.9.10",
|
"@quasar/extras": "^1.9.10",
|
||||||
|
"@types/crypto-js": "^4.0.1",
|
||||||
"@vue/composition-api": "^0.6.4",
|
"@vue/composition-api": "^0.6.4",
|
||||||
"axios": "^0.18.1",
|
"axios": "^0.18.1",
|
||||||
"core-js": "^3.7.0",
|
"core-js": "^3.7.0",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
"quasar": "^1.14.3",
|
"quasar": "^1.14.3",
|
||||||
"vue-router": "3.3.2"
|
"vue-router": "3.3.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,7 +37,7 @@ export default boot<Store<StateInterface>>(({ router, store }) => {
|
||||||
} else {
|
} else {
|
||||||
if (store.state.user.currentUser && !to.params['logout']) {
|
if (store.state.user.currentUser && !to.params['logout']) {
|
||||||
// Called login while already logged in
|
// Called login while already logged in
|
||||||
void next({ name: 'user-main' });
|
void next({ name: 'dashboard' });
|
||||||
} else {
|
} else {
|
||||||
// Not logged in or from logout
|
// Not logged in or from logout
|
||||||
next();
|
next();
|
||||||
|
|
|
@ -9,7 +9,7 @@ const config = {
|
||||||
// Do not change required Modules !!
|
// Do not change required Modules !!
|
||||||
requiredModules: ['User'],
|
requiredModules: ['User'],
|
||||||
// here you can import plugins.
|
// here you can import plugins.
|
||||||
loadModules: ['Balance']
|
loadModules: ['Balance', 'Schedule']
|
||||||
};
|
};
|
||||||
|
|
||||||
// do not change anything here !!
|
// do not change anything here !!
|
||||||
|
@ -164,6 +164,9 @@ function loadPlugin(
|
||||||
plugin.outRoutes
|
plugin.outRoutes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (plugin.widget) {
|
||||||
|
loadedPlugins.widgets.push(plugin.widget);
|
||||||
|
}
|
||||||
if (plugin.store) {
|
if (plugin.store) {
|
||||||
console.log(plugin.store);
|
console.log(plugin.store);
|
||||||
console.log(plugin.store.keys());
|
console.log(plugin.store.keys());
|
||||||
|
@ -176,7 +179,7 @@ function loadPlugin(
|
||||||
version: plugin.version
|
version: plugin.version
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.exception(`Don't find required Plugin ${requiredModule}`);
|
console.exception(`Could not find required Plugin ${requiredModule}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return loadedPlugins;
|
return loadedPlugins;
|
||||||
|
@ -191,7 +194,8 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
|
||||||
plugins: [],
|
plugins: [],
|
||||||
mainLinks: [],
|
mainLinks: [],
|
||||||
shortcuts: [],
|
shortcuts: [],
|
||||||
shortcutsOut: []
|
shortcutsOut: [],
|
||||||
|
widgets: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// get all plugins
|
// get all plugins
|
||||||
|
@ -210,7 +214,7 @@ export default boot<Store<StateInterface>>(({ Vue, router, store }) => {
|
||||||
);
|
);
|
||||||
loadedPlugins = loadPlugin(loadedPlugins, config.loadModules, plugins, store);
|
loadedPlugins = loadPlugin(loadedPlugins, config.loadModules, plugins, store);
|
||||||
|
|
||||||
console.log(loadedPlugins.routes);
|
loadedPlugins.widgets.sort((a, b) => b.priority - a.priority);
|
||||||
|
|
||||||
// add new routes for plugins
|
// add new routes for plugins
|
||||||
router.addRoutes(loadedPlugins.routes);
|
router.addRoutes(loadedPlugins.routes);
|
||||||
|
|
|
@ -13,12 +13,17 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-toolbar-title>
|
<q-toolbar-title>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'dashboard' }"
|
||||||
|
style="text-decoration: none; color: inherit;"
|
||||||
|
>
|
||||||
<q-avatar>
|
<q-avatar>
|
||||||
<img src="logo.svg" />
|
<img src="logo.svg" />
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
<span class="gt-xs">
|
<span class="gt-xs">
|
||||||
Flaschengeist
|
Flaschengeist
|
||||||
</span>
|
</span>
|
||||||
|
</router-link>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
|
|
||||||
<!-- Hier kommen die Shortlinks hin -->
|
<!-- Hier kommen die Shortlinks hin -->
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<q-page
|
||||||
|
padding
|
||||||
|
style="grid-auto-rows: 1fr;"
|
||||||
|
class="fit row justify-around items-start q-col-gutter-sm"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in widgets"
|
||||||
|
:key="index"
|
||||||
|
class="col-4 full-height col-sm-6 col-xs-12"
|
||||||
|
>
|
||||||
|
<component v-bind:is="item" />
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted, ref } from '@vue/composition-api';
|
||||||
|
import { AsyncComponentPromise } from 'vue/types/options';
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'Dashboard',
|
||||||
|
setup(_, { root }) {
|
||||||
|
const widgets = ref<Array<AsyncComponentPromise>>([]);
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('mounted!');
|
||||||
|
root.$flaschengeistPlugins.widgets.forEach(widget =>
|
||||||
|
widgets.value.push(widget.widget)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
widgets
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -40,7 +40,7 @@ import { Loading } from 'quasar';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
// name: 'PageName'
|
// name: 'PageName'
|
||||||
setup(_, { root }) {
|
setup(_, { root }) {
|
||||||
const mainRoute = { name: 'user-main' };
|
const mainRoute = { name: 'dashboard' };
|
||||||
|
|
||||||
/* Stuff for the real login page */
|
/* Stuff for the real login page */
|
||||||
const userid = ref('');
|
const userid = ref('');
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { RouteConfig } from 'vue-router';
|
import { RouteConfig } from 'vue-router';
|
||||||
import { Module } from 'vuex';
|
import { Module } from 'vuex';
|
||||||
import { StateInterface } from 'src/store';
|
import { StateInterface } from 'src/store';
|
||||||
|
import { AsyncComponentPromise } from 'vue/types/options';
|
||||||
|
|
||||||
declare namespace FG_Plugin {
|
declare namespace FG_Plugin {
|
||||||
interface ShortCutLink {
|
interface ShortCutLink {
|
||||||
link: string;
|
link: string;
|
||||||
|
@ -21,6 +23,7 @@ declare namespace FG_Plugin {
|
||||||
mainRoutes?: PluginRouteConfig[];
|
mainRoutes?: PluginRouteConfig[];
|
||||||
outRoutes?: PluginRouteConfig[];
|
outRoutes?: PluginRouteConfig[];
|
||||||
store?: Map<string, Module<any, StateInterface>>;
|
store?: Map<string, Module<any, StateInterface>>;
|
||||||
|
widget?: Widget;
|
||||||
requiredModules: string[];
|
requiredModules: string[];
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
@ -42,11 +45,17 @@ declare namespace FG_Plugin {
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Widget {
|
||||||
|
widget: AsyncComponentPromise;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
interface LoadedPlugins {
|
interface LoadedPlugins {
|
||||||
plugins: LoadedPlugin[];
|
plugins: LoadedPlugin[];
|
||||||
routes: RouteConfig[];
|
routes: RouteConfig[];
|
||||||
mainLinks: PluginMainLink[];
|
mainLinks: PluginMainLink[];
|
||||||
shortcuts: ShortCutLink[];
|
shortcuts: ShortCutLink[];
|
||||||
shortcutsOut: ShortCutLink[];
|
shortcutsOut: ShortCutLink[];
|
||||||
|
widgets: Widget[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<template>
|
||||||
|
<q-card style="text-align: center;">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Gerücht: {{ balance.toFixed(2) }} €</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, onBeforeMount } from '@vue/composition-api';
|
||||||
|
import { BalanceInterface } from 'src/plugins/balance/store/balance';
|
||||||
|
import { Store } from 'vuex';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'BalanceWidget',
|
||||||
|
setup(_, { root }) {
|
||||||
|
onBeforeMount(() => {
|
||||||
|
store.dispatch('balance/getBalance').catch(err => {
|
||||||
|
console.warn(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const store: Store<{ balance: BalanceInterface }> = <
|
||||||
|
Store<{ balance: BalanceInterface }>
|
||||||
|
>root.$store;
|
||||||
|
|
||||||
|
const balance = computed<number>(() => {
|
||||||
|
return store.state.balance.balance;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { balance };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -11,7 +11,11 @@ const plugin: FG_Plugin.Plugin = {
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
store: new Map<string, Module<BalanceInterface, StateInterface>>([
|
store: new Map<string, Module<BalanceInterface, StateInterface>>([
|
||||||
['balance', balance]
|
['balance', balance]
|
||||||
])
|
]),
|
||||||
|
widget: {
|
||||||
|
widget: () => import('./components/Widget.vue'),
|
||||||
|
priority: 0
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default plugin;
|
export default plugin;
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<template>
|
||||||
|
<q-card class="row justify-center content-center" style="text-align: center;">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6 col-12">Dienste diesen Monat: {{ jobs }}</div>
|
||||||
|
<div class="text-h6 col-12">Nächster Dienst: {{ nextJob | date }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, onBeforeMount } from '@vue/composition-api';
|
||||||
|
import { BalanceInterface } from 'src/plugins/balance/store/balance';
|
||||||
|
import { Store } from 'vuex';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DummyWidget',
|
||||||
|
setup(_, { root }) {
|
||||||
|
function randomNumber(start: number, end: number) {
|
||||||
|
return start + Math.floor(Math.random() * Math.floor(end));
|
||||||
|
}
|
||||||
|
const jobs = randomNumber(0, 5);
|
||||||
|
const nextJob = new Date(2021, randomNumber(1, 12), randomNumber(1, 31));
|
||||||
|
return { jobs, nextJob };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { FG_Plugin } from 'src/plugins';
|
||||||
|
|
||||||
|
const plugin: FG_Plugin.Plugin = {
|
||||||
|
name: 'Schedule',
|
||||||
|
requiredModules: [],
|
||||||
|
version: '0.0.1',
|
||||||
|
widget: {
|
||||||
|
widget: () => import('./components/Widget.vue'),
|
||||||
|
priority: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default plugin;
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<q-card style="text-align: center;">
|
||||||
|
<q-card-section class="row justify-center content-stretch">
|
||||||
|
<div class="col-4">
|
||||||
|
<q-avatar style="width: 100%; height: auto;">
|
||||||
|
<img :src="avatarLink" />
|
||||||
|
</q-avatar>
|
||||||
|
</div>
|
||||||
|
<div class="col-8">
|
||||||
|
<span class="text-h6">{{ name }}</span
|
||||||
|
><br />
|
||||||
|
<span>Andere Infos wo ich aber nicht weiß was</span>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref } from '@vue/composition-api';
|
||||||
|
import { Store } from 'vuex';
|
||||||
|
import { StateInterface } from 'src/store';
|
||||||
|
import MD5 from 'crypto-js/md5';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'DummyWidget',
|
||||||
|
setup(_, { root }) {
|
||||||
|
const store = <Store<StateInterface>>root.$store;
|
||||||
|
const avatarLink = computed(() => {
|
||||||
|
const hash = MD5(store.state.user.currentUser?.mail.trim());
|
||||||
|
return `https://www.gravatar.com/avatar/${hash}?s=500&d=robohash`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const name = ref(store.state.user.currentUser?.display_name);
|
||||||
|
|
||||||
|
return { avatarLink, name };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1,37 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<q-page padding class="fit row justify-center content-center items-center">
|
|
||||||
<q-card class="col-4" height="">
|
|
||||||
<q-card-section>
|
|
||||||
Name: {{ userObj.firstname }} {{ userObj.lastname }}<br />
|
|
||||||
E-Mail: {{ userObj.mail }}<br />
|
|
||||||
Roles:
|
|
||||||
<ul v-for="(role, index) in userObj.roles" :key="'role' + index">
|
|
||||||
<li>{{ role }}</li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
Token expires: {{ sessionObj.expires | dateTime }}
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</q-page>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, computed } from '@vue/composition-api';
|
|
||||||
import { Store } from 'vuex';
|
|
||||||
import { StateInterface } from 'src/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
// name: 'PageName'
|
|
||||||
setup(_, { root }) {
|
|
||||||
const store = <Store<StateInterface>>root.$store;
|
|
||||||
|
|
||||||
const userObj = computed(() => store.state.user.currentUser);
|
|
||||||
|
|
||||||
const sessionObj = computed(() => store.state.session.currentSession);
|
|
||||||
|
|
||||||
return { userObj, sessionObj };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -13,7 +13,11 @@ const plugin: FG_Plugin.Plugin = {
|
||||||
store: new Map<string, Module<any, StateInterface>>([
|
store: new Map<string, Module<any, StateInterface>>([
|
||||||
['user', userStore],
|
['user', userStore],
|
||||||
['session', sessionsStore]
|
['session', sessionsStore]
|
||||||
])
|
]),
|
||||||
|
widget: {
|
||||||
|
priority: 1,
|
||||||
|
widget: () => import('./components/Widget.vue')
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default plugin;
|
export default plugin;
|
||||||
|
|
|
@ -8,18 +8,9 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
||||||
component: () => import('../pages/MainPage.vue'),
|
component: () => import('../pages/MainPage.vue'),
|
||||||
meta: { permissions: ['user'] },
|
meta: { permissions: ['user'] },
|
||||||
children: [
|
children: [
|
||||||
{
|
|
||||||
title: 'Hauptkanal',
|
|
||||||
icon: 'mdi-account-hard-hat',
|
|
||||||
path: 'user-main',
|
|
||||||
name: 'user-main',
|
|
||||||
shortcut: false,
|
|
||||||
meta: { permissions: ['user'] },
|
|
||||||
component: () => import('../pages/User.vue')
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Einstellungen',
|
title: 'Einstellungen',
|
||||||
icon: 'mdi-cog',
|
icon: 'mdi-account-edit',
|
||||||
path: 'settings',
|
path: 'settings',
|
||||||
name: 'user-settings',
|
name: 'user-settings',
|
||||||
shortcut: true,
|
shortcut: true,
|
||||||
|
|
|
@ -20,9 +20,15 @@ const routes: RouteConfig[] = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/main',
|
path: '/main',
|
||||||
redirect: 'user',
|
redirect: 'dashboard',
|
||||||
component: () => import('layouts/MainLayout.vue'),
|
component: () => import('layouts/MainLayout.vue'),
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
name: 'dashboard',
|
||||||
|
path: 'dashboard',
|
||||||
|
meta: { permission: 'user' },
|
||||||
|
component: () => import('pages/Dashboard.vue')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'about',
|
name: 'about',
|
||||||
path: 'about',
|
path: 'about',
|
||||||
|
|
Loading…
Reference in New Issue