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 @@
}
}
.gl-xl-ml-3 {
@include media-breakpoint-up(lg) {
margin-left: $gl-spacing-scale-3;
}
}
.gl-mb-n3 {
margin-bottom: -$gl-spacing-scale-3;
}
......
......@@ -57,7 +57,7 @@ export default {
},
},
computed: {
...mapState(['progressTracking']),
...mapState(['progressTracking', 'isProgressTrackingActive']),
timelineBarInnerStyle() {
return {
maxWidth: `${this.clientWidth - EPIC_DETAILS_CELL_WIDTH}px`,
......@@ -141,7 +141,10 @@ export default {
<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>
<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
class="epic-bar-progress gl-flex-grow-1 gl-mr-2"
:value="epicPercentage"
......
......@@ -82,7 +82,7 @@ export default {
:timeframe-range-type="timeframeRangeType"
@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" />
<epics-list-empty
v-else-if="epicsFetchResultEmpty"
......
......@@ -94,7 +94,7 @@ export default {
<gl-dropdown
id="roadmap-daterange"
icon="calendar"
class="gl-mb-3 roadmap-daterange-dropdown"
class="roadmap-daterange-dropdown"
toggle-class="gl-rounded-base!"
:text="daterangeDropdownText"
data-testid="daterange-dropdown"
......@@ -110,7 +110,7 @@ export default {
{{ dateRange.text }}
</gl-dropdown-item>
</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
data-testid="daterange-presets"
:checked="presetType"
......
......@@ -76,6 +76,7 @@ export default {
'epicsState',
'sortedBy',
'filterParams',
'isProgressTrackingActive',
'progressTracking',
'isShowingMilestones',
'milestonesType',
......@@ -254,7 +255,7 @@ export default {
<gl-button
v-if="glFeatures.roadmapSettings"
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"
data-testid="settings-button"
@click="$emit('toggleSettings', $event)"
......
<script>
import { GlFormGroup, GlFormRadioGroup } from '@gitlab/ui';
import { GlFormGroup, GlFormRadioGroup, GlToggle } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale';
......@@ -9,12 +9,13 @@ export default {
components: {
GlFormGroup,
GlFormRadioGroup,
GlToggle,
},
computed: {
...mapState(['progressTracking']),
...mapState(['progressTracking', 'isProgressTrackingActive']),
},
methods: {
...mapActions(['setProgressTracking']),
...mapActions(['setProgressTracking', 'toggleProgressTrackingActive']),
handleProgressTrackingChange(option) {
if (option !== this.progressTracking) {
this.setProgressTracking(option);
......@@ -23,6 +24,7 @@ export default {
},
i18n: {
header: __('Progress tracking'),
toggleLabel: __('Display progress of child issues'),
},
PROGRESS_TRACKING_OPTIONS,
};
......@@ -33,12 +35,24 @@ export default {
<gl-form-group
class="gl-mb-0"
:label="$options.i18n.header"
label-class="gl-pb-2!"
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
v-if="isProgressTrackingActive"
:checked="progressTracking"
stacked
:options="$options.PROGRESS_TRACKING_OPTIONS"
class="gl-mt-3"
@change="handleProgressTrackingChange"
/>
</gl-form-group>
......
......@@ -23,18 +23,6 @@ export default {
required: true,
},
},
methods: {
getDrawerHeaderHeight() {
const wrapperEl = document.querySelector('.roadmap-container');
if (wrapperEl) {
const topPosition = wrapperEl.getBoundingClientRect().top + window.pageYOffset;
return `${topPosition}px`;
}
return '';
},
},
};
</script>
......@@ -42,7 +30,7 @@ export default {
<gl-drawer
v-bind="$attrs"
:open="isOpen"
:header-height="getDrawerHeaderHeight()"
class="gl-absolute"
@close="$emit('toggleSettings', $event)"
>
<template #title>
......
......@@ -54,6 +54,7 @@ export default {
'not[my_reaction_emoji]': notMyReactionEmoji,
'not[label_name][]': notLabelName,
progress: this.progressTracking,
show_progress: this.isProgressTrackingActive,
show_milestones: this.isShowingMilestones,
milestones_type: this.milestonesType,
};
......
......@@ -109,6 +109,10 @@ export default () => {
presetType,
timeframe,
progressTracking: rawFilterParams.progress || PROGRESS_WEIGHT,
isProgressTrackingActive:
rawFilterParams.show_progress === undefined
? true
: parseBoolean(rawFilterParams.show_progress),
isShowingMilestones:
rawFilterParams.show_milestones === undefined
? true
......@@ -132,6 +136,7 @@ export default () => {
isChildEpics: this.isChildEpics,
hasFiltersApplied: this.hasFiltersApplied,
allowSubEpics: this.allowSubEpics,
isProgressTrackingActive: this.isProgressTrackingActive,
progressTracking: this.progressTracking,
isShowingMilestones: this.isShowingMilestones,
milestonesType: this.milestonesType,
......
......@@ -330,6 +330,9 @@ export const setSortedBy = ({ commit }, sortedBy) => commit(types.SET_SORTED_BY,
export const setProgressTracking = ({ commit }, progressTracking) =>
commit(types.SET_PROGRESS_TRACKING, progressTracking);
export const toggleProgressTrackingActive = ({ commit }) =>
commit(types.TOGGLE_PROGRESS_TRACKING_ACTIVE);
export const setMilestonesType = ({ commit }, milestonesType) =>
commit(types.SET_MILESTONES_TYPE, milestonesType);
......
......@@ -33,5 +33,6 @@ export const SET_DATERANGE = 'SET_DATERANGE';
export const SET_FILTER_PARAMS = 'SET_FILTER_PARAMS';
export const SET_SORTED_BY = 'SET_SORTED_BY';
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 TOGGLE_MILESTONES = 'TOGGLE_MILESTONES';
......@@ -145,6 +145,10 @@ export default {
state.progressTracking = progressTracking;
},
[types.TOGGLE_PROGRESS_TRACKING_ACTIVE](state) {
state.isProgressTrackingActive = !state.isProgressTrackingActive;
},
[types.SET_MILESTONES_TYPE](state, milestonesType) {
state.milestonesType = milestonesType;
},
......
......@@ -3,6 +3,7 @@ export default () => ({
basePath: '',
epicsState: '',
progressTracking: '',
isProgressTrackingActive: true,
filterParams: null,
isShowingMilestones: true,
milestonesType: '',
......
......@@ -525,11 +525,9 @@ html.group-epics-roadmap-html {
.sort-dropdown-container {
// This override is needed to make sort-dropdown have same height
// as filtered search bar.
@include media-breakpoint-up(sm) {
.dropdown,
> button {
margin-bottom: $gl-padding-8;
}
.dropdown,
> button {
margin-bottom: $gl-padding-8;
}
}
}
......@@ -247,6 +247,43 @@ RSpec.describe 'group epic roadmap', :js do
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
def select_milestones(milestones)
page.within('[data-testid="roadmap-milestones-settings"]') do
......
......@@ -23,11 +23,13 @@ const createComponent = ({
timeframeItem = mockTimeframeMonths[0],
timeframeString = '',
progressTracking = PROGRESS_WEIGHT,
isProgressTrackingActive = true,
} = {}) => {
const store = createStore();
store.dispatch('setInitialData', {
progressTracking,
isProgressTrackingActive,
});
return shallowMount(EpicItemTimeline, {
......@@ -75,6 +77,16 @@ describe('EpicItemTimelineComponent', () => {
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`
progressTracking | icon
${PROGRESS_WEIGHT} | ${'weight'}
......
......@@ -61,6 +61,7 @@ const createComponent = ({
sortedBy,
filterParams,
timeframe,
isProgressTrackingActive: true,
progressTracking: PROGRESS_WEIGHT,
milestonesType: MILESTONES_ALL,
});
......@@ -124,7 +125,7 @@ describe('RoadmapFilters', () => {
await nextTick();
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
describe('RoadmapProgressTracking', () => {
let wrapper;
const createComponent = () => {
const createComponent = ({ isProgressTrackingActive = true } = {}) => {
const store = createStore();
store.dispatch('setInitialData', {
progressTracking: PROGRESS_WEIGHT,
isProgressTrackingActive,
});
wrapper = shallowMountExtended(RoadmapProgressTracking, {
......@@ -37,9 +38,20 @@ describe('RoadmapProgressTracking', () => {
expect(findFormGroup().attributes('label')).toBe('Progress tracking');
});
it('renders radio form group', () => {
expect(findFormRadioGroup().exists()).toBe(true);
expect(findFormRadioGroup().props('options')).toEqual(PROGRESS_TRACKING_OPTIONS);
});
it.each`
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);
}
},
);
});
});
......@@ -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', () => {
it('should set milestonesType in store state', () => {
return testAction(
......
......@@ -347,7 +347,6 @@ describe('Roadmap Store Mutations', () => {
describe('SET_PROGRESS_TRACKING', () => {
it('Should set `progressTracking` to the state', () => {
const progressTracking = PROGRESS_COUNT;
setEpicMockData(state);
mutations[types.SET_PROGRESS_TRACKING](state, progressTracking);
......@@ -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', () => {
it('Should set `milestonesType` to the state', () => {
const milestonesType = MILESTONES_GROUP;
......
......@@ -12869,6 +12869,9 @@ msgstr ""
msgid "Display name"
msgstr ""
msgid "Display progress of child issues"
msgstr ""
msgid "Display rendered file"
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