Project

General

Profile

Feature #43355 » 0002-groups-pagination.patch

Takenori TAKAKI, 2026-08-05 06:32

View differences:

app/controllers/groups_controller.rb
119 119
    respond_to do |format|
120 120
      format.html do
121 121
        flash[:notice] = l(:notice_successful_update)
122
        redirect_back_or_default edit_group_path(@group, :tab => 'users')
122
        redirect_back_or_default edit_group_path(@group, group_users_query)
123 123
      end
124 124
      format.js
125 125
      format.api do
......
145 145
      respond_to do |format|
146 146
        format.html do
147 147
          flash[:notice] = l(:notice_successful_delete)
148
          redirect_back_or_default edit_group_path(@group, :tab => 'users')
148
          redirect_back_or_default edit_group_path(@group, group_users_query)
149 149
        end
150 150
        format.api {render_api_ok}
151 151
      end
......
174 174
  def user_count_by_group_id
175 175
    User.joins(:groups).group(:group_id).count.transform_keys(&:to_i)
176 176
  end
177

  
178
  # Keeps the users tab and its pagination when redirecting after add/remove
179
  def group_users_query
180
    query = {:tab => 'users'}
181
    query[:users_page] = params[:users_page] if params[:users_page].present?
182
    query[:per_page] = params[:per_page] if params[:per_page].present?
183
    query
184
  end
177 185
end
app/helpers/groups_helper.rb
50 50
      end
51 51
    s + content_tag('span', links, :class => 'pagination')
52 52
  end
53

  
54
  # Returns the requested page of the group's users together with its paginator
55
  # and the total user count, so the users tab loads only one page at a time
56
  # instead of rendering every user of the group.
57
  def paginate_group_users(group)
58
    scope = group.users.sorted
59
    user_count = scope.count
60
    user_pages = Redmine::Pagination::Paginator.new(user_count, per_page_option, params['users_page'], 'users_page')
61
    users = scope.limit(user_pages.per_page).offset(user_pages.offset).to_a
62
    [users, user_pages, user_count]
63
  end
53 64
end
app/views/groups/_new_users_modal.html.erb
1 1
<h3 class="title"><%= l(:label_user_new) %></h3>
2 2

  
3
<%= form_for(@group, :url => group_users_path(@group), :remote => true, :method => :post) do |f| %>
3
<%= form_for(@group, :url => group_users_path(@group, :users_page => params[:users_page]), :remote => true, :method => :post) do |f| %>
4 4
  <%= render :partial => 'new_users_form' %>
5 5
  <p class="buttons">
6 6
    <%= submit_tag l(:button_add) %>
app/views/groups/_users.html.erb
1
<p><%= link_to sprite_icon('add', l(:label_user_new)), new_group_users_path(@group), :remote => true, :class => "icon icon-add" %></p>
1
<%
2
  # A dedicated 'users_page' parameter is used so it does not clash with the
3
  # 'page' used by the add-user modal's principal list (render_principals_for_new_group_users).
4
  users, user_pages, user_count = paginate_group_users(@group)
5
%>
6
<p><%= link_to sprite_icon('add', l(:label_user_new)), new_group_users_path(@group, :users_page => params[:users_page]), :remote => true, :class => "icon icon-add" %></p>
2 7

  
3
<% if @group.users.any? %>
8
<% if users.any? %>
4 9
  <table class="list users">
5 10
    <thead><tr>
6 11
      <th><%= l(:label_user) %></th>
7 12
      <th style="width:15%"></th>
8 13
    </tr></thead>
9 14
    <tbody>
10
    <% @group.users.sort.each do |user| %>
15
    <% users.each do |user| %>
11 16
      <tr id="user-<%= user.id %>">
12 17
        <td class="name"><%= link_to_user user %></td>
13 18
        <td class="buttons">
14
          <%= link_to sprite_icon('link-break', l(:button_remove)), group_users_path(@group, :user_id => user), :method => :delete, :class => 'icon icon-link-break' %>
19
          <%= link_to sprite_icon('link-break', l(:button_remove)), group_users_path(@group, :user_id => user, :users_page => params[:users_page]), :method => :delete, :class => 'icon icon-link-break' %>
15 20
        </td>
16 21
      </tr>
17 22
    <% end %>
18 23
    </tbody>
19 24
  </table>
25
  <span class="pagination">
26
    <%= pagination_links_full(user_pages, user_count) do |text, parameters, options|
27
          link_to text, edit_group_path(@group, request.query_parameters.merge(parameters).merge(:tab => 'users')), options
28
        end %>
29
  </span>
20 30
<% else %>
21 31
  <p class="nodata"><%= l(:label_no_data) %></p>
22 32
<% end %>
test/functional/groups_controller_test.rb
169 169
    assert_select 'div#tab-content-memberships a.icon-link-break', :text => 'Remove'
170 170
  end
171 171

  
172
  def test_edit_users_tab_should_be_paginated
173
    group = Group.generate!
174
    3.times { group.users << User.generate! }
175

  
176
    with_settings :per_page_options => '2,25,50' do
177
      get(:edit, :params => {:id => group.id, :tab => 'users'})
178
      assert_response :success
179
      assert_select 'div#tab-content-users table.users tbody tr', :count => 2
180
      assert_select 'div#tab-content-users span.pagination'
181
      # Pagination links keep the users tab and use the users_page parameter
182
      assert_select 'div#tab-content-users span.pagination a[href*=?]', 'users_page='
183

  
184
      get(:edit, :params => {:id => group.id, :tab => 'users', :users_page => 2})
185
      assert_response :success
186
      assert_select 'div#tab-content-users table.users tbody tr', :count => 1
187
    end
188
  end
189

  
190
  def test_new_users_xhr_should_keep_current_page_in_form_action
191
    get(:new_users, :params => {:id => 10, :users_page => 2}, :xhr => true)
192
    assert_response :success
193
    # The add-user form posts with the current page so the list stays on it after adding
194
    assert_match %r{/groups/10/users\?users_page=2}, response.body
195
  end
196

  
172 197
  def test_update
173 198
    new_name = 'New name'
174 199
    put(
test/helpers/groups_helper_test.rb
39 39
    assert_select_in result, 'span.pagination li.current span', :text => '1'
40 40
    assert_select_in result, 'a[href=?]', "/groups/#{group.id}/autocomplete_for_user.js?page=2", :text => '2'
41 41
  end
42

  
43
  def test_paginate_group_users_returns_only_the_requested_page
44
    # per_page_option is provided by ApplicationController in the running app
45
    stubs(:per_page_option).returns(2)
46
    group = Group.generate!
47
    3.times { group.users << User.generate! }
48

  
49
    users, user_pages, user_count = paginate_group_users(group)
50

  
51
    assert_equal 2, users.size
52
    assert_equal 2, user_pages.per_page
53
    assert_equal group.users.count, user_count
54
  end
42 55
end
(3-3/3)