Merge remote-tracking branch 'origin/develop' into feature/pricelist

This commit is contained in:
Tim Gröger 2021-03-30 09:59:27 +02:00
commit 1b478d7680
29 changed files with 95 additions and 55 deletions

View File

@ -2,7 +2,7 @@ import config from 'src/config';
import { boot } from 'quasar/wrappers';
import { LocalStorage, Notify } from 'quasar';
import axios, { AxiosError } from 'axios';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
const api = axios.create();

View File

@ -1,5 +1,5 @@
import { boot } from 'quasar/wrappers';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { hasPermissions } from 'src/utils/permission';
import { RouteRecord } from 'vue-router';

View File

@ -5,6 +5,7 @@ import { api } from 'boot/axios';
import { AxiosResponse } from 'axios';
import { RouteRecordRaw } from 'vue-router';
import { Notify } from 'quasar';
import { notEmpty } from 'src/utils/validators';
const config: { [key: string]: Array<string> } = {
// Do not change required Modules !!
@ -56,6 +57,9 @@ interface Backend {
}
export { Backend };
// Handle Notifications
export const translateNotification = (note: FG.Notification): FG_Plugin.Notification => note;
// Combine routes, shortcuts and widgets from plugins
/**
@ -288,6 +292,7 @@ function loadPlugin(
loadedPlugins.plugins.push({
name: plugin.name,
version: plugin.version,
notification: plugin.notification?.bind({}) || translateNotification,
});
return plugin;

View File

@ -1,6 +1,6 @@
import { createPinia } from 'pinia';
import { boot } from 'quasar/wrappers';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default boot(({ app }) => {
app.use(createPinia());

View File

@ -1,7 +1,7 @@
<template>
<q-card bordered class="row q-ma-xs q-pa-xs" style="position: relative">
<div class="col-12 text-weight-light">{{ dateString }}</div>
<div class="col-12">{{ modelValue.text }}</div>
<div :id="`ntfctn-${modelValue.id}`" class="col-12" @click="click">{{ modelValue.text }}</div>
<q-btn
round
dense
@ -12,32 +12,58 @@
style="position: absolute; top: 0; right: 0"
@click="remove"
/>
<q-btn
v-if="modelValue.accept !== undefined"
round
dense
icon="close"
size="sm"
color="positive"
class="q-ma-xs"
style="position: absolute; top: 50px; right: 0"
@click="accept"
/>
</q-card>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { formatDateTime } from 'src/utils/datetime';
import { FG_Plugin } from 'src/plugins';
import { useRouter } from 'vue-router';
export default defineComponent({
name: 'Notification',
props: {
modelValue: {
required: true,
type: Object as PropType<FG.Notification>,
type: Object as PropType<FG_Plugin.Notification>,
},
},
emits: {
remove: (id: number) => !!id,
},
setup(props, { emit }) {
const router = useRouter();
const dateString = computed(() => formatDateTime(props.modelValue.time, true, true));
async function click() {
if (props.modelValue.link) await router.push(props.modelValue.link);
}
function accept() {
if (props.modelValue.accept)
void props.modelValue.accept().then(() => emit('remove', props.modelValue.id));
else emit('remove', props.modelValue.id);
}
function remove() {
if (props.modelValue.reject)
void props.modelValue.reject().then(() => emit('remove', props.modelValue.id));
emit('remove', props.modelValue.id);
}
return { dateString, remove };
return { accept, click, dateString, remove };
},
});
</script>

View File

@ -106,7 +106,7 @@ import ShortcutLink from 'src/components/navigation/ShortcutLink.vue';
import Notification from 'src/components/Notification.vue';
import { Screen } from 'quasar';
import { defineComponent, ref, inject, computed, onBeforeMount } from 'vue';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { FG_Plugin } from 'src/plugins';
import { useRouter } from 'vue-router';

View File

@ -54,7 +54,7 @@
</template>
<script lang="ts">
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useRouter } from 'vue-router';
import { Loading, Notify } from 'quasar';
import { defineComponent, ref } from 'vue';

View File

@ -37,7 +37,7 @@
import { useRouter } from 'vue-router';
import { Loading, Notify } from 'quasar';
import { defineComponent, ref } from 'vue';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
// name: 'PageName'

19
src/plugins.d.ts vendored
View File

@ -1,4 +1,4 @@
import { RouteRecordRaw, RouteRecordName } from 'vue-router';
import { RouteLocationRaw, RouteRecordRaw, RouteRecordName } from 'vue-router';
import { Component, ComputedRef } from 'vue';
declare namespace FG_Plugin {
@ -19,6 +19,8 @@ declare namespace FG_Plugin {
outerRoutes?: MenuRoute[];
/** Routes without menu links, for internal usage */
internalRoutes?: NamedRouteRecordRaw[];
/** Handle notifications, defaults to boot/plugins.ts:translateNotification() */
notification?(msg: FG.Notification): FG_Plugin.Notification;
}
/**
@ -39,12 +41,27 @@ declare namespace FG_Plugin {
widgets: Widget[];
}
/**
* Interface for a frontend notification
*/
interface Notification extends FG.Notification {
/** If set a button for accepting will be shown, this function will get called before deleting the notification */
accept?(): Promise<void>;
/** If set this function is called before the notification gets deleted */
reject?(): Promise<void>;
/** If set the notification text is interpreted as a link to this location */
link?: RouteLocationRaw;
/** If set this icon is used */
icon?: string;
}
/**
* Loaded Flaschengeist plugin
*/
interface LoadedPlugin {
name: string;
version: string;
notification(msg: FG.Notification): FG_Plugin.Notification;
}
/**

View File

@ -62,7 +62,7 @@ import { hasPermission } from 'src/utils/permission';
import BalanceHeader from '../components/BalanceHeader.vue';
import PERMISSIONS from '../permissions';
import { useBalanceStore } from '../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
name: 'BalanceAdd',

View File

@ -20,7 +20,7 @@
import { computed, defineComponent, onBeforeMount, PropType } from 'vue';
import UserSelector from 'src/plugins/user/components/UserSelector.vue';
import { useBalanceStore } from '../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
name: 'BalanceHeader',

View File

@ -29,7 +29,7 @@ import UserSelector from 'src/plugins/user/components/UserSelector.vue';
import BalanceHeader from '../components/BalanceHeader.vue';
import PERMISSIONS from '../permissions';
import { useBalanceStore } from '../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
name: 'BalanceTransfer',

View File

@ -33,7 +33,7 @@
import { ref, computed, defineComponent, onUnmounted, onMounted, PropType } from 'vue';
import { hasPermission } from 'src/utils/permission';
import { formatDateTime } from 'src/utils/datetime';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useUserStore } from 'src/plugins/user/store';
import { useBalanceStore } from '../store';

View File

@ -7,7 +7,7 @@
</template>
<script lang="ts">
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useBalanceStore } from '../store';
import { computed, defineComponent, onBeforeMount } from 'vue';

View File

@ -73,7 +73,7 @@ import BalanceAdd from '../components/BalanceAdd.vue';
import BalanceTransfer from '../components/BalanceTransfer.vue';
import Transaction from '../components/Transaction.vue';
import { useBalanceStore } from '../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
name: 'BalanceManage',

View File

@ -35,7 +35,7 @@
import { computed, defineComponent, onMounted, ref } from 'vue';
import { formatDateTime } from 'src/utils/datetime';
import { useBalanceStore } from '../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useUserStore } from 'src/plugins/user/store';
export default defineComponent({

View File

@ -17,7 +17,7 @@ export interface TransactionsResponse {
}
import { defineStore } from 'pinia';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { AxiosResponse } from 'axios';
import { Notify } from 'quasar';

View File

@ -326,7 +326,7 @@
<script lang="ts">
import { defineComponent, onBeforeMount, ComputedRef, computed, ref } from 'vue';
import DrinkPriceVolumesTable from 'src/plugins/pricelist/components/CalculationTable/DrinkPriceVolumesTable.vue';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { Drink, usePricelistStore } from 'src/plugins/pricelist/store';
import MinPriceSetting from 'src/plugins/pricelist/components/MinPriceSetting.vue';
import NewDrink from 'src/plugins/pricelist/components/CalculationTable/NewDrink.vue';

View File

@ -39,7 +39,7 @@ import { defineComponent, onBeforeMount, computed, PropType } from 'vue';
import { Notify } from 'quasar';
import { asHour } from 'src/utils/datetime';
import { useUserStore } from 'src/plugins/user/store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useScheduleStore } from 'src/plugins/schedule/store';
export default defineComponent({

View File

@ -14,7 +14,7 @@
import { defineComponent, ref } from 'vue';
import UserSelector from '../components/UserSelector.vue';
import MainUserSettings from '../components/settings/MainUserSettings.vue';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useUserStore } from '../store';
export default defineComponent({

View File

@ -26,7 +26,7 @@
</template>
<script lang="ts">
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { computed, defineComponent, onMounted, ref } from 'vue';
import { useUserStore } from '../store';

View File

@ -112,7 +112,7 @@ import { hasPermission } from 'src/utils/permission';
import IsoDateInput from 'src/components/utils/IsoDateInput.vue';
import { defineComponent, computed, ref, onBeforeMount, PropType } from 'vue';
import { useUserStore } from '../../store';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export default defineComponent({
name: 'MainUserSettings',

View File

@ -48,7 +48,7 @@
<script lang="ts">
import { defineComponent, ref, computed, PropType } from 'vue';
import { formatDateTime } from 'src/utils/datetime';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useSessionStore } from '../../store';
export default defineComponent({

View File

@ -22,7 +22,7 @@
import { defineComponent, onBeforeMount, ref } from 'vue';
import Session from '../components/settings/Session.vue';
import MainUserSettings from '../components/settings/MainUserSettings.vue';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { useSessionStore } from '../store';
import { useUserStore } from '../store';

View File

@ -1,5 +1,5 @@
import { FG_Plugin } from 'src/plugins';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
import { computed } from 'vue';
const mainRoutes: FG_Plugin.MenuRoute[] = [

View File

@ -1,7 +1,7 @@
import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';
import { AxiosError, AxiosResponse } from 'axios';
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export const useUserStore = defineStore({
id: 'users',

View File

@ -1,27 +1,11 @@
import { store } from 'quasar/wrappers';
import { createStore } from 'vuex';
export interface StateInterface {
[key: string]: unknown;
}
export default store(function (/* { ssrContext } */) {
const Store = createStore({
modules: {},
// enable strict mode (adds overhead!)
// for dev mode and --debug builds only
strict: !!process.env.DEBUGGING,
});
return Store;
});
import { defineStore } from 'pinia';
import { api } from 'src/boot/axios';
import { AxiosResponse } from 'axios';
import { LocalStorage, SessionStorage } from 'quasar';
import { useUserStore, useSessionStore } from 'src/plugins/user/store';
import { translateNotification } from 'src/boot/plugins';
import { LocalStorage, SessionStorage } from 'quasar';
import { FG_Plugin } from 'src/plugins';
import { AxiosResponse } from 'axios';
import { api } from 'src/boot/axios';
import { defineStore } from 'pinia';
import { inject } from 'vue';
function loadCurrentSession() {
const session = LocalStorage.getItem<FG.Session>('session');
@ -41,7 +25,7 @@ export const useMainStore = defineStore({
state: () => ({
session: loadCurrentSession(),
user: loadUser(),
notifications: [] as Array<FG.Notification>,
notifications: [] as Array<FG_Plugin.Notification>,
}),
getters: {
@ -126,6 +110,7 @@ export const useMainStore = defineStore({
},
async loadNotifications() {
const flaschengeist = inject<FG_Plugin.Flaschengeist>('flaschengeist');
const params =
this.notifications.length > 0
? { from: this.notifications[this.notifications.length - 1].time }
@ -133,12 +118,17 @@ export const useMainStore = defineStore({
const { data } = await api.get<FG.Notification[]>('/notifications', { params: params });
data.forEach((n) => {
n.time = new Date(n.time);
const notif = (
flaschengeist?.plugins.filter((p) => p.name === n.plugin)[0]?.notification ||
translateNotification
)(n);
this.notifications.push(notif);
if (window.Notification.permission === 'granted')
new window.Notification(n.text, {
timestamp: n.time.getTime(),
new window.Notification(notif.text, {
timestamp: notif.time.getTime(),
});
});
this.notifications.push(...data);
},
async removeNotification(id: number) {
@ -154,3 +144,5 @@ export const useMainStore = defineStore({
},
},
});
export default () => useMainStore;

View File

@ -1,4 +1,4 @@
import { useMainStore } from 'src/store';
import { useMainStore } from 'src/stores';
export function hasPermission(permission: string) {
const store = useMainStore();