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