Commit 9cdfcbb5 authored by Alfredo Sumaran's avatar Alfredo Sumaran

Merge branch '25985-combine-members-and-groups-settings-pages' into 'master'

Moved the members and groups to single option called members

Closes #25985

See merge request !8281
parents f77f736b 23e6d8c3
...@@ -215,7 +215,9 @@ ...@@ -215,7 +215,9 @@
new gl.Members(); new gl.Members();
new UsersSelect(); new UsersSelect();
break; 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.MemberExpirationDate();
new gl.Members(); new gl.Members();
new UsersSelect(); new UsersSelect();
...@@ -261,10 +263,6 @@ ...@@ -261,10 +263,6 @@
case 'projects:artifacts:browse': case 'projects:artifacts:browse':
new BuildArtifacts(); new BuildArtifacts();
break; break;
case 'projects:group_links:index':
new gl.MemberExpirationDate();
new GroupsSelect();
break;
case 'search:show': case 'search:show':
new Search(); new Search();
break; break;
......
/* 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 // 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 // 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 // `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. // 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() { function toggleClearInput() {
$(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== '');
} }
const inputs = $(selector);
var inputs = $('.js-access-expiration-date');
inputs.datepicker({ inputs.datepicker({
dateFormat: 'yy-mm-dd', dateFormat: 'yy-mm-dd',
minDate: 1, minDate: 1,
onSelect: function () { onSelect: function onSelect() {
$(this).trigger('change'); $(this).trigger('change');
toggleClearInput.call(this); toggleClearInput.call(this);
} },
}); });
inputs.next('.js-clear-input').on('click', function(event) { inputs.next('.js-clear-input').on('click', function clicked(event) {
event.preventDefault(); 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) input.datepicker('setDate', null)
.trigger('change'); .trigger('change');
toggleClearInput.call(input); toggleClearInput.call(input);
......
...@@ -163,6 +163,10 @@ ul.content-list { ...@@ -163,6 +163,10 @@ ul.content-list {
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
@media(max-width: $screen-xs-max) {
margin: 0 auto;
}
} }
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
} }
.form-horizontal { .form-horizontal {
margin-top: 5px; margin-top: 20px;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
display: -webkit-flex; display: -webkit-flex;
...@@ -98,6 +98,10 @@ ...@@ -98,6 +98,10 @@
padding-right: 35px; padding-right: 35px;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
width: 250px;
}
@media (min-width: $screen-md-min) {
width: 350px; width: 350px;
} }
......
...@@ -4,10 +4,7 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -4,10 +4,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
before_action :authorize_admin_project_member!, only: [:update] before_action :authorize_admin_project_member!, only: [:update]
def index def index
@group_links = project.project_group_links.all redirect_to namespace_project_settings_members_path
@skip_groups = @group_links.pluck(:group_id)
@skip_groups << project.namespace_id unless project.personal?
end end
def create def create
...@@ -25,7 +22,7 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -25,7 +22,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
flash[:alert] = 'Please select a group.' flash[:alert] = 'Please select a group.'
end end
redirect_to namespace_project_group_links_path(project.namespace, project) redirect_to namespace_project_settings_members_path(project.namespace, project)
end end
def update def update
...@@ -39,7 +36,7 @@ class Projects::GroupLinksController < Projects::ApplicationController ...@@ -39,7 +36,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
redirect_to namespace_project_group_links_path(project.namespace, project) redirect_to namespace_project_settings_members_path(project.namespace, project)
end end
format.js { head :ok } format.js { head :ok }
end end
......
...@@ -6,54 +6,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -6,54 +6,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController
before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access] before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access]
def index def index
@sort = params[:sort].presence || sort_value_name sort = params[:sort].presence || sort_value_name
@group_links = @project.project_group_links redirect_to namespace_project_settings_members_path(@project.namespace, @project, sort: sort)
@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
end end
def create def create
status = Members::CreateService.new(@project, current_user, params).execute 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 if status
redirect_to redirect_url, notice: 'Users were successfully added.' redirect_to redirect_url, notice: 'Users were successfully added.'
...@@ -76,14 +36,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -76,14 +36,14 @@ class Projects::ProjectMembersController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
redirect_to namespace_project_project_members_path(@project.namespace, @project) redirect_to namespace_project_settings_members_path(@project.namespace, @project)
end end
format.js { head :ok } format.js { head :ok }
end end
end end
def resend_invite 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]) @project_member = @project.project_members.find(params[:id])
...@@ -106,7 +66,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -106,7 +66,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
return render_404 return render_404
end end
redirect_to(namespace_project_project_members_path(project.namespace, project), redirect_to(namespace_project_settings_members_path(project.namespace, project),
notice: notice) notice: notice)
end end
......
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
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
...@@ -206,4 +206,9 @@ module GitlabRoutingHelper ...@@ -206,4 +206,9 @@ module GitlabRoutingHelper
file_namespace_project_build_artifacts_path(*args) file_namespace_project_build_artifacts_path(*args)
end end
end end
# Settings
def project_settings_members_path(project, *args)
namespace_project_settings_members_path(project.namespace, project, *args)
end
end end
...@@ -75,7 +75,7 @@ module SearchHelper ...@@ -75,7 +75,7 @@ module SearchHelper
{ category: "Current Project", label: "Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) }, { 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: "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: "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) }, { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
] ]
else else
......
- if project_nav_tab? :team - if project_nav_tab? :team
= nav_link(controller: [:project_members, :teams]) do = nav_link(controller: [:members, :teams]) do
= link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do = link_to namespace_project_settings_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
%span %span
Members Members
- if can_edit - 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 = nav_link(controller: :deploy_keys) do
= link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
%span %span
......
...@@ -20,10 +20,10 @@ ...@@ -20,10 +20,10 @@
.form-group .form-group
= label_tag :expires_at, 'Access expiration date', class: 'label-light' = label_tag :expires_at, 'Access expiration date', class: 'label-light'
.clearable-input .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 %i.clear-icon.js-clear-input
.help-block .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" = submit_tag "Share", class: "btn btn-create"
.col-lg-9.col-lg-offset-3 .col-lg-9.col-lg-offset-3
%hr %hr
......
.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"
= form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'users-project-form' } do |f| = form_for @project_member, as: :project_member, url: namespace_project_project_members_path(@project.namespace, @project), html: { class: 'users-project-form' } do |f|
.row .form-group
.col-md-4.col-lg-6 = users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true, placeholder: "Search for members to update or invite")
= users_select_tag(:user_ids, multiple: true, class: "input-clamp", scope: :all, email_user: true)
.help-block.append-bottom-10 .help-block.append-bottom-10
Search for users by name, username, or email, or invite new ones using their email address. Search for members by name, username, or email, or invite new ones using their email address.
.form-group
.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" = 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 .help-block.append-bottom-10
= link_to "Read more", help_page_path("user/permissions"), class: "vlink" = link_to "Read more", help_page_path("user/permissions"), class: "vlink"
about role permissions about role permissions
.form-group
.col-md-3.col-lg-2
.clearable-input .clearable-input
= text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date'
%i.clear-icon.js-clear-input %i.clear-icon.js-clear-input
.help-block.append-bottom-10 .help-block.append-bottom-10
On this date, the user(s) will automatically lose access to this project. On this date, the member(s) will automatically lose access to this project.
= f.submit "Add to project", class: "btn btn-create"
.col-md-2 = link_to "Import", import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-default", title: "Import members from another project"
= f.submit "Add to project", class: "btn btn-create btn-block"
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
Users with access to Members with access to
%strong #{@project.name} %strong #{@project.name}
%span.badge= @project_members.total_count %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 %ul.content-list
= render partial: 'shared/members/member', collection: members, as: :member = render partial: 'shared/members/member', collection: members, as: :member
...@@ -12,5 +12,4 @@ ...@@ -12,5 +12,4 @@
.form-actions .form-actions
= button_tag 'Import project members', class: "btn btn-create" = 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"
- 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"
- 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"
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
%i.clear-icon.js-clear-input %i.clear-icon.js-clear-input
- if can_admin_member - if can_admin_member
= link_to namespace_project_group_link_path(@project.namespace, @project, group_link), = link_to namespace_project_group_link_path(@project.namespace, @project, group_link),
remote: true,
method: :delete, method: :delete,
data: { confirm: "Are you sure you want to remove #{group.name}?" }, data: { confirm: "Are you sure you want to remove #{group.name}?" },
class: 'btn btn-remove prepend-left-10' do class: 'btn btn-remove prepend-left-10' do
......
---
title: Combined the settings options project members and groups into a single one
called members
merge_request:
author:
...@@ -307,6 +307,10 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -307,6 +307,10 @@ constraints(ProjectUrlConstrainer.new) do
end end
end end
namespace :settings do
resource :members, only: [:show]
end
# Since both wiki and repository routing contains wildcard characters # Since both wiki and repository routing contains wildcard characters
# its preferable to keep it below all other project routes # its preferable to keep it below all other project routes
draw :wiki draw :wiki
......
...@@ -114,8 +114,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps ...@@ -114,8 +114,10 @@ class Spinach::Features::ProjectTeamManagement < Spinach::FeatureSteps
end end
step 'I click link "Import team from another project"' do step 'I click link "Import team from another project"' do
page.within '.users-project-form' do
click_link "Import" click_link "Import"
end end
end
When 'I submit "Website" project for import team' do When 'I submit "Website" project for import team' do
project = Project.find_by(name: "Website") project = Project.find_by(name: "Website")
......
...@@ -31,7 +31,7 @@ describe Projects::GroupLinksController do ...@@ -31,7 +31,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do it 'redirects to project group links page' do
expect(response).to redirect_to( expect(response).to redirect_to(
namespace_project_group_links_path(project.namespace, project) namespace_project_settings_members_path(project.namespace, project)
) )
end end
end end
...@@ -62,7 +62,7 @@ describe Projects::GroupLinksController do ...@@ -62,7 +62,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do it 'redirects to project group links page' do
expect(response).to redirect_to( expect(response).to redirect_to(
namespace_project_group_links_path(project.namespace, project) namespace_project_settings_members_path(project.namespace, project)
) )
end end
end end
...@@ -76,7 +76,7 @@ describe Projects::GroupLinksController do ...@@ -76,7 +76,7 @@ describe Projects::GroupLinksController do
it 'redirects to project group links page' do it 'redirects to project group links page' do
expect(response).to redirect_to( 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.') expect(flash[:alert]).to eq('Please select a group.')
end end
......
...@@ -5,11 +5,11 @@ describe Projects::ProjectMembersController do ...@@ -5,11 +5,11 @@ describe Projects::ProjectMembersController do
let(:project) { create(:empty_project, :public, :access_requestable) } let(:project) { create(:empty_project, :public, :access_requestable) }
describe 'GET index' do 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 get :index, namespace_id: project.namespace, project_id: project
expect(response).to have_http_status(200) expect(response).to have_http_status(302)
expect(response).to render_template(:index) expect(response.location).to include namespace_project_settings_members_path(project.namespace, project)
end end
end end
...@@ -44,7 +44,7 @@ describe Projects::ProjectMembersController do ...@@ -44,7 +44,7 @@ describe Projects::ProjectMembersController do
access_level: Gitlab::Access::GUEST access_level: Gitlab::Access::GUEST
expect(response).to set_flash.to 'Users were successfully added.' 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 end
it 'adds no user to members' do it 'adds no user to members' do
...@@ -56,7 +56,7 @@ describe Projects::ProjectMembersController do ...@@ -56,7 +56,7 @@ describe Projects::ProjectMembersController do
access_level: Gitlab::Access::GUEST access_level: Gitlab::Access::GUEST
expect(response).to set_flash.to 'No users or groups specified.' 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 end
end end
...@@ -99,7 +99,7 @@ describe Projects::ProjectMembersController do ...@@ -99,7 +99,7 @@ describe Projects::ProjectMembersController do
id: member id: member
expect(response).to redirect_to( 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 expect(project.members).not_to include member
end end
...@@ -259,7 +259,7 @@ describe Projects::ProjectMembersController do ...@@ -259,7 +259,7 @@ describe Projects::ProjectMembersController do
expect(project.team_members).to include member expect(project.team_members).to include member
expect(response).to set_flash.to 'Successfully imported' expect(response).to set_flash.to 'Successfully imported'
expect(response).to redirect_to( expect(response).to redirect_to(
namespace_project_project_members_path(project.namespace, project) namespace_project_settings_members_path(project.namespace, project)
) )
end end
end end
......
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
...@@ -14,10 +14,10 @@ feature 'Project group links', feature: true, js: true do ...@@ -14,10 +14,10 @@ feature 'Project group links', feature: true, js: true do
context 'setting an expiration date for a group link' do context 'setting an expiration date for a group link' do
before 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' 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 page.find('body').click
click_on 'Share' click_on 'Share'
end end
......
...@@ -11,10 +11,10 @@ feature 'Projects > Members > Anonymous user sees members', feature: true do ...@@ -11,10 +11,10 @@ feature 'Projects > Members > Anonymous user sees members', feature: true do
end end
scenario "anonymous user visits the project's members page and sees the list of members" do 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( 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) expect(page).to have_content(user.name)
end end
end end
...@@ -12,7 +12,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t ...@@ -12,7 +12,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t
@group_link = create(:project_group_link, project: project, group: group) @group_link = create(:project_group_link, project: project, group: group)
login_as(user) login_as(user)
visit namespace_project_project_members_path(project.namespace, project) visit namespace_project_settings_members_path(project.namespace, project)
end end
it 'updates group access level' do it 'updates group access level' do
...@@ -24,7 +24,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t ...@@ -24,7 +24,7 @@ feature 'Projects > Members > Anonymous user sees members', feature: true, js: t
wait_for_ajax 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') expect(first('.group_member')).to have_content('Guest')
end end
......
...@@ -19,7 +19,7 @@ feature 'Projects members', feature: true do ...@@ -19,7 +19,7 @@ feature 'Projects members', feature: true do
context 'with a group invitee' do context 'with a group invitee' do
before do before do
group_invitee group_invitee
visit namespace_project_project_members_path(project.namespace, project) visit namespace_project_settings_members_path(project.namespace, project)
end end
scenario 'does not appear in the project members page' do scenario 'does not appear in the project members page' do
...@@ -33,7 +33,7 @@ feature 'Projects members', feature: true do ...@@ -33,7 +33,7 @@ feature 'Projects members', feature: true do
before do before do
group_invitee group_invitee
project_invitee project_invitee
visit namespace_project_project_members_path(project.namespace, project) visit namespace_project_settings_members_path(project.namespace, project)
end end
scenario 'shows the project invitee, the project developer, and the group owner' do scenario 'shows the project invitee, the project developer, and the group owner' do
...@@ -54,7 +54,7 @@ feature 'Projects members', feature: true do ...@@ -54,7 +54,7 @@ feature 'Projects members', feature: true do
context 'with a group requester' do context 'with a group requester' do
before do before do
group.request_access(group_requester) group.request_access(group_requester)
visit namespace_project_project_members_path(project.namespace, project) visit namespace_project_settings_members_path(project.namespace, project)
end end
scenario 'does not appear in the project members page' do scenario 'does not appear in the project members page' do
...@@ -68,7 +68,7 @@ feature 'Projects members', feature: true do ...@@ -68,7 +68,7 @@ feature 'Projects members', feature: true do
before do before do
group.request_access(group_requester) group.request_access(group_requester)
project.request_access(project_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 end
scenario 'shows the project requester, the project developer, and the group owner' do scenario 'shows the project requester, the project developer, and the group owner' do
......
...@@ -14,15 +14,15 @@ feature 'Projects > Members > Master adds member with expiration date', feature: ...@@ -14,15 +14,15 @@ feature 'Projects > Members > Master adds member with expiration date', feature:
login_as(master) login_as(master)
end 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 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 page.within '.users-project-form' do
select2(new_member.id, from: '#user_ids', multiple: true) select2(new_member.id, from: '#user_ids', multiple: true)
fill_in 'expires_at', with: '2016-08-10' fill_in 'expires_at', with: '2016-08-10'
click_on 'Add to project'
end end
find('.users-project-form').click
click_on 'Add to project'
page.within "#project_member_#{new_member.project_members.first.id}" do page.within "#project_member_#{new_member.project_members.first.id}" do
expect(page).to have_content('Expires in 4 days') expect(page).to have_content('Expires in 4 days')
......
...@@ -39,7 +39,7 @@ feature 'Projects > Members > User requests access', feature: true do ...@@ -39,7 +39,7 @@ feature 'Projects > Members > User requests access', feature: true do
open_project_settings_menu open_project_settings_menu
click_link 'Members' 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 page.within('.content') do
expect(page).not_to have_content(user.name) expect(page).not_to have_content(user.name)
end end
......
...@@ -82,8 +82,8 @@ describe "Internal Project Access", feature: true do ...@@ -82,8 +82,8 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/project_members" do describe "GET /:project_path/settings/members" do
subject { namespace_project_project_members_path(project.namespace, project) } subject { namespace_project_settings_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:owner).of(project) }
......
...@@ -82,8 +82,8 @@ describe "Private Project Access", feature: true do ...@@ -82,8 +82,8 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:visitor) } it { is_expected.to be_denied_for(:visitor) }
end end
describe "GET /:project_path/project_members" do describe "GET /:project_path/settings/members" do
subject { namespace_project_project_members_path(project.namespace, project) } subject { namespace_project_settings_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:owner).of(project) }
......
...@@ -82,8 +82,8 @@ describe "Public Project Access", feature: true do ...@@ -82,8 +82,8 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for(:visitor) } it { is_expected.to be_allowed_for(:visitor) }
end end
describe "GET /:project_path/project_members" do describe "GET /:project_path/settings/members" do
subject { namespace_project_project_members_path(project.namespace, project) } subject { namespace_project_settings_members_path(project.namespace, project) }
it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) } it { is_expected.to be_allowed_for(:owner).of(project) }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment