diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6 index 1c1b6cd2dad7ace00fac525a1399b6cf93bd91c8..496fa9903cc50950bc9a763169a5aaa7ce38c8cc 100644 --- a/app/assets/javascripts/dispatcher.js.es6 +++ b/app/assets/javascripts/dispatcher.js.es6 @@ -215,7 +215,9 @@ new gl.Members(); new UsersSelect(); break; - case 'projects:project_members:index': + case 'projects:members:show': + new gl.MemberExpirationDate('.js-access-expiration-date-groups'); + new GroupsSelect(); new gl.MemberExpirationDate(); new gl.Members(); new UsersSelect(); @@ -261,10 +263,6 @@ case 'projects:artifacts:browse': new BuildArtifacts(); break; - case 'projects:group_links:index': - new gl.MemberExpirationDate(); - new GroupsSelect(); - break; case 'search:show': new Search(); break; diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js.es6 similarity index 66% rename from app/assets/javascripts/member_expiration_date.js rename to app/assets/javascripts/member_expiration_date.js.es6 index 7741cd2979334ea5402371b76e1a65d7c3ca3412..bf6c0ec27982d962f0ed6a28b61c98a00415d422 100644 --- a/app/assets/javascripts/member_expiration_date.js +++ b/app/assets/javascripts/member_expiration_date.js.es6 @@ -1,30 +1,29 @@ -/* eslint-disable func-names, space-before-function-paren, vars-on-top, no-var, object-shorthand, comma-dangle, max-len */ -(function() { +(() => { // Add datepickers to all `js-access-expiration-date` elements. If those elements are // children of an element with the `clearable-input` class, and have a sibling // `js-clear-input` element, then show that element when there is a value in the // datepicker, and make clicking on that element clear the field. // - gl.MemberExpirationDate = function() { + window.gl = window.gl || {}; + gl.MemberExpirationDate = (selector = '.js-access-expiration-date') => { function toggleClearInput() { $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); } - - var inputs = $('.js-access-expiration-date'); + const inputs = $(selector); inputs.datepicker({ dateFormat: 'yy-mm-dd', minDate: 1, - onSelect: function () { + onSelect: function onSelect() { $(this).trigger('change'); toggleClearInput.call(this); - } + }, }); - inputs.next('.js-clear-input').on('click', function(event) { + inputs.next('.js-clear-input').on('click', function clicked(event) { event.preventDefault(); - var input = $(this).closest('.clearable-input').find('.js-access-expiration-date'); + const input = $(this).closest('.clearable-input').find(selector); input.datepicker('setDate', null) .trigger('change'); toggleClearInput.call(input); diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 277d4202950dba1383dca590002ccb913fd5007f..cb25b808374704c9daa252d5316f78435661667b 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -163,6 +163,10 @@ ul.content-list { &:last-child { margin-right: 0; + + @media(max-width: $screen-xs-max) { + margin: 0 auto; + } } } diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index 36ee5d17211abcae41d134fdadb86a7f46d6f006..be7193bae04aa93c5396381e371c89e67d845500 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -25,7 +25,7 @@ } .form-horizontal { - margin-top: 5px; + margin-top: 20px; @media (min-width: $screen-sm-min) { display: -webkit-flex; @@ -98,6 +98,10 @@ padding-right: 35px; @media (min-width: $screen-sm-min) { + width: 250px; + } + + @media (min-width: $screen-md-min) { width: 350px; } diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb index 9eaf26a0dbf966743dcfe1998824b94771491313..66b7bdbd9889bec4f5e44180a661e32cf26b7938 100644 --- a/app/controllers/projects/group_links_controller.rb +++ b/app/controllers/projects/group_links_controller.rb @@ -4,10 +4,7 @@ class Projects::GroupLinksController < Projects::ApplicationController before_action :authorize_admin_project_member!, only: [:update] def index - @group_links = project.project_group_links.all - - @skip_groups = @group_links.pluck(:group_id) - @skip_groups << project.namespace_id unless project.personal? + redirect_to namespace_project_settings_members_path end def create @@ -25,7 +22,7 @@ def create flash[:alert] = 'Please select a group.' end - redirect_to namespace_project_group_links_path(project.namespace, project) + redirect_to namespace_project_settings_members_path(project.namespace, project) end def update @@ -39,7 +36,7 @@ def destroy respond_to do |format| format.html do - redirect_to namespace_project_group_links_path(project.namespace, project) + redirect_to namespace_project_settings_members_path(project.namespace, project) end format.js { head :ok } end diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 3aec6f18e27a39ab234adf20b60f0ec526fda7f5..6e158e685e99470e5d6b1203266732f5c0b4c819 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,54 +6,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] def index - @sort = params[:sort].presence || sort_value_name - @group_links = @project.project_group_links - - @project_members = @project.project_members - @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) - - group = @project.group - - if group - # We need `.where.not(user_id: nil)` here otherwise when a group has an - # invitee, it would make the following query return 0 rows since a NULL - # user_id would be present in the subquery - # See http://stackoverflow.com/questions/129077/not-in-clause-and-null-values - # FIXME: This whole logic should be moved to a finder! - non_null_user_ids = @project_members.where.not(user_id: nil).select(:user_id) - group_members = group.group_members.where.not(user_id: non_null_user_ids) - group_members = group_members.non_invite unless can?(current_user, :admin_group, @group) - end - - if params[:search].present? - user_ids = @project.users.search(params[:search]).select(:id) - @project_members = @project_members.where(user_id: user_ids) - - if group_members - user_ids = group.users.search(params[:search]).select(:id) - group_members = group_members.where(user_id: user_ids) - end - - @group_links = @project.project_group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id)) - end - - wheres = ["members.id IN (#{@project_members.select(:id).to_sql})"] - wheres << "members.id IN (#{group_members.select(:id).to_sql})" if group_members - - @project_members = Member. - where(wheres.join(' OR ')). - sort(@sort). - page(params[:page]) - - @requesters = AccessRequestsFinder.new(@project).execute(current_user) - - @project_member = @project.project_members.new + sort = params[:sort].presence || sort_value_name + redirect_to namespace_project_settings_members_path(@project.namespace, @project, sort: sort) end def create status = Members::CreateService.new(@project, current_user, params).execute - redirect_url = namespace_project_project_members_path(@project.namespace, @project) + redirect_url = namespace_project_settings_members_path(@project.namespace, @project) if status redirect_to redirect_url, notice: 'Users were successfully added.' @@ -76,14 +36,14 @@ def destroy respond_to do |format| format.html do - redirect_to namespace_project_project_members_path(@project.namespace, @project) + redirect_to namespace_project_settings_members_path(@project.namespace, @project) end format.js { head :ok } end end def resend_invite - redirect_path = namespace_project_project_members_path(@project.namespace, @project) + redirect_path = namespace_project_settings_members_path(@project.namespace, @project) @project_member = @project.project_members.find(params[:id]) @@ -106,7 +66,7 @@ def apply_import return render_404 end - redirect_to(namespace_project_project_members_path(project.namespace, project), + redirect_to(namespace_project_settings_members_path(project.namespace, project), notice: notice) end diff --git a/app/controllers/projects/settings/members_controller.rb b/app/controllers/projects/settings/members_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..5735e281f66e772b5b31600ef71e777a233d94d6 --- /dev/null +++ b/app/controllers/projects/settings/members_controller.rb @@ -0,0 +1,55 @@ +module Projects + module Settings + class MembersController < Projects::ApplicationController + include SortingHelper + + def show + @sort = params[:sort].presence || sort_value_name + @group_links = @project.project_group_links + + @project_members = @project.project_members + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) + + group = @project.group + + # group links + @group_links = @project.project_group_links.all + + @skip_groups = @group_links.pluck(:group_id) + @skip_groups << @project.namespace_id unless @project.personal? + + if group + # We need `.where.not(user_id: nil)` here otherwise when a group has an + # invitee, it would make the following query return 0 rows since a NULL + # user_id would be present in the subquery + # See http://stackoverflow.com/questions/129077/not-in-clause-and-null-values + group_members = MembersFinder.new(@project_members, group).execute(current_user) + end + + if params[:search].present? + user_ids = @project.users.search(params[:search]).select(:id) + @project_members = @project_members.where(user_id: user_ids) + + if group_members + user_ids = group.users.search(params[:search]).select(:id) + group_members = group_members.where(user_id: user_ids) + end + + @group_links = @project.project_group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id)) + end + + wheres = ["members.id IN (#{@project_members.select(:id).to_sql})"] + wheres << "members.id IN (#{group_members.select(:id).to_sql})" if group_members + + @project_members = Member. + where(wheres.join(' OR ')). + sort(@sort). + page(params[:page]) + + @requesters = AccessRequestsFinder.new(@project).execute(current_user) + + @project_member = @project.project_members.new + end + end + end +end diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb new file mode 100644 index 0000000000000000000000000000000000000000..702944404f50909d3fcb37f1ea5eb2b440f9c1fd --- /dev/null +++ b/app/finders/members_finder.rb @@ -0,0 +1,13 @@ +class MembersFinder < Projects::ApplicationController + def initialize(project_members, project_group) + @project_members = project_members + @project_group = project_group + end + + def execute(current_user) + non_null_user_ids = @project_members.where.not(user_id: nil).select(:user_id) + group_members = @project_group.group_members.where.not(user_id: non_null_user_ids) + group_members = group_members.non_invite unless can?(current_user, :admin_group, @project_group) + group_members + end +end diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 99db73c9ee04b2778e922140cf3fbb9266afc47b..5742fec44581f21ce79bd5ecb8002ebdf41a59ff 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -206,4 +206,9 @@ def artifacts_action_path(path, project, build) file_namespace_project_build_artifacts_path(*args) end end + + # Settings + def project_settings_members_path(project, *args) + namespace_project_settings_members_path(project.namespace, project, *args) + end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index cdb9663877cd37b0a2d994c24d6c7a2956f39e1c..8660e13081fce4b378a42f2ea1e15a343fffa6e0 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -75,7 +75,7 @@ def project_autocomplete { category: "Current Project", label: "Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) }, { category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) }, { category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) }, - { category: "Current Project", label: "Members", url: namespace_project_project_members_path(@project.namespace, @project) }, + { category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) }, { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }, ] else diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 613b8b7d3013d1b3c30e5156ef20a0f519e9898f..0fb2bb460cbbd096ff750969b6db6e9d7e02926e 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -1,14 +1,9 @@ - if project_nav_tab? :team - = nav_link(controller: [:project_members, :teams]) do - = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do + = nav_link(controller: [:members, :teams]) do + = link_to namespace_project_settings_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do %span Members - if can_edit - - if @project.allowed_to_share_with_group? - = nav_link(controller: :group_links) do - = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do - %span - Groups = nav_link(controller: :deploy_keys) do = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do %span diff --git a/app/views/projects/group_links/index.html.haml b/app/views/projects/group_links/_index.html.haml similarity index 92% rename from app/views/projects/group_links/index.html.haml rename to app/views/projects/group_links/_index.html.haml index 1b0dbbb8111aaebf8eee4dfd145e18d1957471fc..99d0df2ac34e42ef94d2f08ad70424addcd2c9d3 100644 --- a/app/views/projects/group_links/index.html.haml +++ b/app/views/projects/group_links/_index.html.haml @@ -20,10 +20,10 @@ .form-group = label_tag :expires_at, 'Access expiration date', class: 'label-light' .clearable-input - = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Select access expiration date' + = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date-groups', placeholder: 'Select access expiration date', id: 'expires_at_groups' %i.clear-icon.js-clear-input .help-block - On this date, all users in the group will automatically lose access to this project. + On this date, all members in the group will automatically lose access to this project. = submit_tag "Share", class: "btn btn-create" .col-lg-9.col-lg-offset-3 %hr diff --git a/app/views/projects/project_members/_index.html.haml b/app/views/projects/project_members/_index.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..ab0771b5751c3d4c8ab41ab5d8a0b73c21c3d9a6 --- /dev/null +++ b/app/views/projects/project_members/_index.html.haml @@ -0,0 +1,22 @@ +.row.prepend-top-default + .col-lg-3.settings-sidebar + %h4.prepend-top-0 + Members + - if can?(current_user, :admin_project_member, @project) + %p + Add a new member to + %strong= @project.name + .col-lg-9 + .light.prepend-top-default + - if can?(current_user, :admin_project_member, @project) + = render "projects/project_members/new_project_member" + + = render 'shared/members/requests', membership_source: @project, requesters: @requesters + .append-bottom-default.clearfix + %h5.member.existing-title + Existing members and groups + - if @group_links.any? + = render 'projects/project_members/groups', group_links: @group_links + + = render 'projects/project_members/team', members: @project_members + = paginate @project_members, theme: "gitlab" diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 79dcd7a6ee9acb501ef63897603233be50dcbd0d..2b1c23f7dda85be6d0eab1da9bdbd7f068e834ad 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -1,22 +1,18 @@ = form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'users-project-form' } do |f| - .row - .col-md-4.col-lg-6 - = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true) - .help-block.append-bottom-10 - Search for users by name, username, or email, or invite new ones using their email address. - - .col-md-3.col-lg-2 - = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select" - .help-block.append-bottom-10 - = link_to "Read more", help_page_path("user/permissions"), class: "vlink" - about role permissions - - .col-md-3.col-lg-2 - .clearable-input - = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' - %i.clear-icon.js-clear-input - .help-block.append-bottom-10 - On this date, the user(s) will automatically lose access to this project. - - .col-md-2 - = f.submit "Add to project", class: "btn btn-create btn-block" + .form-group + = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true, placeholder: "Search for members to update or invite") + .help-block.append-bottom-10 + Search for members by name, username, or email, or invite new ones using their email address. + .form-group + = select_tag :access_level, options_for_select(ProjectMember.access_level_roles, @project_member.access_level), class: "form-control project-access-select" + .help-block.append-bottom-10 + = link_to "Read more", help_page_path("user/permissions"), class: "vlink" + about role permissions + .form-group + .clearable-input + = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' + %i.clear-icon.js-clear-input + .help-block.append-bottom-10 + On this date, the member(s) will automatically lose access to this project. + = f.submit "Add to project", class: "btn btn-create" + = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default", title: "Import members from another project" diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml index c1e894d8f40f1395c5c2dc46800634a21a4c44d9..5292e73be7af837289dfa7b8ca116baebb0918c0 100644 --- a/app/views/projects/project_members/_team.html.haml +++ b/app/views/projects/project_members/_team.html.haml @@ -1,7 +1,13 @@ .panel.panel-default .panel-heading - Users with access to + Members with access to %strong #{@project.name} %span.badge= @project_members.total_count + = form_tag namespace_project_settings_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do + .form-group + = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } + %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } + = icon("search") + = render 'shared/members/sort_dropdown' %ul.content-list = render partial: 'shared/members/member', collection: members, as: :member diff --git a/app/views/projects/project_members/import.html.haml b/app/views/projects/project_members/import.html.haml index eef97107d7710db73515b0493e0d32cb2a2f95d8..42ce4f8001b8dce7980fe4f36d916498f4a80646 100644 --- a/app/views/projects/project_members/import.html.haml +++ b/app/views/projects/project_members/import.html.haml @@ -12,5 +12,4 @@ .form-actions = button_tag 'Import project members', class: "btn btn-create" - = link_to "Cancel", namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-cancel" - + = link_to "Cancel", namespace_project_settings_members_path(@project.namespace, @project), class: "btn btn-cancel" diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml deleted file mode 100644 index 4f1cec20f8579d1118d12119a590ddf69dfb310f..0000000000000000000000000000000000000000 --- a/app/views/projects/project_members/index.html.haml +++ /dev/null @@ -1,29 +0,0 @@ -- page_title "Members" - -.project-members-page.prepend-top-default - %h4.project-members-title.clearfix - Members - = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default pull-right hidden-xs", title: "Import members from another project" - - if can?(current_user, :admin_project_member, @project) - .project-members-new.append-bottom-default - %p.clearfix - Add new user to - %strong= @project.name - = render "new_project_member" - - = render 'shared/members/requests', membership_source: @project, requesters: @requesters - - .append-bottom-default.clearfix - %h5.member.existing-title - Existing users and groups - = form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do - .form-group - = search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false } - %button.member-search-btn{ type: "submit", "aria-label" => "Submit search" } - = icon("search") - = render 'shared/members/sort_dropdown' - - if @group_links.any? - = render 'groups', group_links: @group_links - - = render 'team', members: @project_members - = paginate @project_members, theme: "gitlab" diff --git a/app/views/projects/settings/members/show.html.haml b/app/views/projects/settings/members/show.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..d81ed7bb6097af815cb5fc6d40e47037e5082365 --- /dev/null +++ b/app/views/projects/settings/members/show.html.haml @@ -0,0 +1,6 @@ +- page_title "Members" + += render "projects/project_members/index" +- if can?(current_user, :admin_project, @project) + - if @project.allowed_to_share_with_group? + = render "projects/group_links/index" diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml index a46ba3b060595bffaa9d9aec54657367acfc5076..81b5bc1de300c2ccfc8767f83afcafe72a7e2089 100644 --- a/app/views/shared/members/_group.html.haml +++ b/app/views/shared/members/_group.html.haml @@ -37,7 +37,6 @@ %i.clear-icon.js-clear-input - if can_admin_member = link_to namespace_project_group_link_path(@project.namespace, @project, group_link), - remote: true, method: :delete, data: { confirm: "Are you sure you want to remove #{group.name}?" }, class: 'btn btn-remove prepend-left-10' do diff --git a/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml b/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml new file mode 100644 index 0000000000000000000000000000000000000000..206be8fe3cb769e5925e195886c099c2b0debfdb --- /dev/null +++ b/changelogs/unreleased/25985-combine-members-and-groups-settings-pages.yml @@ -0,0 +1,5 @@ +--- +title: Combined the settings options project members and groups into a single one + called members +merge_request: +author: diff --git a/config/routes/project.rb b/config/routes/project.rb index 4d20acbef7a129854e06bf9e867981734c5fb170..26e2dc9e6e72078eeaaff62ca348beb4eee36887 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -307,6 +307,10 @@ end end + namespace :settings do + resource :members, only: [:show] + end + # Since both wiki and repository routing contains wildcard characters # its preferable to keep it below all other project routes draw :wiki diff --git a/features/steps/project/team_management.rb b/features/steps/project/team_management.rb index 22d971fadfb594aca7f3a0f790bc81ea53e884fb..c89f587f14d3c7c137dc781e1726500a3f75b86e 100644 --- a/features/steps/project/team_management.rb +++ b/features/steps/project/team_management.rb @@ -113,8 +113,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps project.team << [user, :reporter] end - step 'I click link "Import team from another project"' do - click_link "Import" + step 'I click link "Import team from another project"' do + page.within '.users-project-form' do + click_link "Import" + end end When 'I submit "Website" project for import team' do diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index b9d9117c928c4a14a51e59c4babba304d03cefed..17dc101b7ee63a4e9be6db33d3b77b999d2d8d64 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -31,7 +31,7 @@ it 'redirects to project group links page' do expect(response).to redirect_to( - namespace_project_group_links_path(project.namespace, project) + namespace_project_settings_members_path(project.namespace, project) ) end end @@ -62,7 +62,7 @@ it 'redirects to project group links page' do expect(response).to redirect_to( - namespace_project_group_links_path(project.namespace, project) + namespace_project_settings_members_path(project.namespace, project) ) end end @@ -76,7 +76,7 @@ it 'redirects to project group links page' do expect(response).to redirect_to( - namespace_project_group_links_path(project.namespace, project) + namespace_project_settings_members_path(project.namespace, project) ) expect(flash[:alert]).to eq('Please select a group.') end diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index b52137fbe7e595fb2cd1455f6e347b478b5f3cca..442f81187dc2def2a9fc9046154b91f98795e834 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -5,11 +5,11 @@ let(:project) { create(:empty_project, :public, :access_requestable) } describe 'GET index' do - it 'renders index with 200 status code' do + it 'should have the settings/members address with a 302 status code' do get :index, namespace_id: project.namespace, project_id: project - expect(response).to have_http_status(200) - expect(response).to render_template(:index) + expect(response).to have_http_status(302) + expect(response.location).to include namespace_project_settings_members_path(project.namespace, project) end end @@ -44,7 +44,7 @@ access_level: Gitlab::Access::GUEST expect(response).to set_flash.to 'Users were successfully added.' - expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) + expect(response).to redirect_to(namespace_project_settings_members_path(project.namespace, project)) end it 'adds no user to members' do @@ -56,7 +56,7 @@ access_level: Gitlab::Access::GUEST expect(response).to set_flash.to 'No users or groups specified.' - expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) + expect(response).to redirect_to(namespace_project_settings_members_path(project.namespace, project)) end end end @@ -99,7 +99,7 @@ id: member expect(response).to redirect_to( - namespace_project_project_members_path(project.namespace, project) + namespace_project_settings_members_path(project.namespace, project) ) expect(project.members).not_to include member end @@ -259,7 +259,7 @@ expect(project.team_members).to include member expect(response).to set_flash.to 'Successfully imported' expect(response).to redirect_to( - namespace_project_project_members_path(project.namespace, project) + namespace_project_settings_members_path(project.namespace, project) ) end end diff --git a/spec/controllers/projects/settings/members_controller_spec.rb b/spec/controllers/projects/settings/members_controller_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..076d6cd9c6ee0b287f33186cda996a1d8423e202 --- /dev/null +++ b/spec/controllers/projects/settings/members_controller_spec.rb @@ -0,0 +1,14 @@ +require('spec_helper') + +describe Projects::Settings::MembersController do + let(:project) { create(:empty_project, :public, :access_requestable) } + + describe 'GET show' do + it 'renders show with 200 status code' do + get :show, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(200) + expect(response).to render_template(:show) + end + end +end diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 1a71a03fbd9fc0f03736af9a7471c716ba9c666e..8b302a6aa23c7b0f776fd05c8e7e1f7cefd2e3ce 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -14,10 +14,10 @@ context 'setting an expiration date for a group link' do before do - visit namespace_project_group_links_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) select2 group.id, from: '#link_group_id' - fill_in 'expires_at', with: (Time.current + 4.5.days).strftime('%Y-%m-%d') + fill_in 'expires_at_groups', with: (Time.current + 4.5.days).strftime('%Y-%m-%d') page.find('body').click click_on 'Share' end diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb index c5e3d143d919ae4b25d7c6dd764fc6748ce4f68e..d82cf53c690fac4d50506eb0a69f717490b4d5ff 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -11,10 +11,10 @@ end scenario "anonymous user visits the project's members page and sees the list of members" do - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) expect(current_path).to eq( - namespace_project_project_members_path(project.namespace, project)) + namespace_project_settings_members_path(project.namespace, project)) expect(page).to have_content(user.name) end end diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index 94995f7cf95ff5f7b406c3e0879514291553c7b0..cffb935ad5ad1db674c1107af0f4e6238ffd7dfb 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -12,7 +12,7 @@ @group_link = create(:project_group_link, project: project, group: group) login_as(user) - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) end it 'updates group access level' do @@ -24,7 +24,7 @@ wait_for_ajax - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) expect(first('.group_member')).to have_content('Guest') end diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb index 7d0065ee2c4c6be39c8a22f5c1da5bcc24c40576..3385e5972ff7438442263ce56e08cc403ca4bf0e 100644 --- a/spec/features/projects/members/group_members_spec.rb +++ b/spec/features/projects/members/group_members_spec.rb @@ -19,7 +19,7 @@ context 'with a group invitee' do before do group_invitee - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) end scenario 'does not appear in the project members page' do @@ -33,7 +33,7 @@ before do group_invitee project_invitee - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) end scenario 'shows the project invitee, the project developer, and the group owner' do @@ -54,7 +54,7 @@ context 'with a group requester' do before do group.request_access(group_requester) - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) end scenario 'does not appear in the project members page' do @@ -68,7 +68,7 @@ before do group.request_access(group_requester) project.request_access(project_requester) - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) end scenario 'shows the project requester, the project developer, and the group owner' do diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index b7273021c958b485756b3d46e0af31db2734b1ca..f136d9ce0fa20f60973c085a0699b4b3387d385d 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -14,15 +14,15 @@ login_as(master) end - scenario 'expiration date is displayed in the members list' do + scenario 'expiration date is displayed in the members list', js: true do travel_to Time.zone.parse('2016-08-06 08:00') do - visit namespace_project_project_members_path(project.namespace, project) - + visit namespace_project_settings_members_path(project.namespace, project) page.within '.users-project-form' do select2(new_member.id, from: '#user_ids', multiple: true) fill_in 'expires_at', with: '2016-08-10' - click_on 'Add to project' end + find('.users-project-form').click + click_on 'Add to project' page.within "#project_member_#{new_member.project_members.first.id}" do expect(page).to have_content('Expires in 4 days') diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index 97c42bd7f017f14b326ef81b77f5da14e23f858b..0b4dcaa39c693a264d1732569debc43e06d5d682 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -39,7 +39,7 @@ open_project_settings_menu click_link 'Members' - visit namespace_project_project_members_path(project.namespace, project) + visit namespace_project_settings_members_path(project.namespace, project) page.within('.content') do expect(page).not_to have_content(user.name) end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 1897c8119d28b16c09880455dd81cfbc5b0af7c1..ecebabefff87cfb28f5a3bdff37ece893d6010f6 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -82,8 +82,8 @@ it { is_expected.to be_denied_for(:visitor) } end - describe "GET /:project_path/project_members" do - subject { namespace_project_project_members_path(project.namespace, project) } + describe "GET /:project_path/settings/members" do + subject { namespace_project_settings_members_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index f52e23f94338c2365e0fd9c961054e9991bac2fc..9bc59a7c4f99c992d38008c9189544ce7dfb7d90 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -82,8 +82,8 @@ it { is_expected.to be_denied_for(:visitor) } end - describe "GET /:project_path/project_members" do - subject { namespace_project_project_members_path(project.namespace, project) } + describe "GET /:project_path/settings/members" do + subject { namespace_project_settings_members_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index bed9e92fcb6071a60630a07550bf9200506f062a..a8d43b3d5816322a52a60db2abbcda63f1e43372 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -82,8 +82,8 @@ it { is_expected.to be_allowed_for(:visitor) } end - describe "GET /:project_path/project_members" do - subject { namespace_project_project_members_path(project.namespace, project) } + describe "GET /:project_path/settings/members" do + subject { namespace_project_settings_members_path(project.namespace, project) } it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) }