IA update: Update access and control section

This is the fifth commit of the information architecture changes and
has the following changes:

- The icon for access and control has been updated
- Access and control section has been updated to security and
access section
- Security settings page has been updated to policies page and moved to
security and access section
- Client sessions page has been updated to sessions page
- Local user management page has been updated to user management page
- SSL certificates page has been updated to certificates page

Signed-off-by: Sandeepa Singh <sandeepa.singh@ibm.com>
Change-Id: Ie93cee9002742ecf7d33615636f4f159f4395fc4
diff --git a/src/views/SecurityAndAccess/UserManagement/ModalSettings.vue b/src/views/SecurityAndAccess/UserManagement/ModalSettings.vue
new file mode 100644
index 0000000..0f05123
--- /dev/null
+++ b/src/views/SecurityAndAccess/UserManagement/ModalSettings.vue
@@ -0,0 +1,215 @@
+<template>
+  <b-modal
+    id="modal-settings"
+    ref="modal"
+    :title="$t('pageUserManagement.accountPolicySettings')"
+    @hidden="resetForm"
+  >
+    <b-form id="form-settings" novalidate @submit.prevent="handleSubmit">
+      <b-container>
+        <b-row>
+          <b-col>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.maxFailedLoginAttempts')"
+              label-for="lockout-threshold"
+            >
+              <b-form-text id="lockout-threshold-help-block">
+                {{
+                  $t('global.form.valueMustBeBetween', {
+                    min: 0,
+                    max: 65535,
+                  })
+                }}
+              </b-form-text>
+              <b-form-input
+                id="lockout-threshold"
+                v-model.number="form.lockoutThreshold"
+                type="number"
+                aria-describedby="lockout-threshold-help-block"
+                data-test-id="userManagement-input-lockoutThreshold"
+                :state="getValidationState($v.form.lockoutThreshold)"
+                @input="$v.form.lockoutThreshold.$touch()"
+              />
+              <b-form-invalid-feedback role="alert">
+                <template v-if="!$v.form.lockoutThreshold.required">
+                  {{ $t('global.form.fieldRequired') }}
+                </template>
+                <template
+                  v-if="
+                    !$v.form.lockoutThreshold.minLength ||
+                    !$v.form.lockoutThreshold.maxLength
+                  "
+                >
+                  {{
+                    $t('global.form.valueMustBeBetween', {
+                      min: 0,
+                      max: 65535,
+                    })
+                  }}
+                </template>
+              </b-form-invalid-feedback>
+            </b-form-group>
+          </b-col>
+          <b-col>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.userUnlockMethod')"
+            >
+              <b-form-radio
+                v-model="form.unlockMethod"
+                name="unlock-method"
+                class="mb-2"
+                :value="0"
+                data-test-id="userManagement-radio-manualUnlock"
+                @input="$v.form.unlockMethod.$touch()"
+              >
+                {{ $t('pageUserManagement.modal.manual') }}
+              </b-form-radio>
+              <b-form-radio
+                v-model="form.unlockMethod"
+                name="unlock-method"
+                :value="1"
+                data-test-id="userManagement-radio-automaticUnlock"
+                @input="$v.form.unlockMethod.$touch()"
+              >
+                {{ $t('pageUserManagement.modal.automaticAfterTimeout') }}
+              </b-form-radio>
+              <div class="mt-3 ml-4">
+                <b-form-text id="lockout-duration-help-block">
+                  {{ $t('pageUserManagement.modal.timeoutDurationSeconds') }}
+                </b-form-text>
+                <b-form-input
+                  v-model.number="form.lockoutDuration"
+                  aria-describedby="lockout-duration-help-block"
+                  type="number"
+                  data-test-id="userManagement-input-lockoutDuration"
+                  :state="getValidationState($v.form.lockoutDuration)"
+                  :readonly="$v.form.unlockMethod.$model === 0"
+                  @input="$v.form.lockoutDuration.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <template v-if="!$v.form.lockoutDuration.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </template>
+                  <template v-else-if="!$v.form.lockoutDuration.minvalue">
+                    {{ $t('global.form.mustBeAtLeast', { value: 1 }) }}
+                  </template>
+                </b-form-invalid-feedback>
+              </div>
+            </b-form-group>
+          </b-col>
+        </b-row>
+      </b-container>
+    </b-form>
+    <template #modal-footer="{ cancel }">
+      <b-button
+        variant="secondary"
+        data-test-id="userManagement-button-cancel"
+        @click="cancel()"
+      >
+        {{ $t('global.action.cancel') }}
+      </b-button>
+      <b-button
+        form="form-settings"
+        type="submit"
+        variant="primary"
+        data-test-id="userManagement-button-submit"
+        @click="onOk"
+      >
+        {{ $t('global.action.save') }}
+      </b-button>
+    </template>
+  </b-modal>
+</template>
+
+<script>
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
+import {
+  required,
+  requiredIf,
+  minValue,
+  maxValue,
+} from 'vuelidate/lib/validators';
+
+export default {
+  mixins: [VuelidateMixin],
+  props: {
+    settings: {
+      type: Object,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      form: {
+        lockoutThreshold: 0,
+        unlockMethod: 0,
+        lockoutDuration: null,
+      },
+    };
+  },
+  watch: {
+    settings: function ({ lockoutThreshold, lockoutDuration }) {
+      this.form.lockoutThreshold = lockoutThreshold;
+      this.form.unlockMethod = lockoutDuration ? 1 : 0;
+      this.form.lockoutDuration = lockoutDuration ? lockoutDuration : null;
+    },
+  },
+  validations: {
+    form: {
+      lockoutThreshold: {
+        minValue: minValue(0),
+        maxValue: maxValue(65535),
+        required,
+      },
+      unlockMethod: { required },
+      lockoutDuration: {
+        minValue: function (value) {
+          return this.form.unlockMethod === 0 || value > 0;
+        },
+        required: requiredIf(function () {
+          return this.form.unlockMethod === 1;
+        }),
+      },
+    },
+  },
+  methods: {
+    handleSubmit() {
+      this.$v.$touch();
+      if (this.$v.$invalid) return;
+
+      let lockoutThreshold;
+      let lockoutDuration;
+      if (this.$v.form.lockoutThreshold.$dirty) {
+        lockoutThreshold = this.form.lockoutThreshold;
+      }
+      if (this.$v.form.unlockMethod.$dirty) {
+        lockoutDuration = this.form.unlockMethod
+          ? this.form.lockoutDuration
+          : 0;
+      }
+
+      this.$emit('ok', { lockoutThreshold, lockoutDuration });
+      this.closeModal();
+    },
+    onOk(bvModalEvt) {
+      // prevent modal close
+      bvModalEvt.preventDefault();
+      this.handleSubmit();
+    },
+    closeModal() {
+      this.$nextTick(() => {
+        this.$refs.modal.hide();
+      });
+    },
+    resetForm() {
+      // Reset form models
+      this.form.lockoutThreshold = this.settings.lockoutThreshold;
+      this.form.unlockMethod = this.settings.lockoutDuration ? 1 : 0;
+      this.form.lockoutDuration = this.settings.lockoutDuration
+        ? this.settings.lockoutDuration
+        : null;
+      this.$v.$reset(); // clear validations
+    },
+  },
+};
+</script>
diff --git a/src/views/SecurityAndAccess/UserManagement/ModalUser.vue b/src/views/SecurityAndAccess/UserManagement/ModalUser.vue
new file mode 100644
index 0000000..0f8757c
--- /dev/null
+++ b/src/views/SecurityAndAccess/UserManagement/ModalUser.vue
@@ -0,0 +1,386 @@
+<template>
+  <b-modal id="modal-user" ref="modal" @hidden="resetForm">
+    <template #modal-title>
+      <template v-if="newUser">
+        {{ $t('pageUserManagement.addUser') }}
+      </template>
+      <template v-else>
+        {{ $t('pageUserManagement.editUser') }}
+      </template>
+    </template>
+    <b-form id="form-user" novalidate @submit.prevent="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('pageUserManagement.modal.accountLocked') }}
+              </template>
+              <template v-else>
+                {{ $t('pageUserManagement.modal.clickSaveToUnlockAccount') }}
+              </template>
+            </alert>
+          </b-col>
+          <b-col sm="3">
+            <input
+              v-model="form.manualUnlock"
+              data-test-id="userManagement-input-manualUnlock"
+              type="hidden"
+              value="false"
+            />
+            <b-button
+              variant="primary"
+              :disabled="$v.form.manualUnlock.$dirty"
+              data-test-id="userManagement-button-manualUnlock"
+              @click="$v.form.manualUnlock.$touch()"
+            >
+              {{ $t('pageUserManagement.modal.unlock') }}
+            </b-button>
+          </b-col>
+        </b-row>
+        <b-row>
+          <b-col>
+            <b-form-group :label="$t('pageUserManagement.modal.accountStatus')">
+              <b-form-radio
+                v-model="form.status"
+                name="user-status"
+                :value="true"
+                data-test-id="userManagement-radioButton-statusEnabled"
+                @input="$v.form.status.$touch()"
+              >
+                {{ $t('global.status.enabled') }}
+              </b-form-radio>
+              <b-form-radio
+                v-model="form.status"
+                name="user-status"
+                data-test-id="userManagement-radioButton-statusDisabled"
+                :value="false"
+                @input="$v.form.status.$touch()"
+              >
+                {{ $t('global.status.disabled') }}
+              </b-form-radio>
+            </b-form-group>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.username')"
+              label-for="username"
+            >
+              <b-form-text id="username-help-block">
+                {{ $t('pageUserManagement.modal.cannotStartWithANumber') }}
+                <br />
+                {{
+                  $t(
+                    'pageUserManagement.modal.noSpecialCharactersExceptUnderscore'
+                  )
+                }}
+              </b-form-text>
+              <b-form-input
+                id="username"
+                v-model="form.username"
+                type="text"
+                aria-describedby="username-help-block"
+                data-test-id="userManagement-input-username"
+                :state="getValidationState($v.form.username)"
+                :disabled="!newUser && originalUsername === 'root'"
+                @input="$v.form.username.$touch()"
+              />
+              <b-form-invalid-feedback role="alert">
+                <template v-if="!$v.form.username.required">
+                  {{ $t('global.form.fieldRequired') }}
+                </template>
+                <template v-else-if="!$v.form.username.maxLength">
+                  {{
+                    $t('global.form.lengthMustBeBetween', { min: 1, max: 16 })
+                  }}
+                </template>
+                <template v-else-if="!$v.form.username.pattern">
+                  {{ $t('global.form.invalidFormat') }}
+                </template>
+              </b-form-invalid-feedback>
+            </b-form-group>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.privilege')"
+              label-for="privilege"
+            >
+              <b-form-select
+                id="privilege"
+                v-model="form.privilege"
+                :options="privilegeTypes"
+                data-test-id="userManagement-select-privilege"
+                :state="getValidationState($v.form.privilege)"
+                @input="$v.form.privilege.$touch()"
+              >
+                <template #first>
+                  <b-form-select-option :value="null" disabled>
+                    {{ $t('global.form.selectAnOption') }}
+                  </b-form-select-option>
+                </template>
+              </b-form-select>
+              <b-form-invalid-feedback role="alert">
+                <template v-if="!$v.form.privilege.required">
+                  {{ $t('global.form.fieldRequired') }}
+                </template>
+              </b-form-invalid-feedback>
+            </b-form-group>
+          </b-col>
+          <b-col>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.userPassword')"
+              label-for="password"
+            >
+              <b-form-text id="password-help-block">
+                {{
+                  $t('pageUserManagement.modal.passwordMustBeBetween', {
+                    min: passwordRequirements.minLength,
+                    max: passwordRequirements.maxLength,
+                  })
+                }}
+              </b-form-text>
+              <input-password-toggle>
+                <b-form-input
+                  id="password"
+                  v-model="form.password"
+                  type="password"
+                  data-test-id="userManagement-input-password"
+                  aria-describedby="password-help-block"
+                  :state="getValidationState($v.form.password)"
+                  class="form-control-with-button"
+                  @input="$v.form.password.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <template v-if="!$v.form.password.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </template>
+                  <template
+                    v-if="
+                      !$v.form.password.minLength || !$v.form.password.maxLength
+                    "
+                  >
+                    {{
+                      $t('pageUserManagement.modal.passwordMustBeBetween', {
+                        min: passwordRequirements.minLength,
+                        max: passwordRequirements.maxLength,
+                      })
+                    }}
+                  </template>
+                </b-form-invalid-feedback>
+              </input-password-toggle>
+            </b-form-group>
+            <b-form-group
+              :label="$t('pageUserManagement.modal.confirmUserPassword')"
+              label-for="password-confirmation"
+            >
+              <input-password-toggle>
+                <b-form-input
+                  id="password-confirmation"
+                  v-model="form.passwordConfirmation"
+                  data-test-id="userManagement-input-passwordConfirmation"
+                  type="password"
+                  :state="getValidationState($v.form.passwordConfirmation)"
+                  class="form-control-with-button"
+                  @input="$v.form.passwordConfirmation.$touch()"
+                />
+                <b-form-invalid-feedback role="alert">
+                  <template v-if="!$v.form.passwordConfirmation.required">
+                    {{ $t('global.form.fieldRequired') }}
+                  </template>
+                  <template
+                    v-else-if="!$v.form.passwordConfirmation.sameAsPassword"
+                  >
+                    {{ $t('pageUserManagement.modal.passwordsDoNotMatch') }}
+                  </template>
+                </b-form-invalid-feedback>
+              </input-password-toggle>
+            </b-form-group>
+          </b-col>
+        </b-row>
+      </b-container>
+    </b-form>
+    <template #modal-footer="{ cancel }">
+      <b-button
+        variant="secondary"
+        data-test-id="userManagement-button-cancel"
+        @click="cancel()"
+      >
+        {{ $t('global.action.cancel') }}
+      </b-button>
+      <b-button
+        form="form-user"
+        data-test-id="userManagement-button-submit"
+        type="submit"
+        variant="primary"
+        @click="onOk"
+      >
+        <template v-if="newUser">
+          {{ $t('pageUserManagement.addUser') }}
+        </template>
+        <template v-else>
+          {{ $t('global.action.save') }}
+        </template>
+      </b-button>
+    </template>
+  </b-modal>
+</template>
+
+<script>
+import {
+  required,
+  maxLength,
+  minLength,
+  sameAs,
+  helpers,
+  requiredIf,
+} 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: { Alert, InputPasswordToggle },
+  mixins: [VuelidateMixin],
+  props: {
+    user: {
+      type: Object,
+      default: null,
+    },
+    passwordRequirements: {
+      type: Object,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      originalUsername: '',
+      form: {
+        status: true,
+        username: '',
+        privilege: null,
+        password: '',
+        passwordConfirmation: '',
+        manualUnlock: false,
+      },
+    };
+  },
+  computed: {
+    newUser() {
+      return this.user ? false : true;
+    },
+    accountSettings() {
+      return this.$store.getters['userManagement/accountSettings'];
+    },
+    manualUnlockPolicy() {
+      return !this.accountSettings.accountLockoutDuration;
+    },
+    privilegeTypes() {
+      return this.$store.getters['userManagement/accountRoles'];
+    },
+  },
+  watch: {
+    user: function (value) {
+      if (value === null) return;
+      this.originalUsername = value.username;
+      this.form.username = value.username;
+      this.form.status = value.Enabled;
+      this.form.privilege = value.privilege;
+    },
+  },
+  validations() {
+    return {
+      form: {
+        status: {
+          required,
+        },
+        username: {
+          required,
+          maxLength: maxLength(16),
+          pattern: helpers.regex('pattern', /^([a-zA-Z_][a-zA-Z0-9_]*)/),
+        },
+        privilege: {
+          required,
+        },
+        password: {
+          required: requiredIf(function () {
+            return this.requirePassword();
+          }),
+          minLength: minLength(this.passwordRequirements.minLength),
+          maxLength: maxLength(this.passwordRequirements.maxLength),
+        },
+        passwordConfirmation: {
+          required: requiredIf(function () {
+            return this.requirePassword();
+          }),
+          sameAsPassword: sameAs('password'),
+        },
+        manualUnlock: {},
+      },
+    };
+  },
+  methods: {
+    handleSubmit() {
+      let userData = {};
+
+      if (this.newUser) {
+        this.$v.$touch();
+        if (this.$v.$invalid) return;
+        userData.username = this.form.username;
+        userData.status = this.form.status;
+        userData.privilege = this.form.privilege;
+        userData.password = this.form.password;
+      } else {
+        if (this.$v.$invalid) return;
+        userData.originalUsername = this.originalUsername;
+        if (this.$v.form.status.$dirty) {
+          userData.status = this.form.status;
+        }
+        if (this.$v.form.username.$dirty) {
+          userData.username = this.form.username;
+        }
+        if (this.$v.form.privilege.$dirty) {
+          userData.privilege = this.form.privilege;
+        }
+        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;
+        }
+      }
+
+      this.$emit('ok', { isNewUser: this.newUser, userData });
+      this.closeModal();
+    },
+    closeModal() {
+      this.$nextTick(() => {
+        this.$refs.modal.hide();
+      });
+    },
+    resetForm() {
+      this.form.originalUsername = '';
+      this.form.status = true;
+      this.form.username = '';
+      this.form.privilege = null;
+      this.form.password = '';
+      this.form.passwordConfirmation = '';
+      this.$v.$reset();
+      this.$emit('hidden');
+    },
+    requirePassword() {
+      if (this.newUser) return true;
+      if (this.$v.form.password.$dirty) return true;
+      if (this.$v.form.passwordConfirmation.$dirty) return true;
+      return false;
+    },
+    onOk(bvModalEvt) {
+      // prevent modal close
+      bvModalEvt.preventDefault();
+      this.handleSubmit();
+    },
+  },
+};
+</script>
diff --git a/src/views/SecurityAndAccess/UserManagement/TableRoles.vue b/src/views/SecurityAndAccess/UserManagement/TableRoles.vue
new file mode 100644
index 0000000..61ef1ee
--- /dev/null
+++ b/src/views/SecurityAndAccess/UserManagement/TableRoles.vue
@@ -0,0 +1,92 @@
+<template>
+  <b-table stacked="sm" hover small :items="items" :fields="fields">
+    <template #cell(administrator)="data">
+      <template v-if="data.value">
+        <checkmark20 />
+      </template>
+    </template>
+    <template #cell(operator)="data">
+      <template v-if="data.value">
+        <checkmark20 />
+      </template>
+    </template>
+    <template #cell(readonly)="data">
+      <template v-if="data.value">
+        <checkmark20 />
+      </template>
+    </template>
+    <template #cell(noaccess)="data">
+      <template v-if="data.value">
+        <checkmark20 />
+      </template>
+    </template>
+  </b-table>
+</template>
+
+<script>
+import Checkmark20 from '@carbon/icons-vue/es/checkmark/20';
+
+export default {
+  components: {
+    Checkmark20,
+  },
+  data() {
+    return {
+      items: [
+        {
+          description: this.$t(
+            'pageUserManagement.tableRoles.configureComponentsManagedByThisService'
+          ),
+          administrator: true,
+          operator: true,
+          readonly: false,
+          noaccess: false,
+        },
+        {
+          description: this.$t(
+            'pageUserManagement.tableRoles.configureManagerResources'
+          ),
+          administrator: true,
+          operator: false,
+          readonly: false,
+          noaccess: false,
+        },
+        {
+          description: this.$t(
+            'pageUserManagement.tableRoles.updatePasswordForCurrentUserAccount'
+          ),
+          administrator: true,
+          operator: true,
+          readonly: true,
+          noaccess: false,
+        },
+        {
+          description: this.$t(
+            'pageUserManagement.tableRoles.configureUsersAndTheirAccounts'
+          ),
+          administrator: true,
+          operator: false,
+          readonly: false,
+          noaccess: false,
+        },
+        {
+          description: this.$t(
+            'pageUserManagement.tableRoles.logInToTheServiceAndReadResources'
+          ),
+          administrator: true,
+          operator: true,
+          readonly: true,
+          noaccess: false,
+        },
+      ],
+      fields: [
+        { key: 'description', label: 'Privilege' },
+        { key: 'administrator', label: 'Administrator', class: 'text-center' },
+        { key: 'operator', label: 'Operator', class: 'text-center' },
+        { key: 'readonly', label: 'ReadOnly', class: 'text-center' },
+        { key: 'noaccess', label: 'NoAccess', class: 'text-center' },
+      ],
+    };
+  },
+};
+</script>
diff --git a/src/views/SecurityAndAccess/UserManagement/UserManagement.vue b/src/views/SecurityAndAccess/UserManagement/UserManagement.vue
new file mode 100644
index 0000000..015fee9
--- /dev/null
+++ b/src/views/SecurityAndAccess/UserManagement/UserManagement.vue
@@ -0,0 +1,388 @@
+<template>
+  <b-container fluid="xl">
+    <page-title />
+    <b-row>
+      <b-col xl="9" class="text-right">
+        <b-button variant="link" @click="initModalSettings">
+          <icon-settings />
+          {{ $t('pageUserManagement.accountPolicySettings') }}
+        </b-button>
+        <b-button
+          variant="primary"
+          data-test-id="userManagement-button-addUser"
+          @click="initModalUser(null)"
+        >
+          <icon-add />
+          {{ $t('pageUserManagement.addUser') }}
+        </b-button>
+      </b-col>
+    </b-row>
+    <b-row>
+      <b-col xl="9">
+        <table-toolbar
+          ref="toolbar"
+          :selected-items-count="selectedRows.length"
+          :actions="tableToolbarActions"
+          @clear-selected="clearSelectedRows($refs.table)"
+          @batch-action="onBatchAction"
+        />
+        <b-table
+          ref="table"
+          responsive="md"
+          selectable
+          show-empty
+          no-select-on-click
+          hover
+          :fields="fields"
+          :items="tableItems"
+          :empty-text="$t('global.table.emptyMessage')"
+          @row-selected="onRowSelected($event, tableItems.length)"
+        >
+          <!-- Checkbox column -->
+          <template #head(checkbox)>
+            <b-form-checkbox
+              v-model="tableHeaderCheckboxModel"
+              data-test-id="userManagement-checkbox-tableHeaderCheckbox"
+              :indeterminate="tableHeaderCheckboxIndeterminate"
+              @change="onChangeHeaderCheckbox($refs.table)"
+            >
+              <span class="sr-only">{{ $t('global.table.selectAll') }}</span>
+            </b-form-checkbox>
+          </template>
+          <template #cell(checkbox)="row">
+            <b-form-checkbox
+              v-model="row.rowSelected"
+              data-test-id="userManagement-checkbox-toggleSelectRow"
+              @change="toggleSelectRow($refs.table, row.index)"
+            >
+              <span class="sr-only">{{ $t('global.table.selectItem') }}</span>
+            </b-form-checkbox>
+          </template>
+
+          <!-- table actions column -->
+          <template #cell(actions)="{ item }">
+            <table-row-action
+              v-for="(action, index) in item.actions"
+              :key="index"
+              :value="action.value"
+              :enabled="action.enabled"
+              :title="action.title"
+              @click-table-action="onTableRowAction($event, item)"
+            >
+              <template #icon>
+                <icon-edit
+                  v-if="action.value === 'edit'"
+                  :data-test-id="`userManagement-tableRowAction-edit-${index}`"
+                />
+                <icon-trashcan
+                  v-if="action.value === 'delete'"
+                  :data-test-id="`userManagement-tableRowAction-delete-${index}`"
+                />
+              </template>
+            </table-row-action>
+          </template>
+        </b-table>
+      </b-col>
+    </b-row>
+    <b-row>
+      <b-col xl="8">
+        <b-button
+          v-b-toggle.collapse-role-table
+          data-test-id="userManagement-button-viewPrivilegeRoleDescriptions"
+          variant="link"
+          class="mt-3"
+        >
+          <icon-chevron />
+          {{ $t('pageUserManagement.viewPrivilegeRoleDescriptions') }}
+        </b-button>
+        <b-collapse id="collapse-role-table" class="mt-3">
+          <table-roles />
+        </b-collapse>
+      </b-col>
+    </b-row>
+    <!-- Modals -->
+    <modal-settings :settings="settings" @ok="saveAccountSettings" />
+    <modal-user
+      :user="activeUser"
+      :password-requirements="passwordRequirements"
+      @ok="saveUser"
+      @hidden="activeUser = null"
+    />
+  </b-container>
+</template>
+
+<script>
+import IconTrashcan from '@carbon/icons-vue/es/trash-can/20';
+import IconEdit from '@carbon/icons-vue/es/edit/20';
+import IconAdd from '@carbon/icons-vue/es/add--alt/20';
+import IconSettings from '@carbon/icons-vue/es/settings/20';
+import IconChevron from '@carbon/icons-vue/es/chevron--up/20';
+
+import ModalUser from './ModalUser';
+import ModalSettings from './ModalSettings';
+import PageTitle from '@/components/Global/PageTitle';
+import TableRoles from './TableRoles';
+import TableToolbar from '@/components/Global/TableToolbar';
+import TableRowAction from '@/components/Global/TableRowAction';
+
+import BVTableSelectableMixin, {
+  selectedRows,
+  tableHeaderCheckboxModel,
+  tableHeaderCheckboxIndeterminate,
+} from '@/components/Mixins/BVTableSelectableMixin';
+import BVToastMixin from '@/components/Mixins/BVToastMixin';
+import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
+
+export default {
+  name: 'UserManagement',
+  components: {
+    IconAdd,
+    IconChevron,
+    IconEdit,
+    IconSettings,
+    IconTrashcan,
+    ModalSettings,
+    ModalUser,
+    PageTitle,
+    TableRoles,
+    TableRowAction,
+    TableToolbar,
+  },
+  mixins: [BVTableSelectableMixin, BVToastMixin, LoadingBarMixin],
+  beforeRouteLeave(to, from, next) {
+    this.hideLoader();
+    next();
+  },
+  data() {
+    return {
+      activeUser: null,
+      fields: [
+        {
+          key: 'checkbox',
+        },
+        {
+          key: 'username',
+          label: this.$t('pageUserManagement.table.username'),
+        },
+        {
+          key: 'privilege',
+          label: this.$t('pageUserManagement.table.privilege'),
+        },
+        {
+          key: 'status',
+          label: this.$t('pageUserManagement.table.status'),
+        },
+        {
+          key: 'actions',
+          label: '',
+          tdClass: 'text-right text-nowrap',
+        },
+      ],
+      tableToolbarActions: [
+        {
+          value: 'delete',
+          label: this.$t('global.action.delete'),
+        },
+        {
+          value: 'enable',
+          label: this.$t('global.action.enable'),
+        },
+        {
+          value: 'disable',
+          label: this.$t('global.action.disable'),
+        },
+      ],
+      selectedRows: selectedRows,
+      tableHeaderCheckboxModel: tableHeaderCheckboxModel,
+      tableHeaderCheckboxIndeterminate: tableHeaderCheckboxIndeterminate,
+    };
+  },
+  computed: {
+    allUsers() {
+      return this.$store.getters['userManagement/allUsers'];
+    },
+    tableItems() {
+      // transform user data to table data
+      return this.allUsers.map((user) => {
+        return {
+          username: user.UserName,
+          privilege: user.RoleId,
+          status: user.Locked
+            ? 'Locked'
+            : user.Enabled
+            ? 'Enabled'
+            : 'Disabled',
+          actions: [
+            {
+              value: 'edit',
+              enabled: true,
+              title: this.$t('pageUserManagement.editUser'),
+            },
+            {
+              value: 'delete',
+              enabled: user.UserName === 'root' ? false : true,
+              title: this.$tc('pageUserManagement.deleteUser'),
+            },
+          ],
+          ...user,
+        };
+      });
+    },
+    settings() {
+      return this.$store.getters['userManagement/accountSettings'];
+    },
+    passwordRequirements() {
+      return this.$store.getters['userManagement/accountPasswordRequirements'];
+    },
+  },
+  created() {
+    this.startLoader();
+    this.$store
+      .dispatch('userManagement/getUsers')
+      .finally(() => this.endLoader());
+    this.$store.dispatch('userManagement/getAccountSettings');
+    this.$store.dispatch('userManagement/getAccountRoles');
+  },
+  methods: {
+    initModalUser(user) {
+      this.activeUser = user;
+      this.$bvModal.show('modal-user');
+    },
+    initModalDelete(user) {
+      this.$bvModal
+        .msgBoxConfirm(
+          this.$t('pageUserManagement.modal.deleteConfirmMessage', {
+            user: user.username,
+          }),
+          {
+            title: this.$tc('pageUserManagement.deleteUser'),
+            okTitle: this.$tc('pageUserManagement.deleteUser'),
+            cancelTitle: this.$t('global.action.cancel'),
+          }
+        )
+        .then((deleteConfirmed) => {
+          if (deleteConfirmed) {
+            this.deleteUser(user);
+          }
+        });
+    },
+    initModalSettings() {
+      this.$bvModal.show('modal-settings');
+    },
+    saveUser({ isNewUser, userData }) {
+      this.startLoader();
+      if (isNewUser) {
+        this.$store
+          .dispatch('userManagement/createUser', userData)
+          .then((success) => this.successToast(success))
+          .catch(({ message }) => this.errorToast(message))
+          .finally(() => this.endLoader());
+      } else {
+        this.$store
+          .dispatch('userManagement/updateUser', userData)
+          .then((success) => this.successToast(success))
+          .catch(({ message }) => this.errorToast(message))
+          .finally(() => this.endLoader());
+      }
+    },
+    deleteUser({ username }) {
+      this.startLoader();
+      this.$store
+        .dispatch('userManagement/deleteUser', username)
+        .then((success) => this.successToast(success))
+        .catch(({ message }) => this.errorToast(message))
+        .finally(() => this.endLoader());
+    },
+    onBatchAction(action) {
+      switch (action) {
+        case 'delete':
+          this.$bvModal
+            .msgBoxConfirm(
+              this.$tc(
+                'pageUserManagement.modal.batchDeleteConfirmMessage',
+                this.selectedRows.length
+              ),
+              {
+                title: this.$tc(
+                  'pageUserManagement.deleteUser',
+                  this.selectedRows.length
+                ),
+                okTitle: this.$tc(
+                  'pageUserManagement.deleteUser',
+                  this.selectedRows.length
+                ),
+                cancelTitle: this.$t('global.action.cancel'),
+              }
+            )
+            .then((deleteConfirmed) => {
+              if (deleteConfirmed) {
+                this.startLoader();
+                this.$store
+                  .dispatch('userManagement/deleteUsers', this.selectedRows)
+                  .then((messages) => {
+                    messages.forEach(({ type, message }) => {
+                      if (type === 'success') this.successToast(message);
+                      if (type === 'error') this.errorToast(message);
+                    });
+                  })
+                  .finally(() => this.endLoader());
+              }
+            });
+          break;
+        case 'enable':
+          this.startLoader();
+          this.$store
+            .dispatch('userManagement/enableUsers', this.selectedRows)
+            .then((messages) => {
+              messages.forEach(({ type, message }) => {
+                if (type === 'success') this.successToast(message);
+                if (type === 'error') this.errorToast(message);
+              });
+            })
+            .finally(() => this.endLoader());
+          break;
+        case 'disable':
+          this.startLoader();
+          this.$store
+            .dispatch('userManagement/disableUsers', this.selectedRows)
+            .then((messages) => {
+              messages.forEach(({ type, message }) => {
+                if (type === 'success') this.successToast(message);
+                if (type === 'error') this.errorToast(message);
+              });
+            })
+            .finally(() => this.endLoader());
+          break;
+      }
+    },
+    onTableRowAction(action, row) {
+      switch (action) {
+        case 'edit':
+          this.initModalUser(row);
+          break;
+        case 'delete':
+          this.initModalDelete(row);
+          break;
+        default:
+          break;
+      }
+    },
+    saveAccountSettings(settings) {
+      this.startLoader();
+      this.$store
+        .dispatch('userManagement/saveAccountSettings', settings)
+        .then((message) => this.successToast(message))
+        .catch(({ message }) => this.errorToast(message))
+        .finally(() => this.endLoader());
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.btn.collapsed {
+  svg {
+    transform: rotate(180deg);
+  }
+}
+</style>
diff --git a/src/views/SecurityAndAccess/UserManagement/index.js b/src/views/SecurityAndAccess/UserManagement/index.js
new file mode 100644
index 0000000..c3aebec
--- /dev/null
+++ b/src/views/SecurityAndAccess/UserManagement/index.js
@@ -0,0 +1,2 @@
+import UserManagement from './UserManagement.vue';
+export default UserManagement;