logout handling

This commit is contained in:
Sebastian Frank 2017-08-25 12:25:19 +02:00
parent 2ef22fd197
commit cd7a727f0f
No known key found for this signature in database
GPG Key ID: DC2BC5C506EBF6F3
7 changed files with 173 additions and 72 deletions

View File

@ -17,6 +17,11 @@
"name": "Userlist", "name": "Userlist",
"to": "/userlist", "to": "/userlist",
"icon": "fa-news" "icon": "fa-news"
},
{
"name": "Logout",
"to": "/logout",
"icon": "fa-lock"
} }
] ]
} }

View File

@ -5,7 +5,7 @@
"description": "JS UI for Basispanel Server Management", "description": "JS UI for Basispanel Server Management",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"serve": "WEBPACK_ENV=dev webpack-dev-server --inline --hot --open", "serve": "WEBPACK_ENV=dev webpack-dev-server --inline --hot --host 0.0.0.0",
"dev": "WEBPACK_ENV=dev webpack --progress --colors --watch", "dev": "WEBPACK_ENV=dev webpack --progress --colors --watch",
"build": "WEBPACK_ENV=production webpack --colors" "build": "WEBPACK_ENV=production webpack --colors"
}, },

17
src/components/logout.vue Normal file
View File

@ -0,0 +1,17 @@
<template>
<div>
Sie werden ausgeloggt....
</div>
</template>
<script>
export default {
name: 'logout',
created() {
this.$store.commit('clearLogin');
setTimeout(() => {
this.$router.replace('/login');
}, 2000);
}
}
</script>

View File

@ -2,15 +2,19 @@
<div class="My-Table"> <div class="My-Table">
<table> <table>
<tr> <thead>
<th v-for="(c, i) in columns" :key="i">{{ c.heading }}</th> <tr>
</tr> <th v-for="(c, i) in columns" :key="i">{{ c.heading }}</th>
<tr v-for="(r, ri) in rows" :key="ri"> </tr>
<td v-for="(c, ci) in columns" :key="ci"> </thead>
<span v-if="c.prop">{{ r[c.prop] }}</span> <tbody is="transition-group" name="list">
<span v-else-if="c.render">{{ c.render(r) }}</span> <tr v-for="(r, ri) in rows" :key="ri">
</td> <td v-for="(c, ci) in columns" :key="ci + 'c'">
</tr> <span v-if="c.prop">{{ r[c.prop] }}</span>
<span v-else-if="c.render">{{ c.render(r) }}</span>
</td>
</tr>
</tbody>
</table> </table>
</div> </div>
@ -38,4 +42,18 @@ export default {
} }
} }
} }
</script> </script>
<style>
.list-item {
display: inline-block;
margin-right: 10px;
}
.list-enter-active, .list-leave-active {
transition: all 1s;
}
.list-enter, .list-leave-to /* .list-leave-active below version 2.1.8 */ {
opacity: 0;
transform: translateY(30px);
}
</style>

View File

@ -1,8 +1,10 @@
<template> <template>
<div class="Scroll-Table"> <div class="Scroll-Table">
<my-table :columns="columns" :rows="rows"></my-table> <my-table :columns="columns" :rows="rows"></my-table>
<div v-show="hasMore" v-if="!loading" v-observe-visibility="visibilityChanged">...</div> <div v-if="loadingDelayed">loading...</div>
<div v-if="loading">loading...</div> <div style="padding-left: 30%; padding-bottom: 100px;">
<span v-show="hasMore" v-if="!loadingDelayed" v-observe-visibility="visibilityChanged">...</span>
</div>
</div> </div>
</template> </template>
@ -56,15 +58,28 @@ export default {
watch: { watch: {
newRows(rows) { newRows(rows) {
rows.forEach(row => { rows.forEach(row => {
this.rows.push(row) this.rowsToPush.push(row);
}); });
this.currentOffset += rows.length; this.currentOffset += rows.length;
this.pushRows(); // for transition
},
loading(l) {
if (!l) {
// delay after loading for visibility observer
setTimeout(() => {
this.loadingDelayed = false;
}, 200);
} else {
this.loadingDelayed = true;
}
} }
}, },
data() { data() {
return { return {
rows: [ ], rows: [ ],
currentOffset: this.offset rowsToPush: [ ],
currentOffset: this.offset,
loadingDelayed: false
} }
}, },
methods: { methods: {
@ -73,6 +88,15 @@ export default {
// infinite scrolling // infinite scrolling
this.handler(this.currentOffset, this.limit); this.handler(this.currentOffset, this.limit);
} }
},
pushRows() {
let row = this.rowsToPush.shift();
if (row) {
this.rows.push(row);
setTimeout(() => {
this.pushRows();
}, 50);
}
} }
} }
} }

View File

@ -49,9 +49,7 @@ export default {
.then(rows => { .then(rows => {
this.hasMore = (rows.length >= limit); this.hasMore = (rows.length >= limit);
this.newRows = rows; this.newRows = rows;
setTimeout(() => { this.loading = false;
this.loading = false;
}, 200); // for oberserver
}) })
.catch(error => { .catch(error => {
this.loading = false; this.loading = false;

View File

@ -7,6 +7,7 @@ import JwtDecode from 'jwt-decode';
import App from './app.vue'; import App from './app.vue';
import Dashboard from './components/dashboard.vue'; import Dashboard from './components/dashboard.vue';
import LoginForm from './components/forms/login.vue'; import LoginForm from './components/forms/login.vue';
import Logout from './components/logout.vue';
import Userlist from './components/userlist.vue'; import Userlist from './components/userlist.vue';
Vue.use(VueRouter); Vue.use(VueRouter);
@ -25,6 +26,10 @@ const routes = [
{ {
path: '/userlist', path: '/userlist',
component: Userlist component: Userlist
},
{
path: '/logout',
component: Logout
} }
]; ];
@ -36,35 +41,41 @@ const store = new Vuex.Store({
state: { state: {
api: {}, api: {},
navigation: [], navigation: [],
login: {}, persist: {
authToken: '', login: {},
jwt: {}, authToken: '',
credentials: {} jwt: {},
credentials: {}
}
}, },
mutations: { mutations: {
setAPI(state, payload) { setAPI(state, payload) {
state.api = payload; state.api = payload;
}, },
setNavigation(state, payload) { setNavigation(state, payload) {
for (var i=0; i<payload.length; i++) { for (var i = 0; i < payload.length; i++) {
state.navigation.push(payload[i]); // = payload; state.navigation.push(payload[i]); // = payload;
} }
}, },
setCredentials(state, payload) { setCredentials(state, payload) {
state.credentials = { state.persist.credentials = {
username: payload.username, username: payload.username,
password: payload.password password: payload.password
} };
objectToPersist(state.persist, 'persistantStore');
}, },
setLogin(state, payload) { setLogin(state, payload) {
state.login = payload.User; state.persist.login = payload.User;
state.authToken = payload.AuthToken; state.persist.authToken = payload.AuthToken;
state.jwt = JwtDecode(payload.AuthToken); state.persist.jwt = JwtDecode(payload.AuthToken);
objectToPersist(state.persist, 'persistantStore');
}, },
clearLogin() { clearLogin(state) {
state.login = {}; state.persist.login = {};
state.authToken = ''; state.persist.authToken = '';
state.jwt = {}; state.persist.jwt = {};
state.persist.credentials = {};
objectToPersist(state.persist, 'persistantStore');
} }
}, },
actions: { actions: {
@ -78,25 +89,25 @@ const store = new Vuex.Store({
params: payload.params, params: payload.params,
data: payload.data, data: payload.data,
headers: { headers: {
'X-Auth-Token': context.state.authToken 'X-Auth-Token': context.state.persist.authToken
} }
}) })
.then(response => { .then(response => {
console.log(response); console.log(response);
resolve(response.data); resolve(response.data);
}) })
.catch(error => { .catch(error => {
console.dir(error); console.dir(error);
reject(error); reject(error);
}) })
}); });
}; };
if (payload.endpoint != 'login') { if (payload.endpoint != 'login') {
// no jwt check for login call // no jwt check for login call
// empty username = not logged in // empty username = not logged in
if (!context.state.credentials.username) { if (!context.state.persist.credentials.username) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// show login page // show login page
router.push('/login'); router.push('/login');
@ -105,7 +116,7 @@ const store = new Vuex.Store({
} }
let now = Math.round(Date.now() / 1000); let now = Math.round(Date.now() / 1000);
if ( context.state.jwt.exp < (now + 300) ) { if (context.state.persist.jwt.exp < (now + 300)) {
// too old jwt, logout // too old jwt, logout
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
context.commit('clearLogin'); context.commit('clearLogin');
@ -114,11 +125,11 @@ const store = new Vuex.Store({
}); });
} }
if ( (context.state.jwt.exp - 60) < now ) { if ((context.state.persist.jwt.exp - 60) < now) {
// jwt near expire, get new one // jwt near expire, get new one
console.log("getting new jwt"); console.log("getting new jwt");
return context.dispatch('login', context.state.credentials) return context.dispatch('login', context.state.persist.credentials)
.then(() => { .then(() => {
console.log("LOOOGIIIINNN"); console.log("LOOOGIIIINNN");
return doRequest(); return doRequest();
@ -144,43 +155,71 @@ const store = new Vuex.Store({
resolve(data.User); resolve(data.User);
}) })
.catch(error => { .catch(error => {
if (error.response && error.response.data && error.response.data.error) { if (error.response && error.response.data && error.response.data.error) {
reject(error.response.data.error); reject(error.response.data.error);
} else { } else {
reject([]); reject([]);
} }
}); });
}); });
} }
} }
}); });
function objectToPersist(obj, key) {
try {
const serialized = JSON.stringify(obj);
localStorage.setItem(key ? key : 'persistant', serialized);
} catch (error) {
console.error(error);
}
};
function persistToObject(key) {
try {
const serialized = localStorage.getItem(key ? key : 'persistant');
if (serialized === null) {
return undefined;
}
return JSON.parse(serialized);
} catch (error) {
console.log(error);
return undefined;
}
}
// get store persist part from localStorage
let persist = persistToObject('persistantStore');
if (persist) {
store.state.persist = persist;
}
// load init // load init
Axios.get('conf/init.json') Axios.get('conf/init.json')
.then(results => { .then(results => {
// set navigation // set navigation
if ( !Array.isArray(results.data.navigation) ) { if (!Array.isArray(results.data.navigation)) {
alert('invalid data in: ' + this.src); alert('invalid data in init.json');
return; return;
} }
store.commit("setNavigation", results.data.navigation); store.commit("setNavigation", results.data.navigation);
// set api config in store // set api config in store
store.commit("setAPI", results.data.api); store.commit("setAPI", results.data.api);
// load app, when init finishs // load app, when init finishs
new Vue({ new Vue({
el: '#vue-app', el: '#vue-app',
components: { components: {
App App
}, },
data: { data: {
navItems: store.state.navigation navItems: store.state.navigation
}, },
router, router,
store store
}); });
}) })
.catch(error => { .catch(error => {
alert('error loading: ' + error.message); alert('error loading: ' + error.message);
}); });