| <template> | 
 |   <b-container fluid="xl"> | 
 |     <page-title /> | 
 |     <b-row> | 
 |       <b-col md="8" xl="6"> | 
 |         <alert variant="info" class="mb-4"> | 
 |           <span> | 
 |             {{ $t('pageDateTime.alert.message') }} | 
 |             <b-link to="/profile-settings"> | 
 |               {{ $t('pageDateTime.alert.link') }}</b-link | 
 |             > | 
 |           </span> | 
 |         </alert> | 
 |       </b-col> | 
 |     </b-row> | 
 |     <page-section> | 
 |       <b-row> | 
 |         <b-col lg="3"> | 
 |           <dl> | 
 |             <dt>{{ $t('pageDateTime.form.date') }}</dt> | 
 |             <dd v-if="bmcTime">{{ $filters.formatDate(bmcTime) }}</dd> | 
 |             <dd v-else>--</dd> | 
 |           </dl> | 
 |         </b-col> | 
 |         <b-col lg="3"> | 
 |           <dl> | 
 |             <dt>{{ $t('pageDateTime.form.time.label') }}</dt> | 
 |             <dd v-if="bmcTime">{{ $filters.formatTime(bmcTime) }}</dd> | 
 |             <dd v-else>--</dd> | 
 |           </dl> | 
 |         </b-col> | 
 |       </b-row> | 
 |     </page-section> | 
 |     <page-section :section-title="$t('pageDateTime.configureSettings')"> | 
 |       <b-form novalidate @submit.prevent="submitForm"> | 
 |         <b-form-group | 
 |           label="Configure date and time" | 
 |           :disabled="loading" | 
 |           label-sr-only | 
 |         > | 
 |           <b-form-radio | 
 |             v-model="form.configurationSelected" | 
 |             value="manual" | 
 |             data-test-id="dateTime-radio-configureManual" | 
 |           > | 
 |             {{ $t('pageDateTime.form.manual') }} | 
 |           </b-form-radio> | 
 |           <b-row class="mt-3 ml-3"> | 
 |             <b-col sm="6" lg="4" xl="3"> | 
 |               <b-form-group | 
 |                 :label="$t('pageDateTime.form.date')" | 
 |                 label-for="input-manual-date" | 
 |               > | 
 |                 <b-form-text id="date-format-help">YYYY-MM-DD</b-form-text> | 
 |                 <b-input-group> | 
 |                   <b-form-input | 
 |                     id="input-manual-date" | 
 |                     v-model="form.manual.date" | 
 |                     :state="getValidationState(v$.form.manual.date)" | 
 |                     :disabled="ntpOptionSelected" | 
 |                     data-test-id="dateTime-input-manualDate" | 
 |                     class="form-control-with-button" | 
 |                     @blur="v$.form.manual.date.$touch()" | 
 |                   /> | 
 |                   <b-form-invalid-feedback role="alert"> | 
 |                     <div v-if="v$.form.manual.date.pattern.$invalid"> | 
 |                       {{ $t('global.form.invalidFormat') }} | 
 |                     </div> | 
 |                     <div v-if="v$.form.manual.date.required.$invalid"> | 
 |                       {{ $t('global.form.fieldRequired') }} | 
 |                     </div> | 
 |                   </b-form-invalid-feedback> | 
 |                   <b-form-datepicker | 
 |                     v-model="form.manual.date" | 
 |                     class="btn-datepicker btn-icon-only" | 
 |                     button-only | 
 |                     right | 
 |                     :hide-header="true" | 
 |                     :locale="locale" | 
 |                     :label-help=" | 
 |                       $t('global.calendar.useCursorKeysToNavigateCalendarDates') | 
 |                     " | 
 |                     :title="$t('global.calendar.selectDate')" | 
 |                     :disabled="ntpOptionSelected" | 
 |                     button-variant="link" | 
 |                     aria-controls="input-manual-date" | 
 |                   > | 
 |                     <template #button-content> | 
 |                       <icon-calendar /> | 
 |                       <span class="sr-only"> | 
 |                         {{ $t('global.calendar.selectDate') }} | 
 |                       </span> | 
 |                     </template> | 
 |                   </b-form-datepicker> | 
 |                 </b-input-group> | 
 |               </b-form-group> | 
 |             </b-col> | 
 |             <b-col sm="6" lg="4" xl="3"> | 
 |               <b-form-group | 
 |                 :label="$t('pageDateTime.form.time.timezone', { timezone })" | 
 |                 label-for="input-manual-time" | 
 |               > | 
 |                 <b-form-text id="time-format-help">HH:MM</b-form-text> | 
 |                 <b-input-group> | 
 |                   <b-form-input | 
 |                     id="input-manual-time" | 
 |                     v-model="form.manual.time" | 
 |                     :state="getValidationState(v$.form.manual.time)" | 
 |                     :disabled="ntpOptionSelected" | 
 |                     data-test-id="dateTime-input-manualTime" | 
 |                     @blur="v$.form.manual.time.$touch()" | 
 |                   /> | 
 |                   <b-form-invalid-feedback role="alert"> | 
 |                     <div v-if="v$.form.manual.time.pattern.$invalid"> | 
 |                       {{ $t('global.form.invalidFormat') }} | 
 |                     </div> | 
 |                     <div v-if="v$.form.manual.time.required.$invalid"> | 
 |                       {{ $t('global.form.fieldRequired') }} | 
 |                     </div> | 
 |                   </b-form-invalid-feedback> | 
 |                 </b-input-group> | 
 |               </b-form-group> | 
 |             </b-col> | 
 |           </b-row> | 
 |           <b-form-radio | 
 |             v-model="form.configurationSelected" | 
 |             value="ntp" | 
 |             data-test-id="dateTime-radio-configureNTP" | 
 |           > | 
 |             NTP | 
 |           </b-form-radio> | 
 |           <b-row class="mt-3 ml-3"> | 
 |             <b-col sm="6" lg="4" xl="3"> | 
 |               <b-form-group | 
 |                 :label="$t('pageDateTime.form.ntpServers.server1')" | 
 |                 label-for="input-ntp-1" | 
 |               > | 
 |                 <b-input-group> | 
 |                   <b-form-input | 
 |                     id="input-ntp-1" | 
 |                     v-model="form.ntp.firstAddress" | 
 |                     :state="getValidationState(v$.form.ntp.firstAddress)" | 
 |                     :disabled="manualOptionSelected" | 
 |                     data-test-id="dateTime-input-ntpServer1" | 
 |                     @blur="v$.form.ntp.firstAddress.$touch()" | 
 |                   /> | 
 |                   <b-form-invalid-feedback role="alert"> | 
 |                     <div v-if="v$.form.ntp.firstAddress.required.$invalid"> | 
 |                       {{ $t('global.form.fieldRequired') }} | 
 |                     </div> | 
 |                   </b-form-invalid-feedback> | 
 |                 </b-input-group> | 
 |               </b-form-group> | 
 |             </b-col> | 
 |             <b-col sm="6" lg="4" xl="3"> | 
 |               <b-form-group | 
 |                 :label="$t('pageDateTime.form.ntpServers.server2')" | 
 |                 label-for="input-ntp-2" | 
 |               > | 
 |                 <b-input-group> | 
 |                   <b-form-input | 
 |                     id="input-ntp-2" | 
 |                     v-model="form.ntp.secondAddress" | 
 |                     :disabled="manualOptionSelected" | 
 |                     data-test-id="dateTime-input-ntpServer2" | 
 |                   /> | 
 |                 </b-input-group> | 
 |               </b-form-group> | 
 |             </b-col> | 
 |             <b-col sm="6" lg="4" xl="3"> | 
 |               <b-form-group | 
 |                 :label="$t('pageDateTime.form.ntpServers.server3')" | 
 |                 label-for="input-ntp-3" | 
 |               > | 
 |                 <b-input-group> | 
 |                   <b-form-input | 
 |                     id="input-ntp-3" | 
 |                     v-model="form.ntp.thirdAddress" | 
 |                     :disabled="manualOptionSelected" | 
 |                     data-test-id="dateTime-input-ntpServer3" | 
 |                   /> | 
 |                 </b-input-group> | 
 |               </b-form-group> | 
 |             </b-col> | 
 |           </b-row> | 
 |           <b-button | 
 |             variant="primary" | 
 |             type="submit" | 
 |             data-test-id="dateTime-button-saveSettings" | 
 |           > | 
 |             {{ $t('global.action.saveSettings') }} | 
 |           </b-button> | 
 |         </b-form-group> | 
 |       </b-form> | 
 |     </page-section> | 
 |   </b-container> | 
 | </template> | 
 |  | 
 | <script> | 
 | import Alert from '@/components/Global/Alert'; | 
 | import IconCalendar from '@carbon/icons-vue/es/calendar/20'; | 
 | import PageTitle from '@/components/Global/PageTitle'; | 
 | import PageSection from '@/components/Global/PageSection'; | 
 |  | 
 | import BVToastMixin from '@/components/Mixins/BVToastMixin'; | 
 | import LoadingBarMixin, { loading } from '@/components/Mixins/LoadingBarMixin'; | 
 | import LocalTimezoneLabelMixin from '@/components/Mixins/LocalTimezoneLabelMixin'; | 
 | import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js'; | 
 | import { useVuelidate } from '@vuelidate/core'; | 
 |  | 
 | import { mapState } from 'vuex'; | 
 | import { requiredIf } from '@vuelidate/validators'; | 
 | import { helpers } from 'vuelidate/lib/validators'; | 
 | import { useI18n } from 'vue-i18n'; | 
 |  | 
 | const isoDateRegex = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$)/; | 
 | const isoTimeRegex = /^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/; | 
 |  | 
 | export default { | 
 |   name: 'DateTime', | 
 |   components: { Alert, IconCalendar, PageTitle, PageSection }, | 
 |   mixins: [ | 
 |     BVToastMixin, | 
 |     LoadingBarMixin, | 
 |     LocalTimezoneLabelMixin, | 
 |     VuelidateMixin, | 
 |   ], | 
 |   beforeRouteLeave(to, from, next) { | 
 |     this.hideLoader(); | 
 |     next(); | 
 |   }, | 
 |   setup() { | 
 |     return { | 
 |       v$: useVuelidate(), | 
 |     }; | 
 |   }, | 
 |   data() { | 
 |     return { | 
 |       $t: useI18n().t, | 
 |       locale: this.$store.getters['global/languagePreference'], | 
 |       form: { | 
 |         configurationSelected: 'manual', | 
 |         manual: { | 
 |           date: '', | 
 |           time: '', | 
 |         }, | 
 |         ntp: { firstAddress: '', secondAddress: '', thirdAddress: '' }, | 
 |       }, | 
 |       loading, | 
 |     }; | 
 |   }, | 
 |   validations() { | 
 |     return { | 
 |       form: { | 
 |         manual: { | 
 |           date: { | 
 |             required: requiredIf(function () { | 
 |               return this.form.configurationSelected === 'manual'; | 
 |             }), | 
 |             pattern: helpers.regex('pattern', isoDateRegex), | 
 |           }, | 
 |           time: { | 
 |             required: requiredIf(function () { | 
 |               return this.form.configurationSelected === 'manual'; | 
 |             }), | 
 |             pattern: helpers.regex('pattern', isoTimeRegex), | 
 |           }, | 
 |         }, | 
 |         ntp: { | 
 |           firstAddress: { | 
 |             required: requiredIf(function () { | 
 |               return this.form.configurationSelected === 'ntp'; | 
 |             }), | 
 |           }, | 
 |         }, | 
 |       }, | 
 |     }; | 
 |   }, | 
 |   computed: { | 
 |     ...mapState('dateTime', ['ntpServers', 'isNtpProtocolEnabled']), | 
 |     bmcTime() { | 
 |       return this.$store.getters['global/bmcTime']; | 
 |     }, | 
 |     ntpOptionSelected() { | 
 |       return this.form.configurationSelected === 'ntp'; | 
 |     }, | 
 |     manualOptionSelected() { | 
 |       return this.form.configurationSelected === 'manual'; | 
 |     }, | 
 |     isUtcDisplay() { | 
 |       return this.$store.getters['global/isUtcDisplay']; | 
 |     }, | 
 |     timezone() { | 
 |       if (this.isUtcDisplay) { | 
 |         return 'UTC'; | 
 |       } | 
 |       return this.localOffset(); | 
 |     }, | 
 |   }, | 
 |   watch: { | 
 |     ntpServers() { | 
 |       this.setNtpValues(); | 
 |     }, | 
 |     manualDate() { | 
 |       this.emitChange(); | 
 |     }, | 
 |     bmcTime() { | 
 |       this.form.manual.date = this.$filters.formatDate( | 
 |         this.$store.getters['global/bmcTime'], | 
 |       ); | 
 |       this.form.manual.time = this.$filters | 
 |         .formatTime(this.$store.getters['global/bmcTime']) | 
 |         .slice(0, 5); | 
 |     }, | 
 |   }, | 
 |   created() { | 
 |     this.startLoader(); | 
 |     this.setNtpValues(); | 
 |     Promise.all([ | 
 |       this.$store.dispatch('global/getBmcTime'), | 
 |       this.$store.dispatch('dateTime/getNtpData'), | 
 |     ]).finally(() => this.endLoader()); | 
 |   }, | 
 |   methods: { | 
 |     emitChange() { | 
 |       if (this.v$.$invalid) return; | 
 |       this.v$.$reset(); //reset to re-validate on blur | 
 |       this.$emit('change', { | 
 |         manualDate: this.manualDate ? new Date(this.manualDate) : null, | 
 |       }); | 
 |     }, | 
 |     setNtpValues() { | 
 |       this.form.configurationSelected = this.isNtpProtocolEnabled | 
 |         ? 'ntp' | 
 |         : 'manual'; | 
 |       [ | 
 |         this.form.ntp.firstAddress = '', | 
 |         this.form.ntp.secondAddress = '', | 
 |         this.form.ntp.thirdAddress = '', | 
 |       ] = [this.ntpServers[0], this.ntpServers[1], this.ntpServers[2]]; | 
 |     }, | 
 |     submitForm() { | 
 |       this.v$.$touch(); | 
 |       if (this.v$.$invalid) return; | 
 |       this.startLoader(); | 
 |  | 
 |       let dateTimeForm = {}; | 
 |       let isNTPEnabled = this.form.configurationSelected === 'ntp'; | 
 |  | 
 |       if (!isNTPEnabled) { | 
 |         const isUtcDisplay = this.$store.getters['global/isUtcDisplay']; | 
 |         let date; | 
 |  | 
 |         dateTimeForm.ntpProtocolEnabled = false; | 
 |  | 
 |         if (isUtcDisplay) { | 
 |           // Create UTC Date | 
 |           date = this.getUtcDate(this.form.manual.date, this.form.manual.time); | 
 |         } else { | 
 |           // Create local Date | 
 |           date = new Date(`${this.form.manual.date} ${this.form.manual.time}`); | 
 |         } | 
 |  | 
 |         dateTimeForm.updatedDateTime = date.toISOString(); | 
 |       } else { | 
 |         dateTimeForm.ntpProtocolEnabled = true; | 
 |  | 
 |         const ntpArray = [ | 
 |           this.form.ntp.firstAddress, | 
 |           this.form.ntp.secondAddress, | 
 |           this.form.ntp.thirdAddress, | 
 |         ]; | 
 |  | 
 |         // Filter the ntpArray to remove empty strings, | 
 |         // per Redfish spec there should be no empty strings or null on the ntp array. | 
 |         const ntpArrayFiltered = ntpArray.filter((x) => x); | 
 |  | 
 |         dateTimeForm.ntpServersArray = [...ntpArrayFiltered]; | 
 |  | 
 |         [this.ntpServers[0], this.ntpServers[1], this.ntpServers[2]] = [ | 
 |           ...dateTimeForm.ntpServersArray, | 
 |         ]; | 
 |  | 
 |         this.setNtpValues(); | 
 |       } | 
 |  | 
 |       this.$store | 
 |         .dispatch('dateTime/updateDateTime', dateTimeForm) | 
 |         .then((success) => { | 
 |           this.successToast(success); | 
 |           if (!isNTPEnabled) return; | 
 |           // Shift address up if second address is empty | 
 |           // to avoid refreshing after delay when updating NTP | 
 |           if (!this.form.ntp.secondAddress && this.form.ntp.thirdAddres) { | 
 |             this.form.ntp.secondAddress = this.form.ntp.thirdAddres; | 
 |             this.form.ntp.thirdAddress = ''; | 
 |           } | 
 |         }) | 
 |         .then(() => { | 
 |           this.$store.dispatch('global/getBmcTime'); | 
 |         }) | 
 |         .catch(({ message }) => this.errorToast(message)) | 
 |         .finally(() => { | 
 |           this.v$.form.$reset(); | 
 |           this.endLoader(); | 
 |         }); | 
 |     }, | 
 |     getUtcDate(date, time) { | 
 |       // Split user input string values to create | 
 |       // a UTC Date object | 
 |       const datesArray = date.split('-'); | 
 |       const timeArray = time.split(':'); | 
 |       let utcDate = Date.UTC( | 
 |         datesArray[0], // User input year | 
 |         //UTC expects zero-index month value 0-11 (January-December) | 
 |         //for reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC#Parameters | 
 |         parseInt(datesArray[1]) - 1, // User input month | 
 |         datesArray[2], // User input day | 
 |         timeArray[0], // User input hour | 
 |         timeArray[1], // User input minute | 
 |       ); | 
 |       return new Date(utcDate); | 
 |     }, | 
 |   }, | 
 | }; | 
 | </script> |