Commit 4535ff55 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'kp-sort-milestone-autocomplete' into 'master'

Sort milestones within autocomplete dropdown

See merge request gitlab-org/gitlab!55850
parents 42860513 e1c37ace
......@@ -3,11 +3,12 @@ import '~/lib/utils/jquery_at_who';
import { escape, template } from 'lodash';
import * as Emoji from '~/emoji';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import { s__, __, sprintf } from '~/locale';
import { isUserBusy } from '~/set_status_modal/utils';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import AjaxCache from './lib/utils/ajax_cache';
import { spriteIcon } from './lib/utils/common_utils';
import { parsePikadayDate } from './lib/utils/datetime_utility';
import glRegexp from './lib/utils/regexp';
function sanitize(str) {
......@@ -392,7 +393,7 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
tmpl = GfmAutoComplete.Milestones.templateFunction(value.title);
tmpl = GfmAutoComplete.Milestones.templateFunction(value.title, value.expired);
}
return tmpl;
},
......@@ -400,16 +401,39 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave(milestones) {
return $.map(milestones, (m) => {
const parsedMilestones = $.map(milestones, (m) => {
if (m.title == null) {
return m;
}
const dueDate = m.due_date ? parsePikadayDate(m.due_date) : null;
const expired = dueDate ? Date.now() > dueDate.getTime() : false;
return {
id: m.iid,
title: sanitize(m.title),
search: m.title,
expired,
dueDate,
};
});
// Sort milestones by due date when present.
if (typeof parsedMilestones[0] === 'object') {
return parsedMilestones.sort((mA, mB) => {
// Move all expired milestones to the bottom.
if (mA.expired) return 1;
if (mB.expired) return -1;
// Move milestones without due dates just above expired milestones.
if (!mA.dueDate) return 1;
if (!mB.dueDate) return -1;
// Sort by due date in ascending order.
return mA.dueDate - mB.dueDate;
});
}
return parsedMilestones;
},
},
});
......@@ -833,7 +857,12 @@ GfmAutoComplete.Issues = {
};
// Milestones
GfmAutoComplete.Milestones = {
templateFunction(title) {
templateFunction(title, expired) {
if (expired) {
return `<li>${sprintf(__('%{milestone} (expired)'), {
milestone: escape(title),
})}</li>`;
}
return `<li>${escape(title)}</li>`;
},
};
......
......@@ -16,7 +16,7 @@ module Projects
finder_params[:group_ids] = @project.group.self_and_ancestors.select(:id) if @project.group
MilestonesFinder.new(finder_params).execute.select([:iid, :title])
MilestonesFinder.new(finder_params).execute.select([:iid, :title, :due_date])
end
def merge_requests
......
---
title: Sort milestones within autocomplete dropdown
merge_request: 55850
author:
type: changed
......@@ -48,7 +48,7 @@ module Groups
def milestones
group_ids = group.self_and_ancestors.public_or_visible_to_user(current_user).pluck(:id)
MilestonesFinder.new(group_ids: group_ids).execute.select(:iid, :title)
MilestonesFinder.new(group_ids: group_ids).execute.select(:iid, :title, :due_date)
end
# rubocop: enable CodeReuse/ActiveRecord
......
......@@ -402,10 +402,40 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'milestone' do
let!(:object) { create(:milestone, project: project) }
let(:expected_body) { object.to_reference }
let_it_be(:milestone_expired) { create(:milestone, project: project, due_date: 5.days.ago) }
let_it_be(:milestone_no_duedate) { create(:milestone, project: project, title: 'Foo - No due date') }
let_it_be(:milestone1) { create(:milestone, project: project, title: 'Milestone-1', due_date: 20.days.from_now) }
let_it_be(:milestone2) { create(:milestone, project: project, title: 'Milestone-2', due_date: 15.days.from_now) }
let_it_be(:milestone3) { create(:milestone, project: project, title: 'Milestone-3', due_date: 10.days.from_now) }
it_behaves_like 'autocomplete suggestions'
before do
fill_in 'Comment', with: '/milestone %'
wait_for_requests
end
it 'shows milestons list in the autocomplete menu' do
page.within(find_autocomplete_menu) do
expect(page).to have_selector('li', count: 5)
end
end
it 'shows expired milestone at the bottom of the list' do
page.within(find_autocomplete_menu) do
expect(page.find('li:last-child')).to have_content milestone_expired.title
end
end
it 'shows milestone due earliest at the top of the list' do
page.within(find_autocomplete_menu) do
aggregate_failures do
expect(page.all('li')[0]).to have_content milestone3.title
expect(page.all('li')[1]).to have_content milestone2.title
expect(page.all('li')[2]).to have_content milestone1.title
expect(page.all('li')[3]).to have_content milestone_no_duedate.title
end
end
end
end
end
......
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