summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDixsie Wolmers <dixsie@ibm.com>2020-06-05 15:00:06 +0300
committerDerick Montague <derick.montague@ibm.com>2020-07-10 04:13:23 +0300
commit739e459610d92a6fd3021a65398ecb4517cced89 (patch)
tree247ad85d6e7924f838a1c59efc20b65b6e4812ad
parent2f8bbbfe198087497c475029c573727e0711eb04 (diff)
downloadwebui-vue-739e459610d92a6fd3021a65398ecb4517cced89.tar.xz
Add date and time settings
Adds ablity to change date and time manually, or configure using NTP servers. - If NTP is selected, user is required to enter at least one NTP address - Date and time are ISO formatted Signed-off-by: Dixsie Wolmers <dixsie@ibm.com> Change-Id: I0d67c80487fdd815eacc3539ccd702b23618260e
-rw-r--r--src/components/AppNavigation/AppNavigation.vue3
-rw-r--r--src/locales/en-US.json75
-rw-r--r--src/router/index.js8
-rw-r--r--src/store/index.js2
-rw-r--r--src/store/modules/Configuration/DateTimeSettingsStore.js68
-rw-r--r--src/views/Configuration/DateTimeSettings/DateTimeSettings.vue352
-rw-r--r--src/views/Configuration/DateTimeSettings/index.js2
7 files changed, 484 insertions, 26 deletions
diff --git a/src/components/AppNavigation/AppNavigation.vue b/src/components/AppNavigation/AppNavigation.vue
index 1dfba11e..175b0aa0 100644
--- a/src/components/AppNavigation/AppNavigation.vue
+++ b/src/components/AppNavigation/AppNavigation.vue
@@ -59,6 +59,9 @@
<icon-expand class="icon-expand" />
</b-button>
<b-collapse id="configuration-menu" tag="ul" class="nav-item__nav">
+ <b-nav-item to="/configuration/date-time-settings">
+ {{ $t('appNavigation.dateTimeSettings') }}
+ </b-nav-item>
<b-nav-item href="javascript:void(0)">
{{ $t('appNavigation.firmware') }}
</b-nav-item>
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index f0494c76..2a418040 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -25,7 +25,7 @@
},
"calendar": {
"openDatePicker": "Open date picker",
- "useCursorKeysToNavigateCalendarDates" : "Use cursor keys to navigate calendar dates"
+ "useCursorKeysToNavigateCalendarDates": "Use cursor keys to navigate calendar dates"
},
"form": {
"dateMustBeAfter": "Date must be after %{date}",
@@ -73,6 +73,7 @@
"accessControl": "Access Control",
"configuration": "Configuration",
"control": "Control",
+ "dateTimeSettings": "@:appPageTitle.dateTimeSettings",
"eventLogs": "@:appPageTitle.eventLogs",
"firmware": "@:appPageTitle.firmware",
"hardwareStatus": "@:appPageTitle.hardwareStatus",
@@ -92,6 +93,7 @@
"sslCertificates": "@:appPageTitle.sslCertificates"
},
"appPageTitle": {
+ "dateTimeSettings": "Date and time settings",
"eventLogs": "Event logs",
"firmware": "Firmware",
"hardwareStatus": "Hardware status",
@@ -101,7 +103,7 @@
"managePowerUsage": "Manage power usage",
"networkSettings": "Network settings",
"overview": "Overview",
- "profileSettings":"Profile settings",
+ "profileSettings": "Profile settings",
"rebootBmc": "Reboot BMC",
"sensors": "Sensors",
"serialOverLan": "Serial over LAN console",
@@ -111,6 +113,27 @@
"sslCertificates": "SSL Certificates",
"unauthorized": "Unauthorized"
},
+ "pageDateTimeSettings": {
+ "alert": {
+ "message": "To change how date and time are displayed (either UTC or browser offset) throughout the application, visit ",
+ "link": "Profile Settings"
+ },
+ "configureSettings": "Configure settings",
+ "form": {
+ "date": "Date",
+ "manual": "Manual",
+ "time": "Time",
+ "ntpServers": {
+ "server1": "Server 1",
+ "server2": "Server 2",
+ "server3": "Server 3"
+ }
+ },
+ "toast": {
+ "errorSaveDateTimeSettings": "Error saving date and time settings.",
+ "successSaveDateTimeSettings": "Successfully saved date and time settings."
+ }
+ },
"pageEventLogs": {
"modal": {
"deleteTitle": "Delete log | Delete logs",
@@ -138,30 +161,30 @@
"chassis": "Chassis",
"system": "System",
"table": {
- "assetTag": "Asset tag",
- "chassisType": "Chassis type",
- "connectTypesSupported": "Connect types supported",
- "description": "Description",
- "efficiencyPercent": "Efficiency percent",
- "firmwareVersion": "Firmware version",
- "graphicalConsole": "Graphical console",
- "health": "Health",
- "id": "ID",
- "indicatorLed": "Indicator LED",
- "manufacturer": "Manufacturer",
- "maxConcurrentSessions": "Max concurrent sessions",
- "model": "Model",
- "partNumber": "Part number",
- "powerInputWatts": "Power input watts",
- "powerState": "Power state",
- "serialConsole": "Serial console",
- "serialNumber": "Serial number",
- "serviceEnabled": "Service enabled",
- "serviceEntryPointUuid": "Service entry point UUID",
- "statusHealthRollup": "Status (Health rollup)",
- "statusState": "Status (State)",
- "systemType": "System type",
- "uuid": "UUID"
+ "assetTag": "Asset tag",
+ "chassisType": "Chassis type",
+ "connectTypesSupported": "Connect types supported",
+ "description": "Description",
+ "efficiencyPercent": "Efficiency percent",
+ "firmwareVersion": "Firmware version",
+ "graphicalConsole": "Graphical console",
+ "health": "Health",
+ "id": "ID",
+ "indicatorLed": "Indicator LED",
+ "manufacturer": "Manufacturer",
+ "maxConcurrentSessions": "Max concurrent sessions",
+ "model": "Model",
+ "partNumber": "Part number",
+ "powerInputWatts": "Power input watts",
+ "powerState": "Power state",
+ "serialConsole": "Serial console",
+ "serialNumber": "Serial number",
+ "serviceEnabled": "Service enabled",
+ "serviceEntryPointUuid": "Service entry point UUID",
+ "statusHealthRollup": "Status (Health rollup)",
+ "statusState": "Status (State)",
+ "systemType": "System type",
+ "uuid": "UUID"
}
},
"pageLdap": {
diff --git a/src/router/index.js b/src/router/index.js
index a3d28063..3d8c646a 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -82,6 +82,14 @@ const routes = [
}
},
{
+ path: '/configuration/date-time-settings',
+ name: 'date-time-settings',
+ component: () => import('@/views/Configuration/DateTimeSettings'),
+ meta: {
+ title: 'appPageTitle.dateTimeSettings'
+ }
+ },
+ {
path: '/control/manage-power-usage',
name: 'manage-power-usage',
component: () => import('@/views/Control/ManagePowerUsage'),
diff --git a/src/store/index.js b/src/store/index.js
index 6ad05390..392344d0 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -22,6 +22,7 @@ import ChassisStore from './modules/Health/ChassisStore';
import BmcStore from './modules/Health/BmcStore';
import WebSocketPlugin from './plugins/WebSocketPlugin';
+import DateTimeStore from './modules/Configuration/DateTimeSettingsStore';
Vue.use(Vuex);
@@ -32,6 +33,7 @@ export default new Vuex.Store({
modules: {
global: GlobalStore,
authentication: AuthenticationStore,
+ dateTime: DateTimeStore,
ldap: LdapStore,
localUsers: LocalUserManagementStore,
firmware: FirmwareStore,
diff --git a/src/store/modules/Configuration/DateTimeSettingsStore.js b/src/store/modules/Configuration/DateTimeSettingsStore.js
new file mode 100644
index 00000000..9da0cb41
--- /dev/null
+++ b/src/store/modules/Configuration/DateTimeSettingsStore.js
@@ -0,0 +1,68 @@
+import api from '../../api';
+import i18n from '@/i18n';
+
+const DateTimeStore = {
+ namespaced: true,
+ state: {
+ ntpServers: [],
+ isNtpProtocolEnabled: null
+ },
+ getters: {
+ ntpServers: state => state.ntpServers,
+ isNtpProtocolEnabled: state => state.isNtpProtocolEnabled
+ },
+ mutations: {
+ setNtpServers: (state, ntpServers) => (state.ntpServers = ntpServers),
+ setIsNtpProtocolEnabled: (state, isNtpProtocolEnabled) =>
+ (state.isNtpProtocolEnabled = isNtpProtocolEnabled)
+ },
+ actions: {
+ async getNtpData({ commit }) {
+ return await api
+ .get('/redfish/v1/Managers/bmc/NetworkProtocol')
+ .then(response => {
+ const ntpServers = response.data.NTP.NTPServers;
+ const isNtpProtocolEnabled = response.data.NTP.ProtocolEnabled;
+ commit('setNtpServers', ntpServers);
+ commit('setIsNtpProtocolEnabled', isNtpProtocolEnabled);
+ })
+ .catch(error => {
+ console.log(error);
+ });
+ },
+ async updateDateTimeSettings(_, dateTimeForm) {
+ const ntpData = {
+ NTP: {
+ ProtocolEnabled: dateTimeForm.ntpProtocolEnabled
+ }
+ };
+
+ if (dateTimeForm.ntpProtocolEnabled) {
+ ntpData.NTP.NTPServers = dateTimeForm.ntpServersArray;
+ }
+ return await api
+ .patch(`/redfish/v1/Managers/bmc/NetworkProtocol`, ntpData)
+ .then(() => {
+ if (!dateTimeForm.ntpProtocolEnabled) {
+ const dateTimeData = {
+ DateTime: dateTimeForm.updatedDateTime
+ };
+ api.patch(`/redfish/v1/Managers/bmc`, dateTimeData);
+ }
+ })
+ .then(() => {
+ return i18n.t(
+ 'pageDateTimeSettings.toast.successSaveDateTimeSettings'
+ );
+ })
+ .catch(error => {
+ console.log(error);
+ throw new Error(
+ i18n.t('pageDateTimeSettings.toast.errorSaveDateTimeSettings')
+ );
+ });
+ }
+ }
+};
+
+export default DateTimeStore;
diff --git a/src/views/Configuration/DateTimeSettings/DateTimeSettings.vue b/src/views/Configuration/DateTimeSettings/DateTimeSettings.vue
new file mode 100644
index 00000000..d7b97d1a
--- /dev/null
+++ b/src/views/Configuration/DateTimeSettings/DateTimeSettings.vue
@@ -0,0 +1,352 @@
+<template>
+ <b-container fluid="xl">
+ <page-title />
+ <b-row>
+ <b-col md="8" xl="6">
+ <alert variant="info" class="mb-4">
+ <span>
+ {{ $t('pageDateTimeSettings.alert.message') }}
+ <b-link to="/profile-settings">
+ {{ $t('pageDateTimeSettings.alert.link') }}</b-link
+ >
+ </span>
+ </alert>
+ </b-col>
+ </b-row>
+ <page-section>
+ <b-row>
+ <b-col lg="3">
+ <dl>
+ <dt>{{ $t('pageDateTimeSettings.form.date') }}</dt>
+ <dd v-if="bmcTime">{{ bmcTime | formatDate }}</dd>
+ <dd v-else>--</dd>
+ </dl>
+ </b-col>
+ <b-col lg="3">
+ <dl>
+ <dt>{{ $t('pageDateTimeSettings.form.time') }}</dt>
+ <dd v-if="bmcTime">{{ bmcTime | formatTime }}</dd>
+ <dd v-else>--</dd>
+ </dl>
+ </b-col>
+ </b-row>
+ </page-section>
+ <page-section :section-title="$t('pageDateTimeSettings.configureSettings')">
+ <b-form novalidate @submit.prevent="submitForm">
+ <b-form-group label="Configure date and time" label-sr-only>
+ <b-form-radio
+ v-model="form.configurationSelected"
+ value="manual"
+ @change="onChangeConfigType"
+ >
+ {{ $t('pageDateTimeSettings.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('pageDateTimeSettings.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="form.configurationSelected === 'ntp'"
+ @blur="$v.form.manual.date.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <div v-if="!$v.form.manual.date.pattern">
+ {{ $t('global.form.invalidFormat') }}
+ </div>
+ <div v-if="!$v.form.manual.time.required">
+ {{ $t('global.form.fieldRequired') }}
+ </div>
+ </b-form-invalid-feedback>
+ <b-form-datepicker
+ v-model="form.manual.date"
+ button-only
+ right
+ size="sm"
+ :hide-header="true"
+ :locale="locale"
+ :label-help="
+ $t('global.calendar.useCursorKeysToNavigateCalendarDates')
+ "
+ :disabled="form.configurationSelected === 'ntp'"
+ button-variant="link"
+ aria-controls="input-manual-date"
+ >
+ <template v-slot:button-content>
+ <icon-calendar />
+ <span class="sr-only">
+ {{ $t('global.calendar.openDatePicker') }}
+ </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('pageDateTimeSettings.form.time')"
+ 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="form.configurationSelected === 'ntp'"
+ @blur="$v.form.manual.time.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <div v-if="!$v.form.manual.time.pattern">
+ {{ $t('global.form.invalidFormat') }}
+ </div>
+ <div v-if="!$v.form.manual.time.required">
+ {{ $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"
+ @change="onChangeConfigType"
+ >
+ NTP
+ </b-form-radio>
+ <b-row class="mt-3 ml-3">
+ <b-col sm="6" lg="4" xl="3">
+ <b-form-group
+ :label="$t('pageDateTimeSettings.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="form.configurationSelected === 'manual'"
+ @blur="$v.form.ntp.firstAddress.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <div v-if="!$v.form.ntp.firstAddress.required">
+ {{ $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('pageDateTimeSettings.form.ntpServers.server2')"
+ label-for="input-ntp-2"
+ >
+ <b-input-group>
+ <b-form-input
+ id="input-ntp-2"
+ v-model="form.ntp.secondAddress"
+ :disabled="form.configurationSelected === 'manual'"
+ @blur="$v.form.ntp.secondAddress.$touch()"
+ />
+ </b-input-group>
+ </b-form-group>
+ </b-col>
+ <b-col sm="6" lg="4" xl="3">
+ <b-form-group
+ :label="$t('pageDateTimeSettings.form.ntpServers.server3')"
+ label-for="input-ntp-3"
+ >
+ <b-input-group>
+ <b-form-input
+ id="input-ntp-3"
+ v-model="form.ntp.thirdAddress"
+ :disabled="form.configurationSelected === 'manual'"
+ @blur="$v.form.ntp.thirdAddress.$touch()"
+ />
+ </b-input-group>
+ </b-form-group>
+ </b-col>
+ </b-row>
+ </b-form-group>
+ <b-button variant="primary" type="submit">
+ {{ $t('global.action.saveSettings') }}
+ </b-button>
+ </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 from '@/components/Mixins/LoadingBarMixin';
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
+
+import { mapState } from 'vuex';
+import { requiredIf, helpers } from 'vuelidate/lib/validators';
+
+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: 'DateTimeSettings',
+ components: { Alert, IconCalendar, PageTitle, PageSection },
+ mixins: [BVToastMixin, LoadingBarMixin, VuelidateMixin],
+ data() {
+ return {
+ locale: this.$store.getters['global/languagePreference'],
+ form: {
+ configurationSelected: '',
+ manual: {
+ date: '',
+ time: ''
+ },
+ ntp: { firstAddress: '', secondAddress: '', thirdAddress: '' }
+ }
+ };
+ },
+ 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';
+ })
+ },
+ secondAddress: {},
+ thirdAddress: {}
+ }
+ }
+ };
+ },
+ computed: {
+ ...mapState('dateTime', ['ntpServers', 'isNtpProtocolEnabled']),
+ bmcTime() {
+ return this.$store.getters['global/bmcTime'];
+ }
+ },
+ watch: {
+ ntpServers() {
+ this.setNtpValues();
+ },
+ manualDate() {
+ this.emitChange();
+ }
+ },
+ created() {
+ this.startLoader();
+ Promise.all([
+ this.$store.dispatch('global/getBmcTime'),
+ this.$store.dispatch('dateTime/getNtpData')
+ ]).finally(() => this.endLoader());
+ },
+ beforeRouteLeave(to, from, next) {
+ this.hideLoader();
+ next();
+ },
+ 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.ntpServers[0] || '';
+ this.form.ntp.secondAddress = this.ntpServers[1] || '';
+ this.form.ntp.thirdAddress = this.ntpServers[2] || '';
+ },
+ onChangeConfigType() {
+ this.$v.form.$reset();
+ this.setNtpValues();
+ },
+ submitForm() {
+ this.$v.$touch();
+ if (this.$v.$invalid) return;
+ this.startLoader();
+
+ let dateTimeForm = {};
+ let ntpFirstAddress;
+ let ntpSecondAddress;
+ let ntpThirdAddress;
+ let isNTPEnabled = this.form.configurationSelected === 'ntp';
+
+ if (!isNTPEnabled) {
+ dateTimeForm.ntpProtocolEnabled = false;
+ dateTimeForm.updatedDateTime = new Date(
+ `${this.form.manual.date} ${this.form.manual.time}`
+ ).toISOString();
+ } else {
+ ntpFirstAddress = this.form.ntp.firstAddress;
+ ntpSecondAddress = this.form.ntp.secondAddress;
+ ntpThirdAddress = this.form.ntp.thirdAddress;
+ dateTimeForm.ntpProtocolEnabled = true;
+ dateTimeForm.ntpServersArray = [
+ ntpFirstAddress,
+ ntpSecondAddress,
+ ntpThirdAddress
+ ];
+ }
+
+ this.$store
+ .dispatch('dateTime/updateDateTimeSettings', 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 (ntpSecondAddress === '' && ntpThirdAddress !== '') {
+ this.form.ntp.secondAddress = ntpThirdAddress;
+ this.form.ntp.thirdAddress = '';
+ }
+ })
+ .catch(({ message }) => this.errorToast(message))
+ .finally(() => {
+ this.$v.form.$reset();
+ this.endLoader();
+ });
+ }
+ }
+};
+</script>
+
+<style lang="scss" scoped>
+@import 'src/assets/styles/helpers';
+
+.b-form-datepicker {
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: $zindex-dropdown + 1;
+}
+</style>
diff --git a/src/views/Configuration/DateTimeSettings/index.js b/src/views/Configuration/DateTimeSettings/index.js
new file mode 100644
index 00000000..c8b5c08f
--- /dev/null
+++ b/src/views/Configuration/DateTimeSettings/index.js
@@ -0,0 +1,2 @@
+import DateTimeSettings from './DateTimeSettings.vue';
+export default DateTimeSettings;