Commit 1ed1fe07 authored by Florie Guibert's avatar Florie Guibert

Roadmap settings - Turn off progress tracking

Allow user to turn off progress tracking on roadmap
parent b4bdcd48
...@@ -57,7 +57,7 @@ export default { ...@@ -57,7 +57,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState(['progressTracking']), ...mapState(['progressTracking', 'isProgressTrackingActive']),
timelineBarInnerStyle() { timelineBarInnerStyle() {
return { return {
maxWidth: `${this.clientWidth - EPIC_DETAILS_CELL_WIDTH}px`, maxWidth: `${this.clientWidth - EPIC_DETAILS_CELL_WIDTH}px`,
...@@ -141,7 +141,10 @@ export default { ...@@ -141,7 +141,10 @@ export default {
<div class="epic-bar-inner gl-px-3 gl-py-2" :style="timelineBarInnerStyle"> <div class="epic-bar-inner gl-px-3 gl-py-2" :style="timelineBarInnerStyle">
<p class="epic-bar-title gl-text-truncate gl-m-0">{{ timelineBarTitle }}</p> <p class="epic-bar-title gl-text-truncate gl-m-0">{{ timelineBarTitle }}</p>
<div v-if="!isTimelineBarSmall" class="gl-display-flex gl-align-items-center"> <div
v-if="!isTimelineBarSmall && isProgressTrackingActive"
class="gl-display-flex gl-align-items-center"
>
<gl-progress-bar <gl-progress-bar
class="epic-bar-progress gl-flex-grow-1 gl-mr-2" class="epic-bar-progress gl-flex-grow-1 gl-mr-2"
:value="epicPercentage" :value="epicPercentage"
......
...@@ -76,6 +76,7 @@ export default { ...@@ -76,6 +76,7 @@ export default {
'epicsState', 'epicsState',
'sortedBy', 'sortedBy',
'filterParams', 'filterParams',
'isProgressTrackingActive',
'progressTracking', 'progressTracking',
'isShowingMilestones', 'isShowingMilestones',
'milestonesType', 'milestonesType',
......
<script> <script>
import { GlFormGroup, GlFormRadioGroup } from '@gitlab/ui'; import { GlFormGroup, GlFormRadioGroup, GlToggle } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale'; import { __ } from '~/locale';
...@@ -9,12 +9,13 @@ export default { ...@@ -9,12 +9,13 @@ export default {
components: { components: {
GlFormGroup, GlFormGroup,
GlFormRadioGroup, GlFormRadioGroup,
GlToggle,
}, },
computed: { computed: {
...mapState(['progressTracking']), ...mapState(['progressTracking', 'isProgressTrackingActive']),
}, },
methods: { methods: {
...mapActions(['setProgressTracking']), ...mapActions(['setProgressTracking', 'toggleProgressTrackingActive']),
handleProgressTrackingChange(option) { handleProgressTrackingChange(option) {
if (option !== this.progressTracking) { if (option !== this.progressTracking) {
this.setProgressTracking(option); this.setProgressTracking(option);
...@@ -23,6 +24,7 @@ export default { ...@@ -23,6 +24,7 @@ export default {
}, },
i18n: { i18n: {
header: __('Progress tracking'), header: __('Progress tracking'),
toggleLabel: __('Display progress of child issues'),
}, },
PROGRESS_TRACKING_OPTIONS, PROGRESS_TRACKING_OPTIONS,
}; };
...@@ -35,10 +37,24 @@ export default { ...@@ -35,10 +37,24 @@ export default {
:label="$options.i18n.header" :label="$options.i18n.header"
data-testid="roadmap-progress-tracking" data-testid="roadmap-progress-tracking"
> >
<label for="toggle-progress-tracking" class="gl-font-weight-normal">
{{ $options.i18n.toggleLabel }}
</label>
<gl-toggle
id="toggle-progress-tracking"
:value="isProgressTrackingActive"
:label="$options.i18n.toggleLabel"
label-position="hidden"
aria-describedby="toggleTrackingProgress"
data-testid="toggle-progress-tracking"
@change="toggleProgressTrackingActive"
/>
<gl-form-radio-group <gl-form-radio-group
v-if="isProgressTrackingActive"
:checked="progressTracking" :checked="progressTracking"
stacked stacked
:options="$options.PROGRESS_TRACKING_OPTIONS" :options="$options.PROGRESS_TRACKING_OPTIONS"
class="gl-mt-3"
@change="handleProgressTrackingChange" @change="handleProgressTrackingChange"
/> />
</gl-form-group> </gl-form-group>
......
...@@ -53,6 +53,7 @@ export default { ...@@ -53,6 +53,7 @@ export default {
'not[author_username]': notAuthorUsername, 'not[author_username]': notAuthorUsername,
'not[my_reaction_emoji]': notMyReactionEmoji, 'not[my_reaction_emoji]': notMyReactionEmoji,
'not[label_name][]': notLabelName, 'not[label_name][]': notLabelName,
showProgress: this.isProgressTrackingActive,
progress: this.progressTracking, progress: this.progressTracking,
show_milestones: this.isShowingMilestones, show_milestones: this.isShowingMilestones,
milestones_type: this.milestonesType, milestones_type: this.milestonesType,
......
...@@ -109,6 +109,10 @@ export default () => { ...@@ -109,6 +109,10 @@ export default () => {
presetType, presetType,
timeframe, timeframe,
progressTracking: rawFilterParams.progress || PROGRESS_WEIGHT, progressTracking: rawFilterParams.progress || PROGRESS_WEIGHT,
isProgressTrackingActive:
rawFilterParams.showProgress === undefined
? true
: parseBoolean(rawFilterParams.showProgress),
isShowingMilestones: isShowingMilestones:
rawFilterParams.show_milestones === undefined rawFilterParams.show_milestones === undefined
? true ? true
...@@ -132,6 +136,7 @@ export default () => { ...@@ -132,6 +136,7 @@ export default () => {
isChildEpics: this.isChildEpics, isChildEpics: this.isChildEpics,
hasFiltersApplied: this.hasFiltersApplied, hasFiltersApplied: this.hasFiltersApplied,
allowSubEpics: this.allowSubEpics, allowSubEpics: this.allowSubEpics,
isProgressTrackingActive: this.isProgressTrackingActive,
progressTracking: this.progressTracking, progressTracking: this.progressTracking,
isShowingMilestones: this.isShowingMilestones, isShowingMilestones: this.isShowingMilestones,
milestonesType: this.milestonesType, milestonesType: this.milestonesType,
......
...@@ -330,6 +330,9 @@ export const setSortedBy = ({ commit }, sortedBy) => commit(types.SET_SORTED_BY, ...@@ -330,6 +330,9 @@ export const setSortedBy = ({ commit }, sortedBy) => commit(types.SET_SORTED_BY,
export const setProgressTracking = ({ commit }, progressTracking) => export const setProgressTracking = ({ commit }, progressTracking) =>
commit(types.SET_PROGRESS_TRACKING, progressTracking); commit(types.SET_PROGRESS_TRACKING, progressTracking);
export const toggleProgressTrackingActive = ({ commit }) =>
commit(types.TOGGLE_PROGRESS_TRACKING_ACTIVE);
export const setMilestonesType = ({ commit }, milestonesType) => export const setMilestonesType = ({ commit }, milestonesType) =>
commit(types.SET_MILESTONES_TYPE, milestonesType); commit(types.SET_MILESTONES_TYPE, milestonesType);
......
...@@ -33,5 +33,6 @@ export const SET_DATERANGE = 'SET_DATERANGE'; ...@@ -33,5 +33,6 @@ export const SET_DATERANGE = 'SET_DATERANGE';
export const SET_FILTER_PARAMS = 'SET_FILTER_PARAMS'; export const SET_FILTER_PARAMS = 'SET_FILTER_PARAMS';
export const SET_SORTED_BY = 'SET_SORTED_BY'; export const SET_SORTED_BY = 'SET_SORTED_BY';
export const SET_PROGRESS_TRACKING = 'SET_PROGRESS_TRACKING'; export const SET_PROGRESS_TRACKING = 'SET_PROGRESS_TRACKING';
export const TOGGLE_PROGRESS_TRACKING_ACTIVE = 'TOGGLE_PROGRESS_TRACKING_ACTIVE';
export const SET_MILESTONES_TYPE = 'SET_MILESTONES_TYPE'; export const SET_MILESTONES_TYPE = 'SET_MILESTONES_TYPE';
export const TOGGLE_MILESTONES = 'TOGGLE_MILESTONES'; export const TOGGLE_MILESTONES = 'TOGGLE_MILESTONES';
...@@ -145,6 +145,10 @@ export default { ...@@ -145,6 +145,10 @@ export default {
state.progressTracking = progressTracking; state.progressTracking = progressTracking;
}, },
[types.TOGGLE_PROGRESS_TRACKING_ACTIVE](state) {
state.isProgressTrackingActive = !state.isProgressTrackingActive;
},
[types.SET_MILESTONES_TYPE](state, milestonesType) { [types.SET_MILESTONES_TYPE](state, milestonesType) {
state.milestonesType = milestonesType; state.milestonesType = milestonesType;
}, },
......
...@@ -3,6 +3,7 @@ export default () => ({ ...@@ -3,6 +3,7 @@ export default () => ({
basePath: '', basePath: '',
epicsState: '', epicsState: '',
progressTracking: '', progressTracking: '',
isProgressTrackingActive: true,
filterParams: null, filterParams: null,
isShowingMilestones: true, isShowingMilestones: true,
milestonesType: '', milestonesType: '',
......
...@@ -247,6 +247,48 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -247,6 +247,48 @@ RSpec.describe 'group epic roadmap', :js do
end end
end end
describe 'roadmap with epics progress tracking' do
def select_progress_tracking(tracking)
page.within('[data-testid="roadmap-progress-tracking"]') do
choose tracking
end
end
before do
open_settings_sidebar
end
it 'renders progress bar using weight' do
select_progress_tracking('Use issue weight')
page.within('.roadmap-container .epics-list-section') do
expect(page).to have_selector('.epic-bar-progress', count: 3)
expect(page).to have_selector('[data-testid="weight-icon"]', count: 3)
end
end
it 'renders progress bar issue count' do
select_progress_tracking('Use issue count')
page.within('.roadmap-container .epics-list-section') do
expect(page).to have_selector('.epic-bar-progress', count: 3)
expect(page).to have_selector('[data-testid="issue-closed-icon"]', count: 3)
end
end
it 'turns off progress tracking' do
page.within('[data-testid="roadmap-progress-tracking"]') do
find('[data-testid="toggle-progress-tracking"]').click
end
page.within('.roadmap-container .epics-list-section') do
expect(page).not_to have_selector('.epic-bar-progress')
expect(page).not_to have_selector('[data-testid="issue-closed-icon"]')
expect(page).not_to have_selector('[data-testid="weight-icon"]')
end
end
end
describe 'roadmap milestones settings' do describe 'roadmap milestones settings' do
def select_milestones(milestones) def select_milestones(milestones)
page.within('[data-testid="roadmap-milestones-settings"]') do page.within('[data-testid="roadmap-milestones-settings"]') do
......
...@@ -23,11 +23,13 @@ const createComponent = ({ ...@@ -23,11 +23,13 @@ const createComponent = ({
timeframeItem = mockTimeframeMonths[0], timeframeItem = mockTimeframeMonths[0],
timeframeString = '', timeframeString = '',
progressTracking = PROGRESS_WEIGHT, progressTracking = PROGRESS_WEIGHT,
isProgressTrackingActive = true,
} = {}) => { } = {}) => {
const store = createStore(); const store = createStore();
store.dispatch('setInitialData', { store.dispatch('setInitialData', {
progressTracking, progressTracking,
isProgressTrackingActive,
}); });
return shallowMount(EpicItemTimeline, { return shallowMount(EpicItemTimeline, {
...@@ -75,6 +77,16 @@ describe('EpicItemTimelineComponent', () => { ...@@ -75,6 +77,16 @@ describe('EpicItemTimelineComponent', () => {
expect(getEpicBar(wrapper).attributes('href')).toBe(mockFormattedEpic.webUrl); expect(getEpicBar(wrapper).attributes('href')).toBe(mockFormattedEpic.webUrl);
}); });
it.each`
isProgressTrackingActive
${true}
${false}
`('displays tracking depending on isProgressTrackingActive', ({ isProgressTrackingActive }) => {
wrapper = createComponent({ isProgressTrackingActive });
expect(wrapper.findComponent(GlProgressBar).exists()).toBe(isProgressTrackingActive);
});
it.each` it.each`
progressTracking | icon progressTracking | icon
${PROGRESS_WEIGHT} | ${'weight'} ${PROGRESS_WEIGHT} | ${'weight'}
......
...@@ -61,6 +61,7 @@ const createComponent = ({ ...@@ -61,6 +61,7 @@ const createComponent = ({
sortedBy, sortedBy,
filterParams, filterParams,
timeframe, timeframe,
isProgressTrackingActive: true,
progressTracking: PROGRESS_WEIGHT, progressTracking: PROGRESS_WEIGHT,
milestonesType: MILESTONES_ALL, milestonesType: MILESTONES_ALL,
}); });
...@@ -124,7 +125,7 @@ describe('RoadmapFilters', () => { ...@@ -124,7 +125,7 @@ describe('RoadmapFilters', () => {
await nextTick(); await nextTick();
expect(global.window.location.href).toBe( expect(global.window.location.href).toBe(
`${TEST_HOST}/?state=${EPICS_STATES.CLOSED}&sort=end_date_asc&layout=MONTHS&author_username=root&label_name%5B%5D=Bug&milestone_title=4.0&confidential=true&progress=WEIGHT&show_milestones=true&milestones_type=ALL`, `${TEST_HOST}/?state=${EPICS_STATES.CLOSED}&sort=end_date_asc&layout=MONTHS&author_username=root&label_name%5B%5D=Bug&milestone_title=4.0&confidential=true&showProgress=true&progress=WEIGHT&show_milestones=true&milestones_type=ALL`,
); );
}); });
}); });
......
...@@ -8,11 +8,12 @@ import { PROGRESS_WEIGHT, PROGRESS_TRACKING_OPTIONS } from 'ee/roadmap/constants ...@@ -8,11 +8,12 @@ import { PROGRESS_WEIGHT, PROGRESS_TRACKING_OPTIONS } from 'ee/roadmap/constants
describe('RoadmapProgressTracking', () => { describe('RoadmapProgressTracking', () => {
let wrapper; let wrapper;
const createComponent = () => { const createComponent = ({ isProgressTrackingActive = true } = {}) => {
const store = createStore(); const store = createStore();
store.dispatch('setInitialData', { store.dispatch('setInitialData', {
progressTracking: PROGRESS_WEIGHT, progressTracking: PROGRESS_WEIGHT,
isProgressTrackingActive,
}); });
wrapper = shallowMountExtended(RoadmapProgressTracking, { wrapper = shallowMountExtended(RoadmapProgressTracking, {
...@@ -37,9 +38,20 @@ describe('RoadmapProgressTracking', () => { ...@@ -37,9 +38,20 @@ describe('RoadmapProgressTracking', () => {
expect(findFormGroup().attributes('label')).toBe('Progress tracking'); expect(findFormGroup().attributes('label')).toBe('Progress tracking');
}); });
it('renders radio form group', () => { it.each`
expect(findFormRadioGroup().exists()).toBe(true); isProgressTrackingActive
${true}
${false}
`(
'displays radio form group depending on isProgressTrackingActive',
({ isProgressTrackingActive }) => {
createComponent({ isProgressTrackingActive });
expect(findFormRadioGroup().exists()).toBe(isProgressTrackingActive);
if (isProgressTrackingActive) {
expect(findFormRadioGroup().props('options')).toEqual(PROGRESS_TRACKING_OPTIONS); expect(findFormRadioGroup().props('options')).toEqual(PROGRESS_TRACKING_OPTIONS);
}); }
},
);
}); });
}); });
...@@ -673,6 +673,18 @@ describe('Roadmap Vuex Actions', () => { ...@@ -673,6 +673,18 @@ describe('Roadmap Vuex Actions', () => {
}); });
}); });
describe('toggleProgressTrackingActive', () => {
it('commit TOGGLE_PROGRESS_TRACKING_ACTIVE mutation', () => {
return testAction(
actions.toggleProgressTrackingActive,
undefined,
state,
[{ type: types.TOGGLE_PROGRESS_TRACKING_ACTIVE }],
[],
);
});
});
describe('setMilestonesType', () => { describe('setMilestonesType', () => {
it('should set milestonesType in store state', () => { it('should set milestonesType in store state', () => {
return testAction( return testAction(
......
...@@ -347,7 +347,6 @@ describe('Roadmap Store Mutations', () => { ...@@ -347,7 +347,6 @@ describe('Roadmap Store Mutations', () => {
describe('SET_PROGRESS_TRACKING', () => { describe('SET_PROGRESS_TRACKING', () => {
it('Should set `progressTracking` to the state', () => { it('Should set `progressTracking` to the state', () => {
const progressTracking = PROGRESS_COUNT; const progressTracking = PROGRESS_COUNT;
setEpicMockData(state);
mutations[types.SET_PROGRESS_TRACKING](state, progressTracking); mutations[types.SET_PROGRESS_TRACKING](state, progressTracking);
...@@ -357,6 +356,20 @@ describe('Roadmap Store Mutations', () => { ...@@ -357,6 +356,20 @@ describe('Roadmap Store Mutations', () => {
}); });
}); });
describe('TOGGLE_PROGRESS_TRACKING_ACTIVE', () => {
it('Should toggle `progressTracking` on state', () => {
expect(state).toMatchObject({
isProgressTrackingActive: true,
});
mutations[types.TOGGLE_PROGRESS_TRACKING_ACTIVE](state);
expect(state).toMatchObject({
isProgressTrackingActive: false,
});
});
});
describe('SET_MILESTONES_TYPE', () => { describe('SET_MILESTONES_TYPE', () => {
it('Should set `milestonesType` to the state', () => { it('Should set `milestonesType` to the state', () => {
const milestonesType = MILESTONES_GROUP; const milestonesType = MILESTONES_GROUP;
......
...@@ -12869,6 +12869,9 @@ msgstr "" ...@@ -12869,6 +12869,9 @@ msgstr ""
msgid "Display name" msgid "Display name"
msgstr "" msgstr ""
msgid "Display progress of child issues"
msgstr ""
msgid "Display rendered file" msgid "Display rendered file"
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