Add local user account manual unlock

Adds ability to manually unlock user account if account
service settings lockout duration set to 0.

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I75351c5e03bd5403e8dc7679d8d98b90adb90277
diff --git a/src/components/Global/Alert.vue b/src/components/Global/Alert.vue
index bc65b6e..d59b25c 100644
--- a/src/components/Global/Alert.vue
+++ b/src/components/Global/Alert.vue
@@ -1,5 +1,5 @@
 <template>
-  <b-alert :show="show" :variant="variant">
+  <b-alert :show="show" :variant="variant" :class="{ small }">
     <div v-if="variant == 'warning' || variant == 'danger'" class="alert-icon">
       <status-icon :status="variant" />
     </div>
@@ -27,7 +27,15 @@
     variant: {
       type: String,
       default: ''
-    }
+    },
+    small: Boolean
   }
 };
 </script>
+
+<style lang="scss" scoped>
+.alert.small {
+  padding: $spacer / 2;
+  font-size: 1rem;
+}
+</style>
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index adc1185..19b2082 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -85,9 +85,11 @@
     "editUser": "Edit user",
     "viewPrivilegeRoleDescriptions": "View privilege role descriptions",
     "modal": {
+      "accountLocked": "Account locked",
       "accountStatus": "Account status",
       "automaticAfterTimeout": "Automatic after timeout",
       "cannotStartWithANumber": "Cannot start with a number",
+      "clickSaveToUnlockAccount": "Click \"Save\" to unlock account",
       "confirmUserPassword": "Confirm user password",
       "deleteConfirmMessage": "Are you sure you want to delete user '%{user}'? This action cannot be undone.",
       "manual": "Manual",
@@ -97,6 +99,7 @@
       "passwordsDoNotMatch": "Passwords do not match",
       "privilege": "Privilege",
       "timeoutDurationSeconds": "Timeout duration (seconds)",
+      "unlock": "Unlock",
       "username": "Username",
       "userPassword": "User password",
       "userUnlockMethod": "User unlock method"
diff --git a/src/store/modules/AccessControl/LocalUserMangementStore.js b/src/store/modules/AccessControl/LocalUserMangementStore.js
index ab314fb..c729d15 100644
--- a/src/store/modules/AccessControl/LocalUserMangementStore.js
+++ b/src/store/modules/AccessControl/LocalUserMangementStore.js
@@ -106,13 +106,14 @@
     },
     async updateUser(
       { dispatch },
-      { originalUsername, username, password, privilege, status }
+      { originalUsername, username, password, privilege, status, locked }
     ) {
       const data = {};
       if (username) data.UserName = username;
       if (password) data.Password = password;
       if (privilege) data.RoleId = privilege;
       if (status !== undefined) data.Enabled = status;
+      if (locked !== undefined) data.Locked = locked;
       return await api
         .patch(`/redfish/v1/AccountService/Accounts/${originalUsername}`, data)
         .then(() => dispatch('getUsers'))
diff --git a/src/views/AccessControl/LocalUserManagement/ModalUser.vue b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
index aacda11..a9c0f6c 100644
--- a/src/views/AccessControl/LocalUserManagement/ModalUser.vue
+++ b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
@@ -10,6 +10,31 @@
     </template>
     <b-form novalidate @submit="handleSubmit">
       <b-container>
+        <!-- Manual unlock form control -->
+        <b-row v-if="!newUser && manualUnlockPolicy && user.Locked">
+          <b-col sm="9">
+            <alert :show="true" variant="warning" small>
+              <template v-if="!$v.form.manualUnlock.$dirty">
+                {{ $t('pageLocalUserManagement.modal.accountLocked') }}
+              </template>
+              <template v-else>
+                {{
+                  $t('pageLocalUserManagement.modal.clickSaveToUnlockAccount')
+                }}
+              </template>
+            </alert>
+          </b-col>
+          <b-col sm="3">
+            <input v-model="form.manualUnlock" type="hidden" value="false" />
+            <b-button
+              variant="primary"
+              :disabled="$v.form.manualUnlock.$dirty"
+              @click="$v.form.manualUnlock.$touch()"
+            >
+              {{ $t('pageLocalUserManagement.modal.unlock') }}
+            </b-button>
+          </b-col>
+        </b-row>
         <b-row>
           <b-col>
             <b-form-group
@@ -183,9 +208,10 @@
 } from 'vuelidate/lib/validators';
 import VuelidateMixin from '../../../components/Mixins/VuelidateMixin.js';
 import InputPasswordToggle from '../../../components/Global/InputPasswordToggle';
+import Alert from '../../../components/Global/Alert';
 
 export default {
-  components: { InputPasswordToggle },
+  components: { Alert, InputPasswordToggle },
   mixins: [VuelidateMixin],
   props: {
     user: {
@@ -206,13 +232,20 @@
         username: '',
         privilege: '',
         password: '',
-        passwordConfirmation: ''
+        passwordConfirmation: '',
+        manualUnlock: false
       }
     };
   },
   computed: {
     newUser() {
       return this.user ? false : true;
+    },
+    accountSettings() {
+      return this.$store.getters['localUsers/accountSettings'];
+    },
+    manualUnlockPolicy() {
+      return !this.accountSettings.accountLockoutDuration;
     }
   },
   watch: {
@@ -250,7 +283,8 @@
             return this.requirePassword();
           }),
           sameAsPassword: sameAs('password')
-        }
+        },
+        manualUnlock: {}
       }
     };
   },
@@ -280,6 +314,11 @@
         if (this.$v.form.password.$dirty) {
           userData.password = this.form.password;
         }
+        if (this.$v.form.manualUnlock.$dirty) {
+          // If form manualUnlock control $dirty then
+          // set user Locked property to false
+          userData.locked = false;
+        }
         if (Object.entries(userData).length === 1) {
           this.closeModal();
           return;