diff --git a/package-lock.json b/package-lock.json index fa52f3ef0..d10956f9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "html-webpack-plugin": "^5.5.0", "lodash": "^4.17.21", "marked": "^4.0.10", + "moment": "^2.29.4", "p-all": "^4.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -16841,6 +16842,14 @@ "node": ">=0.10.0" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/moo": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", @@ -39075,6 +39084,11 @@ "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, "moo": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", diff --git a/package.json b/package.json index 5de25b6c3..90e5fa996 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "html-webpack-plugin": "^5.5.0", "lodash": "^4.17.21", "marked": "^4.0.10", + "moment": "^2.29.4", "p-all": "^4.0.0", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/src/api/api.js b/src/api/api.js index 5a0eeae55..1017c1e4f 100644 --- a/src/api/api.js +++ b/src/api/api.js @@ -196,8 +196,10 @@ export async function getEntities(items, { ...(options.filter && Object.keys(options.filter).length && generateFilter(options.filter)), ...(calculateSystemProfile(filters)), ...(fields && Object.keys(fields).length && generateFilter(fields, 'fields')), - ...filters?.lastSeenFilter?.updatedStart && { updated_start: filters.lastSeenFilter.updatedStart }, - ...filters?.lastSeenFilter?.updatedEnd && { updated_end: filters.lastSeenFilter.updatedEnd } + ...filters?.lastSeenFilter?.updatedStart && + filters?.lastSeenFilter?.updatedStart.length > 0 && { updated_start: filters.lastSeenFilter.updatedStart }, + ...filters?.lastSeenFilter?.updatedEnd && + filters?.lastSeenFilter?.updatedEnd.length > 0 && { updated_end: filters.lastSeenFilter.updatedEnd } } } ) diff --git a/src/components/InventoryTable/EntityTableToolbar.js b/src/components/InventoryTable/EntityTableToolbar.js index 1d081566e..67485a482 100644 --- a/src/components/InventoryTable/EntityTableToolbar.js +++ b/src/components/InventoryTable/EntityTableToolbar.js @@ -53,6 +53,7 @@ import useOperatingSystemFilter from '../filters/useOperatingSystemFilter'; import useFeatureFlag from '../../Utilities/useFeatureFlag'; import useGroupFilter from '../filters/useGroupFilter'; import { DatePicker, Split, SplitItem } from '@patternfly/react-core'; +import { fromValidator, toValidator } from '../filters/helpers'; /** * Table toolbar used at top of inventory table. @@ -112,7 +113,7 @@ const EntityTableToolbar = ({ const [registeredFilter, registeredChip, registeredWithFilter, setRegisteredWithFilter] = useRegisteredWithFilter(reducer); const [rhcdFilterConfig, rhcdFilterChips, rhcdFilterValue, setRhcdFilterValue] = useRhcdFilter(reducer); const [lastSeenFilter, lastSeenChip, lastSeenFilterValue, setLastSeenFilterValue, - toValidator, onFromChange, onToChange, endDate, startDate, fromValidator, + onFromChange, onToChange, endDate, startDate, setStartDate, setEndDate] = useLastSeenFilter(reducer); const [osFilterConfig, osFilterChips, osFilterValue, setOsFilterValue] = useOperatingSystemFilter(); const [updateMethodConfig, updateMethodChips, updateMethodValue, setUpdateMethodValue] = useUpdateMethodFilter(reducer); @@ -348,6 +349,8 @@ const EntityTableToolbar = ({ enabledFilters.lastSeenFilter && setLastSeenFilterValue([]); enabledFilters.updateMethodFilter && setUpdateMethodValue([]); enabledFilters.hostGroupFilter && setHostGroupValue([]); + setEndDate(); + setStartDate(); dispatch(setFilter([])); updateData({ page: 1, filters: [] }); }; @@ -444,7 +447,7 @@ const EntityTableToolbar = ({ @@ -455,8 +458,9 @@ const EntityTableToolbar = ({ diff --git a/src/components/filters/helpers.js b/src/components/filters/helpers.js new file mode 100644 index 000000000..bd72f4d54 --- /dev/null +++ b/src/components/filters/helpers.js @@ -0,0 +1,38 @@ +import moment from 'moment'; + +export const oldestDate = new Date(1950, 1, 1); +//validators control what date ranges can be selected in the component. +//both validators need to keep in mind todays date, and the other components inputed date. + +//maxDate is the other date pickers currently selected Date +//date is patternfly component date +export const fromValidator = (maxDate) => (date) => { + const todaysDate = moment().startOf('day'); + const newMaxDate = moment(maxDate).startOf('day'); + + if (date < oldestDate) { + return 'Date is before the allowable range.'; + } else if (date > newMaxDate) { + return `End date must be later than Start date.`; + } else if (date > todaysDate) { + return ' Start date must be earlier than End date.'; + } else { + return ''; + } +}; + +//minDate is the other components currently selected Date +//dateToValidate is patternfly component date. +export const toValidator = (minDate) => (dateToValidate) => { + const todaysDate = moment().endOf('day'); + const newDatetoValidate = new Date(dateToValidate); + const newMinDate = moment(minDate).startOf('day'); + + if (newDatetoValidate < newMinDate) { + return 'Start date must be earlier than End date.'; + } else if (newDatetoValidate > todaysDate) { + return `Date must be ${todaysDate.toISOString().split('T')[0]} or earlier`; + } else { + return ''; + } +}; diff --git a/src/components/filters/helpers.test.js b/src/components/filters/helpers.test.js new file mode 100644 index 000000000..8af9f2e83 --- /dev/null +++ b/src/components/filters/helpers.test.js @@ -0,0 +1,16 @@ +import { fromValidator, toValidator } from './helpers'; +import moment from 'moment'; + +describe('Validates datepicker dates', () => { + it('ToValidator', () => { + const startOfToday = moment().startOf('day'); + const endOfToday = moment().endOf('day'); + expect(toValidator(startOfToday)(endOfToday)).toEqual(''); + }); + it('FromValidator', () => { + const startOfToday = moment().startOf('day'); + const endOfToday = moment().endOf('day'); + expect(fromValidator(endOfToday)(startOfToday)).toEqual(''); + + }); +}); diff --git a/src/components/filters/useLastSeenFilter.js b/src/components/filters/useLastSeenFilter.js index 353f3fd55..42c18558c 100644 --- a/src/components/filters/useLastSeenFilter.js +++ b/src/components/filters/useLastSeenFilter.js @@ -1,6 +1,7 @@ import { useState } from 'react'; import { LAST_SEEN_CHIP, lastSeenItems } from '../../Utilities/constants'; - +import moment from 'moment'; +import { oldestDate } from './helpers.js'; export const lastSeenFilterState = { lastSeenFilter: [] }; export const LAST_SEEN_FILTER = 'LAST_SEEN_FILTER'; export const lastSeenFilterReducer = (_state, { type, payload }) => ({ @@ -42,81 +43,74 @@ export const useLastSeenFilter = ( ] : []; - const [startDate, setStartDate] = useState(); + const [startDate, setStartDate] = useState(oldestDate); const [endDate, setEndDate] = useState(); - const todaysDate = new Date(); + const todaysDate = moment(); - const manageStartDate = (apiStartDate, apiEndDate)=> { - if (isNaN(apiEndDate) && isNaN(apiStartDate)) { + const manageStartDate = (apiStartDate, apiEndDate) => { + const newApiStartDate = apiStartDate; + const newApiEndDate = apiEndDate; + if (isNaN(newApiEndDate) && isNaN(newApiStartDate)) { setValue({ ...lastSeenValue, updatedStart: null, updatedEnd: null }); - } else if (apiStartDate > apiEndDate || isNaN(apiStartDate) || apiStartDate > todaysDate) { - setValue({ ...lastSeenValue, updatedStart: null, updatedEnd: apiEndDate.toISOString() }); - } else { - setValue({ ...lastSeenValue, updatedStart: apiStartDate.toISOString() }); - } - }; - - const manageEndDate = (apiStartDate, apiEndDate)=> { - if (isNaN(apiEndDate) && isNaN(apiStartDate)) { - setValue({ ...lastSeenValue, updatedStart: null, updatedEnd: null }); - } else if (apiStartDate > apiEndDate || isNaN(apiEndDate)) { - setValue({ ...lastSeenValue, updatedStart: apiStartDate.toISOString(), updatedEnd: null }); - } else { - setValue({ ...lastSeenValue, updatedEnd: apiEndDate.toISOString() }); - } - }; - - const toValidator = (date) => { - const newDate = new Date(date); - const minDate = new Date(startDate); - - if (minDate >= newDate) { - return 'Start date must be earlier than End date.'; - } else if (newDate > todaysDate) { - return `Date must be ${todaysDate.toISOString().split('T')[0]} or earlier`; + } else if ( + newApiStartDate > newApiEndDate || + isNaN(newApiStartDate) || + newApiStartDate > todaysDate + ) { + setValue({ + ...lastSeenValue, + updatedStart: null, + updatedEnd: newApiEndDate + }); } else { - return ''; + setValue({ + ...lastSeenValue, + updatedStart: `${newApiStartDate.format('YYYY-MM-DD')}T00:00:00.000Z` + }); } }; - const fromValidator = (date) => { - const minDate = new Date(1950, 1, 1); - const maxDate = new Date(endDate); + const manageEndDate = (apiStartDate, apiEndDate) => { + const newApiStartDate = apiStartDate.startOf('day'); + const newApiEndDate = apiEndDate.endOf('day'); - if (date < minDate) { - return 'Date is before the allowable range.'; - } else if (date > maxDate) { - return `End date must be later than Start date.`; - } else if (date > todaysDate) { - return ' Start date must be earlier than End date.'; + if (isNaN(newApiEndDate) && isNaN(newApiStartDate)) { + setValue({ ...lastSeenValue, updatedStart: null, updatedEnd: null }); + } else if (newApiStartDate > newApiEndDate || isNaN(newApiEndDate)) { + setValue({ + ...lastSeenValue, + updatedStart: newApiStartDate, + updatedEnd: null + }); } else { - return ''; + setValue({ ...lastSeenValue, updatedEnd: `${newApiEndDate.format('YYYY-MM-DD')}T23:59:00.000Z` }); } }; + //This date comes from patternfly component. This manages the 1st date picker const onFromChange = (date) => { - const newToDate = new Date(endDate); + const newToDate = moment(endDate).endOf('day'); if (date > newToDate) { setStartDate(); return 'End date must be later than Start date.'; } setStartDate(date); - const apiStartDate = new Date(date); - apiStartDate.setUTCHours(0); + const apiStartDate = moment(date).startOf('day'); + manageStartDate(apiStartDate, newToDate); }; + //This date comes from patternfly component. This manages the 2nd date picker const onToChange = (date) => { - if (startDate > new Date(date)) { + if (startDate > moment(date)) { return 'Start date must be earlier than End date.'; - } else if (new Date(date) > todaysDate) { + } else if (moment(date) > todaysDate) { return 'End date must be later than Start date.'; } else { setEndDate(date); - const apiEndDate = new Date(date); - apiEndDate.setUTCHours(23, 59); - manageEndDate(new Date(startDate), apiEndDate); + const apiEndDate = moment(date).endOf('day'); + manageEndDate(moment(startDate), apiEndDate); } }; @@ -125,12 +119,10 @@ export const useLastSeenFilter = ( chip, lastSeenValue, setValue, - toValidator, onFromChange, onToChange, endDate, startDate, - fromValidator, setStartDate, setEndDate ];