xref: /openbmc/webui-vue/src/views/Logs/Dumps/Dumps.vue (revision 828dda9b)
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  </b-container>
109</template>
110
111<script>
112import IconDelete from '@carbon/icons-vue/es/trash-can/20';
113import IconDownload from '@carbon/icons-vue/es/download/20';
114
115import DumpsForm from './DumpsForm';
116import PageSection from '@/components/Global/PageSection';
117import PageTitle from '@/components/Global/PageTitle';
118import Search from '@/components/Global/Search';
119import TableCellCount from '@/components/Global/TableCellCount';
120import TableDateFilter from '@/components/Global/TableDateFilter';
121import TableRowAction from '@/components/Global/TableRowAction';
122import TableToolbar from '@/components/Global/TableToolbar';
123
124import BVTableSelectableMixin, {
125  selectedRows,
126  tableHeaderCheckboxModel,
127  tableHeaderCheckboxIndeterminate,
128} from '@/components/Mixins/BVTableSelectableMixin';
129import BVToastMixin from '@/components/Mixins/BVToastMixin';
130import LoadingBarMixin from '@/components/Mixins/LoadingBarMixin';
131import SearchFilterMixin, {
132  searchFilter,
133} from '@/components/Mixins/SearchFilterMixin';
134import TableFilterMixin from '@/components/Mixins/TableFilterMixin';
135
136export default {
137  components: {
138    DumpsForm,
139    IconDelete,
140    IconDownload,
141    PageSection,
142    PageTitle,
143    Search,
144    TableCellCount,
145    TableDateFilter,
146    TableRowAction,
147    TableToolbar,
148  },
149  mixins: [
150    BVTableSelectableMixin,
151    BVToastMixin,
152    LoadingBarMixin,
153    SearchFilterMixin,
154    TableFilterMixin,
155  ],
156  beforeRouteLeave(to, from, next) {
157    // Hide loader if the user navigates to another page
158    // before request is fulfilled.
159    this.hideLoader();
160    next();
161  },
162  data() {
163    return {
164      fields: [
165        {
166          key: 'checkbox',
167          sortable: false,
168        },
169        {
170          key: 'dateTime',
171          label: this.$t('pageDumps.table.dateAndTime'),
172          sortable: true,
173        },
174        {
175          key: 'dumpType',
176          label: this.$t('pageDumps.table.dumpType'),
177          sortable: true,
178        },
179        {
180          key: 'id',
181          label: this.$t('pageDumps.table.id'),
182          sortable: true,
183        },
184        {
185          key: 'size',
186          label: this.$t('pageDumps.table.size'),
187          sortable: true,
188        },
189        {
190          key: 'actions',
191          sortable: false,
192          label: '',
193          tdClass: 'text-right text-nowrap',
194        },
195      ],
196      batchActions: [
197        {
198          value: 'delete',
199          label: this.$t('global.action.delete'),
200        },
201      ],
202      filterEndDate: null,
203      filterStartDate: null,
204      searchFilter,
205      searchFilteredItemsCount: 0,
206      selectedRows,
207      tableHeaderCheckboxIndeterminate,
208      tableHeaderCheckboxModel,
209    };
210  },
211  computed: {
212    dumps() {
213      return this.$store.getters['dumps/bmcDumps'];
214    },
215    tableItems() {
216      return this.dumps.map((item) => {
217        return {
218          ...item,
219          actions: [
220            {
221              value: 'download',
222              title: this.$t('global.action.download'),
223            },
224            {
225              value: 'delete',
226              title: this.$t('global.action.delete'),
227            },
228          ],
229        };
230      });
231    },
232    filteredTableItems() {
233      return this.getFilteredTableDataByDate(
234        this.tableItems,
235        this.filterStartDate,
236        this.filterEndDate,
237        'dateTime'
238      );
239    },
240    filteredItemCount() {
241      return this.searchFilter
242        ? this.searchFilteredItemsCount
243        : this.filteredTableItems.length;
244    },
245  },
246  created() {
247    this.startLoader();
248    this.$store.dispatch('dumps/getBmcDumps').finally(() => this.endLoader());
249  },
250  methods: {
251    convertBytesToMegabytes(bytes) {
252      return parseFloat((bytes / 1000000).toFixed(3));
253    },
254    onChangeSearchFilter(items) {
255      this.searchFilteredItemsCount = items.length;
256    },
257    onChangeDateTimeFilter({ fromDate, toDate }) {
258      this.filterStartDate = fromDate;
259      this.filterEndDate = toDate;
260    },
261    onTableRowAction(action, dump) {
262      if (action === 'delete') {
263        this.$bvModal
264          .msgBoxConfirm(this.$tc('pageDumps.modal.deleteDumpConfirmation'), {
265            title: this.$tc('pageDumps.modal.deleteDump'),
266            okTitle: this.$tc('pageDumps.modal.deleteDump'),
267            cancelTitle: this.$t('global.action.cancel'),
268          })
269          .then((deleteConfrimed) => {
270            if (deleteConfrimed) {
271              this.$store
272                .dispatch('dumps/deleteDumps', [dump])
273                .then((messages) => {
274                  messages.forEach(({ type, message }) => {
275                    if (type === 'success') {
276                      this.successToast(message);
277                    } else if (type === 'error') {
278                      this.errorToast(message);
279                    }
280                  });
281                });
282            }
283          });
284      }
285    },
286    onTableBatchAction(action) {
287      if (action === 'delete') {
288        this.$bvModal
289          .msgBoxConfirm(
290            this.$tc(
291              'pageDumps.modal.deleteDumpConfirmation',
292              this.selectedRows.length
293            ),
294            {
295              title: this.$tc(
296                'pageDumps.modal.deleteDump',
297                this.selectedRows.length
298              ),
299              okTitle: this.$tc(
300                'pageDumps.modal.deleteDump',
301                this.selectedRows.length
302              ),
303              cancelTitle: this.$t('global.action.cancel'),
304            }
305          )
306          .then((deleteConfrimed) => {
307            if (deleteConfrimed) {
308              if (this.selectedRows.length === this.dumps.length) {
309                this.$store
310                  .dispatch('dumps/deleteAllDumps')
311                  .then((success) => this.successToast(success))
312                  .catch(({ message }) => this.errorToast(message));
313              } else {
314                this.$store
315                  .dispatch('dumps/deleteDumps', this.selectedRows)
316                  .then((messages) => {
317                    messages.forEach(({ type, message }) => {
318                      if (type === 'success') {
319                        this.successToast(message);
320                      } else if (type === 'error') {
321                        this.errorToast(message);
322                      }
323                    });
324                  });
325              }
326            }
327          });
328      }
329    },
330    exportFileName(row) {
331      let filename = row.item.dumpType + '_' + row.item.id + '.tar.gz';
332      filename = filename.replace(RegExp(' ', 'g'), '_');
333      return filename;
334    },
335  },
336};
337</script>
338