summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Schatz <jschatz1@gmail.com>2016-04-16 13:41:58 +0000
committerJacob Schatz <jschatz1@gmail.com>2016-04-16 13:41:58 +0000
commit05920a7964a039fd65d6b665c2ebd130d5ef949c (patch)
tree590bb071f2e40553d4b367355588e765834602cd
parent737087f7e55d8cd981a8f7d19c7cfc0742044d57 (diff)
parent5ddda30c353569d3d0af52c0112be4e66f890586 (diff)
downloadgitlab-ce-05920a7964a039fd65d6b665c2ebd130d5ef949c.tar.gz
Merge branch 'issue_14423' into 'master'
Put issuable owner and participating people first on mention suggestions Closes #14423 **Merge Requests** Author and people who participated are first now <img src="/uploads/dd75937627c61b5efe631b4a35f274c6/Screen_Shot_2016-03-29_at_6.41.29_PM.png" width="235" /> **Issues** Author showing first and no people have participated <img src="/uploads/e17aa96ffe7d46a7dbe293318e999e1d/Screen_Shot_2016-03-29_at_6.41.44_PM.png" width="279" /> See merge request !3448
-rw-r--r--CHANGELOG1
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee63
-rw-r--r--app/services/projects/participants_service.rb43
-rw-r--r--spec/features/participants_autocomplete_spec.rb98
4 files changed, 172 insertions, 33 deletions
diff --git a/CHANGELOG b/CHANGELOG
index f1320b6a28c..5c375fcdb39 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -74,6 +74,7 @@ v 8.7.0 (unreleased)
- Selected diff rows highlight
- Fix emoji categories in the emoji picker
- Add encrypted credentials for imported projects and migrate old ones
+ - Author and participants are displayed first on users autocompletion
v 8.6.6
- Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index 4718bcf7a1e..61e3f811e73 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -2,6 +2,8 @@
window.GitLab ?= {}
GitLab.GfmAutoComplete =
+ dataLoading: false
+
dataSource: ''
# Emoji
@@ -17,17 +19,41 @@ GitLab.GfmAutoComplete =
template: '<li><small>${id}</small> ${title}</li>'
# Add GFM auto-completion to all input fields, that accept GFM input.
- setup: ->
- input = $('.js-gfm-input')
+ setup: (wrap) ->
+ @input = $('.js-gfm-input')
+
+ # destroy previous instances
+ @destroyAtWho()
+
+ # set up instances
+ @setupAtWho()
+
+ if @dataSource
+ if !@dataLoading
+ @dataLoading = true
+ # We should wait until initializations are done
+ # and only trigger the last .setup since
+ # The previous .dataSource belongs to the previous issuable
+ # and the last one will have the **proper** .dataSource property
+ # TODO: Make this a singleton and turn off events when moving to another page
+ setTimeout( =>
+ fetch = @fetchData(@dataSource)
+ fetch.done (data) =>
+ @dataLoading = false
+ @loadData(data)
+ , 1000)
+
+
+ setupAtWho: ->
# Emoji
- input.atwho
+ @input.atwho
at: ':'
displayTpl: @Emoji.template
insertTpl: ':${name}:'
# Team Members
- input.atwho
+ @input.atwho
at: '@'
displayTpl: @Members.template
insertTpl: '${atwho-at}${username}'
@@ -42,7 +68,7 @@ GitLab.GfmAutoComplete =
title: sanitize(title)
search: sanitize("#{m.username} #{m.name}")
- input.atwho
+ @input.atwho
at: '#'
alias: 'issues'
searchKey: 'search'
@@ -55,7 +81,7 @@ GitLab.GfmAutoComplete =
title: sanitize(i.title)
search: "#{i.iid} #{i.title}"
- input.atwho
+ @input.atwho
at: '!'
alias: 'mergerequests'
searchKey: 'search'
@@ -68,13 +94,18 @@ GitLab.GfmAutoComplete =
title: sanitize(m.title)
search: "#{m.iid} #{m.title}"
- if @dataSource
- $.getJSON(@dataSource).done (data) ->
- # load members
- input.atwho 'load', '@', data.members
- # load issues
- input.atwho 'load', 'issues', data.issues
- # load merge requests
- input.atwho 'load', 'mergerequests', data.mergerequests
- # load emojis
- input.atwho 'load', ':', data.emojis
+ destroyAtWho: ->
+ @input.atwho('destroy')
+
+ fetchData: (dataSource) ->
+ $.getJSON(dataSource)
+
+ loadData: (data) ->
+ # load members
+ @input.atwho 'load', '@', data.members
+ # load issues
+ @input.atwho 'load', 'issues', data.issues
+ # load merge requests
+ @input.atwho 'load', 'mergerequests', data.mergerequests
+ # load emojis
+ @input.atwho 'load', ':', data.emojis
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index 0004a399f47..02c4eee3d02 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -1,28 +1,37 @@
module Projects
class ParticipantsService < BaseService
- def execute(note_type, note_id)
- participating =
- if note_type && note_id
- participants_in(note_type, note_id)
- else
- []
- end
+ def execute(noteable_type, noteable_id)
+ @noteable_type = noteable_type
+ @noteable_id = noteable_id
project_members = sorted(project.team.members)
- participants = all_members + groups + project_members + participating
+ participants = target_owner + participants_in_target + all_members + groups + project_members
participants.uniq
end
- def participants_in(type, id)
- target =
- case type
+ def target
+ @target ||=
+ case @noteable_type
when "Issue"
- project.issues.find_by_iid(id)
+ project.issues.find_by_iid(@noteable_id)
when "MergeRequest"
- project.merge_requests.find_by_iid(id)
+ project.merge_requests.find_by_iid(@noteable_id)
when "Commit"
- project.commit(id)
+ project.commit(@noteable_id)
+ else
+ nil
end
-
+ end
+
+ def target_owner
+ return [] unless target && target.author.present?
+
+ [{
+ name: target.author.name,
+ username: target.author.username
+ }]
+ end
+
+ def participants_in_target
return [] unless target
users = target.participants(current_user)
@@ -30,13 +39,13 @@ module Projects
end
def sorted(users)
- users.uniq.to_a.compact.sort_by(&:username).map do |user|
+ users.uniq.to_a.compact.sort_by(&:username).map do |user|
{ username: user.username, name: user.name }
end
end
def groups
- current_user.authorized_groups.sort_by(&:path).map do |group|
+ current_user.authorized_groups.sort_by(&:path).map do |group|
count = group.users.count
{ username: group.path, name: group.name, count: count }
end
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
new file mode 100644
index 00000000000..1adab7e9c6c
--- /dev/null
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -0,0 +1,98 @@
+require 'spec_helper'
+
+feature 'Member autocomplete', feature: true do
+ let(:project) { create(:project, :public) }
+ let(:user) { create(:user) }
+ let(:participant) { create(:user) }
+ let(:author) { create(:user) }
+
+ before do
+ allow_any_instance_of(Commit).to receive(:author).and_return(author)
+ login_as user
+ end
+
+ shared_examples "open suggestions" do
+ it 'suggestions are displayed' do
+ expect(page).to have_selector('.atwho-view', visible: true)
+ end
+
+ it 'author is suggested' do
+ page.within('.atwho-view', visible: true) do
+ expect(page).to have_content(author.username)
+ end
+ end
+
+ it 'participant is suggested' do
+ page.within('.atwho-view', visible: true) do
+ expect(page).to have_content(participant.username)
+ end
+ end
+ end
+
+ context 'adding a new note on a Issue', js: true do
+ before do
+ issue = create(:issue, author: author, project: project)
+ create(:note, note: 'Ultralight Beam', noteable: issue, author: participant)
+ visit_issue(project, issue)
+ end
+
+ context 'when typing @' do
+ include_examples "open suggestions"
+ before do
+ open_member_suggestions
+ end
+ end
+ end
+
+ context 'adding a new note on a Merge Request ', js: true do
+ before do
+ merge = create(:merge_request, source_project: project, target_project: project, author: author)
+ create(:note, note: 'Ultralight Beam', noteable: merge, author: participant)
+ visit_merge_request(project, merge)
+ end
+
+ context 'when typing @' do
+ include_examples "open suggestions"
+ before do
+ open_member_suggestions
+ end
+ end
+ end
+
+ context 'adding a new note on a Commit ', js: true do
+ let(:commit) { project.commit }
+
+ before do
+ allow(commit).to receive(:author).and_return(author)
+ create(:note_on_commit, author: participant, project: project, commit_id: project.repository.commit.id, note: 'No More Parties in LA')
+ visit_commit(project, commit)
+ end
+
+ context 'when typing @' do
+ include_examples "open suggestions"
+ before do
+ open_member_suggestions
+ end
+ end
+ end
+
+ def open_member_suggestions
+ sleep 1
+ page.within('.new-note') do
+ sleep 1
+ find('#note_note').native.send_keys('@')
+ end
+ end
+
+ def visit_issue(project, issue)
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ def visit_merge_request(project, merge)
+ visit namespace_project_merge_request_path(project.namespace, project, merge)
+ end
+
+ def visit_commit(project, commit)
+ visit namespace_project_commit_path(project.namespace, project, commit)
+ end
+end