| <template> | 
 |   <b-container fluid="xl"> | 
 |     <page-title /> | 
 |     <b-row v-if="isServerPowerOffRequired"> | 
 |       <b-col xl="10"> | 
 |         <!-- Operation in progress alert --> | 
 |         <alert v-if="isOperationInProgress" variant="info" class="mb-5"> | 
 |           <p> | 
 |             {{ $t('pageFirmware.singleFileUpload.alert.operationInProgress') }} | 
 |           </p> | 
 |         </alert> | 
 |         <!-- Power off server warning alert --> | 
 |         <alert v-else-if="!isHostOff" variant="warning" class="mb-5"> | 
 |           <p class="mb-0"> | 
 |             {{ | 
 |               $t('pageFirmware.singleFileUpload.alert.serverMustBePoweredOffTo') | 
 |             }} | 
 |           </p> | 
 |           <ul class="m-0"> | 
 |             <li> | 
 |               {{ | 
 |                 $t( | 
 |                   'pageFirmware.singleFileUpload.alert.switchRunningAndBackupImages' | 
 |                 ) | 
 |               }} | 
 |             </li> | 
 |             <li> | 
 |               {{ $t('pageFirmware.singleFileUpload.alert.updateFirmware') }} | 
 |             </li> | 
 |           </ul> | 
 |           <template #action> | 
 |             <b-link to="/control/server-power-operations"> | 
 |               {{ | 
 |                 $t( | 
 |                   'pageFirmware.singleFileUpload.alert.viewServerPowerOperations' | 
 |                 ) | 
 |               }} | 
 |             </b-link> | 
 |           </template> | 
 |         </alert> | 
 |       </b-col> | 
 |     </b-row> | 
 |     <b-row> | 
 |       <b-col xl="10"> | 
 |         <page-section> | 
 |           <b-card-group deck> | 
 |             <!-- Running image --> | 
 |             <b-card> | 
 |               <template #header> | 
 |                 <p class="font-weight-bold m-0"> | 
 |                   {{ $t('pageFirmware.singleFileUpload.runningImage') }} | 
 |                 </p> | 
 |               </template> | 
 |               <dl class="mb-0"> | 
 |                 <dt>{{ $t('pageFirmware.singleFileUpload.bmcAndServer') }}</dt> | 
 |                 <dd class="mb-0">{{ systemFirmwareVersion }}</dd> | 
 |               </dl> | 
 |             </b-card> | 
 |  | 
 |             <!-- Backup image --> | 
 |             <b-card> | 
 |               <template #header> | 
 |                 <p class="font-weight-bold m-0"> | 
 |                   {{ $t('pageFirmware.singleFileUpload.backupImage') }} | 
 |                 </p> | 
 |               </template> | 
 |               <dl> | 
 |                 <dt> | 
 |                   {{ $t('pageFirmware.singleFileUpload.bmcAndServer') }} | 
 |                 </dt> | 
 |                 <dd> | 
 |                   <status-icon v-if="showBackupImageStatus" status="danger" /> | 
 |                   <span v-if="showBackupImageStatus" class="sr-only"> | 
 |                     {{ backupFirmwareStatus }} | 
 |                   </span> | 
 |                   {{ backupFirmwareVersion }} | 
 |                 </dd> | 
 |               </dl> | 
 |               <b-btn | 
 |                 v-b-modal.modal-switch-to-running | 
 |                 data-test-id="firmware-button-switchToRunning" | 
 |                 variant="link" | 
 |                 size="sm" | 
 |                 class="py-0 px-1 mt-2" | 
 |                 :disabled="isPageDisabled || !isRebootFromBackupAvailable" | 
 |               > | 
 |                 <icon-switch class="d-none d-sm-inline-block" /> | 
 |                 {{ $t('pageFirmware.singleFileUpload.switchToRunning') }} | 
 |               </b-btn> | 
 |             </b-card> | 
 |           </b-card-group> | 
 |         </page-section> | 
 |       </b-col> | 
 |     </b-row> | 
 |     <b-row> | 
 |       <!-- Update firmware --> | 
 |       <b-col sm="8" md="6" xl="4"> | 
 |         <page-section | 
 |           :section-title="$t('pageFirmware.singleFileUpload.updateFirmware')" | 
 |         > | 
 |           <div class="form-background p-3"> | 
 |             <b-form @submit.prevent="onSubmitUpload"> | 
 |               <b-form-group | 
 |                 v-if="isTftpUploadAvailable" | 
 |                 :label="$t('pageFirmware.singleFileUpload.fileSource')" | 
 |                 :disabled="isPageDisabled" | 
 |               > | 
 |                 <b-form-radio v-model="isWorkstationSelected" :value="true"> | 
 |                   {{ $t('pageFirmware.form.workstation') }} | 
 |                 </b-form-radio> | 
 |                 <b-form-radio v-model="isWorkstationSelected" :value="false"> | 
 |                   {{ $t('pageFirmware.form.tftpServer') }} | 
 |                 </b-form-radio> | 
 |               </b-form-group> | 
 |  | 
 |               <!-- Workstation Upload --> | 
 |               <template v-if="isWorkstationSelected"> | 
 |                 <b-form-group | 
 |                   :label="$t('pageFirmware.form.imageFile')" | 
 |                   label-for="image-file" | 
 |                 > | 
 |                   <b-form-text id="image-file-help-block"> | 
 |                     {{ $t('pageFirmware.form.onlyTarFilesAccepted') }} | 
 |                   </b-form-text> | 
 |                   <form-file | 
 |                     id="image-file" | 
 |                     accept=".tar" | 
 |                     :disabled="isPageDisabled" | 
 |                     :state="getValidationState($v.file)" | 
 |                     aria-describedby="image-file-help-block" | 
 |                     @input="onFileUpload($event)" | 
 |                   > | 
 |                     <template #invalid> | 
 |                       <b-form-invalid-feedback role="alert"> | 
 |                         {{ $t('global.form.required') }} | 
 |                       </b-form-invalid-feedback> | 
 |                     </template> | 
 |                   </form-file> | 
 |                 </b-form-group> | 
 |               </template> | 
 |  | 
 |               <!-- TFTP Server Upload --> | 
 |               <template v-else> | 
 |                 <b-form-group | 
 |                   :label="$t('pageFirmware.singleFileUpload.fileAddress')" | 
 |                   label-for="tftp-address" | 
 |                 > | 
 |                   <b-form-input | 
 |                     id="tftp-address" | 
 |                     v-model="tftpFileAddress" | 
 |                     type="text" | 
 |                     :state="getValidationState($v.tftpFileAddress)" | 
 |                     :disabled="isPageDisabled" | 
 |                     @input="$v.tftpFileAddress.$touch()" | 
 |                   /> | 
 |                   <b-form-invalid-feedback role="alert"> | 
 |                     {{ $t('global.form.fieldRequired') }} | 
 |                   </b-form-invalid-feedback> | 
 |                 </b-form-group> | 
 |               </template> | 
 |               <b-btn | 
 |                 data-test-id="firmware-button-startUpdate" | 
 |                 type="submit" | 
 |                 variant="primary" | 
 |                 :disabled="isPageDisabled" | 
 |               > | 
 |                 {{ $t('pageFirmware.singleFileUpload.startUpdate') }} | 
 |               </b-btn> | 
 |               <alert | 
 |                 v-if="isServerPowerOffRequired && !isHostOff" | 
 |                 variant="warning" | 
 |                 :small="true" | 
 |                 class="mt-4" | 
 |               > | 
 |                 <p class="col-form-label"> | 
 |                   {{ | 
 |                     $t( | 
 |                       'pageFirmware.singleFileUpload.alert.serverMustBePoweredOffToUpdateFirmware' | 
 |                     ) | 
 |                   }} | 
 |                 </p> | 
 |               </alert> | 
 |             </b-form> | 
 |           </div> | 
 |         </page-section> | 
 |       </b-col> | 
 |     </b-row> | 
 |  | 
 |     <!-- Modals --> | 
 |     <modal-update-firmware | 
 |       :running="systemFirmwareVersion" | 
 |       :backup="backupFirmwareVersion" | 
 |       @ok="updateFirmware" | 
 |     /> | 
 |     <modal-switch-to-running | 
 |       :backup="backupFirmwareVersion" | 
 |       @ok="switchToRunning" | 
 |     /> | 
 |   </b-container> | 
 | </template> | 
 |  | 
 | <script> | 
 | import { requiredIf } from 'vuelidate/lib/validators'; | 
 | import { mapGetters } from 'vuex'; | 
 | import IconSwitch from '@carbon/icons-vue/es/arrows--horizontal/20'; | 
 |  | 
 | import PageSection from '@/components/Global/PageSection'; | 
 | import PageTitle from '@/components/Global/PageTitle'; | 
 | import Alert from '@/components/Global/Alert'; | 
 | import FormFile from '@/components/Global/FormFile'; | 
 | import StatusIcon from '@/components/Global/StatusIcon'; | 
 | import ModalUpdateFirmware from './FirmwareSingleImageModalUpdateFirmware'; | 
 | import ModalSwitchToRunning from './FirmwareSingleImageModalSwitchToRunning'; | 
 |  | 
 | import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js'; | 
 | import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin'; | 
 | import BVToastMixin from '@/components/Mixins/BVToastMixin'; | 
 |  | 
 | export default { | 
 |   name: 'FirmwareSingleImage', | 
 |   components: { | 
 |     Alert, | 
 |     FormFile, | 
 |     IconSwitch, | 
 |     ModalSwitchToRunning, | 
 |     ModalUpdateFirmware, | 
 |     PageSection, | 
 |     PageTitle, | 
 |     StatusIcon, | 
 |   }, | 
 |   mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin], | 
 |   beforeRouteLeave(to, from, next) { | 
 |     this.hideLoader(); | 
 |     next(); | 
 |   }, | 
 |   data() { | 
 |     return { | 
 |       isWorkstationSelected: true, | 
 |       file: null, | 
 |       tftpFileAddress: null, | 
 |       timeoutId: null, | 
 |       loading, | 
 |       isServerPowerOffRequired: | 
 |         process.env.VUE_APP_SERVER_OFF_REQUIRED === 'true', | 
 |     }; | 
 |   }, | 
 |   computed: { | 
 |     hostStatus() { | 
 |       return this.$store.getters['global/hostStatus']; | 
 |     }, | 
 |     isHostOff() { | 
 |       return this.hostStatus === 'off' ? true : false; | 
 |     }, | 
 |     isOperationInProgress() { | 
 |       return this.$store.getters['controls/isOperationInProgress']; | 
 |     }, | 
 |     ...mapGetters('firmwareSingleImage', [ | 
 |       'backupFirmwareStatus', | 
 |       'backupFirmwareVersion', | 
 |       'isRebootFromBackupAvailable', | 
 |       'systemFirmwareVersion', | 
 |       'isTftpUploadAvailable', | 
 |     ]), | 
 |     isPageDisabled() { | 
 |       if (this.isServerPowerOffRequired) { | 
 |         return !this.isHostOff || this.loading || this.isOperationInProgress; | 
 |       } | 
 |       return this.loading || this.isOperationInProgress; | 
 |     }, | 
 |     showBackupImageStatus() { | 
 |       return ( | 
 |         this.backupFirmwareStatus === 'Critical' || | 
 |         this.backupFirmwareStatus === 'Warning' | 
 |       ); | 
 |     }, | 
 |   }, | 
 |   watch: { | 
 |     isWorkstationSelected: function () { | 
 |       this.$v.$reset(); | 
 |       this.file = null; | 
 |       this.tftpFileAddress = null; | 
 |     }, | 
 |   }, | 
 |   created() { | 
 |     this.startLoader(); | 
 |     this.$store.dispatch('firmwareSingleImage/getUpdateServiceSettings'); | 
 |     Promise.all([ | 
 |       this.$store.dispatch('global/getHostStatus'), | 
 |       this.$store.dispatch('firmwareSingleImage/getFirmwareInformation'), | 
 |     ]).finally(() => this.endLoader()); | 
 |   }, | 
 |   validations() { | 
 |     return { | 
 |       file: { | 
 |         required: requiredIf(function () { | 
 |           return this.isWorkstationSelected; | 
 |         }), | 
 |       }, | 
 |       tftpFileAddress: { | 
 |         required: requiredIf(function () { | 
 |           return !this.isWorkstationSelected; | 
 |         }), | 
 |       }, | 
 |     }; | 
 |   }, | 
 |   methods: { | 
 |     updateFirmware() { | 
 |       this.setRebootTimeout(360000, () => { | 
 |         this.infoToast( | 
 |           this.$t('pageFirmware.singleFileUpload.toast.verifyUpdateMessage'), | 
 |           { | 
 |             title: this.$t('pageFirmware.singleFileUpload.toast.verifyUpdate'), | 
 |             refreshAction: true, | 
 |           } | 
 |         ); | 
 |       }); | 
 |       this.infoToast( | 
 |         this.$t('pageFirmware.singleFileUpload.toast.updateStartedMessage'), | 
 |         { | 
 |           title: this.$t('pageFirmware.singleFileUpload.toast.updateStarted'), | 
 |           timestamp: true, | 
 |         } | 
 |       ); | 
 |       if (this.isWorkstationSelected) { | 
 |         this.dispatchWorkstationUpload(); | 
 |       } else { | 
 |         this.dispatchTftpUpload(); | 
 |       } | 
 |     }, | 
 |     dispatchWorkstationUpload() { | 
 |       this.$store | 
 |         .dispatch('firmwareSingleImage/uploadFirmware', this.file) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     dispatchTftpUpload() { | 
 |       this.$store | 
 |         .dispatch( | 
 |           'firmwareSingleImage/uploadFirmwareTFTP', | 
 |           this.tftpFileAddress | 
 |         ) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     switchToRunning() { | 
 |       this.setRebootTimeout(60000, () => { | 
 |         this.infoToast( | 
 |           this.$t('pageFirmware.singleFileUpload.toast.verifySwitchMessage'), | 
 |           { | 
 |             title: this.$t('pageFirmware.singleFileUpload.toast.verifySwitch'), | 
 |             refreshAction: true, | 
 |           } | 
 |         ); | 
 |       }); | 
 |       this.$store | 
 |         .dispatch('firmwareSingleImage/switchFirmwareAndReboot') | 
 |         .then(() => | 
 |           this.infoToast( | 
 |             this.$t('pageFirmware.singleFileUpload.toast.rebootStartedMessage'), | 
 |             { | 
 |               title: this.$t( | 
 |                 'pageFirmware.singleFileUpload.toast.rebootStarted' | 
 |               ), | 
 |             } | 
 |           ) | 
 |         ) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     setRebootTimeout(timeoutMs = 60000, callback) { | 
 |       // Set a timeout to disable page interactions | 
 |       // during a BMC reboot | 
 |       this.startLoader(); | 
 |       this.timeoutId = setTimeout(() => { | 
 |         this.endLoader(); | 
 |         if (callback) callback(); | 
 |       }, timeoutMs); | 
 |     }, | 
 |     clearRebootTimeout() { | 
 |       if (this.timeoutId) { | 
 |         clearTimeout(this.timeoutId); | 
 |         this.endLoader(); | 
 |       } | 
 |     }, | 
 |     onSubmitUpload() { | 
 |       this.$v.$touch(); | 
 |       if (this.$v.$invalid) return; | 
 |       this.$bvModal.show('modal-update-firmware'); | 
 |     }, | 
 |     onFileUpload(file) { | 
 |       this.file = file; | 
 |       this.$v.file.$touch(); | 
 |     }, | 
 |   }, | 
 | }; | 
 | </script> |