Commit f0cdb931 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '349739-roadmap-turn-off-progress-tracking' into 'master'

Roadmap settings - Turn off progress tracking

See merge request gitlab-org/gitlab!80124
parents 6cd95f58 fed9726a
...@@ -200,6 +200,12 @@ ...@@ -200,6 +200,12 @@
} }
} }
.gl-xl-ml-3 {
@include media-breakpoint-up(lg) {
margin-left: $gl-spacing-scale-3;
}
}
.gl-mb-n3 { .gl-mb-n3 {
margin-bottom: -$gl-spacing-scale-3; margin-bottom: -$gl-spacing-scale-3;
} }
......
...@@ -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"
......
...@@ -82,7 +82,7 @@ export default { ...@@ -82,7 +82,7 @@ export default {
:timeframe-range-type="timeframeRangeType" :timeframe-range-type="timeframeRangeType"
@toggleSettings="toggleSettings" @toggleSettings="toggleSettings"
/> />
<div :class="{ 'overflow-reset': epicsFetchResultEmpty }" class="roadmap-container"> <div :class="{ 'overflow-reset': epicsFetchResultEmpty }" class="roadmap-container gl-relative">
<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
v-else-if="epicsFetchResultEmpty" v-else-if="epicsFetchResultEmpty"
......
...@@ -94,7 +94,7 @@ export default { ...@@ -94,7 +94,7 @@ export default {
<gl-dropdown <gl-dropdown
id="roadmap-daterange" id="roadmap-daterange"
icon="calendar" icon="calendar"
class="gl-mb-3 roadmap-daterange-dropdown" class="roadmap-daterange-dropdown"
toggle-class="gl-rounded-base!" toggle-class="gl-rounded-base!"
:text="daterangeDropdownText" :text="daterangeDropdownText"
data-testid="daterange-dropdown" data-testid="daterange-dropdown"
...@@ -110,7 +110,7 @@ export default { ...@@ -110,7 +110,7 @@ export default {
{{ dateRange.text }} {{ dateRange.text }}
</gl-dropdown-item> </gl-dropdown-item>
</gl-dropdown> </gl-dropdown>
<gl-form-group v-if="availablePresets.length" class="gl-mb-0"> <gl-form-group v-if="availablePresets.length" class="gl-mb-0 gl-mt-3">
<gl-form-radio-group <gl-form-radio-group
data-testid="daterange-presets" data-testid="daterange-presets"
:checked="presetType" :checked="presetType"
......
...@@ -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',
...@@ -254,7 +255,7 @@ export default { ...@@ -254,7 +255,7 @@ export default {
<gl-button <gl-button
v-if="glFeatures.roadmapSettings" v-if="glFeatures.roadmapSettings"
icon="settings" icon="settings"
class="gl-mb-3 gl-lg-ml-3 gl-sm-mt-3" class="gl-mb-3 gl-xl-ml-3 gl-inset-border-1-gray-400!"
:aria-label="$options.i18n.settings" :aria-label="$options.i18n.settings"
data-testid="settings-button" data-testid="settings-button"
@click="$emit('toggleSettings', $event)" @click="$emit('toggleSettings', $event)"
......
<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,
}; };
...@@ -33,12 +35,24 @@ export default { ...@@ -33,12 +35,24 @@ export default {
<gl-form-group <gl-form-group
class="gl-mb-0" class="gl-mb-0"
:label="$options.i18n.header" :label="$options.i18n.header"
label-class="gl-pb-2!"
data-testid="roadmap-progress-tracking" data-testid="roadmap-progress-tracking"
> >
<gl-toggle
:value="isProgressTrackingActive"
:label="$options.i18n.toggleLabel"
@change="toggleProgressTrackingActive"
>
<template #label>
<span class="gl-font-weight-normal">{{ $options.i18n.toggleLabel }}</span>
</template>
</gl-toggle>
<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>
......
...@@ -23,18 +23,6 @@ export default { ...@@ -23,18 +23,6 @@ export default {
required: true, required: true,
}, },
}, },
methods: {
getDrawerHeaderHeight() {
const wrapperEl = document.querySelector('.roadmap-container');
if (wrapperEl) {
const topPosition = wrapperEl.getBoundingClientRect().top + window.pageYOffset;
return `${topPosition}px`;
}
return '';
},
},
}; };
</script> </script>
...@@ -42,7 +30,7 @@ export default { ...@@ -42,7 +30,7 @@ export default {
<gl-drawer <gl-drawer
v-bind="$attrs" v-bind="$attrs"
:open="isOpen" :open="isOpen"
:header-height="getDrawerHeaderHeight()" class="gl-absolute"
@close="$emit('toggleSettings', $event)" @close="$emit('toggleSettings', $event)"
> >
<template #title> <template #title>
......
...@@ -54,6 +54,7 @@ export default { ...@@ -54,6 +54,7 @@ export default {
'not[my_reaction_emoji]': notMyReactionEmoji, 'not[my_reaction_emoji]': notMyReactionEmoji,
'not[label_name][]': notLabelName, 'not[label_name][]': notLabelName,
progress: this.progressTracking, progress: this.progressTracking,
show_progress: this.isProgressTrackingActive,
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.show_progress === undefined
? true
: parseBoolean(rawFilterParams.show_progress),
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: '',
......
...@@ -525,11 +525,9 @@ html.group-epics-roadmap-html { ...@@ -525,11 +525,9 @@ html.group-epics-roadmap-html {
.sort-dropdown-container { .sort-dropdown-container {
// This override is needed to make sort-dropdown have same height // This override is needed to make sort-dropdown have same height
// as filtered search bar. // as filtered search bar.
@include media-breakpoint-up(sm) {
.dropdown, .dropdown,
> button { > button {
margin-bottom: $gl-padding-8; margin-bottom: $gl-padding-8;
} }
} }
}
} }
...@@ -247,6 +247,43 @@ RSpec.describe 'group epic roadmap', :js do ...@@ -247,6 +247,43 @@ RSpec.describe 'group epic roadmap', :js do
end end
end end
describe 'roadmap with epics progress tracking' do
def wait_for_epics(count, icon)
page.within('.roadmap-container .epics-list-section') do
expect(page).to have_selector('.epic-bar-progress', count: count)
expect(page).to have_selector("[data-testid='#{icon}']", count: count)
end
end
before do
open_settings_sidebar
end
it 'renders progress bar using weight', :aggregate_failures do
choose 'Use issue weight'
wait_for_epics(3, "weight-icon")
end
it 'renders progress bar issue count', :aggregate_failures do
choose 'Use issue count'
wait_for_epics(3, "issue-closed-icon")
end
it 'turns off progress tracking', :aggregate_failures do
page.within('[data-testid="roadmap-progress-tracking"]') do
click_button class: 'gl-toggle'
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&progress=WEIGHT&show_progress=true&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