summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.js2
-rw-r--r--src/store/api.js6
-rw-r--r--src/store/modules/Authentication/AuthenticanStore.js5
-rw-r--r--src/views/Login/Login.vue186
4 files changed, 145 insertions, 54 deletions
diff --git a/src/main.js b/src/main.js
index 023c24ec..b69c6591 100644
--- a/src/main.js
+++ b/src/main.js
@@ -4,6 +4,7 @@ import router from './router';
import store from './store';
import { dateFilter } from 'vue-date-fns';
import {
+ AlertPlugin,
BadgePlugin,
ButtonPlugin,
CollapsePlugin,
@@ -24,6 +25,7 @@ import {
Vue.filter('date', dateFilter);
+Vue.use(AlertPlugin);
Vue.use(BadgePlugin);
Vue.use(ButtonPlugin);
Vue.use(CollapsePlugin);
diff --git a/src/store/api.js b/src/store/api.js
index 4918d804..0f8c9484 100644
--- a/src/store/api.js
+++ b/src/store/api.js
@@ -10,12 +10,16 @@ api.interceptors.response.use(undefined, error => {
// TODO: Provide user with a notification and way to keep system active
if (response.status == 401) {
- window.location = '/login';
+ if (response.config.url != '/login') {
+ window.location = '/login';
+ }
}
if (response.status == 403) {
router.push({ name: 'unauthorized' });
}
+
+ return Promise.reject(error);
});
export default {
diff --git a/src/store/modules/Authentication/AuthenticanStore.js b/src/store/modules/Authentication/AuthenticanStore.js
index 88456e95..3a554b6b 100644
--- a/src/store/modules/Authentication/AuthenticanStore.js
+++ b/src/store/modules/Authentication/AuthenticanStore.js
@@ -13,7 +13,7 @@ const AuthenticationStore = {
},
mutations: {
authRequest(state) {
- state.status = 'loading';
+ state.status = 'processing';
},
authSuccess(state) {
state.status = 'authenticated';
@@ -22,6 +22,9 @@ const AuthenticationStore = {
authError(state) {
state.status = 'error';
},
+ authReset(state) {
+ state.status = '';
+ },
logout(state) {
state.status = '';
Cookies.remove('XSRF-TOKEN');
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index b6adf9eb..706d3ecc 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -1,67 +1,125 @@
<template>
- <b-container class="login-container" fluid>
- <b-row class="login-row" align-v="center">
- <b-col class="login-branding mt-5 mb-5" md="6">
- <div class="login-branding__container">
- <img
- class="logo"
- width="200px"
- src="@/assets/images/openbmc-logo.svg"
- alt=""
- />
- <h1>OpenBMC</h1>
- </div>
- </b-col>
-
- <b-col class="login-form" md="6">
- <b-form @submit.prevent="login">
- <b-form-group
- id="username-group"
- label="Username"
- label-for="username"
- >
- <b-form-input id="username" v-model="username" type="text" required>
- </b-form-input>
- </b-form-group>
-
- <b-form-group
- id="password-group"
- label="Password"
- label-for="password"
- >
- <b-form-input
- id="password"
- v-model="password"
- type="password"
- required
+ <main>
+ <b-container class="login-container" fluid>
+ <b-row class="login-row" align-v="center">
+ <b-col class="login-branding mt-5 mb-5" md="6">
+ <div class="login-branding__container">
+ <img
+ class="logo"
+ width="200px"
+ src="@/assets/images/openbmc-logo.svg"
+ alt=""
+ />
+ <h1>OpenBMC</h1>
+ </div>
+ </b-col>
+
+ <b-col md="6">
+ <b-form class="login-form" @submit.prevent="login" novalidate>
+ <b-alert
+ class="login-error"
+ v-if="authStatus == 'error'"
+ show
+ variant="danger"
+ >
+ <p id="login-error-alert">
+ <strong>{{ errorMsg.title }}</strong>
+ <span v-if="errorMsg.action">{{ errorMsg.action }}</span>
+ </p>
+ </b-alert>
+ <div class="login-form__section">
+ <label for="username">Username</label>
+ <b-form-input
+ id="username"
+ v-model="userInfo.username"
+ :aria-describedby="
+ authStatus == 'error' ? 'login-error-alert' : ''
+ "
+ type="text"
+ required
+ autofocus="autofocus"
+ >
+ </b-form-input>
+ </div>
+
+ <div class="login-form__section">
+ <label for="password">Password</label>
+ <b-form-input
+ id="password"
+ v-model="userInfo.password"
+ :aria-describedby="
+ authStatus == 'error' ? 'login-error-alert' : ''
+ "
+ type="password"
+ required
+ >
+ </b-form-input>
+ </div>
+
+ <b-button
+ type="submit"
+ variant="primary"
+ :disabled="authStatus == 'processing'"
+ >Log in</b-button
>
- </b-form-input>
- </b-form-group>
-
- <b-button type="submit" variant="primary">Login</b-button>
- </b-form>
- </b-col>
- </b-row>
- </b-container>
+ </b-form>
+ </b-col>
+ </b-row>
+ </b-container>
+ </main>
</template>
<script>
export default {
name: 'Login',
+ computed: {
+ authStatus() {
+ return this.$store.getters['authentication/authStatus'];
+ }
+ },
data() {
return {
- username: '',
- password: ''
+ errorMsg: {
+ title: null,
+ action: null
+ },
+ userInfo: {
+ username: null,
+ password: null
+ },
+ disableSubmitButton: false
};
},
methods: {
+ resetState: function() {
+ this.errorMsg.title = null;
+ this.errorMsg.action = null;
+ this.$store.commit('authentication/authReset');
+ },
+ validateRequiredFields: function() {
+ if (!this.userInfo.username || !this.userInfo.password) {
+ this.$store.commit('authentication/authError');
+ }
+ },
login: function() {
- const username = this.username;
- const password = this.password;
- this.$store
- .dispatch('authentication/login', [username, password])
- .then(() => this.$router.push('/'))
- .catch(error => console.log(error));
+ this.resetState();
+ this.validateRequiredFields();
+ if (this.authStatus !== 'error') {
+ const username = this.userInfo.username;
+ const password = this.userInfo.password;
+ this.$store
+ .dispatch('authentication/login', [username, password])
+ .then(() => {
+ this.$router.push('/');
+ })
+ .catch(error => {
+ this.errorMsg.title = 'Invalid username or password.';
+ this.errorMsg.action = 'Please try again.';
+ console.log(error);
+ });
+ } else {
+ this.errorMsg.title = 'Username and password required.';
+ }
}
}
};
@@ -95,7 +153,7 @@ export default {
}
}
-.login-form form {
+.login-form {
max-width: 360px;
margin-right: auto;
margin-left: auto;
@@ -105,6 +163,30 @@ export default {
}
}
+.login-form__section {
+ margin-bottom: $spacer;
+}
+
+.login-error {
+ margin-bottom: $spacer * 2;
+
+ p {
+ margin-bottom: 0;
+ }
+
+ strong {
+ display: block;
+ font-size: 1rem;
+ font-weight: 600;
+ margin-bottom: 0;
+ }
+
+ strong + span {
+ margin-top: $spacer / 2;
+ margin-bottom: 0;
+ }
+}
+
.login-branding {
text-align: center;
}