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 autoFocusButton: 'ok', 278 }, 279 ) 280 .then((deleteConfirmed) => { 281 if (deleteConfirmed) { 282 this.deleteUser(user); 283 } 284 }); 285 }, 286 initModalSettings() { 287 this.setting = this.settings; 288 this.$bvModal.show('modal-settings'); 289 }, 290 saveUser({ isNewUser, userData }) { 291 this.startLoader(); 292 if (isNewUser) { 293 this.$store 294 .dispatch('userManagement/createUser', userData) 295 .then((success) => this.successToast(success)) 296 .catch(({ message }) => this.errorToast(message)) 297 .finally(() => this.endLoader()); 298 } else { 299 this.$store 300 .dispatch('userManagement/updateUser', userData) 301 .then((success) => this.successToast(success)) 302 .catch(({ message }) => this.errorToast(message)) 303 .finally(() => this.endLoader()); 304 } 305 }, 306 deleteUser({ username }) { 307 this.startLoader(); 308 this.$store 309 .dispatch('userManagement/deleteUser', username) 310 .then((success) => this.successToast(success)) 311 .catch(({ message }) => this.errorToast(message)) 312 .finally(() => this.endLoader()); 313 }, 314 onBatchAction(action) { 315 switch (action) { 316 case 'delete': 317 this.$bvModal 318 .msgBoxConfirm( 319 this.$tc( 320 'pageUserManagement.modal.batchDeleteConfirmMessage', 321 this.selectedRows.length, 322 ), 323 { 324 title: this.$tc( 325 'pageUserManagement.deleteUser', 326 this.selectedRows.length, 327 ), 328 okTitle: this.$tc( 329 'pageUserManagement.deleteUser', 330 this.selectedRows.length, 331 ), 332 cancelTitle: this.$t('global.action.cancel'), 333 autoFocusButton: 'ok', 334 }, 335 ) 336 .then((deleteConfirmed) => { 337 if (deleteConfirmed) { 338 this.startLoader(); 339 this.$store 340 .dispatch('userManagement/deleteUsers', this.selectedRows) 341 .then((messages) => { 342 messages.forEach(({ type, message }) => { 343 if (type === 'success') this.successToast(message); 344 if (type === 'error') this.errorToast(message); 345 }); 346 }) 347 .finally(() => this.endLoader()); 348 } 349 }); 350 break; 351 case 'enable': 352 this.startLoader(); 353 this.$store 354 .dispatch('userManagement/enableUsers', this.selectedRows) 355 .then((messages) => { 356 messages.forEach(({ type, message }) => { 357 if (type === 'success') this.successToast(message); 358 if (type === 'error') this.errorToast(message); 359 }); 360 }) 361 .finally(() => this.endLoader()); 362 break; 363 case 'disable': 364 this.startLoader(); 365 this.$store 366 .dispatch('userManagement/disableUsers', this.selectedRows) 367 .then((messages) => { 368 messages.forEach(({ type, message }) => { 369 if (type === 'success') this.successToast(message); 370 if (type === 'error') this.errorToast(message); 371 }); 372 }) 373 .finally(() => this.endLoader()); 374 break; 375 } 376 }, 377 onTableRowAction(action, row) { 378 switch (action) { 379 case 'edit': 380 this.initModalUser(row); 381 break; 382 case 'delete': 383 this.initModalDelete(row); 384 break; 385 default: 386 break; 387 } 388 }, 389 saveAccountSettings(settings) { 390 this.startLoader(); 391 this.$store 392 .dispatch('userManagement/saveAccountSettings', settings) 393 .then((message) => this.successToast(message)) 394 .catch(({ message }) => this.errorToast(message)) 395 .finally(() => this.endLoader()); 396 }, 397 }, 398}; 399</script> 400 401<style lang="scss" scoped> 402.btn.collapsed { 403 svg { 404 transform: rotate(180deg); 405 } 406} 407</style> 408