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