Commit 05920a79 authored by Jacob Schatz's avatar Jacob Schatz

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
parents 737087f7 5ddda30c
...@@ -74,6 +74,7 @@ v 8.7.0 (unreleased) ...@@ -74,6 +74,7 @@ v 8.7.0 (unreleased)
- Selected diff rows highlight - Selected diff rows highlight
- Fix emoji categories in the emoji picker - Fix emoji categories in the emoji picker
- Add encrypted credentials for imported projects and migrate old ones - Add encrypted credentials for imported projects and migrate old ones
- Author and participants are displayed first on users autocompletion
v 8.6.6 v 8.6.6
- Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413 - Expire the exists cache before deletion to ensure project dir actually exists (Stan Hu). !3413
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
window.GitLab ?= {} window.GitLab ?= {}
GitLab.GfmAutoComplete = GitLab.GfmAutoComplete =
dataLoading: false
dataSource: '' dataSource: ''
# Emoji # Emoji
...@@ -17,17 +19,41 @@ GitLab.GfmAutoComplete = ...@@ -17,17 +19,41 @@ GitLab.GfmAutoComplete =
template: '<li><small>${id}</small> ${title}</li>' template: '<li><small>${id}</small> ${title}</li>'
# Add GFM auto-completion to all input fields, that accept GFM input. # Add GFM auto-completion to all input fields, that accept GFM input.
setup: -> setup: (wrap) ->
input = $('.js-gfm-input') @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 # Emoji
input.atwho @input.atwho
at: ':' at: ':'
displayTpl: @Emoji.template displayTpl: @Emoji.template
insertTpl: ':${name}:' insertTpl: ':${name}:'
# Team Members # Team Members
input.atwho @input.atwho
at: '@' at: '@'
displayTpl: @Members.template displayTpl: @Members.template
insertTpl: '${atwho-at}${username}' insertTpl: '${atwho-at}${username}'
...@@ -42,7 +68,7 @@ GitLab.GfmAutoComplete = ...@@ -42,7 +68,7 @@ GitLab.GfmAutoComplete =
title: sanitize(title) title: sanitize(title)
search: sanitize("#{m.username} #{m.name}") search: sanitize("#{m.username} #{m.name}")
input.atwho @input.atwho
at: '#' at: '#'
alias: 'issues' alias: 'issues'
searchKey: 'search' searchKey: 'search'
...@@ -55,7 +81,7 @@ GitLab.GfmAutoComplete = ...@@ -55,7 +81,7 @@ GitLab.GfmAutoComplete =
title: sanitize(i.title) title: sanitize(i.title)
search: "#{i.iid} #{i.title}" search: "#{i.iid} #{i.title}"
input.atwho @input.atwho
at: '!' at: '!'
alias: 'mergerequests' alias: 'mergerequests'
searchKey: 'search' searchKey: 'search'
...@@ -68,13 +94,18 @@ GitLab.GfmAutoComplete = ...@@ -68,13 +94,18 @@ GitLab.GfmAutoComplete =
title: sanitize(m.title) title: sanitize(m.title)
search: "#{m.iid} #{m.title}" search: "#{m.iid} #{m.title}"
if @dataSource destroyAtWho: ->
$.getJSON(@dataSource).done (data) -> @input.atwho('destroy')
# load members
input.atwho 'load', '@', data.members fetchData: (dataSource) ->
# load issues $.getJSON(dataSource)
input.atwho 'load', 'issues', data.issues
# load merge requests loadData: (data) ->
input.atwho 'load', 'mergerequests', data.mergerequests # load members
# load emojis @input.atwho 'load', '@', data.members
input.atwho 'load', ':', data.emojis # load issues
@input.atwho 'load', 'issues', data.issues
# load merge requests
@input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis
@input.atwho 'load', ':', data.emojis
module Projects module Projects
class ParticipantsService < BaseService class ParticipantsService < BaseService
def execute(note_type, note_id) def execute(noteable_type, noteable_id)
participating = @noteable_type = noteable_type
if note_type && note_id @noteable_id = noteable_id
participants_in(note_type, note_id)
else
[]
end
project_members = sorted(project.team.members) 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 participants.uniq
end end
def participants_in(type, id) def target
target = @target ||=
case type case @noteable_type
when "Issue" when "Issue"
project.issues.find_by_iid(id) project.issues.find_by_iid(@noteable_id)
when "MergeRequest" when "MergeRequest"
project.merge_requests.find_by_iid(id) project.merge_requests.find_by_iid(@noteable_id)
when "Commit" when "Commit"
project.commit(id) project.commit(@noteable_id)
else
nil
end 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 return [] unless target
users = target.participants(current_user) users = target.participants(current_user)
...@@ -30,13 +39,13 @@ module Projects ...@@ -30,13 +39,13 @@ module Projects
end end
def sorted(users) 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 } { username: user.username, name: user.name }
end end
end end
def groups 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 count = group.users.count
{ username: group.path, name: group.name, count: count } { username: group.path, name: group.name, count: count }
end end
......
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
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