| <template> | 
 |   <b-container fluid="xl"> | 
 |     <page-title :description="$t('pageFirmware.pageDescriptionSingleImage')" /> | 
 |     <!-- Operation in progress alert --> | 
 |     <alert v-if="isOperationInProgress" variant="info" class="mb-5"> | 
 |       <p> | 
 |         {{ $t('pageFirmware.alert.operationInProgress') }} | 
 |       </p> | 
 |     </alert> | 
 |     <!-- Shutdown server warning alert --> | 
 |     <alert v-else-if="!isHostOff" variant="warning" class="mb-5"> | 
 |       <p class="font-weight-bold mb-1"> | 
 |         {{ $t('pageFirmware.alert.serverShutdownRequiredBeforeUpdate') }} | 
 |       </p> | 
 |       {{ $t('pageFirmware.alert.serverShutdownRequiredInfo') }} | 
 |       <template #action> | 
 |         <b-btn variant="link" class="text-nowrap" @click="onClickShutDown"> | 
 |           {{ $t('pageFirmware.alert.shutDownServer') }} | 
 |         </b-btn> | 
 |       </template> | 
 |     </alert> | 
 |     <b-row class="mb-4"> | 
 |       <!-- Firmware on system --> | 
 |       <b-col md="10" lg="12" xl="8" class="pr-xl-4"> | 
 |         <page-section :section-title="$t('pageFirmware.firmwareOnSystem')"> | 
 |           <b-card-group deck> | 
 |             <!-- Current FW --> | 
 |             <b-card header-bg-variant="success"> | 
 |               <template #header> | 
 |                 <dl class="mb-0"> | 
 |                   <dt>{{ $t('pageFirmware.current') }}</dt> | 
 |                   <dd class="mb-0">{{ systemFirmwareVersion }}</dd> | 
 |                 </dl> | 
 |               </template> | 
 |               <b-row> | 
 |                 <b-col xs="6"> | 
 |                   <dl class="my-0"> | 
 |                     <dt>{{ $t('pageFirmware.bmcStatus') }}</dt> | 
 |                     <dd>{{ $t('pageFirmware.running') }}</dd> | 
 |                   </dl> | 
 |                 </b-col> | 
 |                 <b-col xs="6"> | 
 |                   <dl class="my-0"> | 
 |                     <dt>{{ $t('pageFirmware.hostStatus') }}</dt> | 
 |                     <dd v-if="hostStatus === 'on'"> | 
 |                       {{ $t('global.status.on') }} | 
 |                     </dd> | 
 |                     <dd v-else-if="hostStatus === 'off'"> | 
 |                       {{ $t('global.status.off') }} | 
 |                     </dd> | 
 |                     <dd v-else> | 
 |                       {{ $t('global.status.notAvailable') }} | 
 |                     </dd> | 
 |                   </dl> | 
 |                 </b-col> | 
 |               </b-row> | 
 |             </b-card> | 
 |  | 
 |             <!-- Backup FW --> | 
 |             <b-card> | 
 |               <template #header> | 
 |                 <dl class="mb-0"> | 
 |                   <dt>{{ $t('pageFirmware.backup') }}</dt> | 
 |                   <dd class="mb-0">{{ backupFirmwareVersion }}</dd> | 
 |                 </dl> | 
 |               </template> | 
 |               <b-row> | 
 |                 <b-col xs="6"> | 
 |                   <dl class="my-0"> | 
 |                     <dt>{{ $t('pageFirmware.state') }}</dt> | 
 |                     <dd>{{ backupFirmwareStatus }}</dd> | 
 |                   </dl> | 
 |                 </b-col> | 
 |               </b-row> | 
 |             </b-card> | 
 |           </b-card-group> | 
 |         </page-section> | 
 |  | 
 |         <!-- Change to backup image --> | 
 |         <page-section :section-title="$t('pageFirmware.changeToBackupImage')"> | 
 |           <dl class="mb-5"> | 
 |             <dt> | 
 |               {{ $t('pageFirmware.backupImage') }} | 
 |             </dt> | 
 |             <dd>{{ backupFirmwareVersion }}</dd> | 
 |           </dl> | 
 |           <b-btn | 
 |             v-b-modal.modal-reboot-backup | 
 |             type="button" | 
 |             variant="primary" | 
 |             :disabled="isPageDisabled || !isRebootFromBackupAvailable" | 
 |           > | 
 |             {{ $t('pageFirmware.changeAndRebootBmc') }} | 
 |           </b-btn> | 
 |         </page-section> | 
 |       </b-col> | 
 |  | 
 |       <!-- Update code --> | 
 |       <b-col sm="8" xl="4" class="update-code pl-xl-4"> | 
 |         <page-section :section-title="$t('pageFirmware.updateCode')"> | 
 |           <b-form @submit.prevent="onSubmitUpload"> | 
 |             <b-form-group | 
 |               :label="$t('pageFirmware.form.uploadLocation')" | 
 |               :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> | 
 |                 <b-form-file | 
 |                   id="image-file" | 
 |                   v-model="file" | 
 |                   accept=".tar" | 
 |                   aria-describedby="image-file-help-block" | 
 |                   :browse-text="$t('global.fileUpload.browseText')" | 
 |                   :drop-placeholder="$t('global.fileUpload.dropPlaceholder')" | 
 |                   :placeholder="$t('global.fileUpload.placeholder')" | 
 |                   :disabled="isPageDisabled" | 
 |                   :state="getValidationState($v.file)" | 
 |                   @input="$v.file.$touch()" | 
 |                 /> | 
 |                 <b-form-invalid-feedback role="alert"> | 
 |                   {{ $t('global.form.required') }} | 
 |                 </b-form-invalid-feedback> | 
 |               </b-form-group> | 
 |             </template> | 
 |  | 
 |             <!-- TFTP Server Upload --> | 
 |             <template v-else> | 
 |               <b-form-group | 
 |                 :label="$t('pageFirmware.form.tftpServerAddress')" | 
 |                 label-for="tftp-ip" | 
 |               > | 
 |                 <b-form-text id="server-address-help-block"> | 
 |                   {{ $t('pageFirmware.form.tftpServerAddressHelper') }} | 
 |                 </b-form-text> | 
 |                 <b-form-input | 
 |                   id="tftp-id" | 
 |                   v-model="tftpIpAddress" | 
 |                   type="text" | 
 |                   :state="getValidationState($v.tftpIpAddress)" | 
 |                   :disabled="isPageDisabled" | 
 |                   aria-describedby="server-address-help-block" | 
 |                   @input="$v.tftpIpAddress.$touch()" | 
 |                 /> | 
 |                 <b-form-invalid-feedback role="alert"> | 
 |                   {{ $t('global.form.fieldRequired') }} | 
 |                 </b-form-invalid-feedback> | 
 |               </b-form-group> | 
 |               <b-form-group | 
 |                 :label="$t('pageFirmware.form.imageFileName')" | 
 |                 label-for="tftp-file-name" | 
 |               > | 
 |                 <b-form-input | 
 |                   id="tftp-file-name" | 
 |                   v-model="tftpFileName" | 
 |                   type="text" | 
 |                   :state="getValidationState($v.tftpFileName)" | 
 |                   :disabled="isPageDisabled" | 
 |                   @input="$v.tftpFileName.$touch()" | 
 |                 /> | 
 |                 <b-form-invalid-feedback role="alert"> | 
 |                   {{ $t('global.form.fieldRequired') }} | 
 |                 </b-form-invalid-feedback> | 
 |               </b-form-group> | 
 |             </template> | 
 |  | 
 |             <!-- Info alert --> | 
 |             <alert variant="info" class="mt-4 mb-5"> | 
 |               <p class="font-weight-bold mb-1"> | 
 |                 {{ $t('pageFirmware.alert.updateProcess') }} | 
 |               </p> | 
 |               <p>{{ $t('pageFirmware.alert.updateProcessInfoSingleImage') }}</p> | 
 |             </alert> | 
 |             <b-form-group> | 
 |               <b-btn type="submit" variant="primary" :disabled="isPageDisabled"> | 
 |                 {{ $t('pageFirmware.form.uploadAndRebootBmc') }} | 
 |               </b-btn> | 
 |             </b-form-group> | 
 |           </b-form> | 
 |         </page-section> | 
 |       </b-col> | 
 |     </b-row> | 
 |  | 
 |     <!-- Modals --> | 
 |     <modal-upload @ok="uploadFirmware" /> | 
 |     <modal-reboot-backup | 
 |       :current="systemFirmwareVersion" | 
 |       :backup="backupFirmwareVersion" | 
 |       @ok="rebootFromBackup" | 
 |     /> | 
 |   </b-container> | 
 | </template> | 
 |  | 
 | <script> | 
 | import { requiredIf } from 'vuelidate/lib/validators'; | 
 | import { mapGetters } from 'vuex'; | 
 |  | 
 | import PageSection from '@/components/Global/PageSection'; | 
 | import PageTitle from '@/components/Global/PageTitle'; | 
 | import Alert from '@/components/Global/Alert'; | 
 | import ModalUpload from './FirmwareSingleImageModalUpload'; | 
 | import ModalRebootBackup from './FirmwareSingleImageModalRebootBackup'; | 
 |  | 
 | 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, | 
 |     ModalRebootBackup, | 
 |     ModalUpload, | 
 |     PageSection, | 
 |     PageTitle, | 
 |   }, | 
 |   mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin], | 
 |   beforeRouteLeave(to, from, next) { | 
 |     this.hideLoader(); | 
 |     this.clearRebootTimeout(); | 
 |     next(); | 
 |   }, | 
 |   data() { | 
 |     return { | 
 |       isWorkstationSelected: true, | 
 |       file: null, | 
 |       tftpIpAddress: null, | 
 |       tftpFileName: null, | 
 |       timeoutId: null, | 
 |       loading, | 
 |     }; | 
 |   }, | 
 |   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', | 
 |     ]), | 
 |     isPageDisabled() { | 
 |       return !this.isHostOff || this.loading || this.isOperationInProgress; | 
 |     }, | 
 |   }, | 
 |   watch: { | 
 |     isWorkstationSelected: function () { | 
 |       this.$v.$reset(); | 
 |       this.file = null; | 
 |       this.tftpIpAddress = null; | 
 |       this.tftpFileName = null; | 
 |     }, | 
 |   }, | 
 |   created() { | 
 |     this.startLoader(); | 
 |     this.$store.dispatch('firmwareSingleImage/getUpdateServiceApplyTime'); | 
 |     Promise.all([ | 
 |       this.$store.dispatch('global/getHostStatus'), | 
 |       this.$store.dispatch('firmwareSingleImage/getFirmwareInformation'), | 
 |     ]).finally(() => this.endLoader()); | 
 |   }, | 
 |   validations() { | 
 |     return { | 
 |       file: { | 
 |         required: requiredIf(function () { | 
 |           return this.isWorkstationSelected; | 
 |         }), | 
 |       }, | 
 |       tftpIpAddress: { | 
 |         required: requiredIf(function () { | 
 |           return !this.isWorkstationSelected; | 
 |         }), | 
 |       }, | 
 |       tftpFileName: { | 
 |         required: requiredIf(function () { | 
 |           return !this.isWorkstationSelected; | 
 |         }), | 
 |       }, | 
 |     }; | 
 |   }, | 
 |   methods: { | 
 |     uploadFirmware() { | 
 |       const startTime = this.$options.filters.formatTime(new Date()); | 
 |       this.setRebootTimeout(360000); //6 minute timeout | 
 |       this.infoToast( | 
 |         this.$t('pageFirmware.toast.infoUploadStartTimeMessage', { startTime }), | 
 |         this.$t('pageFirmware.toast.infoUploadStartTimeTitle') | 
 |       ); | 
 |       if (this.isWorkstationSelected) { | 
 |         this.dispatchWorkstationUpload(); | 
 |       } else { | 
 |         this.dispatchTftpUpload(); | 
 |       } | 
 |     }, | 
 |     dispatchWorkstationUpload() { | 
 |       this.$store | 
 |         .dispatch('firmwareSingleImage/uploadFirmware', this.file) | 
 |         .then((success) => | 
 |           this.infoToast( | 
 |             success, | 
 |             this.$t('pageFirmware.toast.successUploadTitle') | 
 |           ) | 
 |         ) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     dispatchTftpUpload() { | 
 |       const data = { | 
 |         address: this.tftpIpAddress, | 
 |         filename: this.tftpFileName, | 
 |       }; | 
 |       this.$store | 
 |         .dispatch('firmwareSingleImage/uploadFirmwareTFTP', data) | 
 |         .then((success) => | 
 |           this.infoToast( | 
 |             success, | 
 |             this.$t('pageFirmware.toast.successUploadTitle') | 
 |           ) | 
 |         ) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     rebootFromBackup() { | 
 |       this.setRebootTimeout(); | 
 |       this.$store | 
 |         .dispatch('firmwareSingleImage/switchFirmwareAndReboot') | 
 |         .then((success) => | 
 |           this.infoToast(success, this.$t('global.status.success')) | 
 |         ) | 
 |         .catch(({ message }) => { | 
 |           this.errorToast(message); | 
 |           this.clearRebootTimeout(); | 
 |         }); | 
 |     }, | 
 |     setRebootTimeout(timeoutMs = 60000) { | 
 |       // Set a timeout to disable page interactions while | 
 |       // an upload or BMC reboot is in progress | 
 |       this.startLoader(); | 
 |       this.timeoutId = setTimeout(() => { | 
 |         this.endLoader(); | 
 |         this.infoToast( | 
 |           this.$t('pageFirmware.toast.infoRefreshApplicationMessage'), | 
 |           this.$t('pageFirmware.toast.infoRefreshApplicationTitle') | 
 |         ); | 
 |       }, timeoutMs); | 
 |     }, | 
 |     clearRebootTimeout() { | 
 |       if (this.timeoutId) { | 
 |         clearTimeout(this.timeoutId); | 
 |         this.endLoader(); | 
 |       } | 
 |     }, | 
 |     onSubmitUpload() { | 
 |       this.$v.$touch(); | 
 |       if (this.$v.$invalid) return; | 
 |       this.$bvModal.show('modal-upload'); | 
 |     }, | 
 |     onClickShutDown() { | 
 |       this.$bvModal | 
 |         .msgBoxConfirm(this.$t('pageFirmware.modal.serverShutdownMessage'), { | 
 |           title: this.$t('pageFirmware.modal.serverShutdownWillCauseOutage'), | 
 |           okTitle: this.$t('pageFirmware.modal.shutDownServer'), | 
 |           cancelTitle: this.$t('global.action.cancel'), | 
 |           okVariant: 'danger', | 
 |         }) | 
 |         .then((shutdownConfirmed) => { | 
 |           if (shutdownConfirmed) | 
 |             this.$store.dispatch('controls/hostSoftPowerOff'); | 
 |         }); | 
 |     }, | 
 |   }, | 
 | }; | 
 | </script> | 
 |  | 
 | <style lang="scss" scoped> | 
 | .update-code { | 
 |   border-left: none; | 
 |   @include media-breakpoint-up(xl) { | 
 |     border-left: 1px solid gray('300'); | 
 |   } | 
 | } | 
 | </style> |