xref: /openbmc/webui-vue/src/views/Logs/Dumps/Dumps.vue (revision de23ea23d88451a2fa2774ec72053772603c23ae)
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';
175
176export 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