Commit 8fd72c63 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-issue_5603' into 'master'

[CE] - Add milestones autocomplete for epics

See merge request gitlab-org/gitlab-ce!23660
parents f689b161 ffc3b98c
...@@ -4,6 +4,8 @@ module Banzai ...@@ -4,6 +4,8 @@ module Banzai
module Filter module Filter
# HTML filter that replaces milestone references with links. # HTML filter that replaces milestone references with links.
class MilestoneReferenceFilter < AbstractReferenceFilter class MilestoneReferenceFilter < AbstractReferenceFilter
include Gitlab::Utils::StrongMemoize
self.reference_type = :milestone self.reference_type = :milestone
def self.object_class def self.object_class
...@@ -13,16 +15,34 @@ module Banzai ...@@ -13,16 +15,34 @@ module Banzai
# Links to project milestones contain the IID, but when we're handling # Links to project milestones contain the IID, but when we're handling
# 'regular' references, we need to use the global ID to disambiguate # 'regular' references, we need to use the global ID to disambiguate
# between group and project milestones. # between group and project milestones.
def find_object(project, id) def find_object(parent, id)
return unless project.is_a?(Project) return unless valid_context?(parent)
find_milestone_with_finder(project, id: id) find_milestone_with_finder(parent, id: id)
end end
def find_object_from_link(project, iid) def find_object_from_link(parent, iid)
return unless project.is_a?(Project) return unless valid_context?(parent)
find_milestone_with_finder(parent, iid: iid)
end
def valid_context?(parent)
strong_memoize(:valid_context) do
group_context?(parent) || project_context?(parent)
end
end
def group_context?(parent)
strong_memoize(:group_context) do
parent.is_a?(Group)
end
end
find_milestone_with_finder(project, iid: iid) def project_context?(parent)
strong_memoize(:project_context) do
parent.is_a?(Project)
end
end end
def references_in(text, pattern = Milestone.reference_pattern) def references_in(text, pattern = Milestone.reference_pattern)
...@@ -44,13 +64,15 @@ module Banzai ...@@ -44,13 +64,15 @@ module Banzai
def find_milestone(project_ref, namespace_ref, milestone_id, milestone_name) def find_milestone(project_ref, namespace_ref, milestone_id, milestone_name)
project_path = full_project_path(namespace_ref, project_ref) project_path = full_project_path(namespace_ref, project_ref)
project = parent_from_ref(project_path)
return unless project && project.is_a?(Project) # Returns group if project is not found by path
parent = parent_from_ref(project_path)
return unless parent
milestone_params = milestone_params(milestone_id, milestone_name) milestone_params = milestone_params(milestone_id, milestone_name)
find_milestone_with_finder(project, milestone_params) find_milestone_with_finder(parent, milestone_params)
end end
def milestone_params(iid, name) def milestone_params(iid, name)
...@@ -61,16 +83,28 @@ module Banzai ...@@ -61,16 +83,28 @@ module Banzai
end end
end end
def find_milestone_with_finder(project, params) def find_milestone_with_finder(parent, params)
finder_params = { project_ids: [project.id], order: nil, state: 'all' } finder_params = milestone_finder_params(parent, params[:iid].present?)
# We don't support IID lookups for group milestones, because IIDs can MilestonesFinder.new(finder_params).find_by(params)
# clash between group and project milestones.
if project.group && !params[:iid]
finder_params[:group_ids] = project.group.self_and_ancestors_ids
end end
MilestonesFinder.new(finder_params).find_by(params) def milestone_finder_params(parent, find_by_iid)
{ order: nil, state: 'all' }.tap do |params|
params[:project_ids] = parent.id if project_context?(parent)
# We don't support IID lookups because IIDs can clash between
# group/project milestones and group/subgroup milestones.
params[:group_ids] = self_and_ancestors_ids(parent) unless find_by_iid
end
end
def self_and_ancestors_ids(parent)
if group_context?(parent)
parent.self_and_ancestors_ids
elsif project_context?(parent)
parent.group&.self_and_ancestors_ids
end
end end
def url_for_object(milestone, project) def url_for_object(milestone, project)
......
...@@ -351,7 +351,10 @@ describe Banzai::Filter::MilestoneReferenceFilter do ...@@ -351,7 +351,10 @@ describe Banzai::Filter::MilestoneReferenceFilter do
end end
context 'group context' do context 'group context' do
let(:context) { { project: nil, group: create(:group) } } let(:group) { create(:group) }
let(:context) { { project: nil, group: group } }
context 'when project milestone' do
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
it 'links to a valid reference' do it 'links to a valid reference' do
...@@ -369,6 +372,32 @@ describe Banzai::Filter::MilestoneReferenceFilter do ...@@ -369,6 +372,32 @@ describe Banzai::Filter::MilestoneReferenceFilter do
end end
end end
context 'when group milestone' do
let(:group_milestone) { create(:milestone, title: 'group_milestone', group: group) }
context 'for subgroups', :nested_groups do
let(:sub_group) { create(:group, parent: group) }
let(:sub_group_milestone) { create(:milestone, title: 'sub_group_milestone', group: sub_group) }
it 'links to a valid reference of subgroup and group milestones' do
[group_milestone, sub_group_milestone].each do |milestone|
reference = "%#{milestone.title}"
result = reference_filter("See #{reference}", { project: nil, group: sub_group })
expect(result.css('a').first.attr('href')).to eq(urls.milestone_url(milestone))
end
end
end
it 'ignores internal references' do
exp = act = "See %#{group_milestone.iid}"
expect(reference_filter(act, context).to_html).to eq exp
end
end
end
context 'when milestone is open' do context 'when milestone is open' do
context 'project milestones' do context 'project milestones' do
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
......
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