1<template>
2  <page-section :section-title="$t('pageInventory.fans')">
3    <b-row class="align-items-end">
4      <b-col sm="6" md="5" xl="4">
5        <search
6          @change-search="onChangeSearchInput"
7          @clear-search="onClearSearchInput"
8        />
9      </b-col>
10      <b-col sm="6" md="3" xl="2">
11        <table-cell-count
12          :filtered-items-count="filteredRows"
13          :total-number-of-cells="fans.length"
14        ></table-cell-count>
15      </b-col>
16    </b-row>
17    <b-table
18      sort-icon-left
19      no-sort-reset
20      hover
21      responsive="md"
22      sort-by="health"
23      show-empty
24      :items="fans"
25      :fields="fields"
26      :sort-desc="true"
27      :sort-compare="sortCompare"
28      :filter="searchFilter"
29      :empty-text="$t('global.table.emptyMessage')"
30      :empty-filtered-text="$t('global.table.emptySearchMessage')"
31      @filtered="onFiltered"
32    >
33      <!-- Expand chevron icon -->
34      <template #cell(expandRow)="row">
35        <b-button
36          variant="link"
37          data-test-id="hardwareStatus-button-expandFans"
38          :title="expandRowLabel"
39          class="btn-icon-only"
40          @click="toggleRowDetails(row)"
41        >
42          <icon-chevron />
43          <span class="sr-only">{{ expandRowLabel }}</span>
44        </b-button>
45      </template>
46
47      <!-- Health -->
48      <template #cell(health)="{ value }">
49        <status-icon :status="statusIcon(value)" />
50        {{ value }}
51      </template>
52
53      <template #row-details="{ item }">
54        <b-container fluid>
55          <b-row>
56            <b-col sm="6" xl="4">
57              <dl>
58                <!-- Name -->
59                <dt>{{ $t('pageInventory.table.name') }}:</dt>
60                <dd>{{ dataFormatter(item.name) }}</dd>
61              </dl>
62              <dl>
63                <!-- Serial number -->
64                <dt>{{ $t('pageInventory.table.serialNumber') }}:</dt>
65                <dd>{{ dataFormatter(item.serialNumber) }}</dd>
66              </dl>
67              <dl>
68                <!-- Part number -->
69                <dt>{{ $t('pageInventory.table.partNumber') }}:</dt>
70                <dd>{{ dataFormatter(item.partNumber) }}</dd>
71              </dl>
72              <dl>
73                <!-- Fan speed -->
74                <dt>{{ $t('pageInventory.table.fanSpeed') }}:</dt>
75                <dd>{{ dataFormatter(item.speed) }}</dd>
76              </dl>
77            </b-col>
78            <b-col sm="6" xl="4">
79              <dl>
80                <!-- Status state -->
81                <dt>{{ $t('pageInventory.table.statusState') }}:</dt>
82                <dd>{{ dataFormatter(item.statusState) }}</dd>
83              </dl>
84              <dl>
85                <!-- Health Rollup state -->
86                <dt>{{ $t('pageInventory.table.statusHealthRollup') }}:</dt>
87                <dd>{{ dataFormatter(item.healthRollup) }}</dd>
88              </dl>
89            </b-col>
90          </b-row>
91        </b-container>
92      </template>
93    </b-table>
94  </page-section>
95</template>
96
97<script>
98import PageSection from '@/components/Global/PageSection';
99import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
100import TableCellCount from '@/components/Global/TableCellCount';
101
102import StatusIcon from '@/components/Global/StatusIcon';
103import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin';
104import TableSortMixin from '@/components/Mixins/TableSortMixin';
105import Search from '@/components/Global/Search';
106import SearchFilterMixin, {
107  searchFilter,
108} from '@/components/Mixins/SearchFilterMixin';
109import TableRowExpandMixin, {
110  expandRowLabel,
111} from '@/components/Mixins/TableRowExpandMixin';
112
113export default {
114  components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount },
115  mixins: [
116    TableRowExpandMixin,
117    DataFormatterMixin,
118    TableSortMixin,
119    SearchFilterMixin,
120  ],
121  data() {
122    return {
123      fields: [
124        {
125          key: 'expandRow',
126          label: '',
127          tdClass: 'table-row-expand',
128          sortable: false,
129        },
130        {
131          key: 'id',
132          label: this.$t('pageInventory.table.id'),
133          formatter: this.dataFormatter,
134          sortable: true,
135        },
136        {
137          key: 'health',
138          label: this.$t('pageInventory.table.health'),
139          formatter: this.dataFormatter,
140          sortable: true,
141          tdClass: 'text-nowrap',
142        },
143        {
144          key: 'partNumber',
145          label: this.$t('pageInventory.table.partNumber'),
146          formatter: this.dataFormatter,
147          sortable: true,
148        },
149        {
150          key: 'serialNumber',
151          label: this.$t('pageInventory.table.serialNumber'),
152          formatter: this.dataFormatter,
153        },
154      ],
155      searchFilter: searchFilter,
156      searchTotalFilteredRows: 0,
157      expandRowLabel: expandRowLabel,
158    };
159  },
160  computed: {
161    filteredRows() {
162      return this.searchFilter
163        ? this.searchTotalFilteredRows
164        : this.fans.length;
165    },
166    fans() {
167      return this.$store.getters['fan/fans'];
168    },
169  },
170  created() {
171    this.$store.dispatch('fan/getFanInfo').finally(() => {
172      // Emit initial data fetch complete to parent component
173      this.$root.$emit('hardware-status-fans-complete');
174    });
175  },
176  methods: {
177    sortCompare(a, b, key) {
178      if (key === 'health') {
179        return this.sortStatus(a, b, key);
180      }
181    },
182    onFiltered(filteredItems) {
183      this.searchTotalFilteredRows = filteredItems.length;
184    },
185  },
186};
187</script>
188