listmonk/frontend/src/App.vue

165 lines
4.5 KiB
Vue

<template>
<div id="app">
<b-navbar :fixed-top="true" v-if="$root.isLoaded">
<template #brand>
<div class="logo">
<router-link :to="{name: 'dashboard'}">
<img class="full" src="@/assets/logo.svg"/>
<img class="favicon" src="@/assets/favicon.png"/>
</router-link>
</div>
</template>
<template #end>
<navigation v-if="isMobile" :isMobile="isMobile"
:activeItem="activeItem" :activeGroup="activeGroup" @toggleGroup="toggleGroup"
@doLogout="doLogout" />
<b-navbar-item v-else tag="div">
<a href="#" @click.prevent="doLogout">{{ $t('users.logout') }}</a>
</b-navbar-item>
</template>
</b-navbar>
<div class="wrapper" v-if="$root.isLoaded">
<section class="sidebar">
<b-sidebar
position="static"
mobile="hide"
:fullheight="true"
:open="true"
:can-cancel="false"
>
<div>
<b-menu :accordion="false">
<navigation v-if="!isMobile" :isMobile="isMobile"
:activeItem="activeItem" :activeGroup="activeGroup" @toggleGroup="toggleGroup" />
</b-menu>
</div>
</b-sidebar>
</section>
<!-- sidebar-->
<!-- body //-->
<div class="main">
<div class="global-notices" v-if="serverConfig.needs_restart || serverConfig.update">
<div v-if="serverConfig.needs_restart" class="notification is-danger">
{{ $t('settings.needsRestart') }}
&mdash;
<b-button class="is-primary" size="is-small"
@click="$utils.confirm($t('settings.confirmRestart'), reloadApp)">
{{ $t('settings.restart') }}
</b-button>
</div>
<div v-if="serverConfig.update" class="notification is-success">
{{ $t('settings.updateAvailable', { version: serverConfig.update.version }) }}
<a :href="serverConfig.update.url" target="_blank">View</a>
</div>
</div>
<router-view :key="$route.fullPath" />
</div>
</div>
<b-loading v-if="!$root.isLoaded" active />
</div>
</template>
<script>
import Vue from 'vue';
import { mapState } from 'vuex';
import { uris } from './constants';
import Navigation from './components/Navigation.vue';
export default Vue.extend({
name: 'App',
components: {
Navigation,
},
data() {
return {
activeItem: {},
activeGroup: {},
windowWidth: window.innerWidth,
};
},
watch: {
$route(to) {
// Set the current route name to true for active+expanded keys in the
// menu to pick up.
this.activeItem = { [to.name]: true };
if (to.meta.group) {
this.activeGroup = { [to.meta.group]: true };
} else {
// Reset activeGroup to collapse menu items on navigating
// to non group items from sidebar
this.activeGroup = {};
}
},
},
methods: {
toggleGroup(group, state) {
this.activeGroup = state ? { [group]: true } : {};
},
reloadApp() {
this.$api.reloadApp().then(() => {
this.$utils.toast('Reloading app ...');
// Poll until there's a 200 response, waiting for the app
// to restart and come back up.
const pollId = setInterval(() => {
this.$api.getHealth().then(() => {
clearInterval(pollId);
document.location.reload();
});
}, 500);
});
},
doLogout() {
const http = new XMLHttpRequest();
const u = uris.root.substr(-1) === '/' ? uris.root : `${uris.root}/`;
http.open('get', `${u}api/logout`, false, 'logout_non_user', 'logout_non_user');
http.onload = () => {
document.location.href = uris.root;
};
http.onerror = () => {
document.location.href = uris.root;
};
http.send();
},
},
computed: {
...mapState(['serverConfig']),
version() {
return process.env.VUE_APP_VERSION;
},
isMobile() {
return this.windowWidth <= 768;
},
},
mounted() {
// Lists is required across different views. On app load, fetch the lists
// and have them in the store.
this.$api.getLists({ minimal: true });
window.addEventListener('resize', () => {
this.windowWidth = window.innerWidth;
});
},
});
</script>
<style lang="scss">
@import "assets/style.scss";
@import "assets/icons/fontello.css";
</style>