Merge branch 'master' into matdev
This commit is contained in:
commit
8899a291fc
119
.gitlab-ci.yml
119
.gitlab-ci.yml
@ -1,7 +1,7 @@
|
|||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
# - test
|
# - test
|
||||||
- deploy
|
- review
|
||||||
|
|
||||||
build_ui:
|
build_ui:
|
||||||
image: node
|
image: node
|
||||||
@ -23,62 +23,81 @@ build_ui:
|
|||||||
- build
|
- build
|
||||||
- conf
|
- conf
|
||||||
- index.html
|
- index.html
|
||||||
|
- Dockerfile
|
||||||
|
- docker-compose.yml
|
||||||
|
|
||||||
|
|
||||||
|
#start_review:
|
||||||
|
# image: mwienk/docker-lftp
|
||||||
|
# tags:
|
||||||
|
# - docker
|
||||||
|
# dependencies:
|
||||||
|
# - build_ui
|
||||||
|
# stage: deploy
|
||||||
|
# script:
|
||||||
|
# - cat index.html
|
||||||
|
# - mkdir _for_upload
|
||||||
|
# - mv assets build conf index.html _for_upload
|
||||||
|
# - lftp -c "set sftp:auto-confirm yes; open -u intern_basispanel_ui,$FTP_PASSWORD sftp://ftp.basehosts.de;mkdir -f /$CI_COMMIT_REF_NAME; mirror -v -n -e -R -L _for_upload/ /$CI_COMMIT_REF_NAME"
|
||||||
|
# environment:
|
||||||
|
# name: review/$CI_COMMIT_REF_NAME
|
||||||
|
# url: http://ui.basispanel.de/$CI_COMMIT_REF_NAME/
|
||||||
|
# on_stop: stop_review
|
||||||
|
#
|
||||||
|
#stop_review:
|
||||||
|
# image: mwienk/docker-lftp
|
||||||
|
# tags:
|
||||||
|
# - docker
|
||||||
|
# stage: deploy
|
||||||
|
# variables:
|
||||||
|
# GIT_STRATEGY: none
|
||||||
|
# script:
|
||||||
|
# - echo stopping env
|
||||||
|
# environment:
|
||||||
|
# name: review/$CI_COMMIT_REF_NAME
|
||||||
|
# action: stop
|
||||||
|
# when: manual
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#fullsync_review:
|
||||||
|
# image: mwienk/docker-lftp
|
||||||
|
# tags:
|
||||||
|
# - docker
|
||||||
|
# dependencies:
|
||||||
|
# - build_ui
|
||||||
|
# stage: deploy
|
||||||
|
# script:
|
||||||
|
# - mkdir _for_upload
|
||||||
|
# - mv assets build conf index.html _for_upload
|
||||||
|
# - lftp -c "set sftp:auto-confirm yes; open -u intern_basispanel_ui,$FTP_PASSWORD sftp://ftp.basehosts.de;mkdir -f /$CI_COMMIT_REF_NAME; mirror -v --transfer-all -e -R -L _for_upload/ /$CI_COMMIT_REF_NAME"
|
||||||
|
# when: manual
|
||||||
|
|
||||||
|
|
||||||
start_review:
|
start_review:
|
||||||
image: mwienk/docker-lftp
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
dependencies:
|
|
||||||
- build_ui
|
|
||||||
stage: deploy
|
|
||||||
script:
|
|
||||||
- cat index.html
|
|
||||||
- mkdir _for_upload
|
|
||||||
- mv assets build conf index.html _for_upload
|
|
||||||
- lftp -c "set sftp:auto-confirm yes; open -u intern_basispanel_ui,$FTP_PASSWORD sftp://ftp.basehosts.de;mkdir -f /$CI_COMMIT_REF_NAME; mirror -v -n -e -R -L _for_upload/ /$CI_COMMIT_REF_NAME"
|
|
||||||
environment:
|
|
||||||
name: review/$CI_COMMIT_REF_NAME
|
|
||||||
url: http://ui.basispanel.de/$CI_COMMIT_REF_NAME/
|
|
||||||
on_stop: stop_review
|
|
||||||
|
|
||||||
stop_review:
|
|
||||||
image: mwienk/docker-lftp
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
stage: deploy
|
|
||||||
variables:
|
|
||||||
GIT_STRATEGY: none
|
|
||||||
script:
|
|
||||||
- echo stopping env
|
|
||||||
environment:
|
|
||||||
name: review/$CI_COMMIT_REF_NAME
|
|
||||||
action: stop
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fullsync_review:
|
|
||||||
image: mwienk/docker-lftp
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
dependencies:
|
|
||||||
- build_ui
|
|
||||||
stage: deploy
|
|
||||||
script:
|
|
||||||
- mkdir _for_upload
|
|
||||||
- mv assets build conf index.html _for_upload
|
|
||||||
- lftp -c "set sftp:auto-confirm yes; open -u intern_basispanel_ui,$FTP_PASSWORD sftp://ftp.basehosts.de;mkdir -f /$CI_COMMIT_REF_NAME; mirror -v --transfer-all -e -R -L _for_upload/ /$CI_COMMIT_REF_NAME"
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
|
|
||||||
docker_test:
|
|
||||||
tags:
|
tags:
|
||||||
- shell
|
- shell
|
||||||
dependencies:
|
dependencies:
|
||||||
- build_ui
|
- build_ui
|
||||||
stage: deploy
|
stage: review
|
||||||
script:
|
script:
|
||||||
- mkdir _for_docker
|
- mkdir _for_docker
|
||||||
- mv assets build conf index.html _for_docker
|
- mv assets build conf index.html _for_docker
|
||||||
- docker-compose up -d --build
|
- docker-compose -p ${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME} up -d --build
|
||||||
|
environment:
|
||||||
|
name: review/$CI_COMMIT_REF_NAME
|
||||||
|
url: http://${CI_COMMIT_REF_NAME}.${CI_PROJECT_NAME}.dev.basehosts.de/
|
||||||
|
on_stop: stop_review
|
||||||
|
|
||||||
|
stop_review:
|
||||||
|
tags:
|
||||||
|
- shell
|
||||||
|
variables:
|
||||||
|
GIT_STRATEGY: none
|
||||||
|
stage: review
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- docker-compose -p ${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME} down
|
||||||
|
environment:
|
||||||
|
name: review/$CI_COMMIT_REF_NAME
|
||||||
|
action: stop
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
[![pipeline status](https://git.basehosts.de:20443/panel/basispanel-ui/badges/master/pipeline.svg)](https://git.basehosts.de:20443/panel/basispanel-ui/commits/master)
|
[![pipeline status](https://git.basehosts.de:20443/panel/basispanel-ui/badges/master/pipeline.svg)](https://git.basehosts.de:20443/panel/basispanel-ui/commits/master)
|
||||||
# basispanel UI
|
# basispanel UI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Entwicklungsprozess
|
## Entwicklungsprozess
|
||||||
|
|
||||||
### Allgemeines
|
### Allgemeines
|
||||||
|
@ -4,7 +4,6 @@ services:
|
|||||||
frontend:
|
frontend:
|
||||||
build: .
|
build: .
|
||||||
image: ${CI_PROJECT_NAME}:${CI_COMMIT_REF_NAME}
|
image: ${CI_PROJECT_NAME}:${CI_COMMIT_REF_NAME}
|
||||||
container_name: ${CI_PROJECT_NAME}_${CI_COMMIT_REF_NAME}
|
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- web
|
- web
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="vue-app">
|
<div id="vue-app">
|
||||||
<app></app>
|
<div is="app">Lade, bitte warten...</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="build/main.bundle.js"></script>
|
<script src="build/baseui-main.bundle.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -23,7 +23,6 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "MyForm",
|
name: "MyForm",
|
||||||
components: {},
|
|
||||||
props: {
|
props: {
|
||||||
elements: {
|
elements: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="Scroll-Table">
|
<div class="Scroll-Table">
|
||||||
<my-input :props="{type: 'text', placeholder: 'Suche'}" @change="searchChanged" v-model="currentSearch"></my-input>
|
<my-input :props="{type: 'text', placeholder: 'Suche'}" @input="searchChanged" v-model="currentSearch"></my-input>
|
||||||
<my-table :actions="actions" :columns="columns" :rows="rows"
|
<my-table :actions="actions" :columns="columns" :rows="rows"
|
||||||
:currentOrderBy="currentOrderBy"
|
:currentOrderBy="currentOrderBy"
|
||||||
:currentOrderDesc="currentOrderDesc"
|
:currentOrderDesc="currentOrderDesc"
|
||||||
@ -14,20 +14,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MyTable from 'components/my-table';
|
|
||||||
import MyInput from 'components/my-input';
|
|
||||||
|
|
||||||
import { ObserveVisibility } from 'vue-observe-visibility/dist/vue-observe-visibility';
|
import { ObserveVisibility } from 'vue-observe-visibility/dist/vue-observe-visibility';
|
||||||
|
import { debounce } from 'lib/util';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ScrollTable",
|
name: "ScrollTable",
|
||||||
directives: {
|
directives: {
|
||||||
ObserveVisibility
|
ObserveVisibility
|
||||||
},
|
},
|
||||||
components: {
|
|
||||||
MyTable,
|
|
||||||
MyInput
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
actions: {
|
actions: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -141,11 +135,11 @@ export default {
|
|||||||
this.reloadTriggered = true;
|
this.reloadTriggered = true;
|
||||||
this.clear();
|
this.clear();
|
||||||
},
|
},
|
||||||
searchChanged(e) {
|
searchChanged: debounce(function(e) {
|
||||||
this.currentSearch = e;
|
this.currentSearch = e;
|
||||||
this.reloadTriggered = true;
|
this.reloadTriggered = true;
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}, 300)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -12,7 +12,7 @@
|
|||||||
</a>
|
</a>
|
||||||
<nav class="user_menu">
|
<nav class="user_menu">
|
||||||
<ul>
|
<ul>
|
||||||
<router-link tag="li" v-for="(item, i) in items" :key="i" v-if="showIf(item.show)" :to="item.to" active-class="active" exact>
|
<router-link tag="li" v-for="(item, i) in items" :key="i" v-if="showIf(item.show)" :to="item.to" active-class="active" exact @click.native="toggleMenu">
|
||||||
<a>
|
<a>
|
||||||
<i :class="['icon', item.icon]"></i>
|
<i :class="['icon', item.icon]"></i>
|
||||||
<div class="title">{{ item.name }}</div>
|
<div class="title">{{ item.name }}</div>
|
||||||
|
239
src/lib/baseui.js
Normal file
239
src/lib/baseui.js
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import Vuex from 'vuex';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import Axios from 'axios';
|
||||||
|
import JwtDecode from 'jwt-decode';
|
||||||
|
|
||||||
|
import App from 'app.vue';
|
||||||
|
|
||||||
|
import MyForm from 'components/my-form.vue';
|
||||||
|
import MyInput from 'components/my-input.vue';
|
||||||
|
import TextareaInput from 'components/textarea-input.vue';
|
||||||
|
import MyTable from 'components/my-table.vue';
|
||||||
|
import ScrollTable from 'components/scroll-table.vue';
|
||||||
|
|
||||||
|
Vue.use(VueRouter);
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
|
Vue.component('my-form', MyForm);
|
||||||
|
Vue.component('my-input', MyInput);
|
||||||
|
Vue.component('textarea-input', TextareaInput);
|
||||||
|
Vue.component('my-table', MyTable);
|
||||||
|
Vue.component('scroll-table', ScrollTable);
|
||||||
|
|
||||||
|
const globalConf = {
|
||||||
|
loginEndpoint: 'login',
|
||||||
|
loginRoute: '/login',
|
||||||
|
authHeader: 'X-Auth-Token',
|
||||||
|
responseType: 'json',
|
||||||
|
initUrl: 'conf/init.json',
|
||||||
|
el: '#my-app'
|
||||||
|
}
|
||||||
|
|
||||||
|
const Router = new VueRouter();
|
||||||
|
|
||||||
|
const Store = new Vuex.Store({
|
||||||
|
state: {
|
||||||
|
ui: {},
|
||||||
|
persist: {
|
||||||
|
login: {},
|
||||||
|
authToken: '',
|
||||||
|
jwt: {},
|
||||||
|
credentials: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
setUI(state, payload) {
|
||||||
|
state.ui = payload;
|
||||||
|
},
|
||||||
|
setCredentials(state, payload) {
|
||||||
|
state.persist.credentials = payload;
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
|
},
|
||||||
|
setLogin(state, payload) {
|
||||||
|
state.persist.login = payload.User;
|
||||||
|
state.persist.authToken = payload.AuthToken;
|
||||||
|
state.persist.jwt = JwtDecode(payload.AuthToken);
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
|
},
|
||||||
|
clearLogin(state) {
|
||||||
|
state.persist.login = {};
|
||||||
|
state.persist.authToken = '';
|
||||||
|
state.persist.jwt = {};
|
||||||
|
state.persist.credentials = {};
|
||||||
|
objectToPersist(state.persist, 'persistantStore');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
apiRequest(context, payload) {
|
||||||
|
let doRequest = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const addHeader = {};
|
||||||
|
addHeader[globalConf.authHeader] = context.state.persist.authToken;
|
||||||
|
Axios({
|
||||||
|
method: payload.method ? payload.method : 'get',
|
||||||
|
baseURL: context.state.ui.api.baseURL,
|
||||||
|
url: payload.endpoint,
|
||||||
|
params: payload.params,
|
||||||
|
data: payload.data,
|
||||||
|
headers: addHeader,
|
||||||
|
responseType: globalConf.responseType
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
console.log(response);
|
||||||
|
resolve(response.data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.dir(error);
|
||||||
|
reject(error);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (payload.endpoint != globalConf.loginEndpoint) {
|
||||||
|
// no jwt check for login call
|
||||||
|
|
||||||
|
if (!context.state.persist.jwt.exp) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// show login page
|
||||||
|
Router.push(globalConf.loginRoute);
|
||||||
|
reject(['not logged in']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Math.round(Date.now() / 1000);
|
||||||
|
if (context.state.persist.jwt.exp < (now + 300)) {
|
||||||
|
// too old jwt, logout
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
context.commit('clearLogin');
|
||||||
|
Router.push(globalConf.loginRoute);
|
||||||
|
reject(['jwt too old, logout']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((context.state.persist.jwt.exp - 60) < now) {
|
||||||
|
// jwt near expire, get new one
|
||||||
|
console.log("getting new jwt");
|
||||||
|
|
||||||
|
return context.dispatch(globalConf.loginEndpoint, context.state.persist.credentials)
|
||||||
|
.then(() => {
|
||||||
|
console.log("LOOOGIIIINNN");
|
||||||
|
return doRequest();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return doRequest();
|
||||||
|
},
|
||||||
|
login(context, payload) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
context.dispatch('apiRequest', {
|
||||||
|
method: 'post',
|
||||||
|
endpoint: globalConf.loginEndpoint,
|
||||||
|
data: payload
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
context.commit('setCredentials', payload);
|
||||||
|
context.commit('setLogin', data);
|
||||||
|
resolve(data.User);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
if (error.response && error.response.data && error.response.data.error) {
|
||||||
|
reject(error.response.data.error);
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Vue,
|
||||||
|
Router,
|
||||||
|
Store,
|
||||||
|
Axios,
|
||||||
|
InitApp(config) { // config: {initUrl, views, el}
|
||||||
|
Object.assign(globalConf, config);
|
||||||
|
Axios.get(globalConf.initUrl)
|
||||||
|
.then(results => {
|
||||||
|
// set navigation
|
||||||
|
if (!Array.isArray(results.data.routes)) {
|
||||||
|
alert('invalid data in init.json, no routes');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set ui config in store
|
||||||
|
Store.commit("setUI", results.data.ui);
|
||||||
|
|
||||||
|
// add routes
|
||||||
|
let routes = [];
|
||||||
|
let rIdx = 0;
|
||||||
|
results.data.routes.forEach(({ name, to, content, data }) => routes.push({
|
||||||
|
name: name,
|
||||||
|
path: to,
|
||||||
|
meta: {
|
||||||
|
title: name
|
||||||
|
},
|
||||||
|
component: {
|
||||||
|
template: '<div id="' + name + rIdx + '">' + content + '</div>',
|
||||||
|
components: globalConf.views,
|
||||||
|
data: function (data) {
|
||||||
|
if (typeof data != 'object') {
|
||||||
|
return () => { return {}; };
|
||||||
|
}
|
||||||
|
return () => { return data; };
|
||||||
|
}(data)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
Router.addRoutes(routes);
|
||||||
|
Router.beforeEach((to, from, next) => {
|
||||||
|
document.title = (to.meta && to.meta.title) ? results.data.ui.title + ': ' + to.meta.title : results.data.title;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
// load app, when init finishs
|
||||||
|
new Vue({
|
||||||
|
el: globalConf.el,
|
||||||
|
render: h => h(App),
|
||||||
|
router: Router,
|
||||||
|
store: Store
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
alert('error loading: ' + error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
36
src/lib/util.js
Normal file
36
src/lib/util.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
const now = Date.now || function() {
|
||||||
|
return new Date().getTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
export function debounce(func, wait, immediate) {
|
||||||
|
var timeout, args, context, timestamp, result;
|
||||||
|
|
||||||
|
var later = function() {
|
||||||
|
var last = now() - timestamp;
|
||||||
|
|
||||||
|
if (last < wait && last >= 0) {
|
||||||
|
timeout = setTimeout(later, wait - last);
|
||||||
|
} else {
|
||||||
|
timeout = null;
|
||||||
|
if (!immediate) {
|
||||||
|
result = func.apply(context, args);
|
||||||
|
if (!timeout) context = args = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function() {
|
||||||
|
context = this;
|
||||||
|
args = arguments;
|
||||||
|
timestamp = now();
|
||||||
|
var callNow = immediate && !timeout;
|
||||||
|
if (!timeout) timeout = setTimeout(later, wait);
|
||||||
|
if (callNow) {
|
||||||
|
result = func.apply(context, args);
|
||||||
|
context = args = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
222
src/main.js
222
src/main.js
@ -1,218 +1,10 @@
|
|||||||
import Vue from 'vue';
|
import BaseUI from './lib/baseui.js';
|
||||||
import Vuex from 'vuex';
|
import Views from './views/views.js';
|
||||||
import VueRouter from 'vue-router';
|
|
||||||
import Axios from 'axios';
|
|
||||||
import JwtDecode from 'jwt-decode';
|
|
||||||
|
|
||||||
import App from './app.vue';
|
|
||||||
// import Views from './views/views.js';
|
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
|
||||||
Vue.use(Vuex);
|
|
||||||
|
|
||||||
const router = new VueRouter();
|
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
|
||||||
state: {
|
|
||||||
ui: {},
|
|
||||||
persist: {
|
|
||||||
login: {},
|
|
||||||
authToken: '',
|
|
||||||
jwt: {},
|
|
||||||
credentials: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
setUI(state, payload) {
|
|
||||||
state.ui = payload;
|
|
||||||
},
|
|
||||||
setCredentials(state, payload) {
|
|
||||||
state.persist.credentials = {
|
|
||||||
username: payload.username,
|
|
||||||
password: payload.password
|
|
||||||
};
|
|
||||||
objectToPersist(state.persist, 'persistantStore');
|
|
||||||
},
|
|
||||||
setLogin(state, payload) {
|
|
||||||
state.persist.login = payload.User;
|
|
||||||
state.persist.authToken = payload.AuthToken;
|
|
||||||
state.persist.jwt = JwtDecode(payload.AuthToken);
|
|
||||||
objectToPersist(state.persist, 'persistantStore');
|
|
||||||
},
|
|
||||||
clearLogin(state) {
|
|
||||||
state.persist.login = {};
|
|
||||||
state.persist.authToken = '';
|
|
||||||
state.persist.jwt = {};
|
|
||||||
state.persist.credentials = {};
|
|
||||||
objectToPersist(state.persist, 'persistantStore');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
apiRequest(context, payload) {
|
|
||||||
let doRequest = () => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
Axios({
|
|
||||||
method: payload.method ? payload.method : 'get',
|
|
||||||
baseURL: context.state.ui.api.baseURL,
|
|
||||||
url: payload.endpoint,
|
|
||||||
params: payload.params,
|
|
||||||
data: payload.data,
|
|
||||||
headers: {
|
|
||||||
'X-Auth-Token': context.state.persist.authToken
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
console.log(response);
|
|
||||||
resolve(response.data);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.dir(error);
|
|
||||||
reject(error);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (payload.endpoint != 'login') {
|
|
||||||
// no jwt check for login call
|
|
||||||
|
|
||||||
// empty username = not logged in
|
|
||||||
if (!context.state.persist.credentials.username) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// show login page
|
|
||||||
router.push('/login');
|
|
||||||
reject(['not logged in']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let now = Math.round(Date.now() / 1000);
|
|
||||||
if (context.state.persist.jwt.exp < (now + 300)) {
|
|
||||||
// too old jwt, logout
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
context.commit('clearLogin');
|
|
||||||
router.push('/login');
|
|
||||||
reject(['jwt too old, logout']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((context.state.persist.jwt.exp - 60) < now) {
|
|
||||||
// jwt near expire, get new one
|
|
||||||
console.log("getting new jwt");
|
|
||||||
|
|
||||||
return context.dispatch('login', context.state.persist.credentials)
|
|
||||||
.then(() => {
|
|
||||||
console.log("LOOOGIIIINNN");
|
|
||||||
return doRequest();
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
throw error;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return doRequest();
|
|
||||||
},
|
|
||||||
login(context, payload) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
context.dispatch('apiRequest', {
|
|
||||||
method: 'post',
|
|
||||||
endpoint: 'login',
|
|
||||||
data: payload
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
context.commit('setCredentials', payload);
|
|
||||||
context.commit('setLogin', data);
|
|
||||||
resolve(data.User);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
if (error.response && error.response.data && error.response.data.error) {
|
|
||||||
reject(error.response.data.error);
|
|
||||||
} else {
|
|
||||||
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 views
|
// load init
|
||||||
import(/* webpackChunkName: "views" */ './views/views.js').then(Views => {
|
BaseUI.InitApp({
|
||||||
// load init
|
el: '#vue-app',
|
||||||
Axios.get('conf/init.json')
|
initUrl: 'conf/init.json',
|
||||||
.then(results => {
|
views: Views
|
||||||
// set navigation
|
|
||||||
if (!Array.isArray(results.data.routes)) {
|
|
||||||
alert('invalid data in init.json, no routes');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set ui config in store
|
|
||||||
store.commit("setUI", results.data.ui);
|
|
||||||
|
|
||||||
// add routes
|
|
||||||
let routes = [];
|
|
||||||
let rIdx = 0;
|
|
||||||
results.data.routes.forEach(({name, to, content, data}) => routes.push({
|
|
||||||
name: name,
|
|
||||||
path: to,
|
|
||||||
meta: {
|
|
||||||
title: name
|
|
||||||
},
|
|
||||||
component: {
|
|
||||||
template: '<div id="' + name + rIdx + '">' + content + '</div>',
|
|
||||||
components: Views.default,
|
|
||||||
data: function(data) {
|
|
||||||
if (typeof data != 'object') {
|
|
||||||
return () => { return {}; };
|
|
||||||
}
|
|
||||||
return () => { return data; };
|
|
||||||
}(data)
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
router.addRoutes(routes);
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
document.title = (to.meta && to.meta.title) ? results.data.ui.title + ': ' + to.meta.title : results.data.title;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
// load app, when init finishs
|
|
||||||
new Vue({
|
|
||||||
el: '#vue-app',
|
|
||||||
render: h => h(App),
|
|
||||||
router,
|
|
||||||
store
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
alert('error loading: ' + error.message);
|
|
||||||
});
|
|
||||||
});
|
});
|
@ -17,22 +17,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MyForm from "components/my-form";
|
|
||||||
import MyInput from "components/my-input";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "LoginForm",
|
name: "LoginForm",
|
||||||
components: {
|
|
||||||
MyForm,
|
|
||||||
MyInput
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
elements: {
|
elements: {
|
||||||
username: {
|
username: {
|
||||||
element: MyInput,
|
element: "my-input",
|
||||||
icon: "icon-user",
|
icon: "icon-user",
|
||||||
required: true,
|
required: true,
|
||||||
requiredMessage: "Der Benutzername wird benötigt!",
|
requiredMessage: "Der Benutzername wird benötigt!",
|
||||||
@ -42,7 +35,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
element: MyInput,
|
element: "my-input",
|
||||||
icon: "icon-key",
|
icon: "icon-key",
|
||||||
required: true,
|
required: true,
|
||||||
requiredMessage: "Das Passwort wird benötigt!",
|
requiredMessage: "Das Passwort wird benötigt!",
|
||||||
|
@ -105,17 +105,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MyForm from "components/my-form";
|
|
||||||
import MyInput from "components/my-input";
|
|
||||||
import TextareaInput from "components/textarea-input";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "FormDemo",
|
name: "FormDemo",
|
||||||
components: {
|
|
||||||
MyForm,
|
|
||||||
MyInput,
|
|
||||||
TextareaInput
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
username: "",
|
username: "",
|
||||||
@ -124,7 +115,7 @@ export default {
|
|||||||
title: {
|
title: {
|
||||||
label: "Titel",
|
label: "Titel",
|
||||||
required: true,
|
required: true,
|
||||||
element: MyInput,
|
element: "my-input",
|
||||||
props: {
|
props: {
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "Titel hier eintragen"
|
placeholder: "Titel hier eintragen"
|
||||||
@ -134,7 +125,7 @@ export default {
|
|||||||
label: "Permalink",
|
label: "Permalink",
|
||||||
description: "Hier steht ein Beschreibungstext für etwas begriffsstutzige Menschen, die eine Beschreibung zum Befüllen des Feldes brauchen.",
|
description: "Hier steht ein Beschreibungstext für etwas begriffsstutzige Menschen, die eine Beschreibung zum Befüllen des Feldes brauchen.",
|
||||||
required: true,
|
required: true,
|
||||||
element: MyInput,
|
element: "my-input",
|
||||||
props: {
|
props: {
|
||||||
type: "text",
|
type: "text",
|
||||||
placeholder: "Permalink"
|
placeholder: "Permalink"
|
||||||
@ -144,7 +135,7 @@ export default {
|
|||||||
label: "Inhalt",
|
label: "Inhalt",
|
||||||
description: "Hier steht ein Beschreibungstext für etwas begriffsstutzige Menschen, die eine Beschreibung zum Befüllen des Feldes brauchen.",
|
description: "Hier steht ein Beschreibungstext für etwas begriffsstutzige Menschen, die eine Beschreibung zum Befüllen des Feldes brauchen.",
|
||||||
required: true,
|
required: true,
|
||||||
element: TextareaInput,
|
element: "textarea-input",
|
||||||
props: {
|
props: {
|
||||||
placeholder: "Inhalt"
|
placeholder: "Inhalt"
|
||||||
}
|
}
|
||||||
@ -152,7 +143,7 @@ export default {
|
|||||||
public: {
|
public: {
|
||||||
label: "Is Public",
|
label: "Is Public",
|
||||||
required: true,
|
required: true,
|
||||||
element: MyInput,
|
element: "my-input",
|
||||||
props: {
|
props: {
|
||||||
type: "checkbox"
|
type: "checkbox"
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollTable from 'components/scroll-table.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Domainlist",
|
name: "Domainlist",
|
||||||
components: {
|
|
||||||
ScrollTable
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
actions: [{
|
actions: [{
|
||||||
|
@ -6,13 +6,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollTable from 'components/scroll-table.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Userlist",
|
name: "Userlist",
|
||||||
components: {
|
|
||||||
ScrollTable
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
actions: [{
|
actions: [{
|
||||||
|
@ -30,17 +30,25 @@ if (env === 'production') {
|
|||||||
|
|
||||||
// Main Settings config
|
// Main Settings config
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: [
|
entry: {
|
||||||
'intersection-observer',
|
lib: [
|
||||||
'babel-polyfill',
|
'intersection-observer',
|
||||||
entryPoint
|
'babel-polyfill',
|
||||||
],
|
'./src/lib/baseui.js'
|
||||||
|
],
|
||||||
|
main: [
|
||||||
|
'intersection-observer',
|
||||||
|
'babel-polyfill',
|
||||||
|
entryPoint
|
||||||
|
]
|
||||||
|
},
|
||||||
devtool: 'source-map',
|
devtool: 'source-map',
|
||||||
output: {
|
output: {
|
||||||
path: exportPath,
|
path: exportPath,
|
||||||
publicPath: 'build/',
|
publicPath: 'build/',
|
||||||
filename: '[name].bundle.js',
|
filename: 'baseui-[name].bundle.js',
|
||||||
chunkFilename: '[name].bundle.js'
|
library: 'baseUI',
|
||||||
|
libraryTarget: 'umd'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [{
|
loaders: [{
|
||||||
|
Loading…
Reference in New Issue
Block a user