Merge branch 'release/release'

This commit is contained in:
Tim Gröger 2019-12-21 08:47:01 +01:00
commit 94ec093a69
20 changed files with 594 additions and 100 deletions

112
package-lock.json generated
View File

@ -1989,6 +1989,48 @@
"integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==",
"dev": true
},
"axios": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz",
"integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==",
"dev": true,
"requires": {
"follow-redirects": "1.5.10",
"is-buffer": "^2.0.2"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"dev": true,
"requires": {
"debug": "=3.1.0"
}
},
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
"dev": true
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
"babel-eslint": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz",
@ -2869,6 +2911,17 @@
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
"dev": true
},
"clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
"integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
"dev": true,
"requires": {
"is-plain-object": "^2.0.4",
"kind-of": "^6.0.2",
"shallow-clone": "^3.0.0"
}
},
"coa": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
@ -6914,6 +6967,12 @@
"object-visit": "^1.0.0"
}
},
"material-design-icons-iconfont": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-5.0.1.tgz",
"integrity": "sha512-Xg6rIdGrfySTqiTZ6d+nQbcFepS6R4uKbJP0oAqyeZXJY/bX6mZDnOmmUJusqLXfhIwirs0c++a6JpqVa8RFvA==",
"dev": true
},
"md5.js": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@ -9183,6 +9242,36 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"sass": {
"version": "1.23.7",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.23.7.tgz",
"integrity": "sha512-cYgc0fanwIpi0rXisGxl+/wadVQ/HX3RhpdRcjLdj2o2ye/sxUTpAxIhbmJy3PLQgRFbf6Pn8Jsrta2vdXcoOQ==",
"dev": true,
"requires": {
"chokidar": ">=2.0.0 <4.0.0"
}
},
"sass-loader": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-8.0.0.tgz",
"integrity": "sha512-+qeMu563PN7rPdit2+n5uuYVR0SSVwm0JsOUsaJXzgYcClWSlmX0iHDnmeOobPkf5kUglVot3QS6SyLyaQoJ4w==",
"dev": true,
"requires": {
"clone-deep": "^4.0.1",
"loader-utils": "^1.2.3",
"neo-async": "^2.6.1",
"schema-utils": "^2.1.0",
"semver": "^6.3.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@ -9397,6 +9486,15 @@
"safe-buffer": "^5.0.1"
}
},
"shallow-clone": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
"integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
"dev": true,
"requires": {
"kind-of": "^6.0.2"
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -10813,6 +10911,20 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true
},
"vuetify": {
"version": "2.1.15",
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.1.15.tgz",
"integrity": "sha512-M35NJvlzkbCpFfsK08xraNvCpiNCIbYUXI/hkzjWHQV1MFIZnjrDTVtYoiudCyJ52zlrhWezAr4pzFOCLAr6RA=="
},
"vuetify-loader": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/vuetify-loader/-/vuetify-loader-1.4.3.tgz",
"integrity": "sha512-fS0wRil682Ebsj2as+eruBoMPKaQYDhu/fDAndnTItzSY4RK4LOEIsssVL4vD6QY8dvUgoGL84SUQ6vGr777CA==",
"dev": true,
"requires": {
"loader-utils": "^1.2.0"
}
},
"vuex": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.2.tgz",

View File

@ -11,6 +11,7 @@
"core-js": "^3.4.3",
"vue": "^2.6.10",
"vue-router": "^3.1.3",
"vuetify": "^2.1.0",
"vuex": "^3.1.2"
},
"devDependencies": {
@ -19,11 +20,16 @@
"@vue/cli-plugin-router": "^4.1.1",
"@vue/cli-plugin-vuex": "^4.1.1",
"@vue/cli-service": "^4.1.0",
"axios": "^0.19.0",
"babel-eslint": "^10.0.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"material-design-icons-iconfont": "^5.0.1",
"sass": "^1.19.0",
"sass-loader": "^8.0.0",
"vue-cli-plugin-vuetify": "^2.0.2",
"vue-template-compiler": "^2.6.10"
"vue-template-compiler": "^2.6.10",
"vuetify-loader": "^1.3.0"
},
"eslintConfig": {
"root": true,

View File

@ -6,6 +6,8 @@
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>newgruecht-vue</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
</head>
<body>
<noscript>

View File

@ -1,32 +1,19 @@
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<v-app>
<router-view/>
</div>
</v-app>
</template>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
<script>
#nav {
padding: 30px;
}
export default {
name: 'App',
#nav a {
font-weight: bold;
color: #2c3e50;
}
components: {
},
#nav a.router-link-exact-active {
color: #42b983;
}
</style>
data: () => ({
//
}),
};
</script>

BIN
src/assets/logo-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

1
src/assets/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>

After

Width:  |  Height:  |  Size: 539 B

BIN
src/assets/logo_256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,58 +0,0 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<v-app-bar
app
flat
clipped-left
absolute
color="blue accent-4"
class="elevation-4"
dark>
<v-btn icon>
<v-img src="@/assets/logo-big.png" contain height="40"></v-img>
</v-btn>
<v-toolbar-title>WU5-Dashboard</v-toolbar-title>
<v-spacer/>
<v-btn icon v-if="isFinanzer">
<v-icon>local_bar</v-icon>
</v-btn>
<v-btn v-if="isLoggedIn" @click="logout">Logout</v-btn>
</v-app-bar>
</template>
<script>
import {mapActions} from "vuex";
export default {
name: "TitleBar",
computed: {
isFinanzer() {
return this.$store.getters.getGroup === 'moneymaster' ? true : false
},
isLoggedIn() {
return this.$store.getters.getToken
}
},
methods: {
...mapActions([
'logout'
])
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,58 @@
<template>
<v-content>
<v-container>
<v-card raised shaped>
<v-container>
<v-row>
<v-col align-self="center">
<v-container>
<v-btn>Col 1</v-btn>
</v-container>
</v-col>
<v-row>
<v-col>
<v-row>
<v-container>
<v-btn>Col 2.1.1</v-btn>
</v-container>
</v-row>
<v-row>
<v-container>
<v-btn>Col 2.1.2</v-btn>
</v-container>
</v-row>
</v-col>
<v-col>
<v-row>
<v-btn>Col 2.2.1</v-btn>
</v-row>
<v-row>
<v-btn>Col 2.2.2</v-btn>
</v-row>
</v-col>
<v-col>
<v-row>
<v-btn>Col 2.3.1</v-btn>
</v-row>
<v-row>
<v-btn>Col 2.3.2</v-btn>
</v-row>
</v-col>
</v-row>
<v-col><v-btn>Col 3</v-btn></v-col>
</v-row>
</v-container>
</v-card>
</v-container>
</v-content>
</template>
<script>
export default {
name: "CreditLists"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,16 @@
<template>
<v-data-table></v-data-table>
</template>
<script>
export default {
name: "Overview",
props: {
year: null
}
}
</script>
<style scoped>
</style>

View File

@ -2,11 +2,13 @@ import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify';
Vue.config.productionTip = false
new Vue({
router,
store,
vuetify,
render: h => h(App)
}).$mount('#app')

11
src/plugins/vuetify.js Normal file
View File

@ -0,0 +1,11 @@
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import 'material-design-icons-iconfont'
Vue.use(Vuetify);
export default new Vuetify({
icons: {
iconfont: 'md',
}
});

View File

@ -1,27 +1,57 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import FinanzerView from "@/views/FinanzerView";
import Login from "@/views/Login";
import store from "@/store/index";
import BarView from "@/views/BarView";
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
path: "/login",
name: "login",
component: Login
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
path: "/finanzer",
name: "finanzer",
component: FinanzerView
},
{
path: "/bar",
name: "bar",
component: BarView
},
{
path: '*',
redirect: {
name: "login"
}
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
store.dispatch('fetchAccessToken');
if (to.fullPath === '/finanzer') {
if (!store.state.user.accessToken) {
next('/login')
}
}
if (to.fullPath === '/login') {
if (store.state.user.accessToken) {
next('/finanzer')
}
}
next();
});
export default router

View File

@ -1,15 +1,97 @@
import Vue from 'vue'
import Vuex from 'vuex'
import router from "@/router";
import axios from 'axios'
Vue.use(Vuex)
const url = 'http://localhost:5000/'
export default new Vuex.Store({
state: {
user: {
username: null,
accessToken: null,
group: null
},
loggingIn: false,
loginError: null
},
mutations: {
loginStart: state => state.loggingIn = true,
loginStop (state, errorMessage){
state.loggingIn = false;
state.loginError = errorMessage;
},
updateAccessToken (state, data) {
// eslint-disable-next-line no-console
if (typeof(data) === typeof("")) {
data = JSON.parse(data)
}
// eslint-disable-next-line no-console
console.log("updateAccessToken data:", typeof (data), data)
if (data === null || data === undefined) {
state.user.username = null;
state.user.accessToken = null;
state.user.group = null;
} else {
this.state.user.username = data.username;
state.user.accessToken = data.accessToken;
state.user.group = data.group;
// eslint-disable-next-line no-console
console.log("state: ", state.user)
}
},
logout (state) {
state.user.accessToken = null;
state.user.username = null;
state.user.group = null;
}
},
actions: {
},
modules: {
doLogin({ commit }, loginData) {
// eslint-disable-next-line no-console
console.log("loginData:", loginData)
commit('loginStart');
axios.post(url+'login', {...loginData})
.then(response => {
localStorage.setItem('user', JSON.stringify({ username: response.data.username, accessToken: response.data.token, group: response.data.group}));
commit('loginStop', null);
commit('updateAccessToken', response.data)
if (this.state.user.group === 'moneymaster') {
router.push('/finanzer');
}
if (this.state.user.group === 'bar') {
router.push('/bar')
}
})
.catch(error => {
commit('loginStop', error.response.data.error)
commit('updateAccessToken', {username: null, accessToken: null, group: null})
})
},
fetchAccessToken({ commit }) {
// eslint-disable-next-line no-console
console.log("localStorage: ", localStorage.getItem('user'))
commit('updateAccessToken', localStorage.getItem('user'))
},
logout({ commit }) {
localStorage.removeItem('user');
commit('logout');
router.push('/login');
},
resetLoginError({ commit }) {
commit("loginStop")
}
},
modules: {
},
getters: {
getGroup: state => {
return state.user.group
},
getToken: state => {
return state.user.accessToken
}
}
})

38
src/views/BarView.vue Normal file
View File

@ -0,0 +1,38 @@
<template>
<div>
<TitleBar/>
<CreditLists></CreditLists>
</div>
</template>
<script>
import TitleBar from "@/components/TitleBar";
import axios from 'axios'
import CreditLists from "@/components/baruser/CreditLists";
export default {
name: "BarView",
components: {CreditLists, TitleBar},
created() {
this.getUser()
},
methods: {
getUser() {
// eslint-disable-next-line no-console
console.log(this.$store.getters.getToken)
axios.get("http://localhost:5000/bar", {headers: {Token: this.$store.getters.getToken}})
.then(response => {
// eslint-disable-next-line no-console
console.log(response.data)
})
.catch(error => {
// eslint-disable-next-line no-console
console.log(error)
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,61 @@
<template>
<div>
<TitleBar/>
<v-navigation-drawer permanent width="auto" app clipped class="elevation-2">
<v-container>
<h1 v-for="user in users" v-bind:key="user.id">{{user.firstname}} {{user.lastname}}</h1>
</v-container>
</v-navigation-drawer>
<v-content>
<v-container>
</v-container>
</v-content>
</div>
</template>
<script>
import TitleBar from "@/components/TitleBar";
import axios from 'axios'
export default {
name: "FinanzerView",
components: {TitleBar},
created() {
this.getUser()
},
data () {
return {
users: [],
}
},
methods: {
getUser() {
axios.get("http://localhost:5000/getFinanzerMain", {headers: {Token: this.$store.getters.getToken}})
.then(response => {
// eslint-disable-next-line no-console
console.log(response.data)
for (let user in response.data) {
// eslint-disable-next-line no-console
console.log(response.data[user])
const lastId = this.users.length > 0 ? this.users[this.users.length - 1].id : 0
this.users.push({id: lastId + 1, username: response.data[user].username, firstname: response.data[user].firstname, lastname: response.data[user].lastname})
}
// eslint-disable-next-line no-console
console.log(this.users)
})
.catch(error => {
// eslint-disable-next-line no-console
console.log("error: ", error.response.data.error)
})
},
}
}
</script>
<style scoped>
</style>

View File

@ -1,18 +1,17 @@
<template>
<div class="home">
<img alt="Vue logo" src="../assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<div>
<TitleBar/>
</div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
import TitleBar from "@/components/TitleBar";
export default {
name: 'home',
components: {
HelloWorld
TitleBar
}
}
</script>

96
src/views/Login.vue Normal file
View File

@ -0,0 +1,96 @@
<template>
<div>
<TitleBar/>
<v-content>
<v-container
class="fill-height"
fluid
>
<v-row
align="center"
justify="center"
>
<v-col
cols="12"
sm="8"
md="4"
>
<v-card class="elevation-12">
<v-toolbar
color="blue accent-4"
dark
flat
>
<v-toolbar-title>Login form</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text>
<v-form >
<v-text-field
label="Login"
name="login"
prepend-icon="person"
type="text"
v-model="username"
ref="first"
@keyup.enter="login"
@change="resetError"
/>
<v-text-field
id="password"
label="Password"
name="password"
prepend-icon="lock"
type="password"
v-model="password"
@keyup.enter="login"
@change="resetError"
/>
</v-form>
</v-card-text>
<v-alert v-if="loginFail" dense type="error">{{ loginFail }}</v-alert>
<v-card-actions>
<v-spacer />
<v-btn @click="login" @submit.prevent="login" color="primary">Login</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</v-content>
</div>
</template>
<script>
import TitleBar from "@/components/TitleBar";
export default {
name: "Login",
components: {TitleBar},
data() {
return {
username: null,
password: null
}
},
methods: {
login() {
// eslint-disable-next-line no-console
let o = {username: this.username, password: this.password}
this.$store.dispatch("doLogin", o)
},
resetError() {
this.$store.dispatch("resetLoginError")
}
},
computed: {
loginFail() {
return this.$store.state.loginError
}
}
}
</script>
<style scoped>
</style>

5
vue.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
"transpileDependencies": [
"vuetify"
]
}