Project

General

Profile

Feature #43825 ยป preserve_checkbox_state.patch

[Agileware]Kota Uchino, 2026-02-13 13:06

View differences:

app/assets/javascripts/application-legacy.js
796 796
  });
797 797
}
798 798

  
799
function observeSearchfield(fieldId, targetId, url) {
799
function observeSearchfield(fieldId, targetId, url, options) {
800 800
  $('#'+fieldId).each(function() {
801 801
    var $this = $(this);
802 802
    $this.addClass('autocomplete');
803 803
    $this.attr('data-value-was', $this.val());
804
    var checkedValues = {};
804 805
    var check = function() {
805 806
      var val = $this.val();
806 807
      if ($this.attr('data-value-was') != val){
807 808
        $this.attr('data-value-was', val);
809
        if (options && options.checkboxSelector) {
810
          $(options.checkboxSelector).each(function() {
811
            if ($(this).prop('checked')) {
812
              checkedValues[$(this).val()] = true;
813
            }
814
          });
815
        }
808 816
        $.ajax({
809 817
          url: url,
810 818
          type: 'get',
811 819
          data: {q: $this.val()},
812
          success: function(data){ if(targetId) $('#'+targetId).html(data); },
813
          beforeSend: function(){ $this.addClass('ajax-loading'); },
814
          complete: function(){ $this.removeClass('ajax-loading'); }
820
          success: function(data){
821
            if(targetId) $('#'+targetId).html(data);
822
          },
823
          complete: function(){
824
            $this.removeClass('ajax-loading');
825
            if (options && options.checkboxSelector) {
826
              $(options.checkboxSelector).each(function() {
827
                if (checkedValues[$(this).val()]) {
828
                  $(this).prop('checked', true);
829
                }
830
              });
831
            }
832
          },
833
          beforeSend: function(){ $this.addClass('ajax-loading'); }
815 834
        });
816 835
      }
817 836
    };
app/views/groups/_new_users_form.html.erb
1 1
<fieldset class="box">
2 2
  <legend><%= label_tag "user_search", l(:label_user_search) %></legend>
3 3
  <p><%= text_field_tag 'user_search', nil %></p>
4
  <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %>
4
  <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }', {checkboxSelector: 'input[name=\"user_ids[]\"]'})" %>
5 5

  
6 6
  <div id="users">
7 7
    <%= render_principals_for_new_group_users(@group) %>
app/views/members/_new_form.html.erb
1 1
<fieldset class="box">
2 2
  <legend><%= label_tag("principal_search", l(:label_principal_search)) %></legend>
3 3
  <p><%= text_field_tag('principal_search', nil) %></p>
4
  <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %>
4
  <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }', {checkboxSelector: 'input[name=\"membership[user_ids][]\"]'})" %>
5 5
  <div id="principals_for_new_member">
6 6
    <%= render_principals_for_new_members(@project) %>
7 7
  </div>
app/views/watchers/_new.html.erb
34 34
                 :object_id => (watchables.present? ? watchables.map(&:id) : nil),
35 35
                 :project_id => @project
36 36
               )
37
             )}'
37
             )}',
38
          {checkboxSelector: 'input[name=\"watcher[user_ids][]\"]'}
38 39
         )"
39 40
       ) %>
40 41
  <div id="users_for_watcher">
test/system/groups_test.rb
1
# frozen_string_literal: true
2

  
3
# Redmine - project management software
4
# Copyright (C) 2006-  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
require_relative '../application_system_test_case'
21

  
22
class GroupsSystemTest < ApplicationSystemTestCase
23
  fixtures :users, :email_addresses, :groups_users
24

  
25
  def test_add_user_to_group_after_search_preserves_selection
26
    group = Group.find(10)  # A Team
27
    rhill = User.find_by_login('rhill')
28
    someone = User.find_by_login('someone')
29

  
30
    assert_not group.users.include?(rhill)
31
    assert_not group.users.include?(someone)
32

  
33
    log_user('admin', 'admin')
34
    visit "/groups/#{group.id}/edit?tab=users"
35

  
36
    click_on 'New user'
37

  
38
    within '#ajax-modal' do
39
      # Check Robert Hill
40
      find('label', text: 'Robert Hill').click
41

  
42
      # Search for 'some' - Robert Hill disappears
43
      fill_in 'user_search', with: 'some'
44
      assert page.has_no_css?('label', text: 'Robert Hill')
45

  
46
      # Check Some One while Robert Hill is hidden
47
      find('label', text: 'Some One').click
48

  
49
      # Clear search - both should be visible and checked
50
      fill_in 'user_search', with: ''
51
      assert page.has_css?('label', text: 'Robert Hill')
52
      assert page.has_css?('label', text: 'Some One')
53

  
54
      # Submit
55
      click_on 'Add'
56
    end
57

  
58
    # Wait for modal to close
59
    assert page.has_no_css?('#ajax-modal')
60

  
61
    # Verify both users were added to the group
62
    group.reload
63
    assert group.users.include?(rhill),
64
      "Expected Robert Hill to be added to group"
65
    assert group.users.include?(someone),
66
      "Expected Some One to be added to group"
67
  end
68
end
test/system/members_test.rb
1
# frozen_string_literal: true
2

  
3
# Redmine - project management software
4
# Copyright (C) 2006-  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
require_relative '../application_system_test_case'
21

  
22
class MembersSystemTest < ApplicationSystemTestCase
23
  fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
24
           :trackers, :projects_trackers, :enabled_modules
25

  
26
  def test_add_member_after_search_preserves_selection
27
    project = Project.find('ecookbook')
28
    rhill = User.find_by_login('rhill')
29
    admin_user = User.find_by_login('admin')
30

  
31
    assert_not project.members.map(&:user).include?(rhill)
32
    assert_not project.members.map(&:user).include?(admin_user)
33

  
34
    log_user('admin', 'admin')
35
    visit '/projects/ecookbook/settings/members'
36

  
37
    click_on 'New member'
38

  
39
    within '#ajax-modal' do
40
      # Check Robert Hill
41
      find('label', text: 'Robert Hill').click
42

  
43
      # Search for 'redmine' - Robert Hill disappears
44
      fill_in 'principal_search', with: 'redmine'
45
      assert page.has_no_css?('label', text: 'Robert Hill')
46

  
47
      # Check Redmine Admin while Robert Hill is hidden
48
      find('label', text: 'Redmine Admin').click
49

  
50
      # Clear search - both should be visible and checked
51
      fill_in 'principal_search', with: ''
52
      assert page.has_css?('label', text: 'Robert Hill')
53
      assert page.has_css?('label', text: 'Redmine Admin')
54

  
55
      # Select a role
56
      check 'Manager'
57

  
58
      # Submit
59
      click_on 'Add'
60
    end
61

  
62
    # Wait for modal to close and page to update
63
    assert page.has_no_css?('#ajax-modal')
64

  
65
    # Verify both users were added as members
66
    project.reload
67
    assert project.members.map(&:user).include?(rhill),
68
      "Expected Robert Hill to be added as member"
69
    assert project.members.map(&:user).include?(admin_user),
70
      "Expected Redmine Admin to be added as member"
71

  
72
    # Verify on the page
73
    assert page.has_css?('#tab-content-members', text: 'Robert Hill')
74
    assert page.has_css?('#tab-content-members', text: 'Redmine Admin')
75
  end
76
end
test/system/watchers_test.rb
1
# frozen_string_literal: true
2

  
3
# Redmine - project management software
4
# Copyright (C) 2006-  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
require_relative '../application_system_test_case'
21

  
22
class WatchersSystemTest < ApplicationSystemTestCase
23
  fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
24
           :trackers, :projects_trackers, :enabled_modules, :issues, :issue_statuses,
25
           :watchers
26

  
27
  def test_add_watcher_after_search_preserves_selection
28
    issue = Issue.find(1)
29
    jsmith = User.find_by_login('jsmith')
30
    dlopper = User.find_by_login('dlopper')
31

  
32
    # Clear existing watchers
33
    issue.watcher_users = []
34

  
35
    assert_not issue.watched_by?(jsmith)
36
    assert_not issue.watched_by?(dlopper)
37

  
38
    log_user('admin', 'admin')
39
    visit "/issues/#{issue.id}"
40

  
41
    # Open watcher modal
42
    within '#sidebar' do
43
      click_on 'Add'
44
    end
45

  
46
    within '#ajax-modal' do
47
      # Check John Smith
48
      find('label', text: 'John Smith').click
49

  
50
      # Search for 'lopper' - John Smith disappears
51
      fill_in 'user_search', with: 'lopper'
52
      assert page.has_no_css?('label', text: 'John Smith')
53

  
54
      # Check Dave Lopper while John Smith is hidden
55
      find('label', text: 'Dave Lopper').click
56

  
57
      # Clear search - both should be visible and checked
58
      fill_in 'user_search', with: ''
59
      assert page.has_css?('label', text: 'John Smith')
60
      assert page.has_css?('label', text: 'Dave Lopper')
61

  
62
      # Submit
63
      click_on 'Add'
64
    end
65

  
66
    # Wait for modal to close
67
    assert page.has_no_css?('#ajax-modal')
68

  
69
    # Verify both users were added as watchers
70
    issue.reload
71
    assert issue.watched_by?(jsmith),
72
      "Expected John Smith to be added as watcher"
73
    assert issue.watched_by?(dlopper),
74
      "Expected Dave Lopper to be added as watcher"
75
  end
76
end
    (1-1/1)