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