1<template>
2  <page-section :section-title="$t('pageInventory.processors')">
3    <!-- Search -->
4    <b-row class="align-items-end">
5      <b-col sm="6" md="5" xl="4">
6        <search
7          @change-search="onChangeSearchInput"
8          @clear-search="onClearSearchInput"
9        />
10      </b-col>
11      <b-col sm="6" md="3" xl="2">
12        <table-cell-count
13          :filtered-items-count="filteredRows"
14          :total-number-of-cells="processors.length"
15        ></table-cell-count>
16      </b-col>
17    </b-row>
18    <b-table
19      sort-icon-left
20      no-sort-reset
21      hover
22      responsive="md"
23      show-empty
24      :items="processors"
25      :fields="fields"
26      :sort-desc="true"
27      :filter="searchFilter"
28      :empty-text="$t('global.table.emptyMessage')"
29      :empty-filtered-text="$t('global.table.emptySearchMessage')"
30      @filtered="onFiltered"
31    >
32      <!-- Expand button -->
33      <template #cell(expandRow)="row">
34        <b-button
35          variant="link"
36          data-test-id="hardwareStatus-button-expandProcessors"
37          :title="expandRowLabel"
38          class="btn-icon-only"
39          @click="toggleRowDetails(row)"
40        >
41          <icon-chevron />
42          <span class="sr-only">{{ expandRowLabel }}</span>
43        </b-button>
44      </template>
45      <!-- Health -->
46      <template #cell(health)="{ value }">
47        <status-icon :status="statusIcon(value)" />
48        {{ value }}
49      </template>
50
51      <!-- Toggle identify LED -->
52      <template #cell(identifyLed)="row">
53        <b-form-checkbox
54          v-if="hasIdentifyLed(row.item.identifyLed)"
55          v-model="row.item.identifyLed"
56          name="switch"
57          switch
58          @change="toggleIdentifyLedValue(row.item)"
59        >
60          <span v-if="row.item.identifyLed">
61            {{ $t('global.status.on') }}
62          </span>
63          <span v-else> {{ $t('global.status.off') }} </span>
64        </b-form-checkbox>
65        <div v-else>--</div>
66      </template>
67
68      <template #row-details="{ item }">
69        <b-container fluid>
70          <b-row>
71            <b-col class="mt-2" sm="6" xl="6">
72              <dl>
73                <!-- Name -->
74                <dt>{{ $t('pageInventory.table.name') }}:</dt>
75                <dd>{{ tableFormatter(item.name) }}</dd>
76                <!-- Part Number -->
77                <dt>{{ $t('pageInventory.table.partNumber') }}:</dt>
78                <dd>{{ tableFormatter(item.partNumber) }}</dd>
79                <!-- Serial Number -->
80                <dt>{{ $t('pageInventory.table.serialNumber') }}:</dt>
81                <dd>{{ tableFormatter(item.serialNumber) }}</dd>
82                <!-- Spare Part Number -->
83                <dt>{{ $t('pageInventory.table.sparePartNumber') }}:</dt>
84                <dd>{{ tableFormatter(item.sparePartNumber) }}</dd>
85                <!-- Model -->
86                <dt>{{ $t('pageInventory.table.model') }}:</dt>
87                <dd>{{ tableFormatter(item.model) }}</dd>
88                <!-- Asset Tag -->
89                <dt>{{ $t('pageInventory.table.assetTag') }}:</dt>
90                <dd>{{ tableFormatter(item.assetTag) }}</dd>
91              </dl>
92            </b-col>
93            <b-col class="mt-2" sm="6" xl="6">
94              <dl>
95                <!-- Status state -->
96                <dt>{{ $t('pageInventory.table.statusState') }}:</dt>
97                <dd>{{ tableFormatter(item.statusState) }}</dd>
98                <!-- Health Rollup -->
99                <dt>{{ $t('pageInventory.table.healthRollup') }}:</dt>
100                <dd>{{ tableFormatter(item.healthRollup) }}</dd>
101              </dl>
102            </b-col>
103          </b-row>
104          <div class="section-divider mb-3 mt-3"></div>
105          <b-row>
106            <b-col class="mt-1" sm="6" xl="6">
107              <dl>
108                <!-- Manufacturer -->
109                <dt>{{ $t('pageInventory.table.manufacturer') }}:</dt>
110                <dd>{{ tableFormatter(item.manufacturer) }}</dd>
111                <!-- Processor Type -->
112                <dt>{{ $t('pageInventory.table.processorType') }}:</dt>
113                <dd>{{ tableFormatter(item.processorType) }}</dd>
114                <!-- Processor Architecture -->
115                <dt>{{ $t('pageInventory.table.processorArchitecture') }}:</dt>
116                <dd>{{ tableFormatter(item.processorArchitecture) }}</dd>
117                <!-- Instruction Set -->
118                <dt>{{ $t('pageInventory.table.instructionSet') }}:</dt>
119                <dd>{{ tableFormatter(item.instructionSet) }}</dd>
120                <!-- Version -->
121                <dt>{{ $t('pageInventory.table.version') }}:</dt>
122                <dd>{{ tableFormatter(item.version) }}</dd>
123              </dl>
124            </b-col>
125            <b-col class="mt-1" sm="6" xl="6">
126              <dl>
127                <!-- Min Speed MHz -->
128                <dt>{{ $t('pageInventory.table.minSpeedMHz') }}:</dt>
129                <dd>{{ tableFormatter(item.minSpeedMHz) }}</dd>
130                <!-- Max Speed MHz -->
131                <dt>{{ $t('pageInventory.table.maxSpeedMHz') }}:</dt>
132                <dd>{{ tableFormatter(item.maxSpeedMHz) }}</dd>
133                <!-- Total Cores -->
134                <dt>{{ $t('pageInventory.table.totalCores') }}:</dt>
135                <dd>{{ tableFormatter(item.totalCores) }}</dd>
136                <!-- Total Threads -->
137                <dt>{{ $t('pageInventory.table.totalThreads') }}:</dt>
138                <dd>{{ tableFormatter(item.totalThreads) }}</dd>
139              </dl>
140            </b-col>
141          </b-row>
142        </b-container>
143      </template>
144    </b-table>
145  </page-section>
146</template>
147
148<script>
149import PageSection from '@/components/Global/PageSection';
150import IconChevron from '@carbon/icons-vue/es/chevron--down/20';
151import StatusIcon from '@/components/Global/StatusIcon';
152import TableCellCount from '@/components/Global/TableCellCount';
153import BVToastMixin from '@/components/Mixins/BVToastMixin';
154import TableSortMixin from '@/components/Mixins/TableSortMixin';
155import TableDataFormatterMixin from '@/components/Mixins/TableDataFormatterMixin';
156import Search from '@/components/Global/Search';
157import SearchFilterMixin, {
158  searchFilter,
159} from '@/components/Mixins/SearchFilterMixin';
160import TableRowExpandMixin, {
161  expandRowLabel,
162} from '@/components/Mixins/TableRowExpandMixin';
163
164export default {
165  components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount },
166  mixins: [
167    BVToastMixin,
168    TableRowExpandMixin,
169    TableDataFormatterMixin,
170    TableSortMixin,
171    SearchFilterMixin,
172  ],
173  data() {
174    return {
175      fields: [
176        {
177          key: 'expandRow',
178          label: '',
179          tdClass: 'table-row-expand',
180          sortable: false,
181        },
182        {
183          key: 'id',
184          label: this.$t('pageInventory.table.id'),
185          formatter: this.tableFormatter,
186          sortable: true,
187        },
188        {
189          key: 'health',
190          label: this.$t('pageInventory.table.health'),
191          formatter: this.tableFormatter,
192          sortable: true,
193          tdClass: 'text-nowrap',
194        },
195        {
196          key: 'locationNumber',
197          label: this.$t('pageInventory.table.locationNumber'),
198          formatter: this.tableFormatter,
199          sortable: true,
200        },
201        {
202          key: 'identifyLed',
203          label: this.$t('pageInventory.table.identifyLed'),
204          formatter: this.tableFormatter,
205          sortable: false,
206        },
207      ],
208      searchFilter: searchFilter,
209      searchTotalFilteredRows: 0,
210      expandRowLabel: expandRowLabel,
211    };
212  },
213  computed: {
214    filteredRows() {
215      return this.searchFilter
216        ? this.searchTotalFilteredRows
217        : this.processors.length;
218    },
219    processors() {
220      return this.$store.getters['processors/processors'];
221    },
222  },
223  created() {
224    this.$store.dispatch('processors/getProcessorsInfo').finally(() => {
225      // Emit initial data fetch complete to parent component
226      this.$root.$emit('hardware-status-processors-complete');
227    });
228  },
229  methods: {
230    onFiltered(filteredItems) {
231      this.searchTotalFilteredRows = filteredItems.length;
232    },
233    toggleIdentifyLedValue(row) {
234      this.$store
235        .dispatch('processors/updateIdentifyLedValue', {
236          uri: row.uri,
237          identifyLed: row.identifyLed,
238        })
239        .catch(({ message }) => this.errorToast(message));
240    },
241    // TO DO: remove hasIdentifyLed when the following is merged:
242    // https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/37045
243    hasIdentifyLed(identifyLed) {
244      return typeof identifyLed === 'boolean';
245    },
246  },
247};
248</script>
249