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