xref: /openbmc/webui-vue/src/views/HardwareStatus/Inventory/InventoryTablePowerSupplies.vue (revision d36ac8a8be8636ddd0e64ce005d507b21bcdeb00)
1<template>
2  <page-section :section-title="$t('pageInventory.powerSupplies')">
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="powerSupplies.length"
14        ></table-cell-count>
15      </b-col>
16    </b-row>
17    <b-table
18      sort-icon-left
19      must-sort
20      hover
21      responsive="md"
22      thead-class="table-light"
23      :sort-by="['health']"
24      show-empty
25      :items="powerSupplies"
26      :fields="fields"
27      :sort-desc="[true]"
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-expandPowerSupplies"
39          :title="expandRowLabel"
40          class="btn-icon-only"
41          :class="{ collapsed: !row.detailsShowing }"
42          @click="toggleRowDetails(row)"
43        >
44          <icon-chevron />
45          <span class="visually-hidden">{{ expandRowLabel }}</span>
46        </b-button>
47      </template>
48
49      <!-- Health -->
50      <template #cell(health)="{ value }">
51        <status-icon :status="statusIcon(value)" />
52        {{ value }}
53      </template>
54
55      <!-- StatusState -->
56      <template #cell(statusState)="{ value }">
57        <status-icon :status="statusStateIcon(value)" />
58        {{ value }}
59      </template>
60
61      <template #row-details="{ item }">
62        <b-container fluid>
63          <b-row>
64            <b-col sm="6" xl="4">
65              <dl>
66                <!-- Name -->
67                <dt>{{ $t('pageInventory.table.name') }}:</dt>
68                <dd>{{ dataFormatter(item.name) }}</dd>
69                <!-- Part number -->
70                <dt>{{ $t('pageInventory.table.partNumber') }}:</dt>
71                <dd>{{ dataFormatter(item.partNumber) }}</dd>
72                <!-- Serial number -->
73                <dt>{{ $t('pageInventory.table.serialNumber') }}:</dt>
74                <dd>{{ dataFormatter(item.serialNumber) }}</dd>
75                <!-- Spare part number -->
76                <dt>{{ $t('pageInventory.table.sparePartNumber') }}:</dt>
77                <dd>
78                  {{ dataFormatter(item.sparePartNumber) }}
79                </dd>
80                <!-- Model -->
81                <dt>{{ $t('pageInventory.table.model') }}:</dt>
82                <dd>{{ dataFormatter(item.model) }}</dd>
83              </dl>
84            </b-col>
85            <b-col sm="6" xl="4">
86              <dl>
87                <!-- Status state -->
88                <dt>{{ $t('pageInventory.table.statusState') }}:</dt>
89                <dd>{{ dataFormatter(item.statusState) }}</dd>
90                <!-- Status Health rollup state -->
91                <dt>{{ $t('pageInventory.table.statusHealthRollup') }}:</dt>
92                <dd>{{ dataFormatter(item.statusHealth) }}</dd>
93                <!-- Efficiency percent -->
94                <dt>{{ $t('pageInventory.table.efficiencyPercent') }}:</dt>
95                <dd>
96                  {{ dataFormatter(item.efficiencyPercent) }}
97                  {{ $t('unit.Percent') }}
98                </dd>
99                <!-- Power input watts -->
100                <dt>{{ $t('pageInventory.table.powerInputWatts') }}:</dt>
101                <dd>
102                  {{ dataFormatter(item.powerInputWatts) }}
103                  {{ $t('unit.W') }}
104                </dd>
105              </dl>
106            </b-col>
107          </b-row>
108          <div class="section-divider mb-3 mt-3"></div>
109          <b-row>
110            <b-col sm="6" xl="4">
111              <dl>
112                <!-- Manufacturer -->
113                <dt>{{ $t('pageInventory.table.manufacturer') }}:</dt>
114                <dd>{{ dataFormatter(item.manufacturer) }}</dd>
115              </dl>
116            </b-col>
117            <b-col sm="6" xl="4">
118              <dl>
119                <!-- Firmware version -->
120                <dt>{{ $t('pageInventory.table.firmwareVersion') }}:</dt>
121                <dd>
122                  {{ dataFormatter(item.firmwareVersion) }}
123                </dd>
124              </dl>
125            </b-col>
126          </b-row>
127        </b-container>
128      </template>
129    </b-table>
130  </page-section>
131</template>
132
133<script>
134import PageSection from '@/components/Global/PageSection';
135import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
136
137import StatusIcon from '@/components/Global/StatusIcon';
138import TableCellCount from '@/components/Global/TableCellCount';
139import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin';
140import TableSortMixin from '@/components/Mixins/TableSortMixin';
141import Search from '@/components/Global/Search';
142import SearchFilterMixin, {
143  searchFilter,
144} from '@/components/Mixins/SearchFilterMixin';
145import TableRowExpandMixin, {
146  expandRowLabel,
147} from '@/components/Mixins/TableRowExpandMixin';
148import { useI18n } from 'vue-i18n';
149import i18n from '@/i18n';
150
151export default {
152  components: {
153    IconChevron,
154    PageSection,
155    StatusIcon,
156    Search,
157    TableCellCount,
158  },
159  mixins: [
160    TableRowExpandMixin,
161    DataFormatterMixin,
162    TableSortMixin,
163    SearchFilterMixin,
164  ],
165  data() {
166    return {
167      $t: useI18n().t,
168      isBusy: true,
169      fields: [
170        {
171          key: 'expandRow',
172          label: '',
173          tdClass: 'table-row-expand',
174          sortable: false,
175        },
176        {
177          key: 'id',
178          label: i18n.global.t('pageInventory.table.id'),
179          formatter: this.dataFormatter,
180          sortable: true,
181        },
182        {
183          key: 'health',
184          label: i18n.global.t('pageInventory.table.health'),
185          formatter: this.dataFormatter,
186          sortable: true,
187          tdClass: 'text-nowrap',
188        },
189        {
190          key: 'statusState',
191          label: i18n.global.t('pageInventory.table.state'),
192          formatter: this.dataFormatter,
193          tdClass: 'text-nowrap',
194        },
195        {
196          key: 'locationNumber',
197          label: i18n.global.t('pageInventory.table.locationNumber'),
198          formatter: this.dataFormatter,
199          sortable: true,
200        },
201        {
202          key: 'identifyLed',
203          label: i18n.global.t('pageInventory.table.identifyLed'),
204          formatter: this.dataFormatter,
205        },
206      ],
207      searchFilter: searchFilter,
208      searchTotalFilteredRows: 0,
209      expandRowLabel: expandRowLabel,
210    };
211  },
212  computed: {
213    filteredRows() {
214      return this.searchFilter
215        ? this.searchTotalFilteredRows
216        : this.powerSupplies.length;
217    },
218    powerSupplies() {
219      return this.$store.getters['powerSupply/powerSupplies'];
220    },
221  },
222  created() {
223    this.$store.dispatch('powerSupply/getAllPowerSupplies').finally(() => {
224      // Emit initial data fetch complete to parent component
225      require('@/eventBus').default.$emit(
226        'hardware-status-power-supplies-complete',
227      );
228      this.isBusy = false;
229    });
230  },
231  methods: {
232    sortCompare(a, b, key) {
233      if (key === 'health') {
234        return this.sortStatus(a, b, key);
235      } else if (key === 'statusState') {
236        return this.sortStatusState(a, b, key);
237      }
238    },
239    onFiltered(filteredItems) {
240      this.searchTotalFilteredRows = filteredItems.length;
241    },
242    /**
243     * Returns the icon to use for status state based on the given status.
244     * @param {string} status The status to determine the icon for.
245     * @return {string} The icon for the given status.
246     */
247    statusStateIcon(status) {
248      switch (status) {
249        case 'Enabled':
250          return 'success';
251        case 'Absent':
252          return 'warning';
253        default:
254          return '';
255      }
256    },
257    /**
258     * Sorts the status state of two objects based on the provided key.
259     * @param {Object} a The first object to compare.
260     * @param {Object} b The second object to compare.
261     * @param {string} key The key to use for comparison.
262     */
263    sortStatusState(a, b, key) {
264      const statusState = ['Enabled', 'Absent'];
265      return statusState.indexOf(a[key]) - statusState.indexOf(b[key]);
266    },
267  },
268};
269</script>
270