1<template> 2 <main> 3 <b-container class="login-container" fluid> 4 <b-row class="login-row" align-v="center"> 5 <b-col class="login-branding mt-5 mb-5" md="6"> 6 <div class="login-branding__container"> 7 <img 8 class="logo" 9 width="200px" 10 src="@/assets/images/openbmc-logo.svg" 11 alt="" 12 /> 13 <h1>OpenBMC</h1> 14 </div> 15 </b-col> 16 17 <b-col md="6"> 18 <b-form class="login-form" @submit.prevent="login" novalidate> 19 <b-alert 20 class="login-error" 21 v-if="authStatus == 'error'" 22 show 23 variant="danger" 24 > 25 <p id="login-error-alert"> 26 <strong>{{ errorMsg.title }}</strong> 27 <span v-if="errorMsg.action">{{ errorMsg.action }}</span> 28 </p> 29 </b-alert> 30 <div class="login-form__section"> 31 <label for="username">Username</label> 32 <b-form-input 33 id="username" 34 v-model="userInfo.username" 35 :aria-describedby=" 36 authStatus == 'error' ? 'login-error-alert' : '' 37 " 38 type="text" 39 required 40 autofocus="autofocus" 41 > 42 </b-form-input> 43 </div> 44 45 <div class="login-form__section"> 46 <label for="password">Password</label> 47 <b-form-input 48 id="password" 49 v-model="userInfo.password" 50 :aria-describedby=" 51 authStatus == 'error' ? 'login-error-alert' : '' 52 " 53 type="password" 54 required 55 > 56 </b-form-input> 57 </div> 58 59 <b-button 60 type="submit" 61 variant="primary" 62 :disabled="authStatus == 'processing'" 63 >Log in</b-button 64 > 65 </b-form> 66 </b-col> 67 </b-row> 68 </b-container> 69 </main> 70</template> 71 72<script> 73export default { 74 name: 'Login', 75 computed: { 76 authStatus() { 77 return this.$store.getters['authentication/authStatus']; 78 } 79 }, 80 data() { 81 return { 82 errorMsg: { 83 title: null, 84 action: null 85 }, 86 userInfo: { 87 username: null, 88 password: null 89 }, 90 disableSubmitButton: false 91 }; 92 }, 93 methods: { 94 resetState: function() { 95 this.errorMsg.title = null; 96 this.errorMsg.action = null; 97 this.$store.commit('authentication/authReset'); 98 }, 99 validateRequiredFields: function() { 100 if (!this.userInfo.username || !this.userInfo.password) { 101 this.$store.commit('authentication/authError'); 102 } 103 }, 104 login: function() { 105 this.resetState(); 106 this.validateRequiredFields(); 107 if (this.authStatus !== 'error') { 108 const username = this.userInfo.username; 109 const password = this.userInfo.password; 110 this.$store 111 .dispatch('authentication/login', [username, password]) 112 .then(() => { 113 this.$router.push('/'); 114 }) 115 .catch(error => { 116 this.errorMsg.title = 'Invalid username or password.'; 117 this.errorMsg.action = 'Please try again.'; 118 console.log(error); 119 }); 120 } else { 121 this.errorMsg.title = 'Username and password required.'; 122 } 123 } 124 } 125}; 126</script> 127 128<style lang="scss" scoped> 129@import '~bootstrap/scss/functions'; 130@import '~bootstrap/scss/variables'; 131@import '~bootstrap/scss/mixins'; 132 133.login-container { 134 @include media-breakpoint-up(md) { 135 background: linear-gradient( 136 to right, 137 var(--light) 50%, 138 var(--secondary-light) 50% 139 ); 140 } 141} 142 143.login-row { 144 @include media-breakpoint-up(md) { 145 min-height: 100vh; 146 } 147} 148 149.login-branding__container { 150 @include media-breakpoint-up(md) { 151 float: right; 152 margin-right: 4rem; 153 } 154} 155 156.login-form { 157 max-width: 360px; 158 margin-right: auto; 159 margin-left: auto; 160 161 @include media-breakpoint-up(md) { 162 margin-left: 4rem; 163 } 164} 165 166.login-form__section { 167 margin-bottom: $spacer; 168} 169 170.login-error { 171 margin-bottom: $spacer * 2; 172 173 p { 174 margin-bottom: 0; 175 } 176 177 strong { 178 display: block; 179 font-size: 1rem; 180 font-weight: 600; 181 margin-bottom: 0; 182 } 183 184 strong + span { 185 margin-top: $spacer / 2; 186 margin-bottom: 0; 187 } 188} 189 190.login-branding { 191 text-align: center; 192} 193</style> 194