Merge branch 'winh-dashboard-any-milestone' into 'master'
Reset milestone filter when clicking "Any Milestone" in dashboard Closes #45295 See merge request gitlab-org/gitlab-ce!18531
This commit is contained in:
commit
c73b5d31e6
|
@ -12,7 +12,8 @@ import ModalStore from './boards/stores/modal_store';
|
||||||
export default class MilestoneSelect {
|
export default class MilestoneSelect {
|
||||||
constructor(currentProject, els, options = {}) {
|
constructor(currentProject, els, options = {}) {
|
||||||
if (currentProject !== null) {
|
if (currentProject !== null) {
|
||||||
this.currentProject = typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
|
this.currentProject =
|
||||||
|
typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.init(els, options);
|
this.init(els, options);
|
||||||
|
@ -26,7 +27,10 @@ export default class MilestoneSelect {
|
||||||
}
|
}
|
||||||
|
|
||||||
$els.each((i, dropdown) => {
|
$els.each((i, dropdown) => {
|
||||||
let milestoneLinkNoneTemplate, milestoneLinkTemplate, selectedMilestone, selectedMilestoneDefault;
|
let milestoneLinkNoneTemplate,
|
||||||
|
milestoneLinkTemplate,
|
||||||
|
selectedMilestone,
|
||||||
|
selectedMilestoneDefault;
|
||||||
const $dropdown = $(dropdown);
|
const $dropdown = $(dropdown);
|
||||||
const projectId = $dropdown.data('projectId');
|
const projectId = $dropdown.data('projectId');
|
||||||
const milestonesUrl = $dropdown.data('milestones');
|
const milestonesUrl = $dropdown.data('milestones');
|
||||||
|
@ -46,45 +50,47 @@ export default class MilestoneSelect {
|
||||||
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
|
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
|
||||||
const $value = $block.find('.value');
|
const $value = $block.find('.value');
|
||||||
const $loading = $block.find('.block-loading').fadeOut();
|
const $loading = $block.find('.block-loading').fadeOut();
|
||||||
selectedMilestoneDefault = (showAny ? '' : null);
|
selectedMilestoneDefault = showAny ? '' : null;
|
||||||
selectedMilestoneDefault = (showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault);
|
selectedMilestoneDefault = showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault;
|
||||||
selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
|
selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
|
||||||
|
|
||||||
if (issueUpdateURL) {
|
if (issueUpdateURL) {
|
||||||
milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>');
|
milestoneLinkTemplate = _.template(
|
||||||
|
'<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
|
||||||
|
);
|
||||||
milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
|
milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
|
||||||
}
|
}
|
||||||
return $dropdown.glDropdown({
|
return $dropdown.glDropdown({
|
||||||
showMenuAbove: showMenuAbove,
|
showMenuAbove: showMenuAbove,
|
||||||
data: (term, callback) => axios.get(milestonesUrl)
|
data: (term, callback) =>
|
||||||
.then(({ data }) => {
|
axios.get(milestonesUrl).then(({ data }) => {
|
||||||
const extraOptions = [];
|
const extraOptions = [];
|
||||||
if (showAny) {
|
if (showAny) {
|
||||||
extraOptions.push({
|
extraOptions.push({
|
||||||
id: 0,
|
id: null,
|
||||||
name: '',
|
name: null,
|
||||||
title: 'Any Milestone'
|
title: 'Any Milestone',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (showNo) {
|
if (showNo) {
|
||||||
extraOptions.push({
|
extraOptions.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
name: 'No Milestone',
|
name: 'No Milestone',
|
||||||
title: 'No Milestone'
|
title: 'No Milestone',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (showUpcoming) {
|
if (showUpcoming) {
|
||||||
extraOptions.push({
|
extraOptions.push({
|
||||||
id: -2,
|
id: -2,
|
||||||
name: '#upcoming',
|
name: '#upcoming',
|
||||||
title: 'Upcoming'
|
title: 'Upcoming',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (showStarted) {
|
if (showStarted) {
|
||||||
extraOptions.push({
|
extraOptions.push({
|
||||||
id: -3,
|
id: -3,
|
||||||
name: '#started',
|
name: '#started',
|
||||||
title: 'Started'
|
title: 'Started',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (extraOptions.length) {
|
if (extraOptions.length) {
|
||||||
|
@ -106,7 +112,7 @@ export default class MilestoneSelect {
|
||||||
`,
|
`,
|
||||||
filterable: true,
|
filterable: true,
|
||||||
search: {
|
search: {
|
||||||
fields: ['title']
|
fields: ['title'],
|
||||||
},
|
},
|
||||||
selectable: true,
|
selectable: true,
|
||||||
toggleLabel: (selected, el, e) => {
|
toggleLabel: (selected, el, e) => {
|
||||||
|
@ -119,7 +125,7 @@ export default class MilestoneSelect {
|
||||||
defaultLabel: defaultLabel,
|
defaultLabel: defaultLabel,
|
||||||
fieldName: $dropdown.data('fieldName'),
|
fieldName: $dropdown.data('fieldName'),
|
||||||
text: milestone => _.escape(milestone.title),
|
text: milestone => _.escape(milestone.title),
|
||||||
id: (milestone) => {
|
id: milestone => {
|
||||||
if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) {
|
if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) {
|
||||||
return milestone.name;
|
return milestone.name;
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,7 +137,7 @@ export default class MilestoneSelect {
|
||||||
// display:block overrides the hide-collapse rule
|
// display:block overrides the hide-collapse rule
|
||||||
return $value.css('display', '');
|
return $value.css('display', '');
|
||||||
},
|
},
|
||||||
opened: (e) => {
|
opened: e => {
|
||||||
const $el = $(e.currentTarget);
|
const $el = $(e.currentTarget);
|
||||||
if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) {
|
if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) {
|
||||||
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
|
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
|
||||||
|
@ -140,7 +146,7 @@ export default class MilestoneSelect {
|
||||||
$(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`, $el).addClass('is-active');
|
$(`[data-milestone-id="${_.escape(selectedMilestone)}"] > a`, $el).addClass('is-active');
|
||||||
},
|
},
|
||||||
vue: $dropdown.hasClass('js-issue-board-sidebar'),
|
vue: $dropdown.hasClass('js-issue-board-sidebar'),
|
||||||
clicked: (clickEvent) => {
|
clicked: clickEvent => {
|
||||||
const { $el, e } = clickEvent;
|
const { $el, e } = clickEvent;
|
||||||
let selected = clickEvent.selectedObj;
|
let selected = clickEvent.selectedObj;
|
||||||
|
|
||||||
|
@ -155,11 +161,14 @@ export default class MilestoneSelect {
|
||||||
|
|
||||||
const page = $('body').attr('data-page');
|
const page = $('body').attr('data-page');
|
||||||
const isIssueIndex = page === 'projects:issues:index';
|
const isIssueIndex = page === 'projects:issues:index';
|
||||||
const isMRIndex = (page === page && page === 'projects:merge_requests:index');
|
const isMRIndex = page === page && page === 'projects:merge_requests:index';
|
||||||
const isSelecting = (selected.name !== selectedMilestone);
|
const isSelecting = selected.name !== selectedMilestone;
|
||||||
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
|
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
|
||||||
|
|
||||||
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
|
if (
|
||||||
|
$dropdown.hasClass('js-filter-bulk-update') ||
|
||||||
|
$dropdown.hasClass('js-issuable-form-dropdown')
|
||||||
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -177,10 +186,13 @@ export default class MilestoneSelect {
|
||||||
return $dropdown.closest('form').submit();
|
return $dropdown.closest('form').submit();
|
||||||
} else if ($dropdown.hasClass('js-issue-board-sidebar')) {
|
} else if ($dropdown.hasClass('js-issue-board-sidebar')) {
|
||||||
if (selected.id !== -1 && isSelecting) {
|
if (selected.id !== -1 && isSelecting) {
|
||||||
gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({
|
gl.issueBoards.boardStoreIssueSet(
|
||||||
|
'milestone',
|
||||||
|
new ListMilestone({
|
||||||
id: selected.id,
|
id: selected.id,
|
||||||
title: selected.name
|
title: selected.name,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
gl.issueBoards.boardStoreIssueDelete('milestone');
|
gl.issueBoards.boardStoreIssueDelete('milestone');
|
||||||
}
|
}
|
||||||
|
@ -188,7 +200,8 @@ export default class MilestoneSelect {
|
||||||
$dropdown.trigger('loading.gl.dropdown');
|
$dropdown.trigger('loading.gl.dropdown');
|
||||||
$loading.removeClass('hidden').fadeIn();
|
$loading.removeClass('hidden').fadeIn();
|
||||||
|
|
||||||
gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update'))
|
gl.issueBoards.BoardsStore.detail.issue
|
||||||
|
.update($dropdown.attr('data-issue-update'))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
$dropdown.trigger('loaded.gl.dropdown');
|
$dropdown.trigger('loaded.gl.dropdown');
|
||||||
$loading.fadeOut();
|
$loading.fadeOut();
|
||||||
|
@ -203,7 +216,8 @@ export default class MilestoneSelect {
|
||||||
data[abilityName].milestone_id = selected != null ? selected : null;
|
data[abilityName].milestone_id = selected != null ? selected : null;
|
||||||
$loading.removeClass('hidden').fadeIn();
|
$loading.removeClass('hidden').fadeIn();
|
||||||
$dropdown.trigger('loading.gl.dropdown');
|
$dropdown.trigger('loading.gl.dropdown');
|
||||||
return axios.put(issueUpdateURL, data)
|
return axios
|
||||||
|
.put(issueUpdateURL, data)
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
$dropdown.trigger('loaded.gl.dropdown');
|
$dropdown.trigger('loaded.gl.dropdown');
|
||||||
$loading.fadeOut();
|
$loading.fadeOut();
|
||||||
|
@ -215,7 +229,10 @@ export default class MilestoneSelect {
|
||||||
data.milestone.name = data.milestone.title;
|
data.milestone.name = data.milestone.title;
|
||||||
$value.html(milestoneLinkTemplate(data.milestone));
|
$value.html(milestoneLinkTemplate(data.milestone));
|
||||||
return $sidebarCollapsedValue
|
return $sidebarCollapsedValue
|
||||||
.attr('data-original-title', `${data.milestone.name}<br />${data.milestone.remaining}`)
|
.attr(
|
||||||
|
'data-original-title',
|
||||||
|
`${data.milestone.name}<br />${data.milestone.remaining}`,
|
||||||
|
)
|
||||||
.find('span')
|
.find('span')
|
||||||
.text(data.milestone.title);
|
.text(data.milestone.title);
|
||||||
} else {
|
} else {
|
||||||
|
@ -230,7 +247,7 @@ export default class MilestoneSelect {
|
||||||
$loading.fadeOut();
|
$loading.fadeOut();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Reset milestone filter when clicking "Any Milestone" in dashboard
|
||||||
|
merge_request: 18531
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -10,13 +10,16 @@ feature 'Dashboard > milestone filter', :js do
|
||||||
let!(:issue) { create :issue, author: user, project: project, milestone: milestone }
|
let!(:issue) { create :issue, author: user, project: project, milestone: milestone }
|
||||||
let!(:issue2) { create :issue, author: user, project: project, milestone: milestone2 }
|
let!(:issue2) { create :issue, author: user, project: project, milestone: milestone2 }
|
||||||
|
|
||||||
|
dropdown_toggle_button = '.js-milestone-select'
|
||||||
|
|
||||||
before do
|
before do
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
visit issues_dashboard_path(author_id: user.id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'default state' do
|
context 'default state' do
|
||||||
it 'shows issues with Any Milestone' do
|
it 'shows issues with Any Milestone' do
|
||||||
|
visit issues_dashboard_path(author_id: user.id)
|
||||||
|
|
||||||
page.all('.issue-info').each do |issue_info|
|
page.all('.issue-info').each do |issue_info|
|
||||||
expect(issue_info.text).to match(/v\d.0/)
|
expect(issue_info.text).to match(/v\d.0/)
|
||||||
end
|
end
|
||||||
|
@ -24,31 +27,51 @@ feature 'Dashboard > milestone filter', :js do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'filtering by milestone' do
|
context 'filtering by milestone' do
|
||||||
milestone_select_selector = '.js-milestone-select'
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
filter_item_select('v1.0', milestone_select_selector)
|
visit issues_dashboard_path(author_id: user.id)
|
||||||
find(milestone_select_selector).click
|
filter_item_select('v1.0', dropdown_toggle_button)
|
||||||
|
find(dropdown_toggle_button).click
|
||||||
wait_for_requests
|
wait_for_requests
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows issues with Milestone v1.0' do
|
it 'shows issues with Milestone v1.0' do
|
||||||
expect(find('.issues-list')).to have_selector('.issue', count: 1)
|
expect(find('.issues-list')).to have_selector('.issue', count: 1)
|
||||||
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
|
expect(find('.milestone-filter .dropdown-content')).to have_selector('a.is-active', count: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should not change active Milestone unless clicked' do
|
it 'should not change active Milestone unless clicked' do
|
||||||
|
page.within '.milestone-filter' do
|
||||||
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
|
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
|
||||||
|
|
||||||
# open & close dropdown
|
|
||||||
find('.dropdown-menu-close').click
|
find('.dropdown-menu-close').click
|
||||||
|
|
||||||
expect(find('.milestone-filter')).not_to have_selector('.dropdown.open')
|
expect(page).not_to have_selector('.dropdown.open')
|
||||||
|
|
||||||
find(milestone_select_selector).click
|
find(dropdown_toggle_button).click
|
||||||
|
|
||||||
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
|
expect(find('.dropdown-content')).to have_selector('a.is-active', count: 1)
|
||||||
expect(find('.dropdown-content a.is-active')).to have_content('v1.0')
|
expect(find('.dropdown-content a.is-active')).to have_content('v1.0')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with milestone filter in URL' do
|
||||||
|
before do
|
||||||
|
visit issues_dashboard_path(author_id: user.id, milestone_title: milestone.title)
|
||||||
|
find(dropdown_toggle_button).click
|
||||||
|
wait_for_requests
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'has milestone selected' do
|
||||||
|
expect(find('.milestone-filter .dropdown-content')).to have_css('.is-active', text: milestone.title)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes milestone filter from URL after clicking "Any Milestone"' do
|
||||||
|
expect(current_url).to include("milestone_title=#{milestone.title}")
|
||||||
|
|
||||||
|
find('.milestone-filter .dropdown-content li', text: 'Any Milestone').click
|
||||||
|
|
||||||
|
expect(current_url).not_to include('milestone_title')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue