summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/assets/styles/_obmc-custom.scss1
-rw-r--r--src/assets/styles/vendor-overrides/bootstrap-vue/_calendar.scss8
-rw-r--r--src/assets/styles/vendor-overrides/bootstrap-vue/_index.scss1
-rw-r--r--src/components/Global/TableDateFilter.vue176
-rw-r--r--src/components/Mixins/TableFilterMixin.js19
-rw-r--r--src/locales/en-US.json8
-rw-r--r--src/main.js2
-rw-r--r--src/store/modules/GlobalStore.js10
-rw-r--r--src/views/Health/EventLogs/EventLogs.vue42
-rw-r--r--src/views/Login/Login.vue5
10 files changed, 254 insertions, 18 deletions
diff --git a/src/assets/styles/_obmc-custom.scss b/src/assets/styles/_obmc-custom.scss
index f443799f..63bed23f 100644
--- a/src/assets/styles/_obmc-custom.scss
+++ b/src/assets/styles/_obmc-custom.scss
@@ -18,3 +18,4 @@
// Vendor overrides must be the last file imported
@import "./vendor-overrides/bootstrap/index";
+@import "./vendor-overrides/bootstrap-vue/index";
diff --git a/src/assets/styles/vendor-overrides/bootstrap-vue/_calendar.scss b/src/assets/styles/vendor-overrides/bootstrap-vue/_calendar.scss
new file mode 100644
index 00000000..bf7572e2
--- /dev/null
+++ b/src/assets/styles/vendor-overrides/bootstrap-vue/_calendar.scss
@@ -0,0 +1,8 @@
+.b-calendar-nav {
+ .btn {
+ &:hover {
+ background: none;
+ color: $dark;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/assets/styles/vendor-overrides/bootstrap-vue/_index.scss b/src/assets/styles/vendor-overrides/bootstrap-vue/_index.scss
new file mode 100644
index 00000000..a6658148
--- /dev/null
+++ b/src/assets/styles/vendor-overrides/bootstrap-vue/_index.scss
@@ -0,0 +1 @@
+@import "./calendar";
diff --git a/src/components/Global/TableDateFilter.vue b/src/components/Global/TableDateFilter.vue
new file mode 100644
index 00000000..e73d7d51
--- /dev/null
+++ b/src/components/Global/TableDateFilter.vue
@@ -0,0 +1,176 @@
+<template>
+ <b-row class="mb-2">
+ <b-col class="d-flex">
+ <b-form-group
+ :label="$t('global.table.fromDate')"
+ label-for="input-from-date"
+ class="mr-3 my-0 w-100"
+ >
+ <b-input-group>
+ <b-form-input
+ id="input-from-date"
+ v-model="fromDate"
+ placeholder="YYYY-MM-DD"
+ :state="getValidationState($v.fromDate)"
+ @blur="$v.fromDate.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.fromDate.pattern">
+ {{ $t('global.form.invalidFormat') }}
+ </template>
+ <template v-if="!$v.fromDate.maxDate">
+ {{ $t('global.form.dateMustBeBefore', { date: toDate }) }}
+ </template>
+ </b-form-invalid-feedback>
+ <template slot:append>
+ <b-form-datepicker
+ v-model="fromDate"
+ button-only
+ right
+ size="sm"
+ :max="toDate"
+ :hide-header="true"
+ :locale="locale"
+ :label-help="
+ $t('global.calendar.useCursorKeysToNavigateCalendarDates')
+ "
+ button-variant="link"
+ aria-controls="input-from-date"
+ >
+ <template v-slot:button-content>
+ <icon-calendar />
+ <span class="sr-only">{{
+ $t('global.calendar.openDatePicker')
+ }}</span>
+ </template>
+ </b-form-datepicker>
+ </template>
+ </b-input-group>
+ </b-form-group>
+ <b-form-group
+ :label="$t('global.table.toDate')"
+ label-for="input-to-date"
+ class="my-0 w-100"
+ >
+ <b-input-group>
+ <b-form-input
+ id="input-to-date"
+ v-model="toDate"
+ placeholder="YYYY-MM-DD"
+ :state="getValidationState($v.toDate)"
+ @blur="$v.toDate.$touch()"
+ />
+ <b-form-invalid-feedback role="alert">
+ <template v-if="!$v.toDate.pattern">
+ {{ $t('global.form.invalidFormat') }}
+ </template>
+ <template v-if="!$v.toDate.minDate">
+ {{ $t('global.form.dateMustBeAfter', { date: fromDate }) }}
+ </template>
+ </b-form-invalid-feedback>
+ <template slot:append>
+ <b-form-datepicker
+ v-model="toDate"
+ button-only
+ right
+ size="sm"
+ :min="fromDate"
+ :hide-header="true"
+ :locale="locale"
+ :label-help="
+ $t('global.calendar.useCursorKeysToNavigateCalendarDates')
+ "
+ button-variant="link"
+ aria-controls="input-to-date"
+ >
+ <template v-slot:button-content>
+ <icon-calendar />
+ <span class="sr-only">{{
+ $t('global.calendar.openDatePicker')
+ }}</span>
+ </template>
+ </b-form-datepicker>
+ </template>
+ </b-input-group>
+ </b-form-group>
+ </b-col>
+ </b-row>
+</template>
+
+<script>
+import IconCalendar from '@carbon/icons-vue/es/calendar/20';
+import { helpers } from 'vuelidate/lib/validators';
+
+import VuelidateMixin from '@/components/Mixins/VuelidateMixin.js';
+
+const isoDateRegex = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/;
+
+export default {
+ components: { IconCalendar },
+ mixins: [VuelidateMixin],
+ data() {
+ return {
+ fromDate: '',
+ toDate: '',
+ offsetToDate: '',
+ locale: this.$store.getters['global/languagePreference']
+ };
+ },
+ validations() {
+ return {
+ fromDate: {
+ pattern: helpers.regex('pattern', isoDateRegex),
+ maxDate: value => {
+ if (!this.toDate) return true;
+ const date = new Date(value);
+ const maxDate = new Date(this.toDate);
+ if (date.getTime() > maxDate.getTime()) return false;
+ return true;
+ }
+ },
+ toDate: {
+ pattern: helpers.regex('pattern', isoDateRegex),
+ minDate: value => {
+ if (!this.fromDate) return true;
+ const date = new Date(value);
+ const minDate = new Date(this.fromDate);
+ if (date.getTime() < minDate.getTime()) return false;
+ return true;
+ }
+ }
+ };
+ },
+ watch: {
+ fromDate() {
+ this.emitChange();
+ },
+ toDate(newVal) {
+ // Offset the end date to end of day to make sure all
+ // entries from selected end date are included in filter
+ this.offsetToDate = new Date(newVal).setUTCHours(23, 59, 59, 999);
+ this.emitChange();
+ }
+ },
+ methods: {
+ emitChange() {
+ if (this.$v.$invalid) return;
+ this.$v.$reset(); //reset to re-validate on blur
+ this.$emit('change', {
+ fromDate: this.fromDate ? new Date(this.fromDate) : null,
+ toDate: this.toDate ? new Date(this.offsetToDate) : null
+ });
+ }
+ }
+};
+</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/components/Mixins/TableFilterMixin.js b/src/components/Mixins/TableFilterMixin.js
index 25c7497a..58e70c57 100644
--- a/src/components/Mixins/TableFilterMixin.js
+++ b/src/components/Mixins/TableFilterMixin.js
@@ -16,6 +16,25 @@ const TableFilterMixin = {
}
return returnRow;
});
+ },
+ getFilteredTableDataByDate(
+ tableData = [],
+ startDate,
+ endDate,
+ propertyKey = 'date'
+ ) {
+ if (!startDate && !endDate) return tableData;
+ const startDateInMs = startDate ? startDate.getTime() : 0;
+ const endDateInMs = endDate
+ ? endDate.getTime()
+ : Number.POSITIVE_INFINITY;
+ return tableData.filter(row => {
+ const date = row[propertyKey];
+ if (!(date instanceof Date)) return;
+
+ const dateInMs = date.getTime();
+ if (dateInMs >= startDateInMs && dateInMs <= endDateInMs) return row;
+ });
}
}
};
diff --git a/src/locales/en-US.json b/src/locales/en-US.json
index 9fc64d0b..8a722e39 100644
--- a/src/locales/en-US.json
+++ b/src/locales/en-US.json
@@ -22,7 +22,13 @@
"showPassword": "Show password as plain text. Note: this will visually expose your password on the screen.",
"tooltip": "Tooltip"
},
+ "calendar": {
+ "openDatePicker": "Open date picker",
+ "useCursorKeysToNavigateCalendarDates" : "Use cursor keys to navigate calendar dates"
+ },
"form": {
+ "dateMustBeAfter": "Date must be after %{date}",
+ "dateMustBeBefore": "Date must be before %{date}",
"fieldRequired": "Field required",
"invalidFormat": "Invalid format",
"invalidValue": "Invalid value",
@@ -46,7 +52,9 @@
"informational": "Informational"
},
"table": {
+ "fromDate": "From date",
"itemsPerPage": "Items per page",
+ "toDate": "To date",
"viewAll": "View all"
}
},
diff --git a/src/main.js b/src/main.js
index 6896ec2f..0c6d5b07 100644
--- a/src/main.js
+++ b/src/main.js
@@ -11,6 +11,7 @@ import {
DropdownPlugin,
FormPlugin,
FormCheckboxPlugin,
+ FormDatepickerPlugin,
FormFilePlugin,
FormGroupPlugin,
FormInputPlugin,
@@ -74,6 +75,7 @@ Vue.use(CollapsePlugin);
Vue.use(DropdownPlugin);
Vue.use(FormPlugin);
Vue.use(FormCheckboxPlugin);
+Vue.use(FormDatepickerPlugin);
Vue.use(FormFilePlugin);
Vue.use(FormGroupPlugin);
Vue.use(FormInputPlugin);
diff --git a/src/store/modules/GlobalStore.js b/src/store/modules/GlobalStore.js
index 1327422a..42e9e2bf 100644
--- a/src/store/modules/GlobalStore.js
+++ b/src/store/modules/GlobalStore.js
@@ -30,16 +30,20 @@ const GlobalStore = {
namespaced: true,
state: {
bmcTime: null,
- hostStatus: 'unreachable'
+ hostStatus: 'unreachable',
+ languagePreference: localStorage.getItem('storedLanguage') || 'en-US'
},
getters: {
hostStatus: state => state.hostStatus,
- bmcTime: state => state.bmcTime
+ bmcTime: state => state.bmcTime,
+ languagePreference: state => state.languagePreference
},
mutations: {
setBmcTime: (state, bmcTime) => (state.bmcTime = bmcTime),
setHostStatus: (state, hostState) =>
- (state.hostStatus = hostStateMapper(hostState))
+ (state.hostStatus = hostStateMapper(hostState)),
+ setLanguagePreference: (state, language) =>
+ (state.languagePreference = language)
},
actions: {
async getBmcTime({ commit }) {
diff --git a/src/views/Health/EventLogs/EventLogs.vue b/src/views/Health/EventLogs/EventLogs.vue
index a5ef3757..44a24859 100644
--- a/src/views/Health/EventLogs/EventLogs.vue
+++ b/src/views/Health/EventLogs/EventLogs.vue
@@ -1,6 +1,11 @@
<template>
<b-container fluid="xl">
<page-title />
+ <b-row class="mb-3">
+ <b-col md="6" lg="7" xl="5" offset-md="6" offset-lg="5" offset-xl="7">
+ <table-date-filter @change="onChangeDateTimeFilter" />
+ </b-col>
+ </b-row>
<b-row>
<b-col class="text-right">
<table-filter :filters="tableFilters" @filterChange="onFilterChange" />
@@ -121,6 +126,7 @@ import { omit } from 'lodash';
import PageTitle from '@/components/Global/PageTitle';
import StatusIcon from '@/components/Global/StatusIcon';
+import TableDateFilter from '@/components/Global/TableDateFilter';
import TableFilter from '@/components/Global/TableFilter';
import TableRowAction from '@/components/Global/TableRowAction';
import TableToolbar from '@/components/Global/TableToolbar';
@@ -143,7 +149,8 @@ export default {
TableFilter,
TableRowAction,
TableToolbar,
- TableToolbarExport
+ TableToolbarExport,
+ TableDateFilter
},
mixins: [
BVPaginationMixin,
@@ -202,7 +209,9 @@ export default {
value: 'delete',
label: this.$t('global.action.delete')
}
- ]
+ ],
+ filterStartDate: null,
+ filterEndDate: null
};
},
computed: {
@@ -223,16 +232,21 @@ export default {
};
});
},
- filteredLogs: {
- get: function() {
- return this.getFilteredTableData(this.allLogs, this.activeFilters);
- },
- set: function(newVal) {
- return newVal;
- }
- },
batchExportData() {
return this.selectedRows.map(row => omit(row, 'actions'));
+ },
+ filteredLogsByDate() {
+ return this.getFilteredTableDataByDate(
+ this.allLogs,
+ this.filterStartDate,
+ this.filterEndDate
+ );
+ },
+ filteredLogs() {
+ return this.getFilteredTableData(
+ this.filteredLogsByDate,
+ this.activeFilters
+ );
}
},
created() {
@@ -273,10 +287,6 @@ export default {
},
onFilterChange({ activeFilters }) {
this.activeFilters = activeFilters;
- this.filteredLogs = this.getFilteredTableData(
- this.allLogs,
- activeFilters
- );
},
onSortCompare(a, b, key) {
if (key === 'severity') {
@@ -316,6 +326,10 @@ export default {
if (deleteConfirmed) this.deleteLogs(uris);
});
}
+ },
+ onChangeDateTimeFilter({ fromDate, toDate }) {
+ this.filterStartDate = fromDate;
+ this.filterEndDate = toDate;
}
}
};
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index d373be22..4d8f2484 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -136,7 +136,10 @@ export default {
this.$store
.dispatch('authentication/login', [username, password])
.then(() => this.$router.push('/'))
- .then(localStorage.setItem('storedLanguage', i18n.locale))
+ .then(() => {
+ localStorage.setItem('storedLanguage', i18n.locale);
+ this.$store.commit('global/setLanguagePreference', i18n.locale);
+ })
.catch(error => console.log(error))
.finally(() => (this.disableSubmitButton = false));
}