Commit 07e89047 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch '323917-remove-roadmap_daterange_filter-ff' into 'master'

Remove `roadmap_daterange_filter` feature flag and related legacy code from Roadmap app

See merge request gitlab-org/gitlab!72419
parents 4f6a4289 605d5dca
<script> <script>
import { GlLoadingIcon, GlAlert } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import Cookies from 'js-cookie';
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import { __, s__ } from '~/locale';
import { import { DATE_RANGES } from '../constants';
EPICS_LIMIT_DISMISSED_COOKIE_NAME,
EPICS_LIMIT_DISMISSED_COOKIE_TIMEOUT,
DATE_RANGES,
} from '../constants';
import EpicsListEmpty from './epics_list_empty.vue'; import EpicsListEmpty from './epics_list_empty.vue';
import RoadmapFilters from './roadmap_filters.vue'; import RoadmapFilters from './roadmap_filters.vue';
import RoadmapShell from './roadmap_shell.vue'; import RoadmapShell from './roadmap_shell.vue';
export default { export default {
i18n: {
warningTitle: s__('GroupRoadmap|Some of your epics might not be visible'),
warningBody: s__(
'GroupRoadmap|Roadmaps can display up to 1,000 epics. These appear in your selected sort order.',
),
warningButtonLabel: __('Learn more'),
},
components: { components: {
EpicsListEmpty, EpicsListEmpty,
GlAlert,
GlLoadingIcon, GlLoadingIcon,
RoadmapFilters, RoadmapFilters,
RoadmapShell, RoadmapShell,
...@@ -43,11 +29,6 @@ export default { ...@@ -43,11 +29,6 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
isWarningDismissed: Cookies.get(EPICS_LIMIT_DISMISSED_COOKIE_NAME) === 'true',
};
},
computed: { computed: {
...mapState([ ...mapState([
'currentGroupId', 'currentGroupId',
...@@ -85,12 +66,6 @@ export default { ...@@ -85,12 +66,6 @@ export default {
}, },
methods: { methods: {
...mapActions(['fetchEpics', 'fetchMilestones']), ...mapActions(['fetchEpics', 'fetchMilestones']),
dismissTooManyEpicsWarning() {
Cookies.set(EPICS_LIMIT_DISMISSED_COOKIE_NAME, 'true', {
expires: EPICS_LIMIT_DISMISSED_COOKIE_TIMEOUT,
});
this.isWarningDismissed = true;
},
}, },
}; };
</script> </script>
...@@ -101,16 +76,6 @@ export default { ...@@ -101,16 +76,6 @@ export default {
v-if="showFilteredSearchbar && !epicIid" v-if="showFilteredSearchbar && !epicIid"
:timeframe-range-type="timeframeRangeType" :timeframe-range-type="timeframeRangeType"
/> />
<gl-alert
v-if="isWarningVisible"
variant="warning"
:title="$options.i18n.warningTitle"
:primary-button-text="$options.i18n.warningButtonLabel"
primary-button-link="https://docs.gitlab.com/ee/user/group/roadmap/"
data-testid="epics_limit_callout"
@dismiss="dismissTooManyEpicsWarning"
>{{ $options.i18n.warningBody }}</gl-alert
>
<div :class="{ 'overflow-reset': epicsFetchResultEmpty }" class="roadmap-container"> <div :class="{ 'overflow-reset': epicsFetchResultEmpty }" class="roadmap-container">
<gl-loading-icon v-if="epicsFetchInProgress" class="gl-mt-5" size="md" /> <gl-loading-icon v-if="epicsFetchInProgress" class="gl-mt-5" size="md" />
<epics-list-empty <epics-list-empty
......
...@@ -11,7 +11,6 @@ import { mapState, mapActions } from 'vuex'; ...@@ -11,7 +11,6 @@ import { mapState, mapActions } from 'vuex';
import { visitUrl, mergeUrlParams, updateHistory, setUrlParams } from '~/lib/utils/url_utility'; import { visitUrl, mergeUrlParams, updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { EPICS_STATES, PRESET_TYPES, DATE_RANGES } from '../constants'; import { EPICS_STATES, PRESET_TYPES, DATE_RANGES } from '../constants';
import EpicsFilteredSearchMixin from '../mixins/filtered_search_mixin'; import EpicsFilteredSearchMixin from '../mixins/filtered_search_mixin';
...@@ -56,7 +55,7 @@ export default { ...@@ -56,7 +55,7 @@ export default {
GlDropdownDivider, GlDropdownDivider,
FilteredSearchBar, FilteredSearchBar,
}, },
mixins: [EpicsFilteredSearchMixin, glFeatureFlagsMixin()], mixins: [EpicsFilteredSearchMixin],
props: { props: {
timeframeRangeType: { timeframeRangeType: {
type: String, type: String,
...@@ -95,10 +94,6 @@ export default { ...@@ -95,10 +94,6 @@ export default {
const months = { text: __('Months'), value: PRESET_TYPES.MONTHS }; const months = { text: __('Months'), value: PRESET_TYPES.MONTHS };
const weeks = { text: __('Weeks'), value: PRESET_TYPES.WEEKS }; const weeks = { text: __('Weeks'), value: PRESET_TYPES.WEEKS };
if (!this.glFeatures.roadmapDaterangeFilter) {
return [quarters, months, weeks];
}
if (this.selectedDaterange === DATE_RANGES.CURRENT_YEAR) { if (this.selectedDaterange === DATE_RANGES.CURRENT_YEAR) {
return [months, weeks]; return [months, weeks];
} else if (this.selectedDaterange === DATE_RANGES.THREE_YEARS) { } else if (this.selectedDaterange === DATE_RANGES.THREE_YEARS) {
...@@ -146,9 +141,7 @@ export default { ...@@ -146,9 +141,7 @@ export default {
handleRoadmapLayoutChange(presetType) { handleRoadmapLayoutChange(presetType) {
visitUrl( visitUrl(
mergeUrlParams( mergeUrlParams(
this.glFeatures.roadmapDaterangeFilter { timeframe_range_type: this.selectedDaterange, layout: presetType },
? { timeframe_range_type: this.selectedDaterange, layout: presetType }
: { layout: presetType },
window.location.href, window.location.href,
), ),
); );
...@@ -175,7 +168,6 @@ export default { ...@@ -175,7 +168,6 @@ export default {
class="epics-details-filters filtered-search-block gl-display-flex gl-flex-direction-column gl-xl-flex-direction-row gl-pb-3 row-content-block second-block" class="epics-details-filters filtered-search-block gl-display-flex gl-flex-direction-column gl-xl-flex-direction-row gl-pb-3 row-content-block second-block"
> >
<gl-dropdown <gl-dropdown
v-if="glFeatures.roadmapDaterangeFilter"
icon="calendar" icon="calendar"
class="gl-mr-0 gl-lg-mr-3 mb-sm-2 roadmap-daterange-dropdown" class="gl-mr-0 gl-lg-mr-3 mb-sm-2 roadmap-daterange-dropdown"
toggle-class="gl-rounded-base!" toggle-class="gl-rounded-base!"
......
...@@ -41,11 +41,6 @@ export const EPICS_STATES = { ...@@ -41,11 +41,6 @@ export const EPICS_STATES = {
CLOSED: 'closed', CLOSED: 'closed',
}; };
export const EXTEND_AS = {
PREPEND: 'prepend',
APPEND: 'append',
};
export const emptyStateDefault = s__( export const emptyStateDefault = s__(
'GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from %{startDate} to %{endDate}.', 'GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from %{startDate} to %{endDate}.',
); );
...@@ -58,18 +53,6 @@ export const emptyStateWithEpicIidFiltered = s__( ...@@ -58,18 +53,6 @@ export const emptyStateWithEpicIidFiltered = s__(
'GroupRoadmap|To make your epics appear in the roadmap, add start or due dates to them.', 'GroupRoadmap|To make your epics appear in the roadmap, add start or due dates to them.',
); );
export const PRESET_DEFAULTS = {
QUARTERS: {
TIMEFRAME_LENGTH: 21,
},
MONTHS: {
TIMEFRAME_LENGTH: 8,
},
WEEKS: {
TIMEFRAME_LENGTH: 7,
},
};
export const EPIC_LEVEL_MARGIN = { export const EPIC_LEVEL_MARGIN = {
1: 'ml-4', 1: 'ml-4',
2: 'ml-6', 2: 'ml-6',
...@@ -77,8 +60,4 @@ export const EPIC_LEVEL_MARGIN = { ...@@ -77,8 +60,4 @@ export const EPIC_LEVEL_MARGIN = {
4: 'ml-10', 4: 'ml-10',
}; };
export const EPICS_LIMIT_DISMISSED_COOKIE_NAME = 'epics_limit_warning_dismissed';
export const EPICS_LIMIT_DISMISSED_COOKIE_TIMEOUT = 365;
export const ROADMAP_PAGE_SIZE = 50; export const ROADMAP_PAGE_SIZE = 50;
...@@ -11,11 +11,10 @@ import EpicItem from './components/epic_item.vue'; ...@@ -11,11 +11,10 @@ import EpicItem from './components/epic_item.vue';
import EpicItemContainer from './components/epic_item_container.vue'; import EpicItemContainer from './components/epic_item_container.vue';
import roadmapApp from './components/roadmap_app.vue'; import roadmapApp from './components/roadmap_app.vue';
import { PRESET_TYPES, EPIC_DETAILS_CELL_WIDTH, DATE_RANGES } from './constants'; import { DATE_RANGES } from './constants';
import createStore from './store'; import createStore from './store';
import { import {
getTimeframeForPreset,
getPresetTypeForTimeframeRangeType, getPresetTypeForTimeframeRangeType,
getTimeframeForRangeType, getTimeframeForRangeType,
} from './utils/roadmap_utils'; } from './utils/roadmap_utils';
...@@ -70,30 +69,16 @@ export default () => { ...@@ -70,30 +69,16 @@ export default () => {
}, },
data() { data() {
const { dataset } = this.$options.el; const { dataset } = this.$options.el;
let timeframe;
let timeframeRangeType;
let presetType;
if (gon.features.roadmapDaterangeFilter) { const timeframeRangeType =
timeframeRangeType =
Object.keys(DATE_RANGES).indexOf(dataset.timeframeRangeType) > -1 Object.keys(DATE_RANGES).indexOf(dataset.timeframeRangeType) > -1
? dataset.timeframeRangeType ? dataset.timeframeRangeType
: DATE_RANGES.CURRENT_QUARTER; : DATE_RANGES.CURRENT_QUARTER;
presetType = getPresetTypeForTimeframeRangeType(timeframeRangeType, dataset.presetType); const presetType = getPresetTypeForTimeframeRangeType(timeframeRangeType, dataset.presetType);
timeframe = getTimeframeForRangeType({ const timeframe = getTimeframeForRangeType({
timeframeRangeType, timeframeRangeType,
presetType, presetType,
}); });
} else {
presetType =
Object.keys(PRESET_TYPES).indexOf(dataset.presetType) > -1
? dataset.presetType
: PRESET_TYPES.MONTHS;
timeframe = getTimeframeForPreset(
presetType,
window.innerWidth - el.offsetLeft - EPIC_DETAILS_CELL_WIDTH,
);
}
const rawFilterParams = queryToObject(window.location.search, { const rawFilterParams = queryToObject(window.location.search, {
gatherArrays: true, gatherArrays: true,
......
...@@ -19,9 +19,6 @@ export const INIT_EPIC_CHILDREN_FLAGS = 'INIT_EPIC_CHILDREN_FLAGS'; ...@@ -19,9 +19,6 @@ export const INIT_EPIC_CHILDREN_FLAGS = 'INIT_EPIC_CHILDREN_FLAGS';
export const EXPAND_EPIC = 'EXPAND_EPIC'; export const EXPAND_EPIC = 'EXPAND_EPIC';
export const COLLAPSE_EPIC = 'COLLAPSE_EPIC'; export const COLLAPSE_EPIC = 'COLLAPSE_EPIC';
export const PREPEND_TIMEFRAME = 'PREPEND_TIMEFRAME';
export const APPEND_TIMEFRAME = 'APPEND_TIMEFRAME';
export const SET_MILESTONES = 'SET_MILESTONES'; export const SET_MILESTONES = 'SET_MILESTONES';
export const UPDATE_MILESTONE_IDS = 'UPDATE_MILESTONE_IDS'; export const UPDATE_MILESTONE_IDS = 'UPDATE_MILESTONE_IDS';
......
...@@ -85,15 +85,6 @@ export default { ...@@ -85,15 +85,6 @@ export default {
state.childrenFlags[parentItemId].itemExpanded = false; state.childrenFlags[parentItemId].itemExpanded = false;
}, },
[types.PREPEND_TIMEFRAME](state, extendedTimeframe) {
state.extendedTimeframe = extendedTimeframe;
state.timeframe.unshift(...extendedTimeframe);
},
[types.APPEND_TIMEFRAME](state, extendedTimeframe) {
state.extendedTimeframe = extendedTimeframe;
state.timeframe.push(...extendedTimeframe);
},
[types.SET_MILESTONES](state, milestones) { [types.SET_MILESTONES](state, milestones) {
state.milestones = milestones; state.milestones = milestones;
}, },
......
...@@ -15,7 +15,6 @@ export default () => ({ ...@@ -15,7 +15,6 @@ export default () => ({
currentGroupId: -1, currentGroupId: -1,
fullPath: '', fullPath: '',
timeframe: [], timeframe: [],
extendedTimeframe: [],
presetType: '', presetType: '',
timeframeRangeType: '', timeframeRangeType: '',
sortedBy: '', sortedBy: '',
......
import { getTimeframeWindowFrom, newDate, totalDaysInMonth } from '~/lib/utils/datetime_utility'; import { getTimeframeWindowFrom, newDate, totalDaysInMonth } from '~/lib/utils/datetime_utility';
import { import { DAYS_IN_WEEK, DATE_RANGES, PRESET_TYPES } from '../constants';
DAYS_IN_WEEK,
EXTEND_AS,
PRESET_DEFAULTS,
DATE_RANGES,
PRESET_TYPES,
TIMELINE_CELL_MIN_WIDTH,
} from '../constants';
const monthsForQuarters = { const monthsForQuarters = {
1: [0, 1, 2], 1: [0, 1, 2],
...@@ -16,355 +9,6 @@ const monthsForQuarters = { ...@@ -16,355 +9,6 @@ const monthsForQuarters = {
4: [9, 10, 11], 4: [9, 10, 11],
}; };
/**
* This method returns array of Objects representing Quarters based on provided initialDate
*
* For eg; If initialDate is 15th Jan 2018
* Then as per Roadmap specs, we need to show
* 2 quarters before current quarters
* current quarter AND
* 4 quarters after current quarter
* thus, total of 7 quarters (21 Months).
*
* So returned array from this method will be;
* [
* {
* quarterSequence: 4,
* year: 2017,
* range: [
* 1 Oct 2017,
* 1 Nov 2017,
* 31 Dec 2017,
* ],
* },
* {
* quarterSequence: 1,
* year: 2018,
* range: [
* 1 Jan 2018,
* 1 Feb 2018,
* 31 Mar 2018,
* ],
* },
* ....
* ....
* ....
* {
* quarterSequence: 1,
* year: 2019,
* range: [
* 1 Jan 2019,
* 1 Feb 2019,
* 31 Mar 2019,
* ],
* },
* ]
*
* @param {Date} initialDate
*/
export const getTimeframeForQuartersView = (initialDate = new Date(), timeframe = []) => {
const startDate = newDate(initialDate);
startDate.setHours(0, 0, 0, 0);
if (!timeframe.length) {
// Get current quarter for current month
const currentQuarter = Math.floor((startDate.getMonth() + 3) / 3);
// Get index of current month in current quarter
// It could be 0, 1, 2 (i.e. first, second or third)
const currentMonthInCurrentQuarter = monthsForQuarters[currentQuarter].indexOf(
startDate.getMonth(),
);
// To move start back to first month of 2 quarters prior by
// adding quarter size (3 + 3) to month order will give us
// exact number of months we need to go back in time
const startMonth = currentMonthInCurrentQuarter + 6;
// Move startDate to first month of previous quarter
startDate.setMonth(startDate.getMonth() - startMonth);
// Get timeframe for the length we determined for this preset
// start from the startDate
timeframe.push(...getTimeframeWindowFrom(startDate, PRESET_DEFAULTS.QUARTERS.TIMEFRAME_LENGTH));
}
const quartersTimeframe = [];
// Iterate over the timeframe and break it down
// in chunks of quarters
for (let i = 0; i < timeframe.length; i += 3) {
const range = timeframe.slice(i, i + 3);
const lastMonthOfQuarter = range[range.length - 1];
const quarterSequence = Math.floor((range[0].getMonth() + 3) / 3);
const year = range[0].getFullYear();
// Ensure that `range` spans across duration of
// entire quarter
lastMonthOfQuarter.setDate(totalDaysInMonth(lastMonthOfQuarter));
quartersTimeframe.push({
quarterSequence,
range,
year,
});
}
return quartersTimeframe;
};
export const extendTimeframeForQuartersView = (initialDate = new Date(), length) => {
const startDate = newDate(initialDate);
startDate.setDate(1);
startDate.setMonth(startDate.getMonth() + (length > 0 ? 1 : -1));
const timeframe = getTimeframeWindowFrom(startDate, length);
return getTimeframeForQuartersView(startDate, length > 0 ? timeframe : timeframe.reverse());
};
/**
* This method returns array of Dates respresenting Months based on provided initialDate
*
* For eg; If initialDate is 15th Jan 2018
* Then as per Roadmap specs, we need to show
* 2 months before current month,
* current month AND
* 5 months after current month
* thus, total of 8 months.
*
* So returned array from this method will be;
* [
* 1 Nov 2017, 1 Dec 2017, 1 Jan 2018, 1 Feb 2018,
* 1 Mar 2018, 1 Apr 2018, 1 May 2018, 30 Jun 2018
* ]
*
* @param {Date} initialDate
*/
export const getTimeframeForMonthsView = (initialDate = new Date()) => {
const startDate = newDate(initialDate);
// Move startDate to a month prior to current month
startDate.setMonth(startDate.getMonth() - 2);
return getTimeframeWindowFrom(startDate, PRESET_DEFAULTS.MONTHS.TIMEFRAME_LENGTH);
};
export const extendTimeframeForMonthsView = (initialDate = new Date(), length) => {
const startDate = newDate(initialDate);
// When length is positive (which means extension is of type APPEND)
// Set initial date as first day of the month.
if (length > 0) {
startDate.setDate(1);
}
const timeframe = getTimeframeWindowFrom(startDate, length - 1).slice(1);
return length > 0 ? timeframe : timeframe.reverse();
};
/**
* This method returns array of Dates respresenting Months based on provided initialDate
*
* For eg; If initialDate is 15th Jan 2018
* Then as per Roadmap specs, we need to show
* 2 weeks before current week,
* current week AND
* 4 weeks after current week
* thus, total of 7 weeks.
* Note that week starts on Sunday
*
* So returned array from this method will be;
* [
* 31 Dec 2017, 7 Jan 2018, 14 Jan 2018, 21 Jan 2018,
* 28 Jan 2018, 4 Mar 2018, 11 Mar 2018
* ]
*
* @param {Date} initialDate
*/
export const getTimeframeForWeeksView = (initialDate = new Date(), length) => {
const timeframe = [];
const startDate = newDate(initialDate);
startDate.setHours(0, 0, 0, 0);
// When length is not provided
// We need to provide standard
// timeframe as per feature specs (see block comment above)
if (!length) {
const dayOfWeek = startDate.getDay();
const daysToFirstDayOfPrevWeek = dayOfWeek + DAYS_IN_WEEK * 2;
// Move startDate to first day (Sunday) of 2 weeks prior
startDate.setDate(startDate.getDate() - daysToFirstDayOfPrevWeek);
}
const rangeLength = length || PRESET_DEFAULTS.WEEKS.TIMEFRAME_LENGTH;
// Iterate for the length of this preset
for (let i = 0; i < rangeLength; i += 1) {
// Push date to timeframe only when day is
// first day (Sunday) of the week
timeframe.push(newDate(startDate));
// Move date next Sunday
startDate.setDate(startDate.getDate() + DAYS_IN_WEEK);
}
return timeframe;
};
export const extendTimeframeForWeeksView = (initialDate = new Date(), length) => {
const startDate = newDate(initialDate);
if (length < 0) {
// When length is negative, we need to go
// back as many weeks in time as value of length
startDate.setDate(startDate.getDate() + length * DAYS_IN_WEEK);
}
return getTimeframeForWeeksView(startDate, Math.abs(length));
};
export const extendTimeframeForPreset = ({
presetType = PRESET_TYPES.MONTHS,
extendAs = EXTEND_AS.PREPEND,
extendByLength = 0,
initialDate,
}) => {
if (presetType === PRESET_TYPES.QUARTERS) {
const length = extendByLength || PRESET_DEFAULTS.QUARTERS.TIMEFRAME_LENGTH;
return extendTimeframeForQuartersView(
initialDate,
extendAs === EXTEND_AS.PREPEND ? -length : length,
);
} else if (presetType === PRESET_TYPES.MONTHS) {
const length = extendByLength || PRESET_DEFAULTS.MONTHS.TIMEFRAME_LENGTH;
return extendTimeframeForMonthsView(
initialDate,
extendAs === EXTEND_AS.PREPEND ? -length : length,
);
}
const length = extendByLength || PRESET_DEFAULTS.WEEKS.TIMEFRAME_LENGTH;
return extendTimeframeForWeeksView(
initialDate,
extendAs === EXTEND_AS.PREPEND ? -length : length,
);
};
export const extendTimeframeForAvailableWidth = ({
timeframe,
timeframeStart,
timeframeEnd,
availableTimeframeWidth,
presetType,
}) => {
let timeframeLength = timeframe.length;
// Estimate how many more timeframe columns are needed
// to fill in extra screen space so that timeline becomes
// horizontally scrollable.
while (availableTimeframeWidth / timeframeLength > TIMELINE_CELL_MIN_WIDTH) {
timeframeLength += 1;
}
// We double the increaseLengthBy to make sure there's enough room
// to perform horizontal scroll without triggering timeframe extension
// on initial page load.
let increaseLengthBy = timeframeLength - timeframe.length;
// Handle a case where window size is leading to
// increaseLength between 1 & 3 which is not big
// enough for extendTimeframeFor*****View methods
if (increaseLengthBy > 0 && increaseLengthBy <= 3) {
increaseLengthBy += 4; // Equalize by adding 2 columns on each end
}
// If there are timeframe items to be added
// to make timeline scrollable, do as follows.
if (increaseLengthBy > 0) {
// Split length in 2 parts and get
// count for both prepend and append.
const prependBy = Math.floor(increaseLengthBy / 2);
const appendBy = Math.ceil(increaseLengthBy / 2);
if (prependBy) {
// Prepend the timeline with
// the count as given by prependBy
timeframe.unshift(
...extendTimeframeForPreset({
extendAs: EXTEND_AS.PREPEND,
initialDate: timeframeStart,
// In case of presetType `quarters`, length would represent
// number of months for total quarters, hence we do `* 3`.
extendByLength: presetType === PRESET_TYPES.QUARTERS ? prependBy * 3 : prependBy,
presetType,
}),
);
}
if (appendBy) {
// Append the timeline with
// the count as given by appendBy
timeframe.push(
...extendTimeframeForPreset({
extendAs: EXTEND_AS.APPEND,
initialDate: timeframeEnd,
// In case of presetType `quarters`, length would represent
// number of months for total quarters, hence we do `* 3`.
//
// For other preset types, we add `2` to appendBy to compensate for
// last item of original timeframe (month or week)
extendByLength: presetType === PRESET_TYPES.QUARTERS ? appendBy * 3 : appendBy + 2,
presetType,
}),
);
}
}
};
export const getTimeframeForPreset = (
presetType = PRESET_TYPES.MONTHS,
availableTimeframeWidth = 0,
) => {
let timeframe;
let timeframeStart;
let timeframeEnd;
// Get timeframe based on presetType and
// extract timeframeStart and timeframeEnd
// date objects
if (presetType === PRESET_TYPES.QUARTERS) {
timeframe = getTimeframeForQuartersView();
[timeframeStart] = timeframe[0].range;
// eslint-disable-next-line prefer-destructuring
timeframeEnd = timeframe[timeframe.length - 1].range[2];
} else if (presetType === PRESET_TYPES.MONTHS) {
timeframe = getTimeframeForMonthsView();
[timeframeStart] = timeframe;
timeframeEnd = timeframe[timeframe.length - 1];
} else {
timeframe = getTimeframeForWeeksView();
timeframeStart = newDate(timeframe[0]);
timeframeEnd = newDate(timeframe[timeframe.length - 1]);
timeframeStart.setDate(timeframeStart.getDate());
timeframeEnd.setDate(timeframeEnd.getDate() + DAYS_IN_WEEK); // Move date ahead by a week
}
// Extend timeframe on initial load to ensure
// timeline is horizontally scrollable in all
// screen sizes.
extendTimeframeForAvailableWidth({
timeframe,
timeframeStart,
timeframeEnd,
availableTimeframeWidth,
presetType,
});
return timeframe;
};
export const getWeeksForDates = (startDate, endDate) => { export const getWeeksForDates = (startDate, endDate) => {
const timeframe = []; const timeframe = [];
const start = newDate(startDate); const start = newDate(startDate);
...@@ -388,9 +32,10 @@ export const getWeeksForDates = (startDate, endDate) => { ...@@ -388,9 +32,10 @@ export const getWeeksForDates = (startDate, endDate) => {
export const getTimeframeForRangeType = ({ export const getTimeframeForRangeType = ({
timeframeRangeType = DATE_RANGES.CURRENT_QUARTER, timeframeRangeType = DATE_RANGES.CURRENT_QUARTER,
presetType = PRESET_TYPES.WEEKS, presetType = PRESET_TYPES.WEEKS,
initialDate = new Date(),
}) => { }) => {
let timeframe = []; let timeframe = [];
const startDate = new Date(); const startDate = newDate(initialDate);
startDate.setHours(0, 0, 0, 0); startDate.setHours(0, 0, 0, 0);
// We need to prepare timeframe containing all the weeks of // We need to prepare timeframe containing all the weeks of
......
...@@ -7,9 +7,6 @@ module Groups ...@@ -7,9 +7,6 @@ module Groups
before_action :check_epics_available! before_action :check_epics_available!
before_action :persist_roadmap_layout, only: [:show] before_action :persist_roadmap_layout, only: [:show]
before_action do
push_frontend_feature_flag(:roadmap_daterange_filter, @group, type: :development, default_enabled: :yaml)
end
feature_category :roadmaps feature_category :roadmaps
......
---
name: roadmap_daterange_filter
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55639
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323917
milestone: '14.3'
type: development
group: group::product planning
default_enabled: true
...@@ -29,7 +29,6 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -29,7 +29,6 @@ RSpec.describe 'group epic roadmap', :js do
before do before do
stub_licensed_features(epics: true) stub_licensed_features(epics: true)
stub_feature_flags(unfiltered_epic_aggregates: false) stub_feature_flags(unfiltered_epic_aggregates: false)
stub_feature_flags(roadmap_daterange_filter: false)
sign_in(user) sign_in(user)
end end
...@@ -47,11 +46,47 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -47,11 +46,47 @@ RSpec.describe 'group epic roadmap', :js do
end end
describe 'roadmap page' do describe 'roadmap page' do
it 'renders roadmap preset buttons correctly' do context 'roadmap daterange filtering' do
page.within('.gl-segmented-control') do def select_date_range(range_type)
expect(page).to have_css('input[value="QUARTERS"]') page.within('.epics-roadmap-filters') do
expect(page).to have_css('input[value="MONTHS"]') page.find('[data-testid="daterange-dropdown"] button.dropdown-toggle').click
expect(page).to have_css('input[value="WEEKS"]') click_button(range_type)
end
end
it 'renders daterange filtering dropdown with "This quarter" selected by default no layout presets available', :aggregate_failures do
page.within('.epics-roadmap-filters') do
expect(page).to have_selector('[data-testid="daterange-dropdown"]')
expect(page).not_to have_selector('.gl-segmented-control')
expect(page.find('[data-testid="daterange-dropdown"] button.dropdown-toggle')).to have_content('This quarter')
end
end
it 'selecting "This year" as daterange shows `Months` and `Weeks` layout presets', :aggregate_failures do
select_date_range('This year')
page.within('.epics-roadmap-filters') do
expect(page).to have_selector('.gl-segmented-control')
expect(page).to have_selector('input[value="MONTHS"]')
expect(page).to have_selector('input[value="WEEKS"]')
end
end
it 'selecting "Within 3 years" as daterange shows `Quarters`, `Months` and `Weeks` layout presets', :aggregate_failures do
select_date_range('Within 3 years')
page.within('.epics-roadmap-filters') do
expect(page).to have_selector('.gl-segmented-control')
expect(page).to have_selector('input[value="QUARTERS"]')
expect(page).to have_selector('input[value="MONTHS"]')
expect(page).to have_selector('input[value="WEEKS"]')
end
end
end
it 'renders the epics state dropdown' do
page.within('.content-wrapper .content .epics-filters') do
expect(page).to have_css('.dropdown-epics-state')
end end
end end
...@@ -192,38 +227,4 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -192,38 +227,4 @@ RSpec.describe 'group epic roadmap', :js do
end end
end end
end end
context 'when over 1000 epics match roadmap filters' do
before do
create_list(:epic, 2, group: group, start_date: 10.days.ago, end_date: 1.day.ago)
visit group_roadmap_path(group)
execute_script("gon.roadmap_epics_limit = 1;")
end
describe 'roadmap page' do
it 'renders warning callout banner' do
page.within('.content-wrapper .content') do
expect(page).to have_selector('[data-testid="epics_limit_callout"]', count: 1)
expect(find('[data-testid="epics_limit_callout"]')).to have_content 'Some of your epics might not be visible Roadmaps can display up to 1,000 epics. These appear in your selected sort order.'
end
page.within('[data-testid="epics_limit_callout"]') do
expect(find_link('Learn more')[:href]).to eq("https://docs.gitlab.com/ee/user/group/roadmap/")
end
end
it 'is removed after dismissal and even after reload' do
page.within('[data-testid="epics_limit_callout"]') do
find('.gl-dismiss-btn').click
end
expect(page).not_to have_selector('[data-testid="epics_limit_callout"]')
refresh
expect(page).not_to have_selector('[data-testid="epics_limit_callout"]')
end
end
end
end end
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import CurrentDayIndicator from 'ee/roadmap/components/current_day_indicator.vue'; import CurrentDayIndicator from 'ee/roadmap/components/current_day_indicator.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
getTimeframeForQuartersView,
getTimeframeForMonthsView,
getTimeframeForWeeksView,
} from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate } from 'ee_jest/roadmap/mock_data';
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate); const mockTimeframeQuarters = getTimeframeForRangeType({
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); timeframeRangeType: DATE_RANGES.THREE_YEARS,
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate); presetType: PRESET_TYPES.QUARTERS,
initialDate: mockTimeframeInitialDate,
});
const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const mockTimeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = () => const createComponent = () =>
shallowMount(CurrentDayIndicator, { shallowMount(CurrentDayIndicator, {
......
...@@ -3,9 +3,9 @@ import { mount } from '@vue/test-utils'; ...@@ -3,9 +3,9 @@ import { mount } from '@vue/test-utils';
import EpicItem from 'ee/roadmap/components/epic_item.vue'; import EpicItem from 'ee/roadmap/components/epic_item.vue';
import EpicItemContainer from 'ee/roadmap/components/epic_item_container.vue'; import EpicItemContainer from 'ee/roadmap/components/epic_item_container.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockTimeframeInitialDate, mockTimeframeInitialDate,
...@@ -15,7 +15,11 @@ import { ...@@ -15,7 +15,11 @@ import {
let store; let store;
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
presetType = PRESET_TYPES.MONTHS, presetType = PRESET_TYPES.MONTHS,
......
...@@ -6,9 +6,9 @@ import CurrentDayIndicator from 'ee/roadmap/components/current_day_indicator.vue ...@@ -6,9 +6,9 @@ import CurrentDayIndicator from 'ee/roadmap/components/current_day_indicator.vue
import EpicItemComponent from 'ee/roadmap/components/epic_item.vue'; import EpicItemComponent from 'ee/roadmap/components/epic_item.vue';
import EpicItemContainer from 'ee/roadmap/components/epic_item_container.vue'; import EpicItemContainer from 'ee/roadmap/components/epic_item_container.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockTimeframeInitialDate, mockTimeframeInitialDate,
...@@ -27,7 +27,11 @@ jest.mock('lodash/delay', () => ...@@ -27,7 +27,11 @@ jest.mock('lodash/delay', () =>
let store; let store;
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
presetType = PRESET_TYPES.MONTHS, presetType = PRESET_TYPES.MONTHS,
......
import { GlPopover, GlProgressBar } from '@gitlab/ui'; import { GlPopover, GlProgressBar } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EpicItemTimeline from 'ee/roadmap/components/epic_item_timeline.vue'; import EpicItemTimeline from 'ee/roadmap/components/epic_item_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockFormattedEpic } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockFormattedEpic } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
epic = mockFormattedEpic, epic = mockFormattedEpic,
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EpicsListEmpty from 'ee/roadmap/components/epics_list_empty.vue'; import EpicsListEmpty from 'ee/roadmap/components/epics_list_empty.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
getTimeframeForQuartersView,
getTimeframeForWeeksView,
getTimeframeForMonthsView,
} from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockSvgPath } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockSvgPath } from 'ee_jest/roadmap/mock_data';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
...@@ -13,9 +9,21 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper'; ...@@ -13,9 +9,21 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
const TEST_EPICS_PATH = '/epics'; const TEST_EPICS_PATH = '/epics';
const TEST_NEW_EPIC_PATH = '/epics/new'; const TEST_NEW_EPIC_PATH = '/epics/new';
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate); const mockTimeframeQuarters = getTimeframeForRangeType({
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); timeframeRangeType: DATE_RANGES.THREE_YEARS,
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate); presetType: PRESET_TYPES.QUARTERS,
initialDate: mockTimeframeInitialDate,
});
const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const mockTimeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: mockTimeframeInitialDate,
});
describe('ee/roadmap/components/epics_list_empty.vue', () => { describe('ee/roadmap/components/epics_list_empty.vue', () => {
let wrapper; let wrapper;
...@@ -78,7 +86,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -78,7 +86,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Jul 1, 2017 to Mar 31, 2019.', 'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Jul 1, 2016 to Jun 30, 2019.',
); );
}); });
...@@ -91,7 +99,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -91,7 +99,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To widen your search, change or remove filters; from Jul 1, 2017 to Mar 31, 2019.', 'To widen your search, change or remove filters; from Jul 1, 2016 to Jun 30, 2019.',
); );
}); });
}); });
...@@ -103,7 +111,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -103,7 +111,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Nov 1, 2017 to Jun 30, 2018.', 'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Jan 1 to Dec 31, 2018.',
); );
}); });
...@@ -114,7 +122,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -114,7 +122,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To widen your search, change or remove filters; from Nov 1, 2017 to Jun 30, 2018.', 'To widen your search, change or remove filters; from Jan 1 to Dec 31, 2018.',
); );
}); });
}); });
...@@ -135,7 +143,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -135,7 +143,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Dec 17, 2017 to Feb 9, 2018.', 'To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from Dec 31, 2017 to Apr 6, 2018.',
); );
}); });
...@@ -148,7 +156,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => { ...@@ -148,7 +156,7 @@ describe('ee/roadmap/components/epics_list_empty.vue', () => {
}); });
expect(findSubTitle().text()).toBe( expect(findSubTitle().text()).toBe(
'To widen your search, change or remove filters; from Dec 17, 2017 to Feb 15, 2018.', 'To widen your search, change or remove filters; from Dec 31, 2017 to Apr 12, 2018.',
); );
}); });
}); });
......
...@@ -4,6 +4,7 @@ import { createLocalVue } from '@vue/test-utils'; ...@@ -4,6 +4,7 @@ import { createLocalVue } from '@vue/test-utils';
import EpicItem from 'ee/roadmap/components/epic_item.vue'; import EpicItem from 'ee/roadmap/components/epic_item.vue';
import EpicsListSection from 'ee/roadmap/components/epics_list_section.vue'; import EpicsListSection from 'ee/roadmap/components/epics_list_section.vue';
import { import {
DATE_RANGES,
PRESET_TYPES, PRESET_TYPES,
EPIC_DETAILS_CELL_WIDTH, EPIC_DETAILS_CELL_WIDTH,
TIMELINE_CELL_MIN_WIDTH, TIMELINE_CELL_MIN_WIDTH,
...@@ -11,7 +12,7 @@ import { ...@@ -11,7 +12,7 @@ import {
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { REQUEST_EPICS_FOR_NEXT_PAGE } from 'ee/roadmap/store/mutation_types'; import { REQUEST_EPICS_FOR_NEXT_PAGE } from 'ee/roadmap/store/mutation_types';
import { scrollToCurrentDay } from 'ee/roadmap/utils/epic_utils'; import { scrollToCurrentDay } from 'ee/roadmap/utils/epic_utils';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockFormattedChildEpic1, mockFormattedChildEpic1,
mockFormattedChildEpic2, mockFormattedChildEpic2,
...@@ -30,7 +31,11 @@ jest.mock('ee/roadmap/utils/epic_utils', () => ({ ...@@ -30,7 +31,11 @@ jest.mock('ee/roadmap/utils/epic_utils', () => ({
scrollToCurrentDay: jest.fn(), scrollToCurrentDay: jest.fn(),
})); }));
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const store = createStore(); const store = createStore();
store.dispatch('setInitialData', { store.dispatch('setInitialData', {
currentGroupId: mockGroupId, currentGroupId: mockGroupId,
......
...@@ -3,18 +3,22 @@ import Vue from 'vue'; ...@@ -3,18 +3,22 @@ import Vue from 'vue';
import milestoneItemComponent from 'ee/roadmap/components/milestone_item.vue'; import milestoneItemComponent from 'ee/roadmap/components/milestone_item.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockMilestone2 } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockMilestone2 } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
presetType = PRESET_TYPES.MONTHS, presetType = PRESET_TYPES.MONTHS,
milestone = mockMilestone2, milestone = mockMilestone2,
timeframe = mockTimeframeMonths, timeframe = mockTimeframeMonths,
timeframeItem = mockTimeframeMonths[0], timeframeItem = mockTimeframeMonths[16], // timeframe item where milestone begins
}) => { }) => {
const Component = Vue.extend(milestoneItemComponent); const Component = Vue.extend(milestoneItemComponent);
......
...@@ -2,12 +2,16 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -2,12 +2,16 @@ import { shallowMount } from '@vue/test-utils';
import MilestoneItem from 'ee/roadmap/components/milestone_item.vue'; import MilestoneItem from 'ee/roadmap/components/milestone_item.vue';
import MilestoneTimelineComponent from 'ee/roadmap/components/milestone_timeline.vue'; import MilestoneTimelineComponent from 'ee/roadmap/components/milestone_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockMilestone2, mockGroupId } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockMilestone2, mockGroupId } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
describe('MilestoneTimelineComponent', () => { describe('MilestoneTimelineComponent', () => {
let wrapper; let wrapper;
......
...@@ -3,13 +3,14 @@ import { shallowMount, createLocalVue } from '@vue/test-utils'; ...@@ -3,13 +3,14 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import MilestoneTimeline from 'ee/roadmap/components/milestone_timeline.vue'; import MilestoneTimeline from 'ee/roadmap/components/milestone_timeline.vue';
import milestonesListSectionComponent from 'ee/roadmap/components/milestones_list_section.vue'; import milestonesListSectionComponent from 'ee/roadmap/components/milestones_list_section.vue';
import { import {
DATE_RANGES,
PRESET_TYPES, PRESET_TYPES,
EPIC_DETAILS_CELL_WIDTH, EPIC_DETAILS_CELL_WIDTH,
TIMELINE_CELL_MIN_WIDTH, TIMELINE_CELL_MIN_WIDTH,
} from 'ee/roadmap/constants'; } from 'ee/roadmap/constants';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { scrollToCurrentDay } from 'ee/roadmap/utils/epic_utils'; import { scrollToCurrentDay } from 'ee/roadmap/utils/epic_utils';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockTimeframeInitialDate, mockTimeframeInitialDate,
mockGroupId, mockGroupId,
...@@ -37,7 +38,11 @@ describe('MilestonesListSectionComponent', () => { ...@@ -37,7 +38,11 @@ describe('MilestonesListSectionComponent', () => {
let wrapper; let wrapper;
let store; let store;
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const findMilestoneCount = () => wrapper.find('[data-testid="count"]'); const findMilestoneCount = () => wrapper.find('[data-testid="count"]');
const findMilestoneCountTooltip = () => getBinding(findMilestoneCount().element, 'gl-tooltip'); const findMilestoneCountTooltip = () => getBinding(findMilestoneCount().element, 'gl-tooltip');
const findExpandButtonContainer = () => wrapper.find('[data-testid="expandButton"]'); const findExpandButtonContainer = () => wrapper.find('[data-testid="expandButton"]');
......
import Vue from 'vue'; import Vue from 'vue';
import MonthsHeaderItemComponent from 'ee/roadmap/components/preset_months/months_header_item.vue'; import MonthsHeaderItemComponent from 'ee/roadmap/components/preset_months/months_header_item.vue';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const mockTimeframeIndex = 0; const mockTimeframeIndex = 0;
const createComponent = ({ const createComponent = ({
...@@ -46,7 +51,7 @@ describe('MonthsHeaderItemComponent', () => { ...@@ -46,7 +51,7 @@ describe('MonthsHeaderItemComponent', () => {
it('returns string containing Year and Month for current timeline header item', () => { it('returns string containing Year and Month for current timeline header item', () => {
vm = createComponent({}); vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Nov'); expect(vm.$el.innerText.trim()).toContain('2018 Jan');
}); });
it('returns string containing only Month for current timeline header item when previous header contained Year', () => { it('returns string containing only Month for current timeline header item when previous header contained Year', () => {
...@@ -55,7 +60,7 @@ describe('MonthsHeaderItemComponent', () => { ...@@ -55,7 +60,7 @@ describe('MonthsHeaderItemComponent', () => {
timeframeItem: mockTimeframeMonths[mockTimeframeIndex + 1], timeframeItem: mockTimeframeMonths[mockTimeframeIndex + 1],
}); });
expect(vm.timelineHeaderLabel).toBe('Dec'); expect(vm.$el.innerText.trim()).toContain('Feb');
}); });
}); });
...@@ -107,7 +112,7 @@ describe('MonthsHeaderItemComponent', () => { ...@@ -107,7 +112,7 @@ describe('MonthsHeaderItemComponent', () => {
const itemLabelEl = vm.$el.querySelector('.item-label'); const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull(); expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Nov'); expect(itemLabelEl.innerText.trim()).toBe('2018 Jan');
}); });
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import MonthsHeaderSubItemComponent from 'ee/roadmap/components/preset_months/months_header_sub_item.vue'; import MonthsHeaderSubItemComponent from 'ee/roadmap/components/preset_months/months_header_sub_item.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
currentDate = mockTimeframeMonths[0], currentDate = mockTimeframeMonths[0],
......
import Vue from 'vue'; import Vue from 'vue';
import QuartersHeaderItemComponent from 'ee/roadmap/components/preset_quarters/quarters_header_item.vue'; import QuartersHeaderItemComponent from 'ee/roadmap/components/preset_quarters/quarters_header_item.vue';
import { getTimeframeForQuartersView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeIndex = 0; const mockTimeframeIndex = 0;
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate); const mockTimeframeQuarters = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.QUARTERS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
timeframeIndex = mockTimeframeIndex, timeframeIndex = mockTimeframeIndex,
...@@ -56,7 +61,7 @@ describe('QuartersHeaderItemComponent', () => { ...@@ -56,7 +61,7 @@ describe('QuartersHeaderItemComponent', () => {
it('returns string containing Year and Quarter for current timeline header item', () => { it('returns string containing Year and Quarter for current timeline header item', () => {
vm = createComponent({}); vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Q3'); expect(vm.$el.innerText.trim()).toContain('2016 Q3');
}); });
it('returns string containing only Quarter for current timeline header item when previous header contained Year', () => { it('returns string containing only Quarter for current timeline header item when previous header contained Year', () => {
...@@ -65,7 +70,7 @@ describe('QuartersHeaderItemComponent', () => { ...@@ -65,7 +70,7 @@ describe('QuartersHeaderItemComponent', () => {
timeframeItem: mockTimeframeQuarters[mockTimeframeIndex + 2], timeframeItem: mockTimeframeQuarters[mockTimeframeIndex + 2],
}); });
expect(vm.timelineHeaderLabel).toBe('2018 Q1'); expect(vm.$el.innerText.trim()).toContain('2017 Q1');
}); });
}); });
...@@ -118,7 +123,7 @@ describe('QuartersHeaderItemComponent', () => { ...@@ -118,7 +123,7 @@ describe('QuartersHeaderItemComponent', () => {
const itemLabelEl = vm.$el.querySelector('.item-label'); const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull(); expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Q3'); expect(itemLabelEl.innerText.trim()).toBe('2016 Q3');
}); });
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import QuartersHeaderSubItemComponent from 'ee/roadmap/components/preset_quarters/quarters_header_sub_item.vue'; import QuartersHeaderSubItemComponent from 'ee/roadmap/components/preset_quarters/quarters_header_sub_item.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants';
import { getTimeframeForQuartersView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate); const mockTimeframeQuarters = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.QUARTERS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
currentDate = mockTimeframeQuarters[0].range[1], currentDate = mockTimeframeQuarters[0].range[1],
......
import Vue from 'vue'; import Vue from 'vue';
import WeeksHeaderItemComponent from 'ee/roadmap/components/preset_weeks/weeks_header_item.vue'; import WeeksHeaderItemComponent from 'ee/roadmap/components/preset_weeks/weeks_header_item.vue';
import { getTimeframeForWeeksView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeIndex = 0; const mockTimeframeIndex = 0;
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate); const mockTimeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
timeframeIndex = mockTimeframeIndex, timeframeIndex = mockTimeframeIndex,
...@@ -42,9 +47,8 @@ describe('WeeksHeaderItemComponent', () => { ...@@ -42,9 +47,8 @@ describe('WeeksHeaderItemComponent', () => {
describe('computed', () => { describe('computed', () => {
describe('lastDayOfCurrentWeek', () => { describe('lastDayOfCurrentWeek', () => {
it('returns date object representing last day of the week as set in `timeframeItem`', () => { it('returns date object representing last day of the week as set in `timeframeItem`', () => {
expect(vm.lastDayOfCurrentWeek.getDate()).toBe( vm = createComponent({});
mockTimeframeWeeks[mockTimeframeIndex].getDate() + 7, expect(vm.lastDayOfCurrentWeek.getDate()).toBe(7);
);
}); });
}); });
...@@ -52,7 +56,7 @@ describe('WeeksHeaderItemComponent', () => { ...@@ -52,7 +56,7 @@ describe('WeeksHeaderItemComponent', () => {
it('returns string containing Year, Month and Date for first timeframe item of the entire timeframe', () => { it('returns string containing Year, Month and Date for first timeframe item of the entire timeframe', () => {
vm = createComponent({}); vm = createComponent({});
expect(vm.timelineHeaderLabel).toBe('2017 Dec 17'); expect(vm.$el.innerText.trim()).toContain('2017 Dec 31');
}); });
it('returns string containing Year, Month and Date for timeframe item when it is first week of the year', () => { it('returns string containing Year, Month and Date for timeframe item when it is first week of the year', () => {
...@@ -66,11 +70,11 @@ describe('WeeksHeaderItemComponent', () => { ...@@ -66,11 +70,11 @@ describe('WeeksHeaderItemComponent', () => {
it('returns string containing only Month and Date timeframe item when it is somewhere in the middle of timeframe', () => { it('returns string containing only Month and Date timeframe item when it is somewhere in the middle of timeframe', () => {
vm = createComponent({ vm = createComponent({
timeframeIndex: mockTimeframeIndex + 1, timeframeIndex: mockTimeframeIndex + 2,
timeframeItem: mockTimeframeWeeks[mockTimeframeIndex + 1], timeframeItem: mockTimeframeWeeks[mockTimeframeIndex + 2],
}); });
expect(vm.timelineHeaderLabel).toBe('Dec 24'); expect(vm.timelineHeaderLabel).toBe('Jan 14');
}); });
}); });
...@@ -116,7 +120,7 @@ describe('WeeksHeaderItemComponent', () => { ...@@ -116,7 +120,7 @@ describe('WeeksHeaderItemComponent', () => {
const itemLabelEl = vm.$el.querySelector('.item-label'); const itemLabelEl = vm.$el.querySelector('.item-label');
expect(itemLabelEl).not.toBeNull(); expect(itemLabelEl).not.toBeNull();
expect(itemLabelEl.innerText.trim()).toBe('2017 Dec 17'); expect(itemLabelEl.innerText.trim()).toBe('2017 Dec 31');
}); });
}); });
}); });
import Vue from 'vue'; import Vue from 'vue';
import WeeksHeaderSubItemComponent from 'ee/roadmap/components/preset_weeks/weeks_header_sub_item.vue'; import WeeksHeaderSubItemComponent from 'ee/roadmap/components/preset_weeks/weeks_header_sub_item.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants';
import { getTimeframeForWeeksView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import { mockTimeframeInitialDate } from '../../mock_data'; import { mockTimeframeInitialDate } from '../../mock_data';
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate); const mockTimeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
currentDate = mockTimeframeWeeks[0], currentDate = mockTimeframeWeeks[0],
......
import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import Cookies from 'js-cookie';
import Vuex from 'vuex'; import Vuex from 'vuex';
import EpicsListEmpty from 'ee/roadmap/components/epics_list_empty.vue'; import EpicsListEmpty from 'ee/roadmap/components/epics_list_empty.vue';
import RoadmapApp from 'ee/roadmap/components/roadmap_app.vue'; import RoadmapApp from 'ee/roadmap/components/roadmap_app.vue';
import RoadmapFilters from 'ee/roadmap/components/roadmap_filters.vue'; import RoadmapFilters from 'ee/roadmap/components/roadmap_filters.vue';
import RoadmapShell from 'ee/roadmap/components/roadmap_shell.vue'; import RoadmapShell from 'ee/roadmap/components/roadmap_shell.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import * as types from 'ee/roadmap/store/mutation_types'; import * as types from 'ee/roadmap/store/mutation_types';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
basePath, basePath,
mockFormattedEpic, mockFormattedEpic,
mockFormattedChildEpic2,
mockGroupId, mockGroupId,
mockSortedBy, mockSortedBy,
mockSvgPath, mockSvgPath,
...@@ -32,7 +30,11 @@ describe('RoadmapApp', () => { ...@@ -32,7 +30,11 @@ describe('RoadmapApp', () => {
const epics = [mockFormattedEpic]; const epics = [mockFormattedEpic];
const hasFiltersApplied = true; const hasFiltersApplied = true;
const presetType = PRESET_TYPES.MONTHS; const presetType = PRESET_TYPES.MONTHS;
const timeframe = getTimeframeForMonthsView(mockTimeframeInitialDate); const timeframe = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = (mountFunction = shallowMount) => { const createComponent = (mountFunction = shallowMount) => {
return mountFunction(RoadmapApp, { return mountFunction(RoadmapApp, {
...@@ -151,31 +153,4 @@ describe('RoadmapApp', () => { ...@@ -151,31 +153,4 @@ describe('RoadmapApp', () => {
}); });
}); });
}); });
describe('roadmap epics limit warning', () => {
beforeEach(() => {
wrapper = createComponent();
store.commit(types.RECEIVE_EPICS_SUCCESS, {
epics: [mockFormattedEpic, mockFormattedChildEpic2],
});
window.gon.roadmap_epics_limit = 1;
});
it('displays warning when epics limit is reached', () => {
expect(wrapper.find(GlAlert).exists()).toBe(true);
expect(wrapper.find(GlAlert).text()).toContain(
'Roadmaps can display up to 1,000 epics. These appear in your selected sort order.',
);
});
it('sets epics_limit_warning_dismissed cookie to true when dismissing alert', () => {
wrapper.find(GlAlert).vm.$emit('dismiss');
expect(Cookies.get('epics_limit_warning_dismissed')).toBe('true');
return wrapper.vm.$nextTick(() => {
expect(wrapper.find(GlAlert).exists()).toBe(false);
});
});
});
}); });
...@@ -5,7 +5,7 @@ import Vuex from 'vuex'; ...@@ -5,7 +5,7 @@ import Vuex from 'vuex';
import RoadmapFilters from 'ee/roadmap/components/roadmap_filters.vue'; import RoadmapFilters from 'ee/roadmap/components/roadmap_filters.vue';
import { PRESET_TYPES, EPICS_STATES, DATE_RANGES } from 'ee/roadmap/constants'; import { PRESET_TYPES, EPICS_STATES, DATE_RANGES } from 'ee/roadmap/constants';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockSortedBy, mockSortedBy,
mockTimeframeInitialDate, mockTimeframeInitialDate,
...@@ -36,10 +36,13 @@ const createComponent = ({ ...@@ -36,10 +36,13 @@ const createComponent = ({
groupFullPath = 'gitlab-org', groupFullPath = 'gitlab-org',
listEpicsPath = '/groups/gitlab-org/-/epics', listEpicsPath = '/groups/gitlab-org/-/epics',
groupMilestonesPath = '/groups/gitlab-org/-/milestones.json', groupMilestonesPath = '/groups/gitlab-org/-/milestones.json',
timeframe = getTimeframeForMonthsView(mockTimeframeInitialDate), timeframe = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
}),
filterParams = {}, filterParams = {},
roadmapDaterangeFilter = false, timeframeRangeType = DATE_RANGES.THREE_YEARS,
timeframeRangeType = DATE_RANGES.CURRENT_QUARTER,
} = {}) => { } = {}) => {
const localVue = createLocalVue(); const localVue = createLocalVue();
const store = createStore(); const store = createStore();
...@@ -61,9 +64,6 @@ const createComponent = ({ ...@@ -61,9 +64,6 @@ const createComponent = ({
groupFullPath, groupFullPath,
groupMilestonesPath, groupMilestonesPath,
listEpicsPath, listEpicsPath,
glFeatures: {
roadmapDaterangeFilter,
},
}, },
props: { props: {
timeframeRangeType, timeframeRangeType,
...@@ -130,16 +130,12 @@ describe('RoadmapFilters', () => { ...@@ -130,16 +130,12 @@ describe('RoadmapFilters', () => {
updateHistory({ url: TEST_HOST, title: document.title, replace: true }); updateHistory({ url: TEST_HOST, title: document.title, replace: true });
}); });
it('renders roadmap layout switching buttons', () => { it('switching layout using roadmap layout switching buttons causes page to reload with selected layout', async () => {
const layoutSwitches = wrapper.find(GlSegmentedControl); wrapper.setData({ selectedDaterange: DATE_RANGES.THREE_YEARS });
expect(layoutSwitches.exists()).toBe(true); await wrapper.vm.$nextTick();
expect(layoutSwitches.props('checked')).toBe(PRESET_TYPES.MONTHS);
expect(layoutSwitches.props('options')).toEqual([quarters, months, weeks]);
});
it('switching layout using roadmap layout switching buttons causes page to reload with selected layout', () => { wrapper.findComponent(GlSegmentedControl).vm.$emit('input', PRESET_TYPES.OPENED);
wrapper.find(GlSegmentedControl).vm.$emit('input', PRESET_TYPES.OPENED);
expect(mergeUrlParams).toHaveBeenCalledWith( expect(mergeUrlParams).toHaveBeenCalledWith(
expect.objectContaining({ layout: PRESET_TYPES.OPENED }), expect.objectContaining({ layout: PRESET_TYPES.OPENED }),
...@@ -312,7 +308,7 @@ describe('RoadmapFilters', () => { ...@@ -312,7 +308,7 @@ describe('RoadmapFilters', () => {
}); });
}); });
describe('when roadmapDaterangeFilter feature flag is enabled', () => { describe('daterange filtering', () => {
let wrapperWithDaterangeFilter; let wrapperWithDaterangeFilter;
const availableRanges = [ const availableRanges = [
{ text: 'This quarter', value: DATE_RANGES.CURRENT_QUARTER }, { text: 'This quarter', value: DATE_RANGES.CURRENT_QUARTER },
...@@ -322,7 +318,6 @@ describe('RoadmapFilters', () => { ...@@ -322,7 +318,6 @@ describe('RoadmapFilters', () => {
beforeEach(async () => { beforeEach(async () => {
wrapperWithDaterangeFilter = createComponent({ wrapperWithDaterangeFilter = createComponent({
roadmapDaterangeFilter: true,
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER, timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
}); });
......
...@@ -7,10 +7,10 @@ import MonthsHeaderItem from 'ee/roadmap/components/preset_months/months_header_ ...@@ -7,10 +7,10 @@ import MonthsHeaderItem from 'ee/roadmap/components/preset_months/months_header_
import MonthsHeaderSubItem from 'ee/roadmap/components/preset_months/months_header_sub_item.vue'; import MonthsHeaderSubItem from 'ee/roadmap/components/preset_months/months_header_sub_item.vue';
import RoadmapShell from 'ee/roadmap/components/roadmap_shell.vue'; import RoadmapShell from 'ee/roadmap/components/roadmap_shell.vue';
import RoadmapTimelineSection from 'ee/roadmap/components/roadmap_timeline_section.vue'; import RoadmapTimelineSection from 'ee/roadmap/components/roadmap_timeline_section.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import createStore from 'ee/roadmap/store'; import createStore from 'ee/roadmap/store';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { import {
mockEpic, mockEpic,
...@@ -19,7 +19,11 @@ import { ...@@ -19,7 +19,11 @@ import {
mockMilestone, mockMilestone,
} from 'ee_jest/roadmap/mock_data'; } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
describe('RoadmapShell', () => { describe('RoadmapShell', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
......
import Vue from 'vue'; import Vue from 'vue';
import roadmapTimelineSectionComponent from 'ee/roadmap/components/roadmap_timeline_section.vue'; import roadmapTimelineSectionComponent from 'ee/roadmap/components/roadmap_timeline_section.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockEpic, mockTimeframeInitialDate } from 'ee_jest/roadmap/mock_data'; import { mockEpic, mockTimeframeInitialDate } from 'ee_jest/roadmap/mock_data';
import mountComponent from 'helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
const createComponent = ({ const createComponent = ({
presetType = PRESET_TYPES.MONTHS, presetType = PRESET_TYPES.MONTHS,
...@@ -46,7 +50,7 @@ describe('RoadmapTimelineSectionComponent', () => { ...@@ -46,7 +50,7 @@ describe('RoadmapTimelineSectionComponent', () => {
it('returns object containing `width` with value based on epic details cell width, timeline cell width and timeframe length', () => { it('returns object containing `width` with value based on epic details cell width, timeline cell width and timeframe length', () => {
expect(vm.sectionContainerStyles).toEqual( expect(vm.sectionContainerStyles).toEqual(
expect.objectContaining({ expect.objectContaining({
width: '1760px', width: '2480px', // We now have fixed columns in timeframe.
}), }),
); );
}); });
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue'; import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data';
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
describe('MonthsPresetMixin', () => { describe('MonthsPresetMixin', () => {
let wrapper; let wrapper;
...@@ -130,28 +134,24 @@ describe('MonthsPresetMixin', () => { ...@@ -130,28 +134,24 @@ describe('MonthsPresetMixin', () => {
describe('getTimelineBarWidthForMonths', () => { describe('getTimelineBarWidthForMonths', () => {
it('returns calculated width value based on Epic.startDate and Epic.endDate', () => { it('returns calculated width value based on Epic.startDate and Epic.endDate', () => {
wrapper = createComponent({ wrapper = createComponent({
timeframeItem: mockTimeframeMonths[1], timeframeItem: mockTimeframeMonths[0],
epic: { epic: {
...mockEpic, ...mockEpic,
startDate: new Date(2017, 11, 15), // Dec 15, 2017 startDate: new Date(2018, 0, 1), // Jan 01, 2018
endDate: new Date(2018, 1, 15), // Feb 15, 2018 endDate: new Date(2018, 2, 15), // Mar 15, 2018
}, },
}); });
/* /*
The epic timeline bar width calculation: The epic timeline bar width calculation:
- The width of the bar should account for 31 - 15 = 16 days from December. Jan: 31 days = 180px
- The width of the bar should fully account for all of January (31 days). + Feb: 28 days = 180px
- The width of the bar should account for only 15 days + Mar: (180px / 31 days) * 15 days ~= 87.15px
Dec: 16 days / 31 days * 180px ~= 92.9px
+ Jan: 31 days = 180px
+ Feb: 15 days / 28 days * 180px ~= 96.43px
--------------------------------------------------- ---------------------------------------------------
Total ~= 369px Total ~= 447px
*/ */
const expectedTimelineBarWidth = 369; // in px. const expectedTimelineBarWidth = 447; // in px.
expect(Math.floor(wrapper.vm.getTimelineBarWidthForMonths())).toBe( expect(Math.floor(wrapper.vm.getTimelineBarWidthForMonths())).toBe(
expectedTimelineBarWidth, expectedTimelineBarWidth,
); );
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue'; import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForQuartersView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data';
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate); const mockTimeframeQuarters = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.QUARTERS,
initialDate: mockTimeframeInitialDate,
});
describe('QuartersPresetMixin', () => { describe('QuartersPresetMixin', () => {
let wrapper; let wrapper;
......
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue'; import EpicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import { getTimeframeForWeeksView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data'; import { mockTimeframeInitialDate, mockEpic } from 'ee_jest/roadmap/mock_data';
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate); const mockTimeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: mockTimeframeInitialDate,
});
describe('WeeksPresetMixin', () => { describe('WeeksPresetMixin', () => {
let wrapper; let wrapper;
...@@ -59,9 +63,9 @@ describe('WeeksPresetMixin', () => { ...@@ -59,9 +63,9 @@ describe('WeeksPresetMixin', () => {
wrapper = createComponent(); wrapper = createComponent();
const lastDayOfWeek = wrapper.vm.getLastDayOfWeek(mockTimeframeWeeks[0]); const lastDayOfWeek = wrapper.vm.getLastDayOfWeek(mockTimeframeWeeks[0]);
expect(lastDayOfWeek.getDate()).toBe(23); expect(lastDayOfWeek.getDate()).toBe(6);
expect(lastDayOfWeek.getMonth()).toBe(11); expect(lastDayOfWeek.getMonth()).toBe(0);
expect(lastDayOfWeek.getFullYear()).toBe(2017); expect(lastDayOfWeek.getFullYear()).toBe(2018);
}); });
}); });
...@@ -197,7 +201,7 @@ describe('WeeksPresetMixin', () => { ...@@ -197,7 +201,7 @@ describe('WeeksPresetMixin', () => {
approximately 154px ^ approximately 154px ^
~ approximately 154px ~ approximately 154px
*/ */
const expectedTimelineBarWidth = 848; // in px; const expectedTimelineBarWidth = 488; // in px;
expect(Math.floor(wrapper.vm.getTimelineBarWidthForWeeks())).toBe(expectedTimelineBarWidth); expect(Math.floor(wrapper.vm.getTimelineBarWidthForWeeks())).toBe(expectedTimelineBarWidth);
}); });
......
import { GlFilteredSearchToken } from '@gitlab/ui'; import { GlFilteredSearchToken } from '@gitlab/ui';
import { import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
getTimeframeForWeeksView, import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
getTimeframeForMonthsView,
getTimeframeForQuartersView,
} from 'ee/roadmap/utils/roadmap_utils';
import { dateFromString } from 'helpers/datetime_helpers'; import { dateFromString } from 'helpers/datetime_helpers';
import { import {
...@@ -137,7 +134,11 @@ export const mockWeekly = { ...@@ -137,7 +134,11 @@ export const mockWeekly = {
Oct 18 2020, Oct 25 2020, Nov 1 2020, Oct 18 2020, Oct 25 2020, Nov 1 2020,
Nov 8 2020 ] Nov 8 2020 ]
*/ */
timeframe: getTimeframeForWeeksView(OCT_11_2020), timeframe: getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: OCT_11_2020,
}),
}; };
const DEC_1_2020 = dateFromString('Dec 1 2020'); const DEC_1_2020 = dateFromString('Dec 1 2020');
...@@ -150,7 +151,11 @@ export const mockMonthly = { ...@@ -150,7 +151,11 @@ export const mockMonthly = {
Jan 1 2021, Feb 1 2021, Mar 1 2021, Jan 1 2021, Feb 1 2021, Mar 1 2021,
Apr 1 2021, May 31 2021 ] Apr 1 2021, May 31 2021 ]
*/ */
timeframe: getTimeframeForMonthsView(DEC_1_2020), timeframe: getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: DEC_1_2020,
}),
}; };
const DEC_25_2020 = dateFromString('Dec 25 2020'); const DEC_25_2020 = dateFromString('Dec 25 2020');
...@@ -170,7 +175,11 @@ export const mockQuarterly = { ...@@ -170,7 +175,11 @@ export const mockQuarterly = {
{ 2021 Q1 }, { 2021 Q2 }, { 2021 Q3 }, { 2021 Q1 }, { 2021 Q2 }, { 2021 Q3 },
{ 2021 Q4 } ] { 2021 Q4 } ]
*/ */
timeframe: getTimeframeForQuartersView(DEC_25_2020), timeframe: getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.QUARTERS,
initialDate: DEC_25_2020,
}),
}; };
export const mockEpic = { export const mockEpic = {
...@@ -269,7 +278,7 @@ export const mockFormattedChildEpic2 = { ...@@ -269,7 +278,7 @@ export const mockFormattedChildEpic2 = {
export const mockFormattedEpic = { export const mockFormattedEpic = {
...mockRawEpic, ...mockRawEpic,
startDate: new Date(2017, 10, 1), startDate: new Date(2018, 0, 1),
originalStartDate: new Date(2017, 5, 26), originalStartDate: new Date(2017, 5, 26),
endDate: new Date(2018, 2, 10), endDate: new Date(2018, 2, 10),
originalEndDate: new Date(2018, 2, 10), originalEndDate: new Date(2018, 2, 10),
...@@ -283,9 +292,9 @@ export const mockFormattedEpic2 = { ...@@ -283,9 +292,9 @@ export const mockFormattedEpic2 = {
...mockRawEpic2, ...mockRawEpic2,
isChildEpic: false, isChildEpic: false,
newEpic: undefined, newEpic: undefined,
startDateOutOfRange: false, startDateOutOfRange: true,
endDateOutOfRange: false, endDateOutOfRange: false,
startDate: new Date(2017, 11, 31), startDate: new Date(2018, 0, 1),
originalStartDate: new Date(2017, 11, 31), originalStartDate: new Date(2017, 11, 31),
endDate: new Date(2018, 1, 15), endDate: new Date(2018, 1, 15),
originalEndDate: new Date(2018, 1, 15), originalEndDate: new Date(2018, 1, 15),
......
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { PRESET_TYPES } from 'ee/roadmap/constants'; import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
import groupMilestones from 'ee/roadmap/queries/groupMilestones.query.graphql'; import groupMilestones from 'ee/roadmap/queries/groupMilestones.query.graphql';
import * as actions from 'ee/roadmap/store/actions'; import * as actions from 'ee/roadmap/store/actions';
import * as types from 'ee/roadmap/store/mutation_types'; import * as types from 'ee/roadmap/store/mutation_types';
import defaultState from 'ee/roadmap/store/state'; import defaultState from 'ee/roadmap/store/state';
import * as epicUtils from 'ee/roadmap/utils/epic_utils'; import * as epicUtils from 'ee/roadmap/utils/epic_utils';
import * as roadmapItemUtils from 'ee/roadmap/utils/roadmap_item_utils'; import * as roadmapItemUtils from 'ee/roadmap/utils/roadmap_item_utils';
import { getTimeframeForMonthsView } from 'ee/roadmap/utils/roadmap_utils'; import { getTimeframeForRangeType } from 'ee/roadmap/utils/roadmap_utils';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
...@@ -33,7 +33,11 @@ import { ...@@ -33,7 +33,11 @@ import {
jest.mock('~/flash'); jest.mock('~/flash');
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate); const mockTimeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: mockTimeframeInitialDate,
});
describe('Roadmap Vuex Actions', () => { describe('Roadmap Vuex Actions', () => {
const timeframeStartDate = mockTimeframeMonths[0]; const timeframeStartDate = mockTimeframeMonths[0];
...@@ -458,8 +462,8 @@ describe('Roadmap Vuex Actions', () => { ...@@ -458,8 +462,8 @@ describe('Roadmap Vuex Actions', () => {
fullPath: 'gitlab-org', fullPath: 'gitlab-org',
state: mockState.milestonessState, state: mockState.milestonessState,
timeframe: { timeframe: {
start: '2017-11-01', start: '2018-01-01',
end: '2018-06-30', end: '2018-12-31',
}, },
includeDescendants: true, includeDescendants: true,
}; };
...@@ -551,9 +555,9 @@ describe('Roadmap Vuex Actions', () => { ...@@ -551,9 +555,9 @@ describe('Roadmap Vuex Actions', () => {
payload: [ payload: [
{ {
...mockFormattedMilestone, ...mockFormattedMilestone,
startDateOutOfRange: false, startDateOutOfRange: true,
endDateOutOfRange: false, endDateOutOfRange: false,
startDate: new Date(2017, 11, 31), startDate: new Date(2018, 0, 1),
originalStartDate: new Date(2017, 11, 31), originalStartDate: new Date(2017, 11, 31),
endDate: new Date(2018, 1, 15), endDate: new Date(2018, 1, 15),
originalEndDate: new Date(2018, 1, 15), originalEndDate: new Date(2018, 1, 15),
......
...@@ -212,30 +212,6 @@ describe('Roadmap Store Mutations', () => { ...@@ -212,30 +212,6 @@ describe('Roadmap Store Mutations', () => {
}); });
}); });
describe('PREPEND_TIMEFRAME', () => {
it('Should set extendedTimeframe to provided extendedTimeframe param and prepend it to timeframe array in state', () => {
state.timeframe.push('foo');
const extendedTimeframe = ['bar'];
mutations[types.PREPEND_TIMEFRAME](state, extendedTimeframe);
expect(state.extendedTimeframe).toBe(extendedTimeframe);
expect(state.timeframe[0]).toBe(extendedTimeframe[0]);
});
});
describe('APPEND_TIMEFRAME', () => {
it('Should set extendedTimeframe to provided extendedTimeframe param and append it to timeframe array in state', () => {
state.timeframe.push('foo');
const extendedTimeframe = ['bar'];
mutations[types.APPEND_TIMEFRAME](state, extendedTimeframe);
expect(state.extendedTimeframe).toBe(extendedTimeframe);
expect(state.timeframe[1]).toBe(extendedTimeframe[0]);
});
});
describe('SET_MILESTONES', () => { describe('SET_MILESTONES', () => {
it('Should provided milestones array in state', () => { it('Should provided milestones array in state', () => {
const milestones = [{ id: 1 }, { id: 2 }]; const milestones = [{ id: 1 }, { id: 2 }];
......
...@@ -161,11 +161,11 @@ describe('timeframeEndDate', () => { ...@@ -161,11 +161,11 @@ describe('timeframeEndDate', () => {
/* /*
Note: there are inconsistencies in how timeframes are generated. Note: there are inconsistencies in how timeframes are generated.
A monthly timeframe generated with roadmap_util's getTimeframeForMonthsView function - A monthly timeframe generated with roadmap_util's getTimeframeForRangeType function -
will always set its last item to the ending date for that month. will always set its last item to the ending date for that month.
E.g., [ Oct 1, Nov 1, Dec 31 ] E.g., [ Oct 1, Nov 1, Dec 31 ]
The same is true of quarterly timeframes generated with getTimeframeForQuarterlyView The same is true of quarterly timeframes generated with getTimeframeForRangeType
E.g., [ ..., { range: [ Oct 1, Nov 1, Dec 31 ] }] 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. In comparison, a weekly timeframe won't have its last item set to the ending date for the week.
...@@ -176,9 +176,9 @@ describe('timeframeEndDate', () => { ...@@ -176,9 +176,9 @@ describe('timeframeEndDate', () => {
*/ */
it.each` it.each`
presetType | endDate | timeframe presetType | endDate | timeframe
${PRESET_TYPES.QUARTERS} | ${dateFromString('Dec 31 2021')} | ${mockQuarterly.timeframe} ${PRESET_TYPES.QUARTERS} | ${dateFromString('May 31 2022')} | ${mockQuarterly.timeframe}
${PRESET_TYPES.MONTHS} | ${dateFromString('May 31 2021')} | ${mockMonthly.timeframe} ${PRESET_TYPES.MONTHS} | ${dateFromString('Dec 31 2020')} | ${mockMonthly.timeframe}
${PRESET_TYPES.WEEKS} | ${dateFromString('Nov 15 2020')} | ${mockWeekly.timeframe} ${PRESET_TYPES.WEEKS} | ${dateFromString('Jan 03 2021')} | ${mockWeekly.timeframe}
`( `(
`should return ending date for the timeframe range array when preset type is $presetType`, `should return ending date for the timeframe range array when preset type is $presetType`,
({ presetType, endDate, timeframe }) => { ({ presetType, endDate, timeframe }) => {
......
import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants'; import { PRESET_TYPES, DATE_RANGES } from 'ee/roadmap/constants';
import { import {
getTimeframeForQuartersView,
extendTimeframeForQuartersView,
getTimeframeForMonthsView,
extendTimeframeForMonthsView,
getTimeframeForWeeksView,
extendTimeframeForWeeksView,
extendTimeframeForAvailableWidth,
getEpicsTimeframeRange, getEpicsTimeframeRange,
getWeeksForDates, getWeeksForDates,
getTimeframeForRangeType, getTimeframeForRangeType,
...@@ -14,299 +7,23 @@ import { ...@@ -14,299 +7,23 @@ import {
getPresetTypeForTimeframeRangeType, getPresetTypeForTimeframeRangeType,
} from 'ee/roadmap/utils/roadmap_utils'; } from 'ee/roadmap/utils/roadmap_utils';
import { import { mockTimeframeInitialDate, mockUnsortedEpics } from '../mock_data';
mockTimeframeInitialDate,
mockTimeframeQuartersPrepend,
mockTimeframeQuartersAppend,
mockTimeframeMonthsPrepend,
mockTimeframeMonthsAppend,
mockTimeframeWeeksPrepend,
mockTimeframeWeeksAppend,
mockUnsortedEpics,
} from '../mock_data';
const mockTimeframeQuarters = getTimeframeForQuartersView(mockTimeframeInitialDate);
const mockTimeframeMonths = getTimeframeForMonthsView(mockTimeframeInitialDate);
const mockTimeframeWeeks = getTimeframeForWeeksView(mockTimeframeInitialDate);
const getDateString = (date) => date.toISOString().split('T')[0];
describe('getTimeframeForQuartersView', () => {
let timeframe;
beforeEach(() => {
timeframe = getTimeframeForQuartersView(new Date(2018, 0, 1));
});
it('returns timeframe with total of 7 quarters', () => {
expect(timeframe).toHaveLength(7);
});
it('each timeframe item has `quarterSequence`, `year` and `range` present', () => {
const timeframeItem = timeframe[0];
expect(timeframeItem.quarterSequence).toEqual(expect.any(Number));
expect(timeframeItem.year).toEqual(expect.any(Number));
expect(Array.isArray(timeframeItem.range)).toBe(true);
});
it('first timeframe item refers to 2 quarters prior to current quarter', () => {
const timeframeItem = timeframe[0];
const expectedQuarter = {
0: { month: 6, date: 1 }, // 1 Jul 2017
1: { month: 7, date: 1 }, // 1 Aug 2017
2: { month: 8, date: 30 }, // 30 Sep 2017
};
expect(timeframeItem.quarterSequence).toEqual(3);
expect(timeframeItem.year).toEqual(2017);
timeframeItem.range.forEach((month, index) => {
expect(month.getFullYear()).toBe(2017);
expect(expectedQuarter[index].month).toBe(month.getMonth());
expect(expectedQuarter[index].date).toBe(month.getDate());
});
});
it('last timeframe item refers to 5th quarter from current quarter', () => {
const timeframeItem = timeframe[timeframe.length - 1];
const expectedQuarter = {
0: { month: 0, date: 1 }, // 1 Jan 2019
1: { month: 1, date: 1 }, // 1 Feb 2019
2: { month: 2, date: 31 }, // 31 Mar 2019
};
expect(timeframeItem.quarterSequence).toEqual(1);
expect(timeframeItem.year).toEqual(2019);
timeframeItem.range.forEach((month, index) => {
expect(month.getFullYear()).toBe(2019);
expect(expectedQuarter[index].month).toBe(month.getMonth());
expect(expectedQuarter[index].date).toBe(month.getDate());
});
});
});
describe('extendTimeframeForQuartersView', () => {
it('returns extended timeframe into the past from current timeframe startDate', () => {
const initialDate = mockTimeframeQuarters[0].range[0];
const extendedTimeframe = extendTimeframeForQuartersView(initialDate, -9);
expect(extendedTimeframe).toHaveLength(mockTimeframeQuartersPrepend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.year).toBe(mockTimeframeQuartersPrepend[index].year);
expect(timeframeItem.quarterSequence).toBe(
mockTimeframeQuartersPrepend[index].quarterSequence,
);
timeframeItem.range.forEach((rangeItem, j) => {
expect(rangeItem.getTime()).toBe(mockTimeframeQuartersPrepend[index].range[j].getTime());
});
});
});
it('returns extended timeframe into the future from current timeframe endDate', () => { const mockTimeframeMonths = getTimeframeForRangeType({
const initialDate = mockTimeframeQuarters[mockTimeframeQuarters.length - 1].range[2]; timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
const extendedTimeframe = extendTimeframeForQuartersView(initialDate, 9);
expect(extendedTimeframe).toHaveLength(mockTimeframeQuartersAppend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.year).toBe(mockTimeframeQuartersAppend[index].year);
expect(timeframeItem.quarterSequence).toBe(
mockTimeframeQuartersAppend[index].quarterSequence,
);
timeframeItem.range.forEach((rangeItem, j) => {
expect(rangeItem.getTime()).toBe(mockTimeframeQuartersAppend[index].range[j].getTime());
});
});
});
});
describe('getTimeframeForMonthsView', () => {
let timeframe;
beforeEach(() => {
timeframe = getTimeframeForMonthsView(new Date(2018, 0, 1));
});
it('returns timeframe with total of 8 months', () => {
expect(timeframe).toHaveLength(8);
});
it('first timeframe item refers to 2 months prior to current month', () => {
const timeframeItem = timeframe[0];
const expectedMonth = {
year: 2017,
month: 10,
date: 1,
};
expect(timeframeItem.getFullYear()).toBe(expectedMonth.year);
expect(timeframeItem.getMonth()).toBe(expectedMonth.month);
expect(timeframeItem.getDate()).toBe(expectedMonth.date);
});
it('last timeframe item refers to 6th month from current month', () => {
const timeframeItem = timeframe[timeframe.length - 1];
const expectedMonth = {
year: 2018,
month: 5,
date: 30,
};
expect(timeframeItem.getFullYear()).toBe(expectedMonth.year);
expect(timeframeItem.getMonth()).toBe(expectedMonth.month);
expect(timeframeItem.getDate()).toBe(expectedMonth.date);
});
});
describe('extendTimeframeForMonthsView', () => {
it('returns extended timeframe into the past from current timeframe startDate', () => {
const initialDate = mockTimeframeMonths[0];
const extendedTimeframe = extendTimeframeForMonthsView(initialDate, -8);
expect(extendedTimeframe).toHaveLength(mockTimeframeMonthsPrepend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.getTime()).toBe(mockTimeframeMonthsPrepend[index].getTime());
});
});
it('returns extended timeframe into the future from current timeframe endDate', () => {
const initialDate = mockTimeframeMonths[mockTimeframeMonths.length - 1];
const extendedTimeframe = extendTimeframeForMonthsView(initialDate, 8);
expect(extendedTimeframe).toHaveLength(mockTimeframeMonthsAppend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.getTime()).toBe(mockTimeframeMonthsAppend[index].getTime());
});
});
});
describe('getTimeframeForWeeksView', () => {
let timeframe;
beforeEach(() => {
timeframe = getTimeframeForWeeksView(mockTimeframeInitialDate);
});
it('returns timeframe with total of 7 weeks', () => {
expect(timeframe).toHaveLength(7);
});
it('first timeframe item refers to 2 weeks prior to current week', () => {
const timeframeItem = timeframe[0];
const expectedMonth = {
year: 2017,
month: 11,
date: 17,
};
expect(timeframeItem.getFullYear()).toBe(expectedMonth.year);
expect(timeframeItem.getMonth()).toBe(expectedMonth.month);
expect(timeframeItem.getDate()).toBe(expectedMonth.date);
});
it('last timeframe item refers to 5th week from current month', () => {
const timeframeItem = timeframe[timeframe.length - 1];
const expectedMonth = {
year: 2018,
month: 0,
date: 28,
};
expect(timeframeItem.getFullYear()).toBe(expectedMonth.year);
expect(timeframeItem.getMonth()).toBe(expectedMonth.month);
expect(timeframeItem.getDate()).toBe(expectedMonth.date);
});
it('returns timeframe starting on a specific date when provided with additional `length` param', () => {
const initialDate = new Date(2018, 0, 7);
timeframe = getTimeframeForWeeksView(initialDate, 5);
const expectedTimeframe = [
initialDate,
new Date(2018, 0, 14),
new Date(2018, 0, 21),
new Date(2018, 0, 28),
new Date(2018, 1, 4),
];
expect(timeframe).toHaveLength(5);
expectedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.getTime()).toBe(expectedTimeframe[index].getTime());
});
});
});
describe('extendTimeframeForWeeksView', () => {
it('returns extended timeframe into the past from current timeframe startDate', () => {
const extendedTimeframe = extendTimeframeForWeeksView(mockTimeframeWeeks[0], -6); // initialDate: 17 Dec 2017
expect(extendedTimeframe).toHaveLength(mockTimeframeWeeksPrepend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.getTime()).toBe(mockTimeframeWeeksPrepend[index].getTime());
});
});
it('returns extended timeframe into the future from current timeframe endDate', () => {
const extendedTimeframe = extendTimeframeForWeeksView(
mockTimeframeWeeks[mockTimeframeWeeks.length - 1], // initialDate: 28 Jan 2018
6,
);
expect(extendedTimeframe).toHaveLength(mockTimeframeWeeksAppend.length);
extendedTimeframe.forEach((timeframeItem, index) => {
expect(timeframeItem.getTime()).toBe(mockTimeframeWeeksAppend[index].getTime());
});
});
});
describe('extendTimeframeForAvailableWidth', () => {
let timeframe;
let timeframeStart;
let timeframeEnd;
beforeEach(() => {
timeframe = mockTimeframeMonths.slice();
[timeframeStart] = timeframe;
timeframeEnd = timeframe[timeframe.length - 1];
});
it('should not extend `timeframe` when availableTimeframeWidth is small enough to force horizontal scrollbar to show up', () => {
extendTimeframeForAvailableWidth({
availableTimeframeWidth: 100,
presetType: PRESET_TYPES.MONTHS,
timeframe,
timeframeStart,
timeframeEnd,
});
expect(timeframe).toHaveLength(mockTimeframeMonths.length);
});
it('should extend `timeframe` when availableTimeframeWidth is large enough that it can fit more timeframe items to show up horizontal scrollbar', () => {
extendTimeframeForAvailableWidth({
availableTimeframeWidth: 2000,
presetType: PRESET_TYPES.MONTHS, presetType: PRESET_TYPES.MONTHS,
timeframe, initialDate: mockTimeframeInitialDate,
timeframeStart,
timeframeEnd,
});
expect(timeframe).toHaveLength(12);
expect(timeframe[0].getTime()).toBe(1504224000000); // 1 Sep 2017
expect(timeframe[timeframe.length - 1].getTime()).toBe(1535673600000); // 31 Aug 2018
});
}); });
const getDateString = (date) => date.toISOString().split('T')[0];
describe('getWeeksForDates', () => { describe('getWeeksForDates', () => {
it('returns weeks for given dates', () => { it('returns weeks for given dates', () => {
const weeks = getWeeksForDates(mockTimeframeInitialDate, mockTimeframeMonths[4]); const weeks = getWeeksForDates(mockTimeframeInitialDate, mockTimeframeMonths[4]);
expect(weeks).toHaveLength(9); expect(weeks).toHaveLength(18);
expect(getDateString(weeks[0])).toBe('2017-12-31'); expect(getDateString(weeks[0])).toBe('2017-12-31');
expect(getDateString(weeks[4])).toBe('2018-01-28'); expect(getDateString(weeks[7])).toBe('2018-02-18');
expect(getDateString(weeks[8])).toBe('2018-02-25'); expect(getDateString(weeks[17])).toBe('2018-04-29');
}); });
}); });
...@@ -408,7 +125,11 @@ describe('getTimeframeForRangeType', () => { ...@@ -408,7 +125,11 @@ describe('getTimeframeForRangeType', () => {
describe('getEpicsTimeframeRange', () => { describe('getEpicsTimeframeRange', () => {
it('returns object containing startDate and dueDate based on provided timeframe for Quarters', () => { it('returns object containing startDate and dueDate based on provided timeframe for Quarters', () => {
const timeframeQuarters = getTimeframeForQuartersView(new Date(2018, 0, 1)); const timeframeQuarters = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.THREE_YEARS,
presetType: PRESET_TYPES.QUARTERS,
initialDate: new Date(2018, 0, 1),
});
const range = getEpicsTimeframeRange({ const range = getEpicsTimeframeRange({
presetType: PRESET_TYPES.QUARTERS, presetType: PRESET_TYPES.QUARTERS,
timeframe: timeframeQuarters, timeframe: timeframeQuarters,
...@@ -417,15 +138,19 @@ describe('getEpicsTimeframeRange', () => { ...@@ -417,15 +138,19 @@ describe('getEpicsTimeframeRange', () => {
expect(range).toEqual( expect(range).toEqual(
expect.objectContaining({ expect.objectContaining({
timeframe: { timeframe: {
start: '2017-07-01', start: '2016-07-01',
end: '2019-03-31', end: '2019-06-30',
}, },
}), }),
); );
}); });
it('returns object containing startDate and dueDate based on provided timeframe for Months', () => { it('returns object containing startDate and dueDate based on provided timeframe for Months', () => {
const timeframeMonths = getTimeframeForMonthsView(new Date(2018, 0, 1)); const timeframeMonths = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_YEAR,
presetType: PRESET_TYPES.MONTHS,
initialDate: new Date(2018, 0, 1),
});
const range = getEpicsTimeframeRange({ const range = getEpicsTimeframeRange({
presetType: PRESET_TYPES.MONTHS, presetType: PRESET_TYPES.MONTHS,
timeframe: timeframeMonths, timeframe: timeframeMonths,
...@@ -434,15 +159,19 @@ describe('getEpicsTimeframeRange', () => { ...@@ -434,15 +159,19 @@ describe('getEpicsTimeframeRange', () => {
expect(range).toEqual( expect(range).toEqual(
expect.objectContaining({ expect.objectContaining({
timeframe: { timeframe: {
start: '2017-11-01', start: '2018-01-01',
end: '2018-06-30', end: '2018-12-31',
}, },
}), }),
); );
}); });
it('returns object containing startDate and dueDate based on provided timeframe for Weeks', () => { it('returns object containing startDate and dueDate based on provided timeframe for Weeks', () => {
const timeframeWeeks = getTimeframeForWeeksView(new Date(2018, 0, 1)); const timeframeWeeks = getTimeframeForRangeType({
timeframeRangeType: DATE_RANGES.CURRENT_QUARTER,
presetType: PRESET_TYPES.WEEKS,
initialDate: new Date(2018, 0, 1),
});
const range = getEpicsTimeframeRange({ const range = getEpicsTimeframeRange({
presetType: PRESET_TYPES.WEEKS, presetType: PRESET_TYPES.WEEKS,
timeframe: timeframeWeeks, timeframe: timeframeWeeks,
...@@ -451,8 +180,8 @@ describe('getEpicsTimeframeRange', () => { ...@@ -451,8 +180,8 @@ describe('getEpicsTimeframeRange', () => {
expect(range).toEqual( expect(range).toEqual(
expect.objectContaining({ expect.objectContaining({
timeframe: { timeframe: {
start: '2017-12-17', start: '2017-12-31',
end: '2018-02-03', end: '2018-03-31',
}, },
}), }),
); );
......
...@@ -16215,12 +16215,6 @@ msgstr "" ...@@ -16215,12 +16215,6 @@ msgstr ""
msgid "GroupRoadmap|No start date – %{dateWord}" msgid "GroupRoadmap|No start date – %{dateWord}"
msgstr "" msgstr ""
msgid "GroupRoadmap|Roadmaps can display up to 1,000 epics. These appear in your selected sort order."
msgstr ""
msgid "GroupRoadmap|Some of your epics might not be visible"
msgstr ""
msgid "GroupRoadmap|Something went wrong while fetching epics" msgid "GroupRoadmap|Something went wrong while fetching epics"
msgstr "" msgstr ""
......
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