xref: /openbmc/webui-vue/src/views/Logs/Dumps/Dumps.vue (revision 7c1cfe7e)
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="onChangeSearchFilter"
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">{{ value | formatDate }}</p>
88              <p class="mb-0">{{ value | formatTime }}</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>
147import IconDelete from '@carbon/icons-vue/es/trash-can/20';
148import IconDownload from '@carbon/icons-vue/es/download/20';
149import DumpsForm from './DumpsForm';
150import PageSection from '@/components/Global/PageSection';
151import PageTitle from '@/components/Global/PageTitle';
152import Search from '@/components/Global/Search';
153import TableCellCount from '@/components/Global/TableCellCount';
154import TableDateFilter from '@/components/Global/TableDateFilter';
155import TableRowAction from '@/components/Global/TableRowAction';
156import TableToolbar from '@/components/Global/TableToolbar';
157import BVTableSelectableMixin, {
158  selectedRows,
159  tableHeaderCheckboxModel,
160  tableHeaderCheckboxIndeterminate,
161} from '@/components/Mixins/BVTableSelectableMixin';
162import BVToastMixin from '@/components/Mixins/BVToastMixin';
163import BVPaginationMixin, {
164  currentPage,
165  perPage,
166  itemsPerPageOptions,
167} from '@/components/Mixins/BVPaginationMixin';
168import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
169import SearchFilterMixin, {
170  searchFilter,
171} from '@/components/Mixins/SearchFilterMixin';
172import TableFilter from '@/components/Global/TableFilter';
173import TableFilterMixin from '@/components/Mixins/TableFilterMixin';
174
175export default {
176  components: {
177    DumpsForm,
178    IconDelete,
179    IconDownload,
180    PageSection,
181    PageTitle,
182    Search,
183    TableCellCount,
184    TableDateFilter,
185    TableRowAction,
186    TableToolbar,
187    TableFilter,
188  },
189  mixins: [
190    BVTableSelectableMixin,
191    BVToastMixin,
192    BVPaginationMixin,
193    LoadingBarMixin,
194    SearchFilterMixin,
195    TableFilterMixin,
196  ],
197  beforeRouteLeave(to, from, next) {
198    // Hide loader if the user navigates to another page
199    // before request is fulfilled.
200    this.hideLoader();
201    next();
202  },
203  data() {
204    return {
205      isBusy: true,
206      fields: [
207        {
208          key: 'checkbox',
209          sortable: false,
210        },
211        {
212          key: 'dateTime',
213          label: this.$t('pageDumps.table.dateAndTime'),
214          sortable: true,
215        },
216        {
217          key: 'dumpType',
218          label: this.$t('pageDumps.table.dumpType'),
219          sortable: true,
220        },
221        {
222          key: 'id',
223          label: this.$t('pageDumps.table.id'),
224          sortable: true,
225        },
226        {
227          key: 'size',
228          label: this.$t('pageDumps.table.size'),
229          sortable: true,
230        },
231        {
232          key: 'actions',
233          sortable: false,
234          label: '',
235          tdClass: 'text-right text-nowrap',
236        },
237      ],
238      batchActions: [
239        {
240          value: 'delete',
241          label: this.$t('global.action.delete'),
242        },
243      ],
244      tableFilters: [
245        {
246          key: 'dumpType',
247          label: this.$t('pageDumps.table.dumpType'),
248          values: [
249            'BMC Dump Entry',
250            'Hostboot Dump Entry',
251            'Resource Dump Entry',
252            'System Dump Entry',
253          ],
254        },
255      ],
256      activeFilters: [],
257      currentPage: currentPage,
258      filterEndDate: null,
259      filterStartDate: null,
260      itemsPerPageOptions: itemsPerPageOptions,
261      perPage: perPage,
262      searchFilter,
263      searchTotalFilteredRows: 0,
264      selectedRows,
265      tableHeaderCheckboxIndeterminate,
266      tableHeaderCheckboxModel,
267    };
268  },
269  computed: {
270    filteredRows() {
271      return this.searchFilter
272        ? this.searchTotalFilteredRows
273        : this.filteredDumps.length;
274    },
275    allDumps() {
276      return this.$store.getters['dumps/allDumps'].map((item) => {
277        return {
278          ...item,
279          actions: [
280            {
281              value: 'download',
282              title: this.$t('global.action.download'),
283            },
284            {
285              value: 'delete',
286              title: this.$t('global.action.delete'),
287            },
288          ],
289        };
290      });
291    },
292    filteredDumpsByDate() {
293      return this.getFilteredTableDataByDate(
294        this.allDumps,
295        this.filterStartDate,
296        this.filterEndDate,
297        'dateTime'
298      );
299    },
300    filteredDumps() {
301      return this.getFilteredTableData(
302        this.filteredDumpsByDate,
303        this.activeFilters
304      );
305    },
306  },
307  created() {
308    this.startLoader();
309    this.$store.dispatch('dumps/getBmcDumpEntries').finally(() => {
310      this.endLoader();
311      this.isBusy = false;
312    });
313  },
314  methods: {
315    convertBytesToMegabytes(bytes) {
316      return parseFloat((bytes / 1000000).toFixed(3));
317    },
318    onFilterChange({ activeFilters }) {
319      this.activeFilters = activeFilters;
320    },
321    onFiltered(filteredItems) {
322      this.searchTotalFilteredRows = filteredItems.length;
323    },
324    onChangeDateTimeFilter({ fromDate, toDate }) {
325      this.filterStartDate = fromDate;
326      this.filterEndDate = toDate;
327    },
328    onTableRowAction(action, dump) {
329      if (action === 'delete') {
330        this.$bvModal
331          .msgBoxConfirm(this.$tc('pageDumps.modal.deleteDumpConfirmation'), {
332            title: this.$tc('pageDumps.modal.deleteDump'),
333            okTitle: this.$tc('pageDumps.modal.deleteDump'),
334            cancelTitle: this.$t('global.action.cancel'),
335          })
336          .then((deleteConfrimed) => {
337            if (deleteConfrimed) {
338              this.$store
339                .dispatch('dumps/deleteDumps', [dump])
340                .then((messages) => {
341                  messages.forEach(({ type, message }) => {
342                    if (type === 'success') {
343                      this.successToast(message);
344                    } else if (type === 'error') {
345                      this.errorToast(message);
346                    }
347                  });
348                });
349            }
350          });
351      }
352    },
353    onTableBatchAction(action) {
354      if (action === 'delete') {
355        this.$bvModal
356          .msgBoxConfirm(
357            this.$tc(
358              'pageDumps.modal.deleteDumpConfirmation',
359              this.selectedRows.length
360            ),
361            {
362              title: this.$tc(
363                'pageDumps.modal.deleteDump',
364                this.selectedRows.length
365              ),
366              okTitle: this.$tc(
367                'pageDumps.modal.deleteDump',
368                this.selectedRows.length
369              ),
370              cancelTitle: this.$t('global.action.cancel'),
371            }
372          )
373          .then((deleteConfrimed) => {
374            if (deleteConfrimed) {
375              if (this.selectedRows.length === this.dumps.length) {
376                this.$store
377                  .dispatch('dumps/deleteAllDumps')
378                  .then((success) => this.successToast(success))
379                  .catch(({ message }) => this.errorToast(message));
380              } else {
381                this.$store
382                  .dispatch('dumps/deleteDumps', this.selectedRows)
383                  .then((messages) => {
384                    messages.forEach(({ type, message }) => {
385                      if (type === 'success') {
386                        this.successToast(message);
387                      } else if (type === 'error') {
388                        this.errorToast(message);
389                      }
390                    });
391                  });
392              }
393            }
394          });
395      }
396    },
397    exportFileName(row) {
398      let filename = row.item.dumpType + '_' + row.item.id + '.tar.xz';
399      filename = filename.replace(RegExp(' ', 'g'), '_');
400      return filename;
401    },
402  },
403};
404</script>
405