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