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