diff options
Diffstat (limited to 'src/views/SecurityAndAccess/UserManagement')
5 files changed, 1083 insertions, 0 deletions
diff --git a/src/views/SecurityAndAccess/UserManagement/ModalSettings.vue b/src/views/SecurityAndAccess/UserManagement/ModalSettings.vue new file mode 100644 index 00000000..0f05123c --- /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 00000000..0f8757ce --- /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 00000000..61ef1ee8 --- /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 00000000..015fee91 --- /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 00000000..c3aebec3 --- /dev/null +++ b/src/views/SecurityAndAccess/UserManagement/index.js @@ -0,0 +1,2 @@ +import UserManagement from './UserManagement.vue'; +export default UserManagement; |