xref: /openbmc/webui-vue/src/views/Login/Login.vue (revision aae4312c)
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