Create password visibility toggle

Reusable component to show/hide password input fields,
added to local user form.

Signed-off-by: Yoshie Muranaka <yoshiemuranaka@gmail.com>
Change-Id: I90fb865e51d99788a225812b057f4d8bacad1bc8
diff --git a/src/components/Global/InputPasswordToggle.vue b/src/components/Global/InputPasswordToggle.vue
new file mode 100644
index 0000000..8c52252
--- /dev/null
+++ b/src/components/Global/InputPasswordToggle.vue
@@ -0,0 +1,57 @@
+<template>
+  <div class="input-password-toggle-container">
+    <slot></slot>
+    <b-button
+      :aria-label="$t('ariaLabels.showPassword')"
+      variant="link"
+      :class="{ isVisible: isVisible }"
+      @click="toggleVisibility"
+    >
+      <icon-view-off v-if="isVisible" aria-hidden="true" />
+      <icon-view v-else aria-hidden="true" />
+    </b-button>
+  </div>
+</template>
+
+<script>
+import IconView from '@carbon/icons-vue/es/view/20';
+import IconViewOff from '@carbon/icons-vue/es/view--off/20';
+
+export default {
+  name: 'InputPasswordToggle',
+  components: { IconView, IconViewOff },
+  data() {
+    return {
+      isVisible: false
+    };
+  },
+  methods: {
+    toggleVisibility() {
+      const firstChild = this.$children[0];
+      const inputEl = firstChild ? firstChild.$el : null;
+
+      this.isVisible = !this.isVisible;
+
+      if (inputEl.nodeName === 'INPUT') {
+        inputEl.type = this.isVisible ? 'text' : 'password';
+      }
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.input-password-toggle-container {
+  position: relative;
+}
+
+.btn {
+  position: absolute;
+  right: 0;
+  top: 0;
+
+  svg {
+    margin-left: 0;
+  }
+}
+</style>
diff --git a/src/locales/en.json b/src/locales/en.json
index d866002..db3a87b 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -6,6 +6,9 @@
     "on": "on",
     "off": "off"
   },
+  "ariaLabels": {
+    "showPassword": "Show password as plain text. Note: this will visually expose your password on the screen."
+  },
   "login": {
     "language": {
       "label": "Language"
diff --git a/src/views/AccessControl/LocalUserManagement/ModalUser.vue b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
index d156c3d..448276b 100644
--- a/src/views/AccessControl/LocalUserManagement/ModalUser.vue
+++ b/src/views/AccessControl/LocalUserManagement/ModalUser.vue
@@ -77,48 +77,52 @@
                 <!-- TODO: Should be dynamic values -->
                 Password must between 8 – 20 characters
               </b-form-text>
-              <b-form-input
-                id="password"
-                v-model="form.password"
-                type="password"
-                aria-describedby="password-help-block"
-                :state="getValidationState($v.form.password)"
-                @input="$v.form.password.$touch()"
-              />
-              <b-form-invalid-feedback role="alert">
-                <template v-if="!$v.form.password.required">
-                  Field required
-                </template>
-                <template
-                  v-if="
-                    !$v.form.password.minLength || !$v.form.password.maxLength
-                  "
-                >
-                  Length must be between 8 – 20 characters
-                </template>
-              </b-form-invalid-feedback>
+              <input-password-toggle>
+                <b-form-input
+                  id="password"
+                  v-model="form.password"
+                  type="password"
+                  aria-describedby="password-help-block"
+                  :state="getValidationState($v.form.password)"
+                  @input="$v.form.password.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <template v-if="!$v.form.password.required">
+                    Field required
+                  </template>
+                  <template
+                    v-if="
+                      !$v.form.password.minLength || !$v.form.password.maxLength
+                    "
+                  >
+                    Length must be between 8 – 20 characters
+                  </template>
+                </b-form-invalid-feedback>
+              </input-password-toggle>
             </b-form-group>
             <b-form-group
               label="Confirm user password"
               label-for="password-confirmation"
             >
-              <b-form-input
-                id="password-confirmation"
-                v-model="form.passwordConfirmation"
-                type="password"
-                :state="getValidationState($v.form.passwordConfirmation)"
-                @input="$v.form.passwordConfirmation.$touch()"
-              />
-              <b-form-invalid-feedback role="alert">
-                <template v-if="!$v.form.passwordConfirmation.required">
-                  Field required
-                </template>
-                <template
-                  v-else-if="!$v.form.passwordConfirmation.sameAsPassword"
-                >
-                  Passwords do not match
-                </template>
-              </b-form-invalid-feedback>
+              <input-password-toggle>
+                <b-form-input
+                  id="password-confirmation"
+                  v-model="form.passwordConfirmation"
+                  type="password"
+                  :state="getValidationState($v.form.passwordConfirmation)"
+                  @input="$v.form.passwordConfirmation.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <template v-if="!$v.form.passwordConfirmation.required">
+                    Field required
+                  </template>
+                  <template
+                    v-else-if="!$v.form.passwordConfirmation.sameAsPassword"
+                  >
+                    Passwords do not match
+                  </template>
+                </b-form-invalid-feedback>
+              </input-password-toggle>
             </b-form-group>
           </b-col>
         </b-row>
@@ -145,8 +149,10 @@
   requiredIf
 } from 'vuelidate/lib/validators';
 import VuelidateMixin from '../../../components/Mixins/VuelidateMixin.js';
+import InputPasswordToggle from '../../../components/Global/InputPasswordToggle';
 
 export default {
+  components: { InputPasswordToggle },
   mixins: [VuelidateMixin],
   props: {
     user: {