blob: 4475a55e20378c50c042594192d327f4734d4c8d [file] [log] [blame]
<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>