Merge branch 'develop' into feature/balance
This commit is contained in:
commit
f98b3d72fc
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<q-expansion-item v-if="isGranted(entry)" clickable tag="a" target="self" :label='title' :icon='entry.icon' expand-separator>
|
||||
<q-list class='q-ml-lg'>
|
||||
<div v-for='child in entry.children' :key='child.link'>
|
||||
<q-item v-if='isGranted(child)' clickable :to='{name: child.link}'>
|
||||
<q-menu context-menu>
|
||||
<q-btn v-close-popup label='Verknüpfung erstellen' dense @click='addShortCut(child)'/>
|
||||
</q-menu>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name='child.icon' />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>
|
||||
{{child.title}}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-expansion-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue';
|
||||
import { hasPermissions } from 'src/utils/permission';
|
||||
import { FG_Plugin } from 'src/plugins';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EssentialExpansionLink',
|
||||
components: { },
|
||||
props: {
|
||||
entry: {
|
||||
type: Object as PropType<FG_Plugin.MenuLink>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
emits: {
|
||||
addShortCut: (val: FG_Plugin.MenuLink) => val.link,
|
||||
},
|
||||
setup(props, {emit}) {
|
||||
|
||||
function isGranted(val: FG_Plugin.MenuLink) { return hasPermissions(val.permissions || [])};
|
||||
const title = computed(() =>
|
||||
typeof props.entry.title === 'object' ? props.entry.title.value : props.entry.title
|
||||
);
|
||||
function addShortCut(val: FG_Plugin.MenuLink) {
|
||||
emit('addShortCut', val)
|
||||
}
|
||||
|
||||
return { isGranted, title, addShortCut};
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -1,5 +1,9 @@
|
|||
<template>
|
||||
<q-btn v-if="isGranted" flat dense :icon="shortcut.icon" :to="{ name: shortcut.link }" />
|
||||
<q-btn v-if="isGranted" flat dense :icon="shortcut.icon" :to="{ name: shortcut.link }" round>
|
||||
<q-menu v-if="context" context-menu>
|
||||
<q-btn v-close-popup label="Verknüpfung entfernen" @click="deleteShortcut" />
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -12,12 +16,22 @@ export default defineComponent({
|
|||
props: {
|
||||
shortcut: {
|
||||
required: true,
|
||||
type: Object as PropType<FG_Plugin.Shortcut>,
|
||||
type: Object as PropType<FG_Plugin.Shortcut | FG_Plugin.MenuLink>,
|
||||
},
|
||||
context: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
emits: {
|
||||
deleteShortcut: (val: FG_Plugin.MenuLink | FG_Plugin.Shortcut) => val.link,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const isGranted = computed(() => hasPermissions(props.shortcut.permissions || []));
|
||||
return { isGranted };
|
||||
function deleteShortcut() {
|
||||
emit('deleteShortcut', props.shortcut);
|
||||
}
|
||||
return { isGranted, deleteShortcut };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -14,8 +14,10 @@
|
|||
</q-toolbar-title>
|
||||
|
||||
<!-- Hier kommen die Shortlinks hin -->
|
||||
<q-btn icon="mdi-message-bulleted" flat dense
|
||||
><q-badge color="negative" floating>{{ notifications.length }}</q-badge>
|
||||
<q-btn icon="mdi-message-bulleted" flat dense round>
|
||||
<q-badge color="negative" floating>
|
||||
{{ notifications.length }}
|
||||
</q-badge>
|
||||
<q-menu style="max-height: 400px; overflow: auto">
|
||||
<q-btn
|
||||
v-if="useNative && noPermission"
|
||||
|
@ -33,11 +35,11 @@
|
|||
<div v-else class="q-pa-sm">Keine neuen Benachrichtigungen</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<shortcut-link
|
||||
v-for="(shortcut, index) in shortcuts"
|
||||
:key="'shortcut' + index"
|
||||
:shortcut="shortcut"
|
||||
/>
|
||||
<drag v-model="shortCuts" item-key="link" ghost-class="ghost">
|
||||
<template #item="{ element }">
|
||||
<shortcut-link :shortcut="element" context @delete-shortcut="deleteShortcut" />
|
||||
</template>
|
||||
</drag>
|
||||
<q-btn flat round dense icon="mdi-exit-to-app" @click="logout()" />
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
@ -51,17 +53,11 @@
|
|||
>
|
||||
<!-- Plugins -->
|
||||
<q-list>
|
||||
<essential-link
|
||||
<essential-expansion-link
|
||||
v-for="(entry, index) in mainLinks"
|
||||
:key="'plugin' + index"
|
||||
:entry="entry"
|
||||
/>
|
||||
<q-separator />
|
||||
<!-- Plugin functions -->
|
||||
<essential-link
|
||||
v-for="(entry, index) in subLinks"
|
||||
:key="'childPlugin' + index"
|
||||
:entry="entry"
|
||||
@add-short-cut="addShortcut"
|
||||
/>
|
||||
</q-list>
|
||||
<q-separator />
|
||||
|
@ -81,13 +77,23 @@
|
|||
import EssentialLink from 'src/components/navigation/EssentialLink.vue';
|
||||
import ShortcutLink from 'src/components/navigation/ShortcutLink.vue';
|
||||
import Notification from 'src/components/Notification.vue';
|
||||
import { defineComponent, ref, inject, computed, onBeforeMount, onBeforeUnmount } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
inject,
|
||||
computed,
|
||||
onBeforeMount,
|
||||
onBeforeUnmount,
|
||||
ComponentPublicInstance,
|
||||
} from 'vue';
|
||||
import { useMainStore } from 'src/stores';
|
||||
import { FG_Plugin } from 'src/plugins';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Screen } from 'quasar';
|
||||
import config from 'src/config';
|
||||
|
||||
import EssentialExpansionLink from 'components/navigation/EssentialExpansionLink.vue';
|
||||
import draggable from 'vuedraggable';
|
||||
const drag: ComponentPublicInstance = <ComponentPublicInstance>draggable;
|
||||
const essentials: FG_Plugin.MenuLink[] = [
|
||||
{
|
||||
title: 'Über Flaschengeist',
|
||||
|
@ -98,28 +104,23 @@ const essentials: FG_Plugin.MenuLink[] = [
|
|||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
components: { EssentialLink, ShortcutLink, Notification },
|
||||
components: { EssentialExpansionLink, EssentialLink, ShortcutLink, Notification, drag },
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const mainStore = useMainStore();
|
||||
const flaschengeist = inject<FG_Plugin.Flaschengeist>('flaschengeist');
|
||||
const leftDrawer = ref(true);
|
||||
const leftDrawerMini = ref(false);
|
||||
const shortcuts = flaschengeist?.shortcuts || [];
|
||||
const mainLinks = flaschengeist?.menuLinks || [];
|
||||
const notifications = computed(() => mainStore.notifications.slice().reverse());
|
||||
const polling = ref(NaN);
|
||||
const useNative = 'Notification' in window && window.Notification !== undefined;
|
||||
const noPermission = ref(!useNative || window.Notification.permission !== 'granted');
|
||||
|
||||
const subLinks = computed(() => {
|
||||
const matched = router.currentRoute.value.matched[1];
|
||||
return flaschengeist?.menuLinks.find((link) => matched.name == link.link)?.children;
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
polling.value = window.setInterval(() => pollNotification(), config.pollingInterval);
|
||||
pollNotification();
|
||||
void mainStore.getShortcuts();
|
||||
});
|
||||
onBeforeUnmount(() => window.clearInterval(polling.value));
|
||||
|
||||
|
@ -165,6 +166,30 @@ export default defineComponent({
|
|||
});
|
||||
}
|
||||
|
||||
const shortCuts = computed({
|
||||
get: () => mainStore.shortcuts,
|
||||
set: (val: Array<FG_Plugin.MenuLink>) => {
|
||||
mainStore.shortcuts = val;
|
||||
void mainStore.setShortcuts();
|
||||
},
|
||||
});
|
||||
|
||||
function addShortcut(val: FG_Plugin.MenuLink) {
|
||||
const idx = shortCuts.value.findIndex((a: FG_Plugin.MenuLink) => a.link === val.link);
|
||||
if (idx < 0) {
|
||||
shortCuts.value.push(val);
|
||||
void mainStore.setShortcuts();
|
||||
}
|
||||
}
|
||||
|
||||
function deleteShortcut(val: FG_Plugin.MenuLink) {
|
||||
const idx = shortCuts.value.findIndex((a: FG_Plugin.MenuLink) => a.link === val.link);
|
||||
if (idx > -1) {
|
||||
shortCuts.value.splice(idx, 1);
|
||||
void mainStore.setShortcuts();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
essentials,
|
||||
leftDrawer,
|
||||
|
@ -176,10 +201,16 @@ export default defineComponent({
|
|||
openMenu,
|
||||
remove,
|
||||
requestPermission,
|
||||
shortcuts,
|
||||
subLinks,
|
||||
useNative,
|
||||
shortCuts,
|
||||
addShortcut,
|
||||
deleteShortcut,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="sass">
|
||||
.ghost
|
||||
opacity: 0.5
|
||||
background: $accent
|
||||
</style>
|
||||
|
|
|
@ -36,9 +36,15 @@
|
|||
</q-form>
|
||||
</q-card-section>
|
||||
<div class="row justify-end">
|
||||
<q-btn v-if='$q.platform.is.cordova || $q.platform.is.electron' flat round icon="mdi-menu-down" @click="openServerSettings" />
|
||||
<q-btn
|
||||
v-if="$q.platform.is.cordova || $q.platform.is.electron"
|
||||
flat
|
||||
round
|
||||
icon="mdi-menu-down"
|
||||
@click="openServerSettings"
|
||||
/>
|
||||
</div>
|
||||
<q-slide-transition v-if='$q.platform.is.cordova || $q.platform.is.electron'>
|
||||
<q-slide-transition v-if="$q.platform.is.cordova || $q.platform.is.electron">
|
||||
<div v-show="visible">
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
|
@ -93,7 +99,7 @@ export default defineComponent({
|
|||
const status = await mainStore.login(userid.value, password.value);
|
||||
|
||||
if (status === true) {
|
||||
mainStore.user = (await useUserStore().getUser(userid.value)) || undefined;
|
||||
mainStore.user = (await useUserStore().getUser(userid.value, true)) || undefined;
|
||||
const x = router.currentRoute.value.query['redirect'];
|
||||
void router.push(typeof x === 'string' ? { path: x } : mainRoute);
|
||||
} else {
|
||||
|
|
|
@ -25,6 +25,7 @@ export const useMainStore = defineStore({
|
|||
session: loadCurrentSession(),
|
||||
user: loadUser(),
|
||||
notifications: [] as Array<FG_Plugin.Notification>,
|
||||
shortcuts: [] as FG_Plugin.MenuLink[],
|
||||
}),
|
||||
|
||||
getters: {
|
||||
|
@ -139,6 +140,17 @@ export const useMainStore = defineStore({
|
|||
this.notifications.splice(idx, this.notifications.length - idx - 1);
|
||||
}
|
||||
},
|
||||
|
||||
async getShortcuts() {
|
||||
const { data } = await api.get<Array<FG_Plugin.MenuLink>>(
|
||||
`users/${this.currentUser.userid}/shortcuts`
|
||||
);
|
||||
this.shortcuts = data;
|
||||
},
|
||||
|
||||
async setShortcuts() {
|
||||
await api.put(`users/${this.currentUser.userid}/shortcuts`, this.shortcuts);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue