Commit f0f88390c1309b0d5a8cead701477e21c2174f05

Authored by Dmitriy Zaporozhets
1 parent 1d48904a

project_user selectbox with ajax autocomplete

Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
app/assets/javascripts/api.js.coffee
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 user_path: "/api/:version/users/:id.json" 3 user_path: "/api/:version/users/:id.json"
4 notes_path: "/api/:version/projects/:id/notes.json" 4 notes_path: "/api/:version/projects/:id/notes.json"
5 namespaces_path: "/api/:version/namespaces.json" 5 namespaces_path: "/api/:version/namespaces.json"
  6 + project_users_path: "/api/:version/projects/:id/users.json"
6 7
7 # Get 20 (depends on api) recent notes 8 # Get 20 (depends on api) recent notes
8 # and sort the ascending from oldest to newest 9 # and sort the ascending from oldest to newest
@@ -50,6 +51,23 @@ @@ -50,6 +51,23 @@
50 ).done (users) -> 51 ).done (users) ->
51 callback(users) 52 callback(users)
52 53
  54 + # Return project users list. Filtered by query
  55 + # Only active users retrieved
  56 + projectUsers: (project_id, query, callback) ->
  57 + url = Api.buildUrl(Api.project_users_path)
  58 + url = url.replace(':id', project_id)
  59 +
  60 + $.ajax(
  61 + url: url
  62 + data:
  63 + private_token: gon.api_token
  64 + search: query
  65 + per_page: 20
  66 + active: true
  67 + dataType: "json"
  68 + ).done (users) ->
  69 + callback(users)
  70 +
53 # Return namespaces list. Filtered by query 71 # Return namespaces list. Filtered by query
54 namespaces: (query, callback) -> 72 namespaces: (query, callback) ->
55 url = Api.buildUrl(Api.namespaces_path) 73 url = Api.buildUrl(Api.namespaces_path)
app/assets/javascripts/project_users_select.js.coffee 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +$ ->
  2 + projectUserFormatResult = (user) ->
  3 + if user.avatar_url
  4 + avatar = user.avatar_url
  5 + else if gon.gravatar_enabled
  6 + avatar = gon.gravatar_url
  7 + avatar = avatar.replace('%{hash}', md5(user.email))
  8 + avatar = avatar.replace('%{size}', '24')
  9 + else
  10 + avatar = gon.relative_url_root + "/assets/no_avatar.png"
  11 +
  12 + "<div class='user-result'>
  13 + <div class='user-image'><img class='avatar s24' src='#{avatar}'></div>
  14 + <div class='user-name'>#{user.name}</div>
  15 + <div class='user-username'>#{user.username}</div>
  16 + </div>"
  17 +
  18 + projectUserFormatSelection = (user) ->
  19 + user.name
  20 +
  21 + $('.ajax-project-users-select').each (i, select) ->
  22 + project_id = $('body').data('project-id')
  23 + $(select).select2
  24 + placeholder: "Search for a user"
  25 + multiple: $(select).hasClass('multiselect')
  26 + minimumInputLength: 0
  27 + query: (query) ->
  28 + Api.projectUsers project_id, query.term, (users) ->
  29 + data = { results: users }
  30 + query.callback(data)
  31 +
  32 + initSelection: (element, callback) ->
  33 + id = $(element).val()
  34 + if id isnt ""
  35 + Api.user(id, callback)
  36 +
  37 +
  38 + formatResult: projectUserFormatResult
  39 + formatSelection: projectUserFormatSelection
  40 + dropdownCssClass: "ajax-project-users-dropdown"
  41 + dropdownAutoWidth: true
  42 + escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
  43 + m
app/assets/stylesheets/generic/selects.scss
@@ -79,6 +79,8 @@ select { @@ -79,6 +79,8 @@ select {
79 margin-right: 10px; 79 margin-right: 10px;
80 } 80 }
81 81
82 -.ajax-users-dropdown .select2-search {  
83 - padding-top: 4px; 82 +.ajax-users-dropdown, .ajax-project-users-dropdown {
  83 + .select2-search {
  84 + padding-top: 4px;
  85 + }
84 } 86 }
app/helpers/application_helper.rb
@@ -162,15 +162,6 @@ module ApplicationHelper @@ -162,15 +162,6 @@ module ApplicationHelper
162 162
163 alias_method :url_to_image, :image_url 163 alias_method :url_to_image, :image_url
164 164
165 - def users_select_tag(id, opts = {})  
166 - css_class = "ajax-users-select "  
167 - css_class << "multiselect " if opts[:multiple]  
168 - css_class << (opts[:class] || '')  
169 - value = opts[:selected] || ''  
170 -  
171 - hidden_field_tag(id, value, class: css_class)  
172 - end  
173 -  
174 def body_data_page 165 def body_data_page
175 path = controller.controller_path.split('/') 166 path = controller.controller_path.split('/')
176 namespace = path.first if path.second 167 namespace = path.first if path.second
app/helpers/selects_helper.rb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +module SelectsHelper
  2 + def users_select_tag(id, opts = {})
  3 + css_class = "ajax-users-select "
  4 + css_class << "multiselect " if opts[:multiple]
  5 + css_class << (opts[:class] || '')
  6 + value = opts[:selected] || ''
  7 +
  8 + hidden_field_tag(id, value, class: css_class)
  9 + end
  10 +
  11 + def project_users_select_tag(id, opts = {})
  12 + css_class = "ajax-project-users-select "
  13 + css_class << "multiselect " if opts[:multiple]
  14 + css_class << (opts[:class] || '')
  15 + value = opts[:selected] || ''
  16 +
  17 + hidden_field_tag(id, value, class: css_class)
  18 + end
  19 +end
app/views/projects/issues/_issues.html.haml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 = form_tag bulk_update_project_issues_path(@project), method: :post do 6 = form_tag bulk_update_project_issues_path(@project), method: :post do
7 %span Update selected issues with &nbsp; 7 %span Update selected issues with &nbsp;
8 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status") 8 = select_tag('update[status]', options_for_select(['open', 'closed']), prompt: "Status")
9 - = select_tag('update[assignee_id]', bulk_update_assignee_options, prompt: "Assignee") 9 + = project_users_select_tag('update[assignee_id]')
10 = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone") 10 = select_tag('update[milestone_id]', bulk_update_milestone_options, prompt: "Milestone")
11 = hidden_field_tag 'update[issues_ids]', [] 11 = hidden_field_tag 'update[issues_ids]', []
12 = hidden_field_tag :status, params[:status] 12 = hidden_field_tag :status, params[:status]
lib/api/projects.rb
@@ -11,7 +11,7 @@ module API @@ -11,7 +11,7 @@ module API
11 end 11 end
12 not_found! 12 not_found!
13 end 13 end
14 - 14 +
15 def map_public_to_visibility_level(attrs) 15 def map_public_to_visibility_level(attrs)
16 publik = attrs.delete(:public) 16 publik = attrs.delete(:public)
17 publik = [ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(publik) 17 publik = [ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(publik)
@@ -308,6 +308,18 @@ module API @@ -308,6 +308,18 @@ module API
308 projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%") 308 projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%")
309 present paginate(projects), with: Entities::Project 309 present paginate(projects), with: Entities::Project
310 end 310 end
  311 +
  312 +
  313 + # Get a users list
  314 + #
  315 + # Example Request:
  316 + # GET /users
  317 + get ':id/users' do
  318 + @users = User.where(id: user_project.team.users.map(&:id))
  319 + @users = @users.search(params[:search]) if params[:search].present?
  320 + @users = paginate @users
  321 + present @users, with: Entities::User
  322 + end
311 end 323 end
312 end 324 end
313 end 325 end