diff --git a/ee/app/assets/javascripts/roadmap/constants.js b/ee/app/assets/javascripts/roadmap/constants.js index 9f4021f9d80ab5c492ae1459ea3126ace8e1a195..f50c5e9b4eaca9e7d1a95ce65d9463712a15c58a 100644 --- a/ee/app/assets/javascripts/roadmap/constants.js +++ b/ee/app/assets/javascripts/roadmap/constants.js @@ -42,3 +42,7 @@ export const PRESET_DEFAULTS = { TIMEFRAME_LENGTH: 7, }, }; + +export const PAST_DATE = new Date(new Date().getFullYear() - 100, 0, 1); + +export const FUTURE_DATE = new Date(new Date().getFullYear() + 100, 0, 1); diff --git a/ee/app/assets/javascripts/roadmap/utils/roadmap_utils.js b/ee/app/assets/javascripts/roadmap/utils/roadmap_utils.js index ffdaff4381d8ed1aaa064cff1c3824960e3786d0..e81597ca357358a4821935c4689e0399356ae314 100644 --- a/ee/app/assets/javascripts/roadmap/utils/roadmap_utils.js +++ b/ee/app/assets/javascripts/roadmap/utils/roadmap_utils.js @@ -6,6 +6,8 @@ import { EXTEND_AS, TIMELINE_CELL_MIN_WIDTH, DAYS_IN_WEEK, + PAST_DATE, + FUTURE_DATE, } from '../constants'; const monthsForQuarters = { @@ -408,45 +410,44 @@ export const getEpicsPathForPreset = ({ return epicsPath; }; +/** + * This function takes two epics and return sortable dates depending on the ' + * type of sorting order -- startDate or endDate. + */ +export function assignDates(a, b, { dateUndefined, outOfRange, originalDate, date, proxyDate }) { + let aDate; + let bDate; + + if (a[dateUndefined]) { + // Set proxy date to be either far in the past or + // far in the future to ensure sort order is + // correct. + aDate = proxyDate; + } else { + aDate = a[outOfRange] ? a[originalDate] : a[date]; + } + + if (b[dateUndefined]) { + bDate = proxyDate; + } else { + bDate = b[outOfRange] ? b[originalDate] : b[date]; + } + + return [aDate, bDate]; +} + export const sortEpics = (epics, sortedBy) => { const sortByStartDate = sortedBy.indexOf('start_date') > -1; const sortOrderAsc = sortedBy.indexOf('asc') > -1; - const pastDate = new Date(new Date().getFullYear() - 100, 0, 1); - const futureDate = new Date(new Date().getFullYear() + 100, 0, 1); epics.sort((a, b) => { - let aDate; - let bDate; - - if (sortByStartDate) { - if (a.startDateUndefined) { - // Set proxy date to be far in the past - // to ensure sort order is correct. - aDate = pastDate; - } else { - aDate = a.startDateOutOfRange ? a.originalStartDate : a.startDate; - } - - if (b.startDateUndefined) { - bDate = pastDate; - } else { - bDate = b.startDateOutOfRange ? b.originalStartDate : b.startDate; - } - } else { - if (a.endDateUndefined) { - // Set proxy date to be far into the future - // to ensure sort order is correct. - aDate = futureDate; - } else { - aDate = a.endDateOutOfRange ? a.originalEndDate : a.endDate; - } - - if (b.endDateUndefined) { - bDate = futureDate; - } else { - bDate = b.endDateOutOfRange ? b.originalEndDate : b.endDate; - } - } + const [aDate, bDate] = assignDates(a, b, { + dateUndefined: sortByStartDate ? 'startDateUndefined' : 'endDateUndefined', + outOfRange: sortByStartDate ? 'startDateOutOfRange' : 'endDateOutOfRange', + originalDate: sortByStartDate ? 'originalStartDate' : 'originalEndDate', + date: sortByStartDate ? 'startDate' : 'endDate', + proxyDate: sortByStartDate ? PAST_DATE : FUTURE_DATE, + }); // Sort in ascending or descending order if (aDate.getTime() < bDate.getTime()) { diff --git a/ee/spec/javascripts/roadmap/utils/roadmap_utils_spec.js b/ee/spec/javascripts/roadmap/utils/roadmap_utils_spec.js index 6806cd268ae364d4d3ca038ff737cce110f32e7e..555e6a1bce091c20d182a4d3fc02fc360b514960 100644 --- a/ee/spec/javascripts/roadmap/utils/roadmap_utils_spec.js +++ b/ee/spec/javascripts/roadmap/utils/roadmap_utils_spec.js @@ -8,6 +8,7 @@ import { extendTimeframeForAvailableWidth, getEpicsPathForPreset, sortEpics, + assignDates, } from 'ee/roadmap/utils/roadmap_utils'; import { PRESET_TYPES } from 'ee/roadmap/constants'; @@ -434,3 +435,114 @@ describe('sortEpics', () => { }); }); }); + +describe('assignDates', () => { + const startDateProps = { + dateUndefined: 'startDateUndefined', + outOfRange: 'startDateOutOfRange', + originalDate: 'originalStartDate', + date: 'startDate', + proxyDate: new Date('1900'), + }; + const endDateProps = { + dateUndefined: 'endDateUndefined', + outOfRange: 'endDateOutOfRange', + originalDate: 'originalEndDate', + date: 'endDate', + proxyDate: new Date('2200'), + }; + + it('returns proxyDate if startDate is undefined', () => { + const epic1 = { startDateUndefined: true }; + const epic2 = { startDateUndefined: false }; + + let [aDate, bDate] = assignDates(epic1, epic2, startDateProps); + + expect(aDate).toEqual(startDateProps.proxyDate); + expect(bDate).not.toEqual(startDateProps.proxyDate); + + epic1.startDateUndefined = false; + epic2.startDateUndefined = true; + [aDate, bDate] = assignDates(epic1, epic2, startDateProps); + + expect(aDate).not.toEqual(startDateProps.proxyDate); + expect(bDate).toEqual(startDateProps.proxyDate); + }); + + it('returns proxyDate if endDate is undefined', () => { + const epic1 = { endDateUndefined: true }; + const epic2 = { endDateUndefined: false }; + + let [aDate, bDate] = assignDates(epic1, epic2, endDateProps); + + expect(aDate).toEqual(endDateProps.proxyDate); + expect(bDate).not.toEqual(endDateProps.proxyDate); + + epic1.endDateUndefined = false; + epic2.endDateUndefined = true; + [aDate, bDate] = assignDates(epic1, epic2, endDateProps); + + expect(aDate).not.toEqual(endDateProps.proxyDate); + expect(bDate).toEqual(endDateProps.proxyDate); + }); + + it('assigns originalStartDate if date is out of range', () => { + const epic1 = { + startDateUndefined: false, + originalStartDate: new Date('2000'), + startDate: new Date('2010'), + startDateOutOfRange: true, + }; + const epic2 = { ...epic1, originalStartDate: new Date('2005') }; + + const [aDate, bDate] = assignDates(epic1, epic2, startDateProps); + + expect(aDate).toEqual(epic1.originalStartDate); + expect(bDate).toEqual(epic2.originalStartDate); + }); + + it('assigns originalEndDate if date is out of range', () => { + const epic1 = { + endDateUndefined: false, + originalEndDate: new Date('2000'), + endDate: new Date('2010'), + endDateOutOfRange: true, + }; + const epic2 = { ...epic1, originalEndDate: new Date('2005') }; + + const [aDate, bDate] = assignDates(epic1, epic2, endDateProps); + + expect(aDate).toEqual(epic1.originalEndDate); + expect(bDate).toEqual(epic2.originalEndDate); + }); + + it('assigns startDate if date is in the range', () => { + const epic1 = { + startDateUndefined: false, + originalStartDate: new Date('2000'), + startDate: new Date('2010'), + startDateOutOfRange: false, + }; + const epic2 = { ...epic1, startDate: new Date('2005') }; + + const [aDate, bDate] = assignDates(epic1, epic2, startDateProps); + + expect(aDate).toEqual(epic1.startDate); + expect(bDate).toEqual(epic2.startDate); + }); + + it('assigns endDate if date is in the range', () => { + const epic1 = { + endDateUndefined: false, + originalEndDate: new Date('2000'), + endDate: new Date('2010'), + endDateOutOfRange: false, + }; + const epic2 = { ...epic1, endDate: new Date('2005') }; + + const [aDate, bDate] = assignDates(epic1, epic2, endDateProps); + + expect(aDate).toEqual(epic1.endDate); + expect(bDate).toEqual(epic2.endDate); + }); +});