1<template> 2 <page-section :section-title="$t('pageInventory.dimmSlot')"> 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="dimms.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 sort-by="health" 22 responsive="md" 23 show-empty 24 :items="dimms" 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-expandDimms" 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 <!-- StatusState --> 55 <template #cell(statusState)="{ value }"> 56 <status-icon :status="statusStateIcon(value)" /> 57 {{ value }} 58 </template> 59 60 <!-- Toggle identify LED --> 61 <template #cell(identifyLed)="row"> 62 <b-form-checkbox 63 v-if="hasIdentifyLed(row.item.identifyLed)" 64 v-model="row.item.identifyLed" 65 name="switch" 66 switch 67 @change="toggleIdentifyLedValue(row.item)" 68 > 69 <span v-if="row.item.identifyLed"> 70 {{ $t('global.status.on') }} 71 </span> 72 <span v-else> {{ $t('global.status.off') }} </span> 73 </b-form-checkbox> 74 <div v-else>--</div> 75 </template> 76 <template #row-details="{ item }"> 77 <b-container fluid> 78 <b-row> 79 <b-col sm="6" xl="6"> 80 <dl> 81 <!-- Manufacturer --> 82 <dt>{{ $t('pageInventory.table.manufacturer') }}:</dt> 83 <dd>{{ dataFormatter(item.manufacturer) }}</dd> 84 </dl> 85 <dl> 86 <!-- Part Number --> 87 <dt>{{ $t('pageInventory.table.partNumber') }}:</dt> 88 <dd>{{ dataFormatter(item.partNumber) }}</dd> 89 </dl> 90 <dl> 91 <!-- Serial Number --> 92 <dt>{{ $t('pageInventory.table.serialNumber') }}:</dt> 93 <dd>{{ dataFormatter(item.serialNumber) }}</dd> 94 </dl> 95 <dl> 96 <!-- Spare Part Number --> 97 <dt>{{ $t('pageInventory.table.sparePartNumber') }}:</dt> 98 <dd>{{ dataFormatter(item.sparePartNumber) }}</dd> 99 </dl> 100 <dl> 101 <!-- Model --> 102 <dt>{{ $t('pageInventory.table.model') }}:</dt> 103 <dd>{{ dataFormatter(item.model) }}</dd> 104 </dl> 105 </b-col> 106 <b-col sm="6" xl="6"> 107 <dl> 108 <!-- Capacity MiB --> 109 <dt>{{ $t('pageInventory.table.capacityMiB') }}:</dt> 110 <dd> 111 {{ dataFormatter(item.capacityMiB) }} 112 {{ $t('unit.MiB') }} 113 </dd> 114 </dl> 115 <dl> 116 <!-- Rank Count --> 117 <dt>{{ $t('pageInventory.table.rankCount') }}:</dt> 118 <dd>{{ dataFormatter(item.rankCount) }}</dd> 119 </dl> 120 <dl> 121 <!-- Status--> 122 <dt>{{ $t('pageInventory.table.statusState') }}:</dt> 123 <dd>{{ dataFormatter(item.statusState) }}</dd> 124 </dl> 125 <dl> 126 <!-- Enabled--> 127 <dt>{{ $t('pageInventory.table.enabled') }}:</dt> 128 <dd>{{ dataFormatter(item.enabled) }}</dd> 129 </dl> 130 </b-col> 131 </b-row> 132 <div class="section-divider mb-3 mt-3"></div> 133 <b-row> 134 <b-col sm="6" xl="6"> 135 <dl> 136 <!-- Description --> 137 <dt>{{ $t('pageInventory.table.description') }}:</dt> 138 <dd>{{ dataFormatter(item.description) }}</dd> 139 </dl> 140 <dl> 141 <!-- Memory Type --> 142 <dt>{{ $t('pageInventory.table.memoryType') }}:</dt> 143 <dd>{{ dataFormatter(item.memoryType) }}</dd> 144 </dl> 145 <dl> 146 <!-- Base Module Type --> 147 <dt>{{ $t('pageInventory.table.baseModuleType') }}:</dt> 148 <dd>{{ dataFormatter(item.baseModuleType) }}</dd> 149 </dl> 150 </b-col> 151 <b-col sm="6" xl="6"> 152 <dl> 153 <!-- Bus Width Bits --> 154 <dt>{{ $t('pageInventory.table.busWidthBits') }}:</dt> 155 <dd> 156 {{ dataFormatter(item.busWidthBits) }} 157 {{ $t('unit.bit') }} 158 </dd> 159 </dl> 160 <dl> 161 <!-- Data Width Bits --> 162 <dt>{{ $t('pageInventory.table.dataWidthBits') }}:</dt> 163 <dd> 164 {{ dataFormatter(item.dataWidthBits) }} 165 {{ $t('unit.bit') }} 166 </dd> 167 </dl> 168 <dl> 169 <!-- Operating Speed Mhz --> 170 <dt>{{ $t('pageInventory.table.operatingSpeedMhz') }}:</dt> 171 <dd> 172 {{ dataFormatter(item.operatingSpeedMhz) }} 173 {{ $t('unit.MHz') }} 174 </dd> 175 </dl> 176 <dl> 177 <!-- Error Correction --> 178 <dt>{{ $t('pageInventory.table.errorCorrection') }}:</dt> 179 <dd>{{ dataFormatter(item.errorCorrection) }}</dd> 180 </dl> 181 </b-col> 182 </b-row> 183 </b-container> 184 </template> 185 </b-table> 186 </page-section> 187</template> 188 189<script> 190import PageSection from '@/components/Global/PageSection'; 191import IconChevron from '@carbon/icons-vue/es/chevron--down/20'; 192 193import StatusIcon from '@/components/Global/StatusIcon'; 194import TableCellCount from '@/components/Global/TableCellCount'; 195 196import BVToastMixin from '@/components/Mixins/BVToastMixin'; 197import DataFormatterMixin from '@/components/Mixins/DataFormatterMixin'; 198import TableSortMixin from '@/components/Mixins/TableSortMixin'; 199import Search from '@/components/Global/Search'; 200import SearchFilterMixin, { 201 searchFilter, 202} from '@/components/Mixins/SearchFilterMixin'; 203import TableRowExpandMixin, { 204 expandRowLabel, 205} from '@/components/Mixins/TableRowExpandMixin'; 206import { useI18n } from 'vue-i18n'; 207import i18n from '@/i18n'; 208 209export default { 210 components: { IconChevron, PageSection, StatusIcon, Search, TableCellCount }, 211 mixins: [ 212 BVToastMixin, 213 TableRowExpandMixin, 214 DataFormatterMixin, 215 TableSortMixin, 216 SearchFilterMixin, 217 ], 218 data() { 219 return { 220 $t: useI18n().t, 221 isBusy: true, 222 fields: [ 223 { 224 key: 'expandRow', 225 label: '', 226 tdClass: 'table-row-expand', 227 }, 228 { 229 key: 'id', 230 label: i18n.global.t('pageInventory.table.id'), 231 formatter: this.dataFormatter, 232 }, 233 { 234 key: 'health', 235 label: i18n.global.t('pageInventory.table.health'), 236 formatter: this.dataFormatter, 237 tdClass: 'text-nowrap', 238 }, 239 { 240 key: 'statusState', 241 label: i18n.global.t('pageInventory.table.state'), 242 formatter: this.dataFormatter, 243 tdClass: 'text-nowrap', 244 }, 245 { 246 key: 'locationNumber', 247 label: i18n.global.t('pageInventory.table.locationNumber'), 248 formatter: this.dataFormatter, 249 }, 250 { 251 key: 'identifyLed', 252 label: i18n.global.t('pageInventory.table.identifyLed'), 253 formatter: this.dataFormatter, 254 }, 255 ], 256 searchFilter: searchFilter, 257 searchTotalFilteredRows: 0, 258 expandRowLabel: expandRowLabel, 259 }; 260 }, 261 computed: { 262 filteredRows() { 263 return this.searchFilter 264 ? this.searchTotalFilteredRows 265 : this.dimms.length; 266 }, 267 dimms() { 268 return this.$store.getters['memory/dimms']; 269 }, 270 }, 271 created() { 272 this.$store.dispatch('memory/getDimms').finally(() => { 273 // Emit initial data fetch complete to parent component 274 this.$root.$emit('hardware-status-dimm-slot-complete'); 275 this.isBusy = false; 276 }); 277 }, 278 methods: { 279 sortCompare(a, b, key) { 280 if (key === 'health') { 281 return this.sortStatus(a, b, key); 282 } else if (key === 'statusState') { 283 return this.sortStatusState(a, b, key); 284 } 285 }, 286 onFiltered(filteredItems) { 287 this.searchTotalFilteredRows = filteredItems.length; 288 }, 289 toggleIdentifyLedValue(row) { 290 this.$store 291 .dispatch('memory/updateIdentifyLedValue', { 292 uri: row.uri, 293 identifyLed: row.identifyLed, 294 }) 295 .then((message) => this.successToast(message)) 296 .catch(({ message }) => this.errorToast(message)); 297 }, 298 hasIdentifyLed(identifyLed) { 299 return typeof identifyLed === 'boolean'; 300 }, 301 statusStateIcon(status) { 302 switch (status) { 303 case 'Enabled': 304 return 'success'; 305 case 'Absent': 306 return 'warning'; 307 default: 308 return ''; 309 } 310 }, 311 sortStatusState(a, b, key) { 312 const statusState = ['Enabled', 'Absent']; 313 return statusState.indexOf(a[key]) - statusState.indexOf(b[key]); 314 }, 315 }, 316}; 317</script> 318