1<template> 2 <b-container fluid="xl"> 3 <page-title /> 4 <b-row> 5 <b-col sm="6" lg="5" xl="4"> 6 <page-section :section-title="$t('pageDumps.initiateDump')"> 7 <dumps-form /> 8 </page-section> 9 </b-col> 10 </b-row> 11 <b-row> 12 <b-col xl="10"> 13 <page-section :section-title="$t('pageDumps.dumpsAvailableOnBmc')"> 14 <b-row class="align-items-start"> 15 <b-col sm="8" xl="6" class="d-sm-flex align-items-end"> 16 <search 17 :placeholder="$t('pageDumps.table.searchDumps')" 18 @change-search="onChangeSearchInput" 19 @clear-search="onClearSearchInput" 20 /> 21 <div class="ms-sm-4"> 22 <table-cell-count 23 :filtered-items-count="filteredRows" 24 :total-number-of-cells="allDumps.length" 25 ></table-cell-count> 26 </div> 27 </b-col> 28 <b-col sm="8" md="7" xl="6"> 29 <table-date-filter @change="onChangeDateTimeFilter" /> 30 </b-col> 31 </b-row> 32 <b-row> 33 <b-col class="text-end"> 34 <table-filter 35 :filters="tableFilters" 36 @filter-change="onFilterChange" 37 /> 38 </b-col> 39 </b-row> 40 <table-toolbar 41 :selected-items-count=" 42 Array.isArray(selectedRows) ? selectedRows.length : 0 43 " 44 :actions="batchActions" 45 @clear-selected="clearSelectedRows($refs.table)" 46 @batch-action="onTableBatchAction" 47 /> 48 <b-table 49 ref="table" 50 show-empty 51 hover 52 sort-icon-left 53 must-sort 54 thead-class="table-light" 55 :sort-desc="[true]" 56 selectable 57 no-select-on-click 58 responsive="md" 59 :sort-by="['dateTime']" 60 :fields="fields" 61 :items="filteredDumps" 62 :empty-text="$t('global.table.emptyMessage')" 63 :empty-filtered-text="$t('global.table.emptySearchMessage')" 64 :filter="searchFilter" 65 :busy="isBusy" 66 @filtered="onFiltered" 67 @row-selected="onRowSelected($event, filteredRows)" 68 > 69 <!-- Checkbox column --> 70 <template #head(checkbox)> 71 <b-form-checkbox 72 v-model="tableHeaderCheckboxModel" 73 :indeterminate="tableHeaderCheckboxIndeterminate" 74 @change="onChangeHeaderCheckbox($refs.table, $event)" 75 > 76 <span class="visually-hidden-focusable"> 77 {{ $t('global.table.selectAll') }} 78 </span> 79 </b-form-checkbox> 80 </template> 81 <template #cell(checkbox)="row"> 82 <b-form-checkbox 83 v-model="row.rowSelected" 84 @change="toggleSelectRow($refs.table, row.index)" 85 > 86 <span class="visually-hidden-focusable"> 87 {{ $t('global.table.selectItem') }} 88 </span> 89 </b-form-checkbox> 90 </template> 91 92 <!-- Date and Time column --> 93 <template #cell(dateTime)="{ value }"> 94 <p class="mb-0">{{ $filters.formatDate(value) }}</p> 95 <p class="mb-0">{{ $filters.formatTime(value) }}</p> 96 </template> 97 98 <!-- Size column --> 99 <template #cell(size)="{ value }"> 100 {{ convertBytesToMegabytes(value) }} MB 101 </template> 102 103 <!-- Actions column --> 104 <template #cell(actions)="row"> 105 <table-row-action 106 v-for="(action, index) in row.item.actions" 107 :key="index" 108 :value="action.value" 109 :title="action.title" 110 :download-location="row.item.data" 111 :export-name="exportFileName(row)" 112 @click-table-action="onTableRowAction($event, row.item)" 113 > 114 <template #icon> 115 <icon-download v-if="action.value === 'download'" /> 116 <icon-delete v-if="action.value === 'delete'" /> 117 </template> 118 </table-row-action> 119 </template> 120 </b-table> 121 </page-section> 122 </b-col> 123 </b-row> 124 <!-- Table pagination --> 125 <b-row> 126 <b-col sm="6" xl="5"> 127 <b-form-group 128 class="table-pagination-select" 129 :label="$t('global.table.itemsPerPage')" 130 label-for="pagination-items-per-page" 131 > 132 <b-form-select 133 id="pagination-items-per-page" 134 v-model="perPage" 135 :options="itemsPerPageOptions" 136 /> 137 </b-form-group> 138 </b-col> 139 <b-col sm="6" xl="5"> 140 <b-pagination 141 v-model="currentPage" 142 first-number 143 last-number 144 :per-page="perPage" 145 :total-rows="getTotalRowCount(filteredRows)" 146 aria-controls="table-dump-entries" 147 /> 148 </b-col> 149 </b-row> 150 </b-container> 151</template> 152 153<script> 154import IconDelete from '@carbon/icons-vue/es/trash-can/20'; 155import IconDownload from '@carbon/icons-vue/es/download/20'; 156import DumpsForm from './DumpsForm'; 157import PageSection from '@/components/Global/PageSection'; 158import PageTitle from '@/components/Global/PageTitle'; 159import Search from '@/components/Global/Search'; 160import TableCellCount from '@/components/Global/TableCellCount'; 161import TableDateFilter from '@/components/Global/TableDateFilter'; 162import TableRowAction from '@/components/Global/TableRowAction'; 163import TableToolbar from '@/components/Global/TableToolbar'; 164import BVTableSelectableMixin, { 165 selectedRows, 166 tableHeaderCheckboxModel, 167 tableHeaderCheckboxIndeterminate, 168} from '@/components/Mixins/BVTableSelectableMixin'; 169import BVToastMixin from '@/components/Mixins/BVToastMixin'; 170import BVPaginationMixin, { 171 currentPage, 172 perPage, 173 itemsPerPageOptions, 174} from '@/components/Mixins/BVPaginationMixin'; 175import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin'; 176import SearchFilterMixin, { 177 searchFilter, 178} from '@/components/Mixins/SearchFilterMixin'; 179import TableFilter from '@/components/Global/TableFilter'; 180import TableFilterMixin from '@/components/Mixins/TableFilterMixin'; 181import i18n from '@/i18n'; 182import { useI18n } from 'vue-i18n'; 183import { useModal } from 'bootstrap-vue-next'; 184 185export default { 186 components: { 187 DumpsForm, 188 IconDelete, 189 IconDownload, 190 PageSection, 191 PageTitle, 192 Search, 193 TableCellCount, 194 TableDateFilter, 195 TableRowAction, 196 TableToolbar, 197 TableFilter, 198 }, 199 mixins: [ 200 BVTableSelectableMixin, 201 BVToastMixin, 202 BVPaginationMixin, 203 LoadingBarMixin, 204 SearchFilterMixin, 205 TableFilterMixin, 206 ], 207 beforeRouteLeave(to, from, next) { 208 // Hide loader if the user navigates to another page 209 // before request is fulfilled. 210 this.hideLoader(); 211 next(); 212 }, 213 setup() { 214 const bvModal = useModal(); 215 return { bvModal }; 216 }, 217 data() { 218 return { 219 $t: useI18n().t, 220 isBusy: true, 221 fields: [ 222 { 223 key: 'checkbox', 224 sortable: false, 225 }, 226 { 227 key: 'dateTime', 228 label: i18n.global.t('pageDumps.table.dateAndTime'), 229 sortable: true, 230 }, 231 { 232 key: 'dumpType', 233 label: i18n.global.t('pageDumps.table.dumpType'), 234 sortable: true, 235 }, 236 { 237 key: 'id', 238 label: i18n.global.t('pageDumps.table.id'), 239 sortable: true, 240 }, 241 { 242 key: 'size', 243 label: i18n.global.t('pageDumps.table.size'), 244 sortable: true, 245 }, 246 { 247 key: 'actions', 248 sortable: false, 249 label: '', 250 tdClass: 'text-end text-nowrap', 251 }, 252 ], 253 batchActions: [ 254 { 255 value: 'delete', 256 label: i18n.global.t('global.action.delete'), 257 }, 258 ], 259 tableFilters: [ 260 { 261 key: 'dumpType', 262 label: i18n.global.t('pageDumps.table.dumpType'), 263 values: [ 264 'BMC Dump Entry', 265 'Hostboot Dump Entry', 266 'Resource Dump Entry', 267 'System Dump Entry', 268 ], 269 }, 270 ], 271 activeFilters: [], 272 currentPage: currentPage, 273 filterEndDate: null, 274 filterStartDate: null, 275 itemsPerPageOptions: itemsPerPageOptions, 276 perPage: perPage, 277 searchFilter, 278 searchTotalFilteredRows: 0, 279 selectedRows, 280 tableHeaderCheckboxIndeterminate, 281 tableHeaderCheckboxModel, 282 }; 283 }, 284 computed: { 285 filteredRows() { 286 return this.searchFilter 287 ? this.searchTotalFilteredRows 288 : this.filteredDumps.length; 289 }, 290 allDumps() { 291 return this.$store.getters['dumps/allDumps'].map((item) => { 292 return { 293 ...item, 294 actions: [ 295 { 296 value: 'download', 297 title: i18n.global.t('global.action.download'), 298 }, 299 { 300 value: 'delete', 301 title: i18n.global.t('global.action.delete'), 302 }, 303 ], 304 }; 305 }); 306 }, 307 filteredDumpsByDate() { 308 return this.getFilteredTableDataByDate( 309 this.allDumps, 310 this.filterStartDate, 311 this.filterEndDate, 312 'dateTime', 313 ); 314 }, 315 filteredDumps() { 316 return this.getFilteredTableData( 317 this.filteredDumpsByDate, 318 this.activeFilters, 319 ); 320 }, 321 }, 322 created() { 323 this.startLoader(); 324 this.$store.dispatch('dumps/getAllDumps').finally(() => { 325 this.endLoader(); 326 this.isBusy = false; 327 }); 328 }, 329 methods: { 330 convertBytesToMegabytes(bytes) { 331 return parseFloat((bytes / 1000000).toFixed(3)); 332 }, 333 onFilterChange({ activeFilters }) { 334 this.activeFilters = activeFilters; 335 }, 336 onFiltered(filteredItems) { 337 this.searchTotalFilteredRows = filteredItems.length; 338 }, 339 onChangeDateTimeFilter({ fromDate, toDate }) { 340 this.filterStartDate = fromDate; 341 this.filterEndDate = toDate; 342 }, 343 async onTableRowAction(action, item) { 344 if (action === 'delete') { 345 const ok = await this.confirmDialog( 346 i18n.global.t('pageDumps.modal.deleteDumpConfirmation', 1), 347 { 348 title: i18n.global.t('pageDumps.modal.deleteDump', 1), 349 okTitle: i18n.global.t('pageDumps.modal.deleteDump', 1), 350 cancelTitle: i18n.global.t('global.action.cancel'), 351 }, 352 ); 353 if (ok) 354 this.$store.dispatch('dumps/deleteDumps', [item]).then((messages) => { 355 messages.forEach(({ type, message }) => { 356 if (type === 'success') { 357 this.successToast(message); 358 } else if (type === 'error') { 359 this.errorToast(message); 360 } 361 }); 362 }); 363 } 364 }, 365 async onTableBatchAction(action) { 366 if (action === 'delete') { 367 const ids = (this.selectedRows || []).map((r) => r.Id); 368 const count = ids.length; 369 const ok = await this.confirmDialog( 370 i18n.global.t('pageDumps.modal.deleteDumpConfirmation', count), 371 { 372 title: i18n.global.t('pageDumps.modal.deleteDump', count), 373 okTitle: i18n.global.t('pageDumps.modal.deleteDump', count), 374 cancelTitle: i18n.global.t('global.action.cancel'), 375 }, 376 ); 377 if (ok) { 378 if (this.selectedRows.length === this.dumps.length) { 379 this.$store 380 .dispatch('dumps/deleteAllDumps') 381 .then((success) => this.successToast(success)) 382 .catch(({ message }) => this.errorToast(message)); 383 } else { 384 this.$store 385 .dispatch('dumps/deleteDumps', this.selectedRows) 386 .then((messages) => { 387 messages.forEach(({ type, message }) => { 388 if (type === 'success') { 389 this.successToast(message); 390 } else if (type === 'error') { 391 this.errorToast(message); 392 } 393 }); 394 }); 395 } 396 } 397 } 398 }, 399 exportFileName(row) { 400 let filename = row.item.dumpType + '_' + row.item.id + '.tar.xz'; 401 filename = filename.replace(RegExp(' ', 'g'), '_'); 402 return filename; 403 }, 404 confirmDialog(message, options = {}) { 405 return this.$confirm({ message, ...options }); 406 }, 407 }, 408}; 409</script> 410