diff --git a/app/assets/javascripts/application-legacy.js b/app/assets/javascripts/application-legacy.js index 9662d2396..bea54ae9a 100644 --- a/app/assets/javascripts/application-legacy.js +++ b/app/assets/javascripts/application-legacy.js @@ -796,22 +796,41 @@ function multipleAutocompleteField(fieldId, url, options) { }); } -function observeSearchfield(fieldId, targetId, url) { +function observeSearchfield(fieldId, targetId, url, options) { $('#'+fieldId).each(function() { var $this = $(this); $this.addClass('autocomplete'); $this.attr('data-value-was', $this.val()); + var checkedValues = {}; var check = function() { var val = $this.val(); if ($this.attr('data-value-was') != val){ $this.attr('data-value-was', val); + if (options && options.checkboxSelector) { + $(options.checkboxSelector).each(function() { + if ($(this).prop('checked')) { + checkedValues[$(this).val()] = true; + } + }); + } $.ajax({ url: url, type: 'get', data: {q: $this.val()}, - success: function(data){ if(targetId) $('#'+targetId).html(data); }, - beforeSend: function(){ $this.addClass('ajax-loading'); }, - complete: function(){ $this.removeClass('ajax-loading'); } + success: function(data){ + if(targetId) $('#'+targetId).html(data); + }, + complete: function(){ + $this.removeClass('ajax-loading'); + if (options && options.checkboxSelector) { + $(options.checkboxSelector).each(function() { + if (checkedValues[$(this).val()]) { + $(this).prop('checked', true); + } + }); + } + }, + beforeSend: function(){ $this.addClass('ajax-loading'); } }); } }; diff --git a/app/views/groups/_new_users_form.html.erb b/app/views/groups/_new_users_form.html.erb index 5c33a966c..da75954d7 100644 --- a/app/views/groups/_new_users_form.html.erb +++ b/app/views/groups/_new_users_form.html.erb @@ -1,7 +1,7 @@
<%= label_tag "user_search", l(:label_user_search) %>

<%= text_field_tag 'user_search', nil %>

- <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %> + <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }', {checkboxSelector: 'input[name=\"user_ids[]\"]'})" %>
<%= render_principals_for_new_group_users(@group) %> diff --git a/app/views/members/_new_form.html.erb b/app/views/members/_new_form.html.erb index 70caa2600..25257cd21 100644 --- a/app/views/members/_new_form.html.erb +++ b/app/views/members/_new_form.html.erb @@ -1,7 +1,7 @@
<%= label_tag("principal_search", l(:label_principal_search)) %>

<%= text_field_tag('principal_search', nil) %>

- <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %> + <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }', {checkboxSelector: 'input[name=\"membership[user_ids][]\"]'})" %>
<%= render_principals_for_new_members(@project) %>
diff --git a/app/views/watchers/_new.html.erb b/app/views/watchers/_new.html.erb index dfff5516c..85a1530fc 100644 --- a/app/views/watchers/_new.html.erb +++ b/app/views/watchers/_new.html.erb @@ -34,7 +34,8 @@ title = :object_id => (watchables.present? ? watchables.map(&:id) : nil), :project_id => @project ) - )}' + )}', + {checkboxSelector: 'input[name=\"watcher[user_ids][]\"]'} )" ) %>
diff --git a/test/system/groups_test.rb b/test/system/groups_test.rb new file mode 100644 index 000000000..d591fb453 --- /dev/null +++ b/test/system/groups_test.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006- Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require_relative '../application_system_test_case' + +class GroupsSystemTest < ApplicationSystemTestCase + fixtures :users, :email_addresses, :groups_users + + def test_add_user_to_group_after_search_preserves_selection + group = Group.find(10) # A Team + rhill = User.find_by_login('rhill') + someone = User.find_by_login('someone') + + assert_not group.users.include?(rhill) + assert_not group.users.include?(someone) + + log_user('admin', 'admin') + visit "/groups/#{group.id}/edit?tab=users" + + click_on 'New user' + + within '#ajax-modal' do + # Check Robert Hill + find('label', text: 'Robert Hill').click + + # Search for 'some' - Robert Hill disappears + fill_in 'user_search', with: 'some' + assert page.has_no_css?('label', text: 'Robert Hill') + + # Check Some One while Robert Hill is hidden + find('label', text: 'Some One').click + + # Clear search - both should be visible and checked + fill_in 'user_search', with: '' + assert page.has_css?('label', text: 'Robert Hill') + assert page.has_css?('label', text: 'Some One') + + # Submit + click_on 'Add' + end + + # Wait for modal to close + assert page.has_no_css?('#ajax-modal') + + # Verify both users were added to the group + group.reload + assert group.users.include?(rhill), + "Expected Robert Hill to be added to group" + assert group.users.include?(someone), + "Expected Some One to be added to group" + end +end diff --git a/test/system/members_test.rb b/test/system/members_test.rb new file mode 100644 index 000000000..8b99e66bd --- /dev/null +++ b/test/system/members_test.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006- Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require_relative '../application_system_test_case' + +class MembersSystemTest < ApplicationSystemTestCase + fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, + :trackers, :projects_trackers, :enabled_modules + + def test_add_member_after_search_preserves_selection + project = Project.find('ecookbook') + rhill = User.find_by_login('rhill') + admin_user = User.find_by_login('admin') + + assert_not project.members.map(&:user).include?(rhill) + assert_not project.members.map(&:user).include?(admin_user) + + log_user('admin', 'admin') + visit '/projects/ecookbook/settings/members' + + click_on 'New member' + + within '#ajax-modal' do + # Check Robert Hill + find('label', text: 'Robert Hill').click + + # Search for 'redmine' - Robert Hill disappears + fill_in 'principal_search', with: 'redmine' + assert page.has_no_css?('label', text: 'Robert Hill') + + # Check Redmine Admin while Robert Hill is hidden + find('label', text: 'Redmine Admin').click + + # Clear search - both should be visible and checked + fill_in 'principal_search', with: '' + assert page.has_css?('label', text: 'Robert Hill') + assert page.has_css?('label', text: 'Redmine Admin') + + # Select a role + check 'Manager' + + # Submit + click_on 'Add' + end + + # Wait for modal to close and page to update + assert page.has_no_css?('#ajax-modal') + + # Verify both users were added as members + project.reload + assert project.members.map(&:user).include?(rhill), + "Expected Robert Hill to be added as member" + assert project.members.map(&:user).include?(admin_user), + "Expected Redmine Admin to be added as member" + + # Verify on the page + assert page.has_css?('#tab-content-members', text: 'Robert Hill') + assert page.has_css?('#tab-content-members', text: 'Redmine Admin') + end +end diff --git a/test/system/watchers_test.rb b/test/system/watchers_test.rb new file mode 100644 index 000000000..b26b38d66 --- /dev/null +++ b/test/system/watchers_test.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Redmine - project management software +# Copyright (C) 2006- Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require_relative '../application_system_test_case' + +class WatchersSystemTest < ApplicationSystemTestCase + fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles, + :trackers, :projects_trackers, :enabled_modules, :issues, :issue_statuses, + :watchers + + def test_add_watcher_after_search_preserves_selection + issue = Issue.find(1) + jsmith = User.find_by_login('jsmith') + dlopper = User.find_by_login('dlopper') + + # Clear existing watchers + issue.watcher_users = [] + + assert_not issue.watched_by?(jsmith) + assert_not issue.watched_by?(dlopper) + + log_user('admin', 'admin') + visit "/issues/#{issue.id}" + + # Open watcher modal + within '#sidebar' do + click_on 'Add' + end + + within '#ajax-modal' do + # Check John Smith + find('label', text: 'John Smith').click + + # Search for 'lopper' - John Smith disappears + fill_in 'user_search', with: 'lopper' + assert page.has_no_css?('label', text: 'John Smith') + + # Check Dave Lopper while John Smith is hidden + find('label', text: 'Dave Lopper').click + + # Clear search - both should be visible and checked + fill_in 'user_search', with: '' + assert page.has_css?('label', text: 'John Smith') + assert page.has_css?('label', text: 'Dave Lopper') + + # Submit + click_on 'Add' + end + + # Wait for modal to close + assert page.has_no_css?('#ajax-modal') + + # Verify both users were added as watchers + issue.reload + assert issue.watched_by?(jsmith), + "Expected John Smith to be added as watcher" + assert issue.watched_by?(dlopper), + "Expected Dave Lopper to be added as watcher" + end +end