1<template> 2 <b-container fluid="xl"> 3 <page-title /> 4 <b-row class="align-items-end"> 5 <b-col sm="6" md="5" xl="4"> 6 <search 7 :placeholder="$t('pageSessions.table.searchSessions')" 8 data-test-id="sessions-input-searchSessions" 9 @change-search="onChangeSearchInput" 10 @clear-search="onClearSearchInput" 11 /> 12 </b-col> 13 <b-col sm="3" md="3" xl="2"> 14 <table-cell-count 15 :filtered-items-count="filteredRows" 16 :total-number-of-cells="allConnections.length" 17 ></table-cell-count> 18 </b-col> 19 </b-row> 20 <b-row> 21 <b-col> 22 <table-toolbar 23 ref="toolbar" 24 :selected-items-count="selectedRows.length" 25 :actions="batchActions" 26 @clear-selected="clearSelectedRows($refs.table)" 27 @batch-action="onBatchAction" 28 > 29 </table-toolbar> 30 <b-table 31 id="table-session-logs" 32 ref="table" 33 responsive="md" 34 selectable 35 no-select-on-click 36 hover 37 show-empty 38 sort-by="clientID" 39 :fields="fields" 40 :items="allConnections" 41 :filter="searchFilter" 42 :empty-text="$t('global.table.emptyMessage')" 43 :per-page="perPage" 44 :current-page="currentPage" 45 @filtered="onFiltered" 46 @row-selected="onRowSelected($event, allConnections.length)" 47 > 48 <!-- Checkbox column --> 49 <template #head(checkbox)> 50 <b-form-checkbox 51 v-model="tableHeaderCheckboxModel" 52 data-test-id="sessions-checkbox-selectAll" 53 :indeterminate="tableHeaderCheckboxIndeterminate" 54 @change="onChangeHeaderCheckbox($refs.table)" 55 > 56 <span class="sr-only">{{ $t('global.table.selectAll') }}</span> 57 </b-form-checkbox> 58 </template> 59 <template #cell(checkbox)="row"> 60 <b-form-checkbox 61 v-model="row.rowSelected" 62 :data-test-id="`sessions-checkbox-selectRow-${row.index}`" 63 @change="toggleSelectRow($refs.table, row.index)" 64 > 65 <span class="sr-only">{{ $t('global.table.selectItem') }}</span> 66 </b-form-checkbox> 67 </template> 68 69 <!-- Actions column --> 70 <template #cell(actions)="row" class="ml-3"> 71 <table-row-action 72 v-for="(action, index) in row.item.actions" 73 :key="index" 74 :value="action.value" 75 :title="action.title" 76 :row-data="row.item" 77 :btn-icon-only="false" 78 :data-test-id="`sessions-button-disconnect-${row.index}`" 79 @click-table-action="onTableRowAction($event, row.item)" 80 ></table-row-action> 81 </template> 82 </b-table> 83 </b-col> 84 </b-row> 85 86 <!-- Table pagination --> 87 <b-row> 88 <b-col sm="6"> 89 <b-form-group 90 class="table-pagination-select" 91 :label="$t('global.table.itemsPerPage')" 92 label-for="pagination-items-per-page" 93 > 94 <b-form-select 95 id="pagination-items-per-page" 96 v-model="perPage" 97 :options="itemsPerPageOptions" 98 /> 99 </b-form-group> 100 </b-col> 101 <b-col sm="6"> 102 <b-pagination 103 v-model="currentPage" 104 first-number 105 last-number 106 :per-page="perPage" 107 :total-rows="getTotalRowCount(filteredRows)" 108 aria-controls="table-session-logs" 109 /> 110 </b-col> 111 </b-row> 112 </b-container> 113</template> 114 115<script> 116import PageTitle from '@/components/Global/PageTitle'; 117import Search from '@/components/Global/Search'; 118import TableCellCount from '@/components/Global/TableCellCount'; 119import TableRowAction from '@/components/Global/TableRowAction'; 120import TableToolbar from '@/components/Global/TableToolbar'; 121 122import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin'; 123import BVPaginationMixin, { 124 currentPage, 125 perPage, 126 itemsPerPageOptions, 127} from '@/components/Mixins/BVPaginationMixin'; 128import BVTableSelectableMixin, { 129 selectedRows, 130 tableHeaderCheckboxModel, 131 tableHeaderCheckboxIndeterminate, 132} from '@/components/Mixins/BVTableSelectableMixin'; 133import BVToastMixin from '@/components/Mixins/BVToastMixin'; 134import SearchFilterMixin, { 135 searchFilter, 136} from '@/components/Mixins/SearchFilterMixin'; 137 138export default { 139 components: { 140 PageTitle, 141 Search, 142 TableCellCount, 143 TableRowAction, 144 TableToolbar, 145 }, 146 mixins: [ 147 BVPaginationMixin, 148 BVTableSelectableMixin, 149 BVToastMixin, 150 LoadingBarMixin, 151 SearchFilterMixin, 152 ], 153 beforeRouteLeave(to, from, next) { 154 // Hide loader if the user navigates to another page 155 // before request is fulfilled. 156 this.hideLoader(); 157 next(); 158 }, 159 data() { 160 return { 161 fields: [ 162 { 163 key: 'checkbox', 164 }, 165 { 166 key: 'clientID', 167 label: this.$t('pageSessions.table.clientID'), 168 }, 169 { 170 key: 'username', 171 label: this.$t('pageSessions.table.username'), 172 }, 173 { 174 key: 'ipAddress', 175 label: this.$t('pageSessions.table.ipAddress'), 176 }, 177 { 178 key: 'actions', 179 label: '', 180 }, 181 ], 182 batchActions: [ 183 { 184 value: 'disconnect', 185 label: this.$t('pageSessions.action.disconnect'), 186 }, 187 ], 188 currentPage: currentPage, 189 itemsPerPageOptions: itemsPerPageOptions, 190 perPage: perPage, 191 selectedRows: selectedRows, 192 searchTotalFilteredRows: 0, 193 tableHeaderCheckboxModel: tableHeaderCheckboxModel, 194 tableHeaderCheckboxIndeterminate: tableHeaderCheckboxIndeterminate, 195 searchFilter: searchFilter, 196 }; 197 }, 198 computed: { 199 filteredRows() { 200 return this.searchFilter 201 ? this.searchTotalFilteredRows 202 : this.allConnections.length; 203 }, 204 allConnections() { 205 return this.$store.getters['sessions/allConnections'].map((session) => { 206 return { 207 ...session, 208 actions: [ 209 { 210 value: 'disconnect', 211 title: this.$t('pageSessions.action.disconnect'), 212 }, 213 ], 214 }; 215 }); 216 }, 217 }, 218 created() { 219 this.startLoader(); 220 this.$store 221 .dispatch('sessions/getSessionsData') 222 .finally(() => this.endLoader()); 223 }, 224 methods: { 225 onFiltered(filteredItems) { 226 this.searchTotalFilteredRows = filteredItems.length; 227 }, 228 onChangeSearchInput(event) { 229 this.searchFilter = event; 230 }, 231 disconnectSessions(uris) { 232 this.$store 233 .dispatch('sessions/disconnectSessions', uris) 234 .then((messages) => { 235 messages.forEach(({ type, message }) => { 236 if (type === 'success') { 237 this.successToast(message); 238 } else if (type === 'error') { 239 this.errorToast(message); 240 } 241 }); 242 }); 243 }, 244 onTableRowAction(action, { uri }) { 245 if (action === 'disconnect') { 246 this.$bvModal 247 .msgBoxConfirm(this.$tc('pageSessions.modal.disconnectMessage'), { 248 title: this.$tc('pageSessions.modal.disconnectTitle'), 249 okTitle: this.$t('pageSessions.action.disconnect'), 250 cancelTitle: this.$t('global.action.cancel'), 251 }) 252 .then((deleteConfirmed) => { 253 if (deleteConfirmed) this.disconnectSessions([uri]); 254 }); 255 } 256 }, 257 onBatchAction(action) { 258 if (action === 'disconnect') { 259 const uris = this.selectedRows.map((row) => row.uri); 260 this.$bvModal 261 .msgBoxConfirm( 262 this.$tc( 263 'pageSessions.modal.disconnectMessage', 264 this.selectedRows.length 265 ), 266 { 267 title: this.$tc( 268 'pageSessions.modal.disconnectTitle', 269 this.selectedRows.length 270 ), 271 okTitle: this.$t('pageSessions.action.disconnect'), 272 cancelTitle: this.$t('global.action.cancel'), 273 } 274 ) 275 .then((deleteConfirmed) => { 276 if (deleteConfirmed) { 277 this.disconnectSessions(uris); 278 } 279 }); 280 } 281 }, 282 }, 283}; 284</script> 285<style lang="scss"> 286#table-session-logs { 287 td .btn-link { 288 width: auto !important; 289 } 290} 291</style> 292