Files
lrc-frontend/src/App.vue

328 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div id="app">
<div id="bg">
<img src="./assets/lens.jpg" alt="">
</div>
<sync-loader :loading="isLoading"></sync-loader>
<!--
<b-alert
:show="dismissCountDown"
dismissible
variant="danger"
@dismissed="dismissCountDown=0"
@dismiss-count-down="countDownChanged"
>
{{alertMessage}}
<b-progress
variant="error"
:max="dismissSecs"
:value="dismissCountDown"
height="4px"
></b-progress>
</b-alert>
<b-alert
:show="messageDismissCountDown"
dismissible
variant="info"
@dismissed="messageDismissCountDown=0"
@dismiss-count-down="messageCountDownChanged"
>
{{message}}
<b-progress
variant="info"
:max="messageDismissSecs"
:value="messageDismissCountDown"
height="4px"
></b-progress>
</b-alert>-->
<div id="nav">
<b-navbar toggleable="lg" type="dark" variant="dark">
<b-navbar-brand to="/">
<img src="https://placekitten.com/g/30/30" class="d-inline-block align-top" alt="Kitten">
LRC - <strong>L</strong>ecture <strong>R</strong>ecord <strong>C</strong>ontrol
</b-navbar-brand>
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<b-navbar-nav>
<b-nav-item to="/about">About</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'rooms'}">{{ $t('Rooms') }}</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'recorders'}">{{ $t('Recorders') }}</b-nav-item>
<b-nav-item v-if="authenticated" :to="{name: 'commands'}">{{ $t('Commands') }}</b-nav-item>
<b-nav-item :to="{name: 'test'}">Test</b-nav-item>
</b-navbar-nav>
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
<b-nav-form>
<b-form-input size="sm" class="mr-sm-2" placeholder="Search"></b-form-input>
<b-button size="sm" class="my-2 my-sm-0" type="submit">Search</b-button>
</b-nav-form>
<b-nav-item-dropdown split split-to="admin" v-if="authenticated" variant="outline-danger" :text="$t('admin')">
<b-dropdown-item :to="{name: 'admin.users'}">{{ $t('users') }}</b-dropdown-item>
<b-dropdown-item :to="{name: 'admin.group'}">{{ $t('groups') }}</b-dropdown-item>
<b-dropdown-item :to="{name: 'admin.permission'}">{{ $t('permissions') }}</b-dropdown-item>
<b-dropdown-item href="#">Something else here...</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown text="Lang" right>
<b-dropdown-item v-for="(lang, i) in langs"
v-bind:key="lang"
@click="setLang(lang)">{{ lang }}
</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item-dropdown v-if="authenticated" right>
<!-- Using 'button-content' slot -->
<template slot="button-content"><em>User</em></template>
<b-dropdown-item :to="{name: 'profile'}">Profile</b-dropdown-item>
<b-dropdown-item to="/logout" @click.prevent="logout()">Sign Out</b-dropdown-item>
</b-nav-item-dropdown>
<b-nav-item v-else to="/login">Login</b-nav-item>
</b-navbar-nav>
</b-collapse>
</b-navbar>
<span v-if="tokenValidity">({{$t('Session will timeout in: ')}}{{tokenValidity}})</span>
<span v-else>{{$t('Session has expired!')}} <a v-if="refreshTokenValidity" href="~"
@click.prevent="refreshToken()">{{$t('Click here to refresh session')}}</a></span>
<span v-if="refreshTokenValidity">&nbsp;|&nbsp;({{refreshTokenValidity}})
<input type="checkbox" id="auto_renew_cb" v-model="autoRenewSession">
<label for="auto_renew_cb">{{$t('auto renew session')}}</label>
</span>
<span v-else>{{$t('Can\'t renew session please login again!')}}</span>
</div>
<div>
</div>
<div id="content_frame">
<router-view :style="main_style"/>
</div>
</div>
</template>
<script>
import {EventBus, getRemainingJwtValiditySeconds} from '@/utils';
import { localize } from 'vee-validate';
import SyncLoader from 'vue-spinner/src/SyncLoader.vue';
export default {
components: {
SyncLoader,
},
data() {
return {
isLoading: false,
tokenValidity: -1,
refreshFailed: false,
refreshTokenValidity: -1,
showAlert: true,
alertMessage: 'NO MESSAGE PROVIDED',
message: 'NO MESSAGE PROVIDED',
langs: ['de', 'en', 'es'],
dismissSecs: 5,
dismissCountDown: 0,
messageDismissSecs: 5,
messageDismissCountDown: 0,
autoRenewSession: true,
main_style: {}
};
},
methods: {
showErrorMessage(msg) {
this.isLoading = false;
this.dismissCountDown = this.dismissSecs;
this.alertMessage = msg;
this.makeToast(msg, 'error')
},
countDownChanged(dismissCountDown) {
this.dismissCountDown = dismissCountDown;
},
showMessage(msg, dismissTime=null) {
this.isLoading = false;
if(dismissTime == null) this.messageDismissCountDown = this.messageDismissSecs;
else {
this.messageDismissSecs = dismissTime;
this.messageDismissCountDown = dismissTime;
}
if(typeof msg === 'object' && msg !== null){
if("time" in msg) {
this.messageDismissCountDown = msg['time'];
this.messageDismissSecs = msg['time'];
}
if("msg" in msg) msg = msg['msg'];
}
this.message = msg;
this.makeToast(msg, 'info')
},
messageCountDownChanged(dismissCountDown) {
this.messageDismissCountDown = dismissCountDown;
},
logout() {
this.$store.dispatch('logout', {revokeRefreshToken: true});
this.$router.push({name: 'home'});
},
refreshToken() {
this.$store.dispatch('refreshToken');
},
setLang(lang) {
this.$i18n.locale=lang;
localize(lang);
},
makeToast(message, variant = null, hide_time=5000, title = null) {
if(title == null){
let now = new Date();
if(variant == null){
title = this.$t('message from') + " " + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds();
} else {
title = this.$t(variant) + " (" + now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds() + ")";
}
}
if(variant === 'error') variant = 'danger';
this.$bvToast.toast(message, {
title: title,
toaster: 'b-toaster-bottom-right',
autoHideDelay: hide_time,
variant: variant,
appendToast: false
})
},
},
mounted() {
EventBus.$on('failedLoadingRecorders', (msg) => {
this.showErrorMessage(msg);
});
EventBus.$on('failedLoadingRooms', (msg) => {
this.showErrorMessage(msg);
});
EventBus.$on('failedRefreshingToken', (msg) => {
this.refreshFailed = true;
});
EventBus.$on('errorMessage', (msg)=> {
this.showErrorMessage(msg);
})
EventBus.$on('normalMessage', (msg)=> {
this.showMessage(msg);
})
this.$nextTick(() => {
window.setInterval(() => {
const tokenValidity = getRemainingJwtValiditySeconds(this.$store.state.access_token);
// this.tokenValidity = this.tokenValidity.format('mm:ss');
const refreshTokenValidity = getRemainingJwtValiditySeconds(this.$store.state.refresh_token);
if (tokenValidity < 50 && refreshTokenValidity > 30 && this.autoRenewSession && !this.refreshFailed) {
this.$store.dispatch('refreshToken'); // renew access token
}
if (this.autoRenewSession && this.refreshFailed) {
this.$store.dispatch('resetToken'); // delete all token info if refresh fails
this.$router.push({name: 'login'});
this.refreshFailed = false;
}
if (isNaN(tokenValidity)) {
this.tokenValidity = false;
} else {
this.tokenValidity = new Date(1000 * tokenValidity).toISOString().substr(14, 5);
}
if (isNaN(tokenValidity)) {
this.refreshTokenValidity = false;
} else {
this.refreshTokenValidity = new Date(1000 * refreshTokenValidity).toISOString().substr(11, 8);
}
}, 1000);
});
},
computed: {
authenticated() {
return this.$store.getters.isAuthenticated;
},
profile() {
return this.$store.state.profile;
},
},
};
</script>
<style lang="scss">
@import '../node_modules/bootstrap/scss/bootstrap.scss';
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #385875;
}
#bg {
z-index: -100;
position: fixed;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
min-width: 50%;
min-height: 50%;
}
h1 {
color: #275d37;
}
#nav {
padding: 0px;
text-align: center;
a {
font-weight: bold;
color: #7ea8d6;
&.router-link-exact-active {
color: #42b983;
}
}
}
/* Absolute Center Spinner */
.v-spinner {
position: fixed;
z-index: 999;
// height: 2em;
// width: 2em;
overflow: visible;
margin: auto;
top: 50%;
left: 50%;
bottom: 0;
right: 0;
}
/* Transparent Overlay */
.v-spinner:before {
content: '';
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.2);
}
</style>