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