Commit 29380f1b authored by Illya Klymov's avatar Illya Klymov

Merge branch 'move-roadmap-getter-methods-into-standalone-helpers' into 'master'

Move getter methods into roadmap_item_utils.js

See merge request gitlab-org/gitlab!50158
parents 545e53df 4bb58c14
......@@ -78,15 +78,16 @@ export const fetchChildrenEpics = (state, { parentItem }) => {
};
export const receiveEpicsSuccess = (
{ commit, dispatch, state, getters },
{ commit, dispatch, state },
{ rawEpics, newEpic, timeframeExtended },
) => {
const epicIds = [];
const epics = rawEpics.reduce((filteredEpics, epic) => {
const { presetType, timeframe } = state;
const formattedEpic = roadmapItemUtils.formatRoadmapItemDetails(
epic,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
);
formattedEpic.isChildEpic = false;
......@@ -126,14 +127,15 @@ export const requestChildrenEpics = ({ commit }, { parentItemId }) => {
commit(types.REQUEST_CHILDREN_EPICS, { parentItemId });
};
export const receiveChildrenSuccess = (
{ commit, dispatch, getters },
{ commit, dispatch, state },
{ parentItemId, rawChildren },
) => {
const children = rawChildren.reduce((filteredChildren, epic) => {
const { presetType, timeframe } = state;
const formattedChild = roadmapItemUtils.formatRoadmapItemDetails(
epic,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
);
formattedChild.isChildEpic = true;
......@@ -180,13 +182,15 @@ export const fetchEpicsForTimeframe = ({ state, commit, dispatch }, { timeframe
*
* @param extendAs An EXTEND_AS enum value
*/
export const extendTimeframe = ({ commit, state, getters }, { extendAs }) => {
export const extendTimeframe = ({ commit, state }, { extendAs }) => {
const isExtendTypePrepend = extendAs === EXTEND_AS.PREPEND;
const { presetType, timeframe } = state;
const timeframeToExtend = extendTimeframeForPreset({
extendAs,
presetType: state.presetType,
initialDate: isExtendTypePrepend ? getters.timeframeStartDate : getters.timeframeEndDate,
presetType,
initialDate: isExtendTypePrepend
? roadmapItemUtils.timeframeStartDate(presetType, timeframe)
: roadmapItemUtils.timeframeEndDate(presetType, timeframe),
});
if (isExtendTypePrepend) {
......@@ -233,22 +237,24 @@ export const toggleEpic = ({ state, dispatch }, { parentItem }) => {
* For epics that have no start or end date, this function updates their start and end dates
* so that the epic bars get longer to appear infinitely scrolling.
*/
export const refreshEpicDates = ({ commit, state, getters }) => {
export const refreshEpicDates = ({ commit, state }) => {
const { presetType, timeframe } = state;
const epics = state.epics.map((epic) => {
// Update child epic dates too
if (epic.children?.edges?.length > 0) {
epic.children.edges.map((childEpic) =>
roadmapItemUtils.processRoadmapItemDates(
childEpic,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
),
);
}
return roadmapItemUtils.processRoadmapItemDates(
epic,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
);
});
......@@ -298,15 +304,16 @@ export const fetchMilestones = ({ state, dispatch }) => {
};
export const receiveMilestonesSuccess = (
{ commit, state, getters },
{ commit, state },
{ rawMilestones, newMilestone }, // timeframeExtended
) => {
const { presetType, timeframe } = state;
const milestoneIds = [];
const milestones = rawMilestones.reduce((filteredMilestones, milestone) => {
const formattedMilestone = roadmapItemUtils.formatRoadmapItemDetails(
milestone,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
);
// Exclude any Milestone that has invalid dates
// or is already present in Roadmap timeline
......@@ -332,12 +339,14 @@ export const receiveMilestonesFailure = ({ commit }) => {
flash(s__('GroupRoadmap|Something went wrong while fetching milestones'));
};
export const refreshMilestoneDates = ({ commit, state, getters }) => {
export const refreshMilestoneDates = ({ commit, state }) => {
const { presetType, timeframe } = state;
const milestones = state.milestones.map((milestone) =>
roadmapItemUtils.processRoadmapItemDates(
milestone,
getters.timeframeStartDate,
getters.timeframeEndDate,
roadmapItemUtils.timeframeStartDate(presetType, timeframe),
roadmapItemUtils.timeframeEndDate(presetType, timeframe),
),
);
......
......@@ -2,7 +2,6 @@ import Vue from 'vue';
import Vuex from 'vuex';
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
......@@ -11,7 +10,6 @@ Vue.use(Vuex);
export default () =>
new Vuex.Store({
actions,
getters,
mutations,
state: state(),
});
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { newDate, parsePikadayDate } from '~/lib/utils/datetime_utility';
import { PRESET_TYPES, DAYS_IN_WEEK } from '../constants';
/**
* Updates provided `epic` or `milestone` object with necessary props
* representing underlying dates.
......@@ -109,3 +111,40 @@ export const extractGroupMilestones = (edges) =>
edges.map(({ node, milestoneNode = node }) => ({
...milestoneNode,
}));
/**
* Returns number representing index of last item of timeframe array
*
* @param {Array} timeframe
*/
export const lastTimeframeIndex = (timeframe) => timeframe.length - 1;
/**
* Returns first item of the timeframe array
*
* @param {string} presetType
* @param {Array} timeframe
*/
export const timeframeStartDate = (presetType, timeframe) => {
if (presetType === PRESET_TYPES.QUARTERS) {
return timeframe[0].range[0];
}
return timeframe[0];
};
/**
* Returns last item of the timeframe array depending on preset type set.
*
* @param {string} presetType
* @param {Array} timeframe
*/
export const timeframeEndDate = (presetType, timeframe) => {
if (presetType === PRESET_TYPES.QUARTERS) {
return timeframe[lastTimeframeIndex(timeframe)].range[2];
} else if (presetType === PRESET_TYPES.MONTHS) {
return timeframe[lastTimeframeIndex(timeframe)];
}
const endDate = newDate(timeframe[lastTimeframeIndex(timeframe)]);
endDate.setDate(endDate.getDate() + DAYS_IN_WEEK);
return endDate;
};
import {
getTimeframeForWeeksView,
getTimeframeForMonthsView,
getTimeframeForQuartersView,
} from 'ee/roadmap/utils/roadmap_utils';
import { dateFromString } from 'helpers/datetime_helpers';
export const mockScrollBarSize = 15;
export const mockGroupId = 2;
......@@ -94,6 +102,52 @@ export const mockTimeframeWeeksAppend = [
new Date(2018, 2, 4),
];
const OCT_11_2020 = dateFromString('Oct 11 2020');
export const mockWeekly = {
currentDate: OCT_11_2020,
/*
Each item in timeframe is a Date object.
timeframe = [ Sep 27 2020, Oct 4 2020, Oct 11 2020, <- current week or currentIndex == 2
Oct 18 2020, Oct 25 2020, Nov 1 2020,
Nov 8 2020 ]
*/
timeframe: getTimeframeForWeeksView(OCT_11_2020),
};
const DEC_1_2020 = dateFromString('Dec 1 2020');
export const mockMonthly = {
currentDate: DEC_1_2020,
/*
Each item in timeframe is a Date object.
timeframe = [ Oct 1 2020, Nov 1 2020, Dec 1 2020, <- current month == index 2
Jan 1 2021, Feb 1 2021, Mar 1 2021,
Apr 1 2021, May 31 2021 ]
*/
timeframe: getTimeframeForMonthsView(DEC_1_2020),
};
const DEC_25_2020 = dateFromString('Dec 25 2020');
export const mockQuarterly = {
currentDate: DEC_25_2020,
/*
The format of quarterly timeframes differs from that of the monthly and weekly ones.
For quarterly, each item in timeframe has the following shape:
{ quarterSequence: number, range: array<Dates>, year: number }
Each item in range is a Date object.
E.g., { 2020 Q2 } = { quarterSequence: 2, range: [ Apr 1 2020, May 1 2020, Jun 30 2020], year 2020 }
timeframe = [ { 2020 Q2 }, { 2020 Q3 }, { 2020 Q4 }, <- current quarter == index 2
{ 2021 Q1 }, { 2021 Q2 }, { 2021 Q3 },
{ 2021 Q4 } ]
*/
timeframe: getTimeframeForQuartersView(DEC_25_2020),
};
export const mockEpic = {
id: 1,
iid: 1,
......
import { PRESET_TYPES } from 'ee/roadmap/constants';
import * as getters from 'ee/roadmap/store/getters';
describe('Roadmap Store Getters', () => {
describe('lastTimeframeIndex', () => {
it('Should return last index of the timeframe array from state', () => {
const roadmapState = {
timeframe: [1, 2, 3, 4],
};
expect(getters.lastTimeframeIndex(roadmapState)).toBe(3);
});
});
describe('timeframeStartDate', () => {
it('Should return first item of the timeframe range array from the state when preset type is Quarters', () => {
const roadmapState = {
timeframe: [{ range: ['foo', 'bar', 'baz'] }, { range: ['abc', 'cde', 'efg'] }],
presetType: PRESET_TYPES.QUARTERS,
};
expect(getters.timeframeStartDate(roadmapState)).toBe('foo');
});
it('Should return first item of the timeframe array from the state when preset type is Months or Weeks', () => {
const roadmapState = {
timeframe: ['foo', 'bar', 'baz'],
presetType: PRESET_TYPES.MONTHS,
};
expect(getters.timeframeStartDate(roadmapState)).toBe('foo');
roadmapState.presetType = PRESET_TYPES.WEEKS;
expect(getters.timeframeStartDate(roadmapState)).toBe('foo');
});
});
describe('timeframeEndDate', () => {
it('Should return last item of the timeframe range array from the state when preset type is Quarters', () => {
const roadmapState = {
timeframe: [{ range: ['foo', 'bar', 'baz'] }, { range: ['abc', 'cde', 'efg'] }],
presetType: PRESET_TYPES.QUARTERS,
};
expect(
getters.timeframeEndDate(roadmapState, {
lastTimeframeIndex: roadmapState.timeframe.length - 1,
}),
).toBe('efg');
});
it('Should return last item of the timeframe array from the state when preset type is Months', () => {
const roadmapState = {
timeframe: ['foo', 'bar', 'baz'],
presetType: PRESET_TYPES.MONTHS,
};
expect(
getters.timeframeEndDate(roadmapState, {
lastTimeframeIndex: roadmapState.timeframe.length - 1,
}),
).toBe('baz');
});
it('Should return last item of the timeframe array from the state when preset type is Weeks', () => {
const roadmapState = {
timeframe: [new Date(2018, 11, 23), new Date(2018, 11, 30), new Date(2019, 0, 6)],
presetType: PRESET_TYPES.WEEKS,
};
expect(
getters
.timeframeEndDate(roadmapState, {
lastTimeframeIndex: roadmapState.timeframe.length - 1,
})
.getTime(),
).toBe(new Date(2019, 0, 13).getTime());
});
});
});
import * as roadmapItemUtils from 'ee/roadmap/utils/roadmap_item_utils';
import { PRESET_TYPES } from 'ee/roadmap/constants';
import { dateFromString } from 'helpers/datetime_helpers';
import { parsePikadayDate } from '~/lib/utils/datetime_utility';
import { rawEpics, mockGroupMilestonesQueryResponse } from '../mock_data';
import {
rawEpics,
mockGroupMilestonesQueryResponse,
mockQuarterly,
mockMonthly,
mockWeekly,
} from '../mock_data';
describe('processRoadmapItemDates', () => {
const timeframeStartDate = new Date(2017, 0, 1);
const timeframeEndDate = new Date(2017, 11, 31);
it('Should set `startDateOutOfRange`/`endDateOutOfRange` as true and `startDate` and `endDate` to dates of timeframe range when epic dates are outside timeframe range', () => {
it('should set `startDateOutOfRange`/`endDateOutOfRange` as true and `startDate` and `endDate` to dates of timeframe range when epic dates are outside timeframe range', () => {
const mockEpic = {
originalStartDate: new Date(2016, 11, 15),
originalEndDate: new Date(2018, 0, 1),
......@@ -26,7 +33,7 @@ describe('processRoadmapItemDates', () => {
expect(updatedEpic.endDate.getTime()).toBe(timeframeEndDate.getTime());
});
it('Should set `startDateOutOfRange`/`endDateOutOfRange` as false and `startDate` and `endDate` to actual epic dates when they are within timeframe range', () => {
it('should set `startDateOutOfRange`/`endDateOutOfRange` as false and `startDate` and `endDate` to actual epic dates when they are within timeframe range', () => {
const mockEpic = {
originalStartDate: new Date(2017, 2, 10),
originalEndDate: new Date(2017, 6, 22),
......@@ -44,7 +51,7 @@ describe('processRoadmapItemDates', () => {
expect(updatedEpic.endDate.getTime()).toBe(mockEpic.originalEndDate.getTime());
});
it('Should set `startDate` and `endDate` to timeframe start and end dates when epic dates are undefined', () => {
it('should set `startDate` and `endDate` to timeframe start and end dates when epic dates are undefined', () => {
const mockEpic = {
startDateUndefined: true,
endDateUndefined: true,
......@@ -79,7 +86,7 @@ describe('formatRoadmapItemDetails', () => {
expect(epic.groupName).toBe(rawEpic.group_name);
});
it('Should return formatted Epic object with `startDate`/`endDate` and `originalStartDate`/originalEndDate` initialized when dates are present', () => {
it('should return formatted Epic object with `startDate`/`endDate` and `originalStartDate`/originalEndDate` initialized when dates are present', () => {
const mockRawEpic = {
start_date: '2017-2-15',
end_date: '2017-7-22',
......@@ -100,7 +107,7 @@ describe('formatRoadmapItemDetails', () => {
expect(epic.originalEndDate.getTime()).toBe(endDate.getTime());
});
it('Should return formatted Epic object with `startDateUndefined`/startDateUndefined` set to true when dates are null/undefined', () => {
it('should return formatted Epic object with `startDateUndefined`/startDateUndefined` set to true when dates are null/undefined', () => {
const epic = roadmapItemUtils.formatRoadmapItemDetails(
{},
timeframeStartDate,
......@@ -127,3 +134,55 @@ describe('extractGroupMilestones', () => {
);
});
});
describe('lastTimeframeIndex', () => {
it('should return last index of the timeframe array', () => {
const timeframe = [1, 2, 3, 4];
expect(roadmapItemUtils.lastTimeframeIndex(timeframe)).toBe(3);
});
});
describe('timeframeStartDate', () => {
it.each`
presetType | startDate | timeframe
${PRESET_TYPES.QUARTERS} | ${mockQuarterly.timeframe[0].range[0]} | ${mockQuarterly.timeframe}
${PRESET_TYPES.MONTHS} | ${mockMonthly.timeframe[0]} | ${mockMonthly.timeframe}
${PRESET_TYPES.WEEKS} | ${mockWeekly.timeframe[0]} | ${mockWeekly.timeframe}
`(
`should return starting date for the timeframe range array when preset type is $presetType`,
({ presetType, startDate, timeframe }) => {
expect(roadmapItemUtils.timeframeStartDate(presetType, timeframe)).toEqual(startDate);
},
);
});
describe('timeframeEndDate', () => {
/*
Note: there are inconsistencies in how timeframes are generated.
A monthly timeframe generated with roadmap_util's getTimeframeForMonthsView function -
will always set its last item to the ending date for that month.
E.g., [ Oct 1, Nov 1, Dec 31 ]
The same is true of quarterly timeframes generated with getTimeframeForQuarterlyView
E.g., [ ..., { range: [ Oct 1, Nov 1, Dec 31 ] }]
In comparison, a weekly timeframe won't have its last item set to the ending date for the week.
E.g., [ Oct 25, Nov 1, Nov 8 ]
In this example,
roadmapItemUtils.timeframeEndDate([ Oct 25, Nov 1, Nov 8 ]) should return 'Nov 15'
*/
it.each`
presetType | endDate | timeframe
${PRESET_TYPES.QUARTERS} | ${dateFromString('Dec 31 2021')} | ${mockQuarterly.timeframe}
${PRESET_TYPES.MONTHS} | ${dateFromString('May 31 2021')} | ${mockMonthly.timeframe}
${PRESET_TYPES.WEEKS} | ${dateFromString('Nov 15 2020')} | ${mockWeekly.timeframe}
`(
`should return ending date for the timeframe range array when preset type is $presetType`,
({ presetType, endDate, timeframe }) => {
expect(roadmapItemUtils.timeframeEndDate(presetType, timeframe)).toEqual(endDate);
},
);
});
import dateFormat from 'dateformat';
/**
* Returns a date object corresponding to the given date string.
*/
export const dateFromString = (dateString) => new Date(dateFormat(dateString));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment