##// END OF EJS Templates
Adds a user search field with autocompleter on project members screen....
Jean-Philippe Lang -
r2549:04e181b8b05d
parent child
Show More
@@ -0,0 +1,5
1 <ul>
2 <% @users.each do |user| -%>
3 <li><%= h user.login %><span class="informal"> (<%= h(user.name(:lastname_coma_firstname)) %>)</span></li>
4 <% end -%>
5 </ul>
@@ -16,8 +16,8
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class MembersController < ApplicationController
19 before_filter :find_member, :except => :new
20 before_filter :find_project, :only => :new
19 before_filter :find_member, :except => [:new, :autocomplete_for_member_login]
20 before_filter :find_project, :only => [:new, :autocomplete_for_member_login]
21 21 before_filter :authorize
22 22
23 23 def new
@@ -60,6 +60,13 class MembersController < ApplicationController
60 60 format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
61 61 end
62 62 end
63
64 def autocomplete_for_member_login
65 @users = User.active.find(:all, :conditions => ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ?", "#{params[:user]}%", "#{params[:user]}%", "#{params[:user]}%"],
66 :limit => 10,
67 :order => 'login ASC') - @project.users
68 render :layout => false
69 end
63 70
64 71 private
65 72 def find_project
@@ -31,6 +31,16 class Member < ActiveRecord::Base
31 31 self.user.name
32 32 end
33 33
34 # Sets user by login
35 def user_login=(login)
36 login = login.to_s
37 unless login.blank?
38 if (u = User.find_by_login(login))
39 self.user = u
40 end
41 end
42 end
43
34 44 def <=>(member)
35 45 role == member.role ? (user <=> member.user) : (role <=> member.role)
36 46 end
@@ -1,7 +1,5
1 1 <%= error_messages_for 'member' %>
2 <% roles = Role.find_all_givable %>
3 <% users = User.active.find(:all).sort - @project.users %>
4 <% # members sorted by role position
2 <% roles = Role.find_all_givable
5 3 members = @project.members.find(:all, :include => [:role, :user]).sort %>
6 4
7 5 <div class="splitcontentleft">
@@ -42,15 +40,24
42 40 <% end %>
43 41 </div>
44 42
43
44 <% users_count = User.active.count - @project.users.count
45 users = (users_count < 300) ? User.active.find(:all, :limit => 200).sort - @project.users : [] %>
46
45 47 <div class="splitcontentright">
46 <% if !users.empty? %>
48 <% if roles.any? && users_count > 0 %>
47 49 <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %>
48 50 <fieldset><legend><%=l(:label_member_new)%></legend>
49 <div>
50 <% users.each do |user| -%>
51 <label><%= check_box_tag 'member[user_ids][]', user.id, false %> <%= user %></label>
52 <% end -%>
53 </div>
51 <p><%= text_field_tag 'member[user_login]', nil, :size => "40" %></p>
52 <div id="member_user_login_choices" class="autocomplete">sqd</div>
53 <%= javascript_tag "new Ajax.Autocompleter('member_user_login', 'member_user_login_choices', '#{ url_for(:controller => 'members', :action => 'autocomplete_for_member_login', :id => @project) }', { minChars: 1, frequency: 0.5, paramName: 'user' });" %>
54 <% unless users.empty? %>
55 <div>
56 <% users.each do |user| -%>
57 <label><%= check_box_tag 'member[user_ids][]', user.id, false %> <%= user %></label>
58 <% end -%>
59 </div>
60 <% end %>
54 61 <p><%= l(:label_role) %>: <%= f.select :role_id, roles.collect{|role| [role.name, role.id]}, :selected => nil %>
55 62 <%= submit_tag l(:button_add) %></p>
56 63 </fieldset>
@@ -22,7 +22,7 Redmine::AccessControl.map do |map|
22 22 map.permission :search_project, {:search => :index}, :public => true
23 23 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
24 24 map.permission :select_project_modules, {:projects => :modules}, :require => :member
25 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
25 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy, :autocomplete_for_member_login]}, :require => :member
26 26 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
27 27
28 28 map.project_module :issue_tracking do |map|
@@ -327,7 +327,7 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px
327 327 /* Project members tab */
328 328 div#tab-content-members .splitcontentleft { width: 64% }
329 329 div#tab-content-members .splitcontentright { width: 34% }
330 div#tab-content-members fieldset { margin-top: -8px; padding-top:0.6em; margin-bottom: 1em; }
330 div#tab-content-members fieldset { padding:1em; margin-bottom: 1em; }
331 331 div#tab-content-members fieldset legend { font-weight: bold; }
332 332 div#tab-content-members fieldset label { display: block; }
333 333 div#tab-content-members fieldset div { max-height: 400px; overflow:auto; }
@@ -486,6 +486,36 border-bottom: 1px solid #fff;
486 486 background-color: #fff;
487 487 }
488 488
489 /***** Auto-complete *****/
490 div.autocomplete {
491 position:absolute;
492 width:250px;
493 background-color:white;
494 margin:0;
495 padding:0;
496 }
497 div.autocomplete ul {
498 list-style-type:none;
499 margin:0;
500 padding:0;
501 }
502 div.autocomplete ul li.selected { background-color: #ffb;}
503 div.autocomplete ul li {
504 list-style-type:none;
505 display:block;
506 margin:0;
507 padding:2px;
508 cursor:pointer;
509 font-size: 90%;
510 border-bottom: 1px solid #ccc;
511 border-left: 1px solid #ccc;
512 border-right: 1px solid #ccc;
513 }
514 div.autocomplete ul li span.informal {
515 font-size: 80%;
516 color: #aaa;
517 }
518
489 519 /***** Diff *****/
490 520 .diff_out { background: #fcc; }
491 521 .diff_in { background: #cfc; }
@@ -48,6 +48,14 class MembersControllerTest < Test::Unit::TestCase
48 48 assert User.find(7).member_of?(Project.find(1))
49 49 end
50 50
51 def test_create_by_user_login
52 assert_difference 'Member.count' do
53 post :new, :id => 1, :member => {:role_id => 1, :user_login => 'someone'}
54 end
55 assert_redirected_to '/projects/ecookbook/settings/members'
56 assert User.find(7).member_of?(Project.find(1))
57 end
58
51 59 def test_create_multiple
52 60 assert_difference 'Member.count', 3 do
53 61 post :new, :id => 1, :member => {:role_id => 1, :user_ids => [7, 8, 9]}
@@ -70,4 +78,12 class MembersControllerTest < Test::Unit::TestCase
70 78 assert_redirected_to '/projects/ecookbook/settings/members'
71 79 assert !User.find(3).member_of?(Project.find(1))
72 80 end
81
82 def test_autocomplete_for_member_login
83 get :autocomplete_for_member_login, :id => 1, :user => 'mis'
84 assert_response :success
85 assert_template 'autocomplete_for_member_login'
86
87 assert_tag :ul, :child => {:tag => 'li', :content => /miscuser8/}
88 end
73 89 end
General Comments 0
You need to be logged in to leave comments. Login now