xref: /openbmc/webui-vue/src/views/Logs/Dumps/Dumps.vue (revision d7cd12c2)
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">{{ 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            autoFocusButton: 'ok',
336          })
337          .then((deleteConfrimed) => {
338            if (deleteConfrimed) {
339              this.$store
340                .dispatch('dumps/deleteDumps', [dump])
341                .then((messages) => {
342                  messages.forEach(({ type, message }) => {
343                    if (type === 'success') {
344                      this.successToast(message);
345                    } else if (type === 'error') {
346                      this.errorToast(message);
347                    }
348                  });
349                });
350            }
351          });
352      }
353    },
354    onTableBatchAction(action) {
355      if (action === 'delete') {
356        this.$bvModal
357          .msgBoxConfirm(
358            this.$tc(
359              'pageDumps.modal.deleteDumpConfirmation',
360              this.selectedRows.length,
361            ),
362            {
363              title: this.$tc(
364                'pageDumps.modal.deleteDump',
365                this.selectedRows.length,
366              ),
367              okTitle: this.$tc(
368                'pageDumps.modal.deleteDump',
369                this.selectedRows.length,
370              ),
371              cancelTitle: this.$t('global.action.cancel'),
372              autoFocusButton: 'ok',
373            },
374          )
375          .then((deleteConfrimed) => {
376            if (deleteConfrimed) {
377              if (this.selectedRows.length === this.dumps.length) {
378                this.$store
379                  .dispatch('dumps/deleteAllDumps')
380                  .then((success) => this.successToast(success))
381                  .catch(({ message }) => this.errorToast(message));
382              } else {
383                this.$store
384                  .dispatch('dumps/deleteDumps', this.selectedRows)
385                  .then((messages) => {
386                    messages.forEach(({ type, message }) => {
387                      if (type === 'success') {
388                        this.successToast(message);
389                      } else if (type === 'error') {
390                        this.errorToast(message);
391                      }
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  },
405};
406</script>
407