Commit 5ed9be1c authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '345158-roadmap-settings-daterange' into 'master'

Roadmap setting - Move daterange to sidebar

See merge request gitlab-org/gitlab!79084
parents ae702ccd 32643d14
...@@ -115,6 +115,7 @@ export default { ...@@ -115,6 +115,7 @@ export default {
<roadmap-settings <roadmap-settings
v-if="glFeatures.roadmapSettings" v-if="glFeatures.roadmapSettings"
:is-open="isSettingsSidebarOpen" :is-open="isSettingsSidebarOpen"
:timeframe-range-type="timeframeRangeType"
data-testid="roadmap-settings" data-testid="roadmap-settings"
@toggleSettings="toggleSettings" @toggleSettings="toggleSettings"
/> />
......
<script>
import { GlFormGroup, GlFormRadioGroup, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { mapState } from 'vuex';
import { visitUrl, mergeUrlParams } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import { PRESET_TYPES, DATE_RANGES } from '../constants';
import { getPresetTypeForTimeframeRangeType } from '../utils/roadmap_utils';
export default {
availableDateRanges: [
{ text: s__('GroupRoadmap|This quarter'), value: DATE_RANGES.CURRENT_QUARTER },
{ text: s__('GroupRoadmap|This year'), value: DATE_RANGES.CURRENT_YEAR },
{ text: s__('GroupRoadmap|Within 3 years'), value: DATE_RANGES.THREE_YEARS },
],
components: {
GlFormGroup,
GlFormRadioGroup,
GlDropdown,
GlDropdownItem,
},
props: {
timeframeRangeType: {
type: String,
required: true,
},
},
data() {
return {
selectedDaterange: this.timeframeRangeType,
};
},
computed: {
...mapState(['presetType']),
daterangeDropdownText() {
switch (this.selectedDaterange) {
case DATE_RANGES.CURRENT_QUARTER:
return s__('GroupRoadmap|This quarter');
case DATE_RANGES.CURRENT_YEAR:
return s__('GroupRoadmap|This year');
case DATE_RANGES.THREE_YEARS:
return s__('GroupRoadmap|Within 3 years');
default:
return '';
}
},
availablePresets() {
const quarters = { text: __('By quarter'), value: PRESET_TYPES.QUARTERS };
const months = { text: __('By month'), value: PRESET_TYPES.MONTHS };
const weeks = { text: __('By week'), value: PRESET_TYPES.WEEKS };
if (this.selectedDaterange === DATE_RANGES.CURRENT_YEAR) {
return [months, weeks];
} else if (this.selectedDaterange === DATE_RANGES.THREE_YEARS) {
return [quarters, months, weeks];
}
return [];
},
},
methods: {
handleDaterangeSelect(value) {
this.selectedDaterange = value;
},
handleDaterangeDropdownOpen() {
this.initialSelectedDaterange = this.selectedDaterange;
},
handleDaterangeDropdownClose() {
if (this.initialSelectedDaterange !== this.selectedDaterange) {
visitUrl(
mergeUrlParams(
{
timeframe_range_type: this.selectedDaterange,
layout: getPresetTypeForTimeframeRangeType(this.selectedDaterange),
},
window.location.href,
),
);
}
},
handleRoadmapLayoutChange(presetType) {
visitUrl(
mergeUrlParams(
{ timeframe_range_type: this.selectedDaterange, layout: presetType },
window.location.href,
),
);
},
},
i18n: {
header: __('Date range'),
},
};
</script>
<template>
<div>
<label for="roadmap-daterange" class="gl-display-block">{{ $options.i18n.header }}</label>
<gl-dropdown
id="roadmap-daterange"
icon="calendar"
class="gl-mb-3 roadmap-daterange-dropdown"
toggle-class="gl-rounded-base!"
:text="daterangeDropdownText"
data-testid="daterange-dropdown"
@show="handleDaterangeDropdownOpen"
@hide="handleDaterangeDropdownClose"
>
<gl-dropdown-item
v-for="dateRange in $options.availableDateRanges"
:key="dateRange.value"
:value="dateRange.value"
@click="handleDaterangeSelect(dateRange.value)"
>
{{ dateRange.text }}
</gl-dropdown-item>
</gl-dropdown>
<gl-form-group v-if="availablePresets.length">
<gl-form-radio-group
:checked="presetType"
stacked
:options="availablePresets"
@change="handleRoadmapLayoutChange"
/>
</gl-form-group>
</div>
</template>
...@@ -176,6 +176,7 @@ export default { ...@@ -176,6 +176,7 @@ 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.roadmapSettings"
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!"
...@@ -192,7 +193,10 @@ export default { ...@@ -192,7 +193,10 @@ export default {
>{{ dateRange.text }}</gl-dropdown-item >{{ dateRange.text }}</gl-dropdown-item
> >
</gl-dropdown> </gl-dropdown>
<gl-form-group v-if="availablePresets.length" class="gl-mr-0 gl-lg-mr-3 mb-sm-2"> <gl-form-group
v-if="availablePresets.length && !glFeatures.roadmapSettings"
class="gl-mr-0 gl-lg-mr-3 mb-sm-2"
>
<gl-segmented-control <gl-segmented-control
:checked="presetType" :checked="presetType"
:options="availablePresets" :options="availablePresets"
......
<script> <script>
import { GlDrawer } from '@gitlab/ui'; import { GlDrawer } from '@gitlab/ui';
import RoadmapDaterange from './roadmap_daterange.vue';
export default { export default {
components: { components: {
GlDrawer, GlDrawer,
RoadmapDaterange,
}, },
props: { props: {
isOpen: { isOpen: {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
timeframeRangeType: {
type: String,
required: true,
},
}, },
methods: { methods: {
getDrawerHeaderHeight() { getDrawerHeaderHeight() {
...@@ -36,5 +42,8 @@ export default { ...@@ -36,5 +42,8 @@ export default {
<template #title> <template #title>
<h2 class="gl-my-0 gl-font-size-h2 gl-line-height-24">{{ __('Roadmap settings') }}</h2> <h2 class="gl-my-0 gl-font-size-h2 gl-line-height-24">{{ __('Roadmap settings') }}</h2>
</template> </template>
<template #default>
<roadmap-daterange :timeframe-range-type="timeframeRangeType" />
</template>
</gl-drawer> </gl-drawer>
</template> </template>
...@@ -46,19 +46,18 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -46,19 +46,18 @@ RSpec.describe 'group epic roadmap', :js do
sign_in(user) sign_in(user)
end end
context 'when epics exist for the group' do context 'with roadmap_settings feature flag off' do
available_tokens = %w[Author Label Milestone Epic My-Reaction]
let!(:epic_with_bug) { create(:labeled_epic, group: group, start_date: 10.days.ago, end_date: 1.day.ago, labels: [bug_label]) } let!(:epic_with_bug) { create(:labeled_epic, group: group, start_date: 10.days.ago, end_date: 1.day.ago, labels: [bug_label]) }
let!(:epic_with_critical) { create(:labeled_epic, group: group, start_date: 20.days.ago, end_date: 2.days.ago, labels: [critical_label]) } let!(:epic_with_critical) { create(:labeled_epic, group: group, start_date: 20.days.ago, end_date: 2.days.ago, labels: [critical_label]) }
let!(:closed_epic) { create(:epic, :closed, group: group, start_date: 20.days.ago, end_date: 2.days.ago) } let!(:closed_epic) { create(:epic, :closed, group: group, start_date: 20.days.ago, end_date: 2.days.ago) }
before do before do
stub_feature_flags(roadmap_settings: false)
visit group_roadmap_path(group) visit group_roadmap_path(group)
wait_for_requests wait_for_requests
end end
describe 'roadmap page' do
context 'roadmap daterange filtering' do context 'roadmap daterange filtering' do
def select_date_range(range_type) def select_date_range(range_type)
page.within('.epics-roadmap-filters') do page.within('.epics-roadmap-filters') do
...@@ -96,6 +95,69 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -96,6 +95,69 @@ RSpec.describe 'group epic roadmap', :js do
end end
end end
end end
end
context 'when epics exist for the group' do
available_tokens = %w[Author Label Milestone Epic My-Reaction]
let!(:epic_with_bug) { create(:labeled_epic, group: group, start_date: 10.days.ago, end_date: 1.day.ago, labels: [bug_label]) }
let!(:epic_with_critical) { create(:labeled_epic, group: group, start_date: 20.days.ago, end_date: 2.days.ago, labels: [critical_label]) }
let!(:closed_epic) { create(:epic, :closed, group: group, start_date: 20.days.ago, end_date: 2.days.ago) }
before do
visit group_roadmap_path(group)
wait_for_requests
end
describe 'roadmap page' do
context 'roadmap daterange filtering' do
def open_settings_sidebar
click_button 'Settings'
expect(page).to have_selector('[data-testid="roadmap-settings"]')
end
def select_date_range(range_type)
open_settings_sidebar
page.within('[data-testid="roadmap-settings"]') do
page.find('[data-testid="daterange-dropdown"] button.dropdown-toggle').click
click_button(range_type)
end
open_settings_sidebar
end
it 'renders daterange filtering dropdown with "This quarter" selected by default no layout presets available', :aggregate_failures do
open_settings_sidebar
page.within('[data-testid="roadmap-settings"]') do
expect(page).to have_selector('[data-testid="daterange-dropdown"]')
expect(page).not_to have_selector('.gl-form-checkbox-group')
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('[data-testid="roadmap-settings"]') do
expect(page).to have_selector('.gl-form-checkbox-group')
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('[data-testid="roadmap-settings"]') do
expect(page).to have_selector('.gl-form-checkbox-group')
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 it 'renders the epics state dropdown' do
page.within('.content-wrapper .content .epics-filters') do page.within('.content-wrapper .content .epics-filters') do
......
import { GlDropdown, GlFormGroup, GlFormRadioGroup } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createStore from 'ee/roadmap/store';
import RoadmapDaterange from 'ee/roadmap/components/roadmap_daterange.vue';
import { DATE_RANGES, PRESET_TYPES } from 'ee/roadmap/constants';
describe('RoadmapDaterange', () => {
let wrapper;
const quarters = { text: 'By quarter', value: PRESET_TYPES.QUARTERS };
const months = { text: 'By month', value: PRESET_TYPES.MONTHS };
const weeks = { text: 'By week', value: PRESET_TYPES.WEEKS };
const createComponent = ({ timeframeRangeType = DATE_RANGES.CURRENT_QUARTER } = {}) => {
const store = createStore();
store.dispatch('setInitialData', {
presetType: PRESET_TYPES.MONTHS,
});
wrapper = shallowMountExtended(RoadmapDaterange, {
store,
propsData: { timeframeRangeType },
});
};
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findFormGroup = () => wrapper.findComponent(GlFormGroup);
const findFormRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('template', () => {
it('renders labels', () => {
expect(wrapper.find('label').exists()).toBe(true);
expect(wrapper.find('label').text()).toContain('Date range');
});
it('renders dropdown', () => {
expect(findDropdown().exists()).toBe(true);
});
it.each`
timeframeRangeType | hasFormGroup | availablePresets
${DATE_RANGES.CURRENT_QUARTER} | ${false} | ${[]}
${DATE_RANGES.CURRENT_YEAR} | ${true} | ${[months, weeks]}
${DATE_RANGES.THREE_YEARS} | ${true} | ${[quarters, months, weeks]}
`(
'renders radio group depending on timeframeRangeType',
async ({ timeframeRangeType, hasFormGroup, availablePresets }) => {
createComponent({ timeframeRangeType });
await nextTick();
expect(findFormGroup().exists()).toBe(hasFormGroup);
if (hasFormGroup) {
expect(findFormRadioGroup().props('options')).toEqual(availablePresets);
}
},
);
});
});
import { GlDrawer } from '@gitlab/ui'; import { GlDrawer } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import RoadmapSettings from 'ee/roadmap/components/roadmap_settings.vue'; import RoadmapSettings from 'ee/roadmap/components/roadmap_settings.vue';
import RoadmapDaterange from 'ee/roadmap/components/roadmap_daterange.vue';
describe('RoadmapSettings', () => { describe('RoadmapSettings', () => {
let wrapper; let wrapper;
const createComponent = ({ isOpen = false } = {}) => { const createComponent = ({ isOpen = false } = {}) => {
wrapper = shallowMountExtended(RoadmapSettings, { wrapper = shallowMountExtended(RoadmapSettings, {
propsData: { isOpen }, propsData: { isOpen, timeframeRangeType: 'CURRENT_QUARTER' },
}); });
}; };
const findSettingsDrawer = () => wrapper.findComponent(GlDrawer); const findSettingsDrawer = () => wrapper.findComponent(GlDrawer);
const findDaterange = () => wrapper.findComponent(RoadmapDaterange);
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
...@@ -22,9 +24,13 @@ describe('RoadmapSettings', () => { ...@@ -22,9 +24,13 @@ describe('RoadmapSettings', () => {
}); });
describe('template', () => { describe('template', () => {
it('render drawer and title', () => { it('renders drawer and title', () => {
expect(findSettingsDrawer().exists()).toBe(true); expect(findSettingsDrawer().exists()).toBe(true);
expect(findSettingsDrawer().text()).toContain('Roadmap settings'); expect(findSettingsDrawer().text()).toContain('Roadmap settings');
}); });
it('renders roadmap daterange component', () => {
expect(findDaterange().exists()).toBe(true);
});
}); });
}); });
...@@ -6228,6 +6228,15 @@ msgstr "" ...@@ -6228,6 +6228,15 @@ msgstr ""
msgid "By default, all projects and groups will use the global notifications setting." msgid "By default, all projects and groups will use the global notifications setting."
msgstr "" msgstr ""
msgid "By month"
msgstr ""
msgid "By quarter"
msgstr ""
msgid "By week"
msgstr ""
msgid "ByAuthor|by" msgid "ByAuthor|by"
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