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="settings" @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 fields: [ 162 { 163 key: 'checkbox', 164 }, 165 { 166 key: 'username', 167 label: this.$t('pageUserManagement.table.username'), 168 }, 169 { 170 key: 'privilege', 171 label: this.$t('pageUserManagement.table.privilege'), 172 }, 173 { 174 key: 'status', 175 label: this.$t('pageUserManagement.table.status'), 176 }, 177 { 178 key: 'actions', 179 label: '', 180 tdClass: 'text-right text-nowrap', 181 }, 182 ], 183 tableToolbarActions: [ 184 { 185 value: 'delete', 186 label: this.$t('global.action.delete'), 187 }, 188 { 189 value: 'enable', 190 label: this.$t('global.action.enable'), 191 }, 192 { 193 value: 'disable', 194 label: this.$t('global.action.disable'), 195 }, 196 ], 197 selectedRows: selectedRows, 198 tableHeaderCheckboxModel: tableHeaderCheckboxModel, 199 tableHeaderCheckboxIndeterminate: tableHeaderCheckboxIndeterminate, 200 }; 201 }, 202 computed: { 203 allUsers() { 204 return this.$store.getters['userManagement/allUsers']; 205 }, 206 tableItems() { 207 // transform user data to table data 208 return this.allUsers.map((user) => { 209 return { 210 username: user.UserName, 211 privilege: user.RoleId, 212 status: user.Locked 213 ? 'Locked' 214 : user.Enabled 215 ? 'Enabled' 216 : 'Disabled', 217 actions: [ 218 { 219 value: 'edit', 220 enabled: this.editEnable(user), 221 title: this.$t('pageUserManagement.editUser'), 222 }, 223 { 224 value: 'delete', 225 enabled: 226 user.UserName === this.$store.getters['global/username'] 227 ? false 228 : true && user.UserName === 'root' 229 ? false 230 : true, 231 title: this.$tc('pageUserManagement.deleteUser'), 232 }, 233 ], 234 ...user, 235 }; 236 }); 237 }, 238 settings() { 239 return this.$store.getters['userManagement/accountSettings']; 240 }, 241 passwordRequirements() { 242 return this.$store.getters['userManagement/accountPasswordRequirements']; 243 }, 244 }, 245 created() { 246 this.startLoader(); 247 this.$store.dispatch('userManagement/getUsers').finally(() => { 248 this.endLoader(); 249 this.isBusy = false; 250 }); 251 this.$store.dispatch('userManagement/getAccountSettings'); 252 this.$store.dispatch('userManagement/getAccountRoles'); 253 }, 254 methods: { 255 editEnable(user) { 256 if ('root' === this.$store.getters['global/username']) { 257 return true; 258 } else { 259 return user.UserName === 'root' ? false : true; 260 } 261 }, 262 initModalUser(user) { 263 this.activeUser = user; 264 this.$bvModal.show('modal-user'); 265 }, 266 initModalDelete(user) { 267 this.$bvModal 268 .msgBoxConfirm( 269 this.$t('pageUserManagement.modal.deleteConfirmMessage', { 270 user: user.username, 271 }), 272 { 273 title: this.$tc('pageUserManagement.deleteUser'), 274 okTitle: this.$tc('pageUserManagement.deleteUser'), 275 cancelTitle: this.$t('global.action.cancel'), 276 } 277 ) 278 .then((deleteConfirmed) => { 279 if (deleteConfirmed) { 280 this.deleteUser(user); 281 } 282 }); 283 }, 284 initModalSettings() { 285 this.$bvModal.show('modal-settings'); 286 }, 287 saveUser({ isNewUser, userData }) { 288 this.startLoader(); 289 if (isNewUser) { 290 this.$store 291 .dispatch('userManagement/createUser', userData) 292 .then((success) => this.successToast(success)) 293 .catch(({ message }) => this.errorToast(message)) 294 .finally(() => this.endLoader()); 295 } else { 296 this.$store 297 .dispatch('userManagement/updateUser', userData) 298 .then((success) => this.successToast(success)) 299 .catch(({ message }) => this.errorToast(message)) 300 .finally(() => this.endLoader()); 301 } 302 }, 303 deleteUser({ username }) { 304 this.startLoader(); 305 this.$store 306 .dispatch('userManagement/deleteUser', username) 307 .then((success) => this.successToast(success)) 308 .catch(({ message }) => this.errorToast(message)) 309 .finally(() => this.endLoader()); 310 }, 311 onBatchAction(action) { 312 switch (action) { 313 case 'delete': 314 this.$bvModal 315 .msgBoxConfirm( 316 this.$tc( 317 'pageUserManagement.modal.batchDeleteConfirmMessage', 318 this.selectedRows.length 319 ), 320 { 321 title: this.$tc( 322 'pageUserManagement.deleteUser', 323 this.selectedRows.length 324 ), 325 okTitle: this.$tc( 326 'pageUserManagement.deleteUser', 327 this.selectedRows.length 328 ), 329 cancelTitle: this.$t('global.action.cancel'), 330 } 331 ) 332 .then((deleteConfirmed) => { 333 if (deleteConfirmed) { 334 this.startLoader(); 335 this.$store 336 .dispatch('userManagement/deleteUsers', this.selectedRows) 337 .then((messages) => { 338 messages.forEach(({ type, message }) => { 339 if (type === 'success') this.successToast(message); 340 if (type === 'error') this.errorToast(message); 341 }); 342 }) 343 .finally(() => this.endLoader()); 344 } 345 }); 346 break; 347 case 'enable': 348 this.startLoader(); 349 this.$store 350 .dispatch('userManagement/enableUsers', this.selectedRows) 351 .then((messages) => { 352 messages.forEach(({ type, message }) => { 353 if (type === 'success') this.successToast(message); 354 if (type === 'error') this.errorToast(message); 355 }); 356 }) 357 .finally(() => this.endLoader()); 358 break; 359 case 'disable': 360 this.startLoader(); 361 this.$store 362 .dispatch('userManagement/disableUsers', this.selectedRows) 363 .then((messages) => { 364 messages.forEach(({ type, message }) => { 365 if (type === 'success') this.successToast(message); 366 if (type === 'error') this.errorToast(message); 367 }); 368 }) 369 .finally(() => this.endLoader()); 370 break; 371 } 372 }, 373 onTableRowAction(action, row) { 374 switch (action) { 375 case 'edit': 376 this.initModalUser(row); 377 break; 378 case 'delete': 379 this.initModalDelete(row); 380 break; 381 default: 382 break; 383 } 384 }, 385 saveAccountSettings(settings) { 386 this.startLoader(); 387 this.$store 388 .dispatch('userManagement/saveAccountSettings', settings) 389 .then((message) => this.successToast(message)) 390 .catch(({ message }) => this.errorToast(message)) 391 .finally(() => this.endLoader()); 392 }, 393 }, 394}; 395</script> 396 397<style lang="scss" scoped> 398.btn.collapsed { 399 svg { 400 transform: rotate(180deg); 401 } 402} 403</style> 404