1<template> 2 <b-container fluid="xl"> 3 <page-title /> 4 <b-row> 5 <b-col xl="9" class="text-right"> 6 <b-button variant="link" @click="initModalSettings"> 7 <icon-settings /> 8 {{ $t('pageUserManagement.accountPolicySettings') }} 9 </b-button> 10 <b-button 11 variant="primary" 12 data-test-id="userManagement-button-addUser" 13 @click="initModalUser(null)" 14 > 15 <icon-add /> 16 {{ $t('pageUserManagement.addUser') }} 17 </b-button> 18 </b-col> 19 </b-row> 20 <b-row> 21 <b-col xl="9"> 22 <table-toolbar 23 ref="toolbar" 24 :selected-items-count="selectedRows.length" 25 :actions="tableToolbarActions" 26 @clear-selected="clearSelectedRows($refs.table)" 27 @batch-action="onBatchAction" 28 /> 29 <b-table 30 ref="table" 31 responsive="md" 32 selectable 33 show-empty 34 no-select-on-click 35 hover 36 :busy="isBusy" 37 :fields="fields" 38 :items="tableItems" 39 :empty-text="$t('global.table.emptyMessage')" 40 @row-selected="onRowSelected($event, tableItems.length)" 41 > 42 <!-- Checkbox column --> 43 <template #head(checkbox)> 44 <b-form-checkbox 45 v-model="tableHeaderCheckboxModel" 46 data-test-id="userManagement-checkbox-tableHeaderCheckbox" 47 :indeterminate="tableHeaderCheckboxIndeterminate" 48 @change="onChangeHeaderCheckbox($refs.table)" 49 > 50 <span class="sr-only">{{ $t('global.table.selectAll') }}</span> 51 </b-form-checkbox> 52 </template> 53 <template #cell(checkbox)="row"> 54 <b-form-checkbox 55 v-model="row.rowSelected" 56 data-test-id="userManagement-checkbox-toggleSelectRow" 57 @change="toggleSelectRow($refs.table, row.index)" 58 > 59 <span class="sr-only">{{ $t('global.table.selectItem') }}</span> 60 </b-form-checkbox> 61 </template> 62 63 <!-- table actions column --> 64 <template #cell(actions)="{ item }"> 65 <table-row-action 66 v-for="(action, index) in item.actions" 67 :key="index" 68 :value="action.value" 69 :enabled="action.enabled" 70 :title="action.title" 71 @click-table-action="onTableRowAction($event, item)" 72 > 73 <template #icon> 74 <icon-edit 75 v-if="action.value === 'edit'" 76 :data-test-id="`userManagement-tableRowAction-edit-${index}`" 77 /> 78 <icon-trashcan 79 v-if="action.value === 'delete'" 80 :data-test-id="`userManagement-tableRowAction-delete-${index}`" 81 /> 82 </template> 83 </table-row-action> 84 </template> 85 </b-table> 86 </b-col> 87 </b-row> 88 <b-row> 89 <b-col xl="8"> 90 <b-button 91 v-b-toggle.collapse-role-table 92 data-test-id="userManagement-button-viewPrivilegeRoleDescriptions" 93 variant="link" 94 class="mt-3" 95 > 96 <icon-chevron /> 97 {{ $t('pageUserManagement.viewPrivilegeRoleDescriptions') }} 98 </b-button> 99 <b-collapse id="collapse-role-table" class="mt-3"> 100 <table-roles /> 101 </b-collapse> 102 </b-col> 103 </b-row> 104 <!-- Modals --> 105 <modal-settings :settings="setting" @ok="saveAccountSettings" /> 106 <modal-user 107 :user="activeUser" 108 :password-requirements="passwordRequirements" 109 @ok="saveUser" 110 @hidden="activeUser = null" 111 /> 112 </b-container> 113</template> 114 115<script> 116import IconTrashcan from '@carbon/icons-vue/es/trash-can/20'; 117import IconEdit from '@carbon/icons-vue/es/edit/20'; 118import IconAdd from '@carbon/icons-vue/es/add--alt/20'; 119import IconSettings from '@carbon/icons-vue/es/settings/20'; 120import IconChevron from '@carbon/icons-vue/es/chevron--up/20'; 121 122import ModalUser from './ModalUser'; 123import ModalSettings from './ModalSettings'; 124import PageTitle from '@/components/Global/PageTitle'; 125import TableRoles from './TableRoles'; 126import TableToolbar from '@/components/Global/TableToolbar'; 127import TableRowAction from '@/components/Global/TableRowAction'; 128 129import BVTableSelectableMixin, { 130 selectedRows, 131 tableHeaderCheckboxModel, 132 tableHeaderCheckboxIndeterminate, 133} from '@/components/Mixins/BVTableSelectableMixin'; 134import BVToastMixin from '@/components/Mixins/BVToastMixin'; 135import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin'; 136 137export default { 138 name: 'UserManagement', 139 components: { 140 IconAdd, 141 IconChevron, 142 IconEdit, 143 IconSettings, 144 IconTrashcan, 145 ModalSettings, 146 ModalUser, 147 PageTitle, 148 TableRoles, 149 TableRowAction, 150 TableToolbar, 151 }, 152 mixins: [BVTableSelectableMixin, BVToastMixin, LoadingBarMixin], 153 beforeRouteLeave(to, from, next) { 154 this.hideLoader(); 155 next(); 156 }, 157 data() { 158 return { 159 isBusy: true, 160 activeUser: null, 161 setting: {}, 162 fields: [ 163 { 164 key: 'checkbox', 165 }, 166 { 167 key: 'username', 168 label: this.$t('pageUserManagement.table.username'), 169 }, 170 { 171 key: 'privilege', 172 label: this.$t('pageUserManagement.table.privilege'), 173 }, 174 { 175 key: 'status', 176 label: this.$t('pageUserManagement.table.status'), 177 }, 178 { 179 key: 'actions', 180 label: '', 181 tdClass: 'text-right text-nowrap', 182 }, 183 ], 184 tableToolbarActions: [ 185 { 186 value: 'delete', 187 label: this.$t('global.action.delete'), 188 }, 189 { 190 value: 'enable', 191 label: this.$t('global.action.enable'), 192 }, 193 { 194 value: 'disable', 195 label: this.$t('global.action.disable'), 196 }, 197 ], 198 selectedRows: selectedRows, 199 tableHeaderCheckboxModel: tableHeaderCheckboxModel, 200 tableHeaderCheckboxIndeterminate: tableHeaderCheckboxIndeterminate, 201 }; 202 }, 203 computed: { 204 allUsers() { 205 return this.$store.getters['userManagement/allUsers']; 206 }, 207 tableItems() { 208 // transform user data to table data 209 return this.allUsers.map((user) => { 210 return { 211 username: user.UserName, 212 privilege: user.RoleId, 213 status: user.Locked 214 ? 'Locked' 215 : user.Enabled 216 ? 'Enabled' 217 : 'Disabled', 218 actions: [ 219 { 220 value: 'edit', 221 enabled: this.editEnable(user), 222 title: this.$t('pageUserManagement.editUser'), 223 }, 224 { 225 value: 'delete', 226 enabled: 227 user.UserName === this.$store.getters['global/username'] 228 ? false 229 : true && user.UserName === 'root' 230 ? false 231 : true, 232 title: this.$tc('pageUserManagement.deleteUser'), 233 }, 234 ], 235 ...user, 236 }; 237 }); 238 }, 239 settings() { 240 return this.$store.getters['userManagement/accountSettings']; 241 }, 242 passwordRequirements() { 243 return this.$store.getters['userManagement/accountPasswordRequirements']; 244 }, 245 }, 246 created() { 247 this.startLoader(); 248 this.$store.dispatch('userManagement/getUsers').finally(() => { 249 this.endLoader(); 250 this.isBusy = false; 251 }); 252 this.$store.dispatch('userManagement/getAccountSettings'); 253 this.$store.dispatch('userManagement/getAccountRoles'); 254 }, 255 methods: { 256 editEnable(user) { 257 if ('root' === this.$store.getters['global/username']) { 258 return true; 259 } else { 260 return user.UserName === 'root' ? false : true; 261 } 262 }, 263 initModalUser(user) { 264 this.activeUser = user; 265 this.$bvModal.show('modal-user'); 266 }, 267 initModalDelete(user) { 268 this.$bvModal 269 .msgBoxConfirm( 270 this.$t('pageUserManagement.modal.deleteConfirmMessage', { 271 user: user.username, 272 }), 273 { 274 title: this.$tc('pageUserManagement.deleteUser'), 275 okTitle: this.$tc('pageUserManagement.deleteUser'), 276 cancelTitle: this.$t('global.action.cancel'), 277 } 278 ) 279 .then((deleteConfirmed) => { 280 if (deleteConfirmed) { 281 this.deleteUser(user); 282 } 283 }); 284 }, 285 initModalSettings() { 286 this.setting = this.settings; 287 this.$bvModal.show('modal-settings'); 288 }, 289 saveUser({ isNewUser, userData }) { 290 this.startLoader(); 291 if (isNewUser) { 292 this.$store 293 .dispatch('userManagement/createUser', userData) 294 .then((success) => this.successToast(success)) 295 .catch(({ message }) => this.errorToast(message)) 296 .finally(() => this.endLoader()); 297 } else { 298 this.$store 299 .dispatch('userManagement/updateUser', userData) 300 .then((success) => this.successToast(success)) 301 .catch(({ message }) => this.errorToast(message)) 302 .finally(() => this.endLoader()); 303 } 304 }, 305 deleteUser({ username }) { 306 this.startLoader(); 307 this.$store 308 .dispatch('userManagement/deleteUser', username) 309 .then((success) => this.successToast(success)) 310 .catch(({ message }) => this.errorToast(message)) 311 .finally(() => this.endLoader()); 312 }, 313 onBatchAction(action) { 314 switch (action) { 315 case 'delete': 316 this.$bvModal 317 .msgBoxConfirm( 318 this.$tc( 319 'pageUserManagement.modal.batchDeleteConfirmMessage', 320 this.selectedRows.length 321 ), 322 { 323 title: this.$tc( 324 'pageUserManagement.deleteUser', 325 this.selectedRows.length 326 ), 327 okTitle: this.$tc( 328 'pageUserManagement.deleteUser', 329 this.selectedRows.length 330 ), 331 cancelTitle: this.$t('global.action.cancel'), 332 } 333 ) 334 .then((deleteConfirmed) => { 335 if (deleteConfirmed) { 336 this.startLoader(); 337 this.$store 338 .dispatch('userManagement/deleteUsers', this.selectedRows) 339 .then((messages) => { 340 messages.forEach(({ type, message }) => { 341 if (type === 'success') this.successToast(message); 342 if (type === 'error') this.errorToast(message); 343 }); 344 }) 345 .finally(() => this.endLoader()); 346 } 347 }); 348 break; 349 case 'enable': 350 this.startLoader(); 351 this.$store 352 .dispatch('userManagement/enableUsers', this.selectedRows) 353 .then((messages) => { 354 messages.forEach(({ type, message }) => { 355 if (type === 'success') this.successToast(message); 356 if (type === 'error') this.errorToast(message); 357 }); 358 }) 359 .finally(() => this.endLoader()); 360 break; 361 case 'disable': 362 this.startLoader(); 363 this.$store 364 .dispatch('userManagement/disableUsers', this.selectedRows) 365 .then((messages) => { 366 messages.forEach(({ type, message }) => { 367 if (type === 'success') this.successToast(message); 368 if (type === 'error') this.errorToast(message); 369 }); 370 }) 371 .finally(() => this.endLoader()); 372 break; 373 } 374 }, 375 onTableRowAction(action, row) { 376 switch (action) { 377 case 'edit': 378 this.initModalUser(row); 379 break; 380 case 'delete': 381 this.initModalDelete(row); 382 break; 383 default: 384 break; 385 } 386 }, 387 saveAccountSettings(settings) { 388 this.startLoader(); 389 this.$store 390 .dispatch('userManagement/saveAccountSettings', settings) 391 .then((message) => this.successToast(message)) 392 .catch(({ message }) => this.errorToast(message)) 393 .finally(() => this.endLoader()); 394 }, 395 }, 396}; 397</script> 398 399<style lang="scss" scoped> 400.btn.collapsed { 401 svg { 402 transform: rotate(180deg); 403 } 404} 405</style> 406