diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/assets/styles/_obmc-custom.scss | 1 | ||||
-rw-r--r-- | src/assets/styles/vendor-overrides/bootstrap-vue/_calendar.scss | 8 | ||||
-rw-r--r-- | src/assets/styles/vendor-overrides/bootstrap-vue/_index.scss | 1 | ||||
-rw-r--r-- | src/components/Global/TableDateFilter.vue | 176 | ||||
-rw-r--r-- | src/components/Mixins/TableFilterMixin.js | 19 | ||||
-rw-r--r-- | src/locales/en-US.json | 8 | ||||
-rw-r--r-- | src/main.js | 2 | ||||
-rw-r--r-- | src/store/modules/GlobalStore.js | 10 | ||||
-rw-r--r-- | src/views/Health/EventLogs/EventLogs.vue | 42 | ||||
-rw-r--r-- | src/views/Login/Login.vue | 5 |
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)); } |