Commit 0784b57b authored by Doug Stull's avatar Doug Stull Committed by Peter Leitzen

Move project members to top level

- previously for admins it was buried in settings
- this will make it top level for everyone instead as
  a way to match group level setup
parent e8bc265c
......@@ -6,7 +6,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
before_action :authorize_admin_project_member!, only: [:update]
def index
redirect_to namespace_project_settings_members_path
redirect_to namespace_project_project_members_path
end
def create
......
......@@ -677,7 +677,6 @@ module ProjectsHelper
def sidebar_settings_paths
%w[
projects#edit
project_members#index
integrations#show
services#edit
hooks#index
......
......@@ -330,6 +330,18 @@
%strong.fly-out-top-item-name
= _('Snippets')
= nav_link(controller: :project_members) do
= link_to project_project_members_path(@project), title: _('Members'), class: 'qa-members-link', id: 'js-onboarding-members-link' do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Members')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do
= link_to project_project_members_path(@project) do
%strong.fly-out-top-item-name
= _('Members')
- if project_nav_tab? :settings
= nav_link(path: sidebar_settings_paths) do
= link_to edit_project_path(@project), class: 'shortcuts-tree' do
......@@ -350,10 +362,6 @@
= link_to edit_project_path(@project), title: _('General'), class: 'qa-general-settings-link' do
%span
= _('General')
= nav_link(controller: :project_members) do
= link_to project_project_members_path(@project), title: _('Members'), class: 'qa-link-members-settings', id: 'js-onboarding-settings-members-link' do
%span
= _('Members')
- if can_edit
= nav_link(controller: [:integrations, :services]) do
= link_to project_settings_integrations_path(@project), title: _('Integrations'), data: { qa_selector: 'integrations_settings_link' } do
......@@ -389,19 +397,6 @@
= render_if_exists 'projects/sidebar/settings_audit_events'
- else
= nav_link(controller: :project_members) do
= link_to project_settings_members_path(@project), title: _('Members'), class: 'shortcuts-tree' do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Members')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do
= link_to project_project_members_path(@project) do
%strong.fly-out-top-item-name
= _('Members')
= render 'shared/sidebar_toggle_button'
-# Shortcut to Project > Activity
......
---
title: Move the Members section from settings to the side nav for projects
merge_request: 32667
author:
type: changed
......@@ -71,8 +71,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
namespace :settings do
get :members, to: redirect("%{namespace_id}/%{project_id}/-/project_members")
resource :ci_cd, only: [:show, :update], controller: 'ci_cd' do
post :reset_cache
put :reset_registration_token
......
......@@ -123,7 +123,7 @@ Capybara DSL, potentially leading to confusion and bugs.
**Good**
```ruby
Page::Project::Settings::Members.perform do |members|
Page::Project::Members.perform do |members|
members.do_something
end
```
......@@ -149,7 +149,7 @@ end
**Bad**
```ruby
Page::Project::Settings::Members.perform do |project_settings_members_page|
Page::Project::Members.perform do |project_settings_members_page|
project_settings_members_page.do_something
end
```
......
......@@ -103,7 +103,7 @@ Any of the following groups would be eligible to be specified as code owners:
- `@group/sub-group`
- `@group/sub-group/sub-subgroup`
In addition, any groups that have been invited to the project using the **Settings > Members** tool will also be recognized as eligible code owners.
In addition, any groups that have been invited to the project using the **Members** tool will also be recognized as eligible code owners.
The order in which the paths are defined is significant: the last
pattern that matches a given path will be used to find the code
......
......@@ -8,7 +8,7 @@ You should have Maintainer or Owner [permissions](../../permissions.md) to add
or import a new user to your project.
To view, edit, add, and remove project's members, go to your
project's **Settings > Members**.
project's **Members**.
## Inherited membership
......
......@@ -18,7 +18,7 @@ This is where the group sharing feature can be of use.
To share 'Project Acme' with the 'Engineering' group:
1. For 'Project Acme' use the left navigation menu to go to **Settings > Members**
1. For 'Project Acme' use the left navigation menu to go to **Members**
![share project with groups](img/share_project_with_groups.png)
......
......@@ -34,7 +34,7 @@ For each project access token created, a bot user will also be created and added
["Maintainer" level permissions](../../permissions.md#project-members-permissions). API calls made with a
project access token will be associated to the corresponding bot user.
These users will appear in **{settings}** **Settings > Members** but can not be modified.
These users will appear in **Members** but can not be modified.
Furthermore, the bot user can not be added to any other project.
When the project access token is [revoked](#revoking-a-project-access-token) the bot user will be deleted and all
......
......@@ -468,7 +468,7 @@ const INVITE_COLLEAGUES_TOUR = [
forUrl: ({ createdProjectPath }) => new RegExp(`${createdProjectPath}/edit$`, ''),
getHelpContent: null,
actionPopover: {
selector: '#js-onboarding-settings-members-link',
selector: '#js-onboarding-members-link',
text: sprintf(
s__('UserOnboardingTour|Awesome! Now click on %{emphasisStart}Members%{emphasisEnd}.'),
{
......
......@@ -108,7 +108,7 @@ describe 'Projects > Audit Events', :js do
end
it "appears in the project's audit events" do
visit project_settings_members_path(project)
visit project_project_members_path(project)
project_member = project.project_member(pete)
......
......@@ -11,7 +11,7 @@ describe 'Project > Members > Invite group and members', :js do
describe 'Share group lock' do
shared_examples 'the project cannot be shared with groups' do
it 'user is only able to share with members' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).not_to have_selector('#invite-member-tab')
expect(page).not_to have_selector('#invite-group-tab')
......@@ -22,7 +22,7 @@ describe 'Project > Members > Invite group and members', :js do
shared_examples 'the project cannot be shared with members' do
it 'user is only able to share with groups' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).not_to have_selector('#invite-member-tab')
expect(page).not_to have_selector('#invite-group-tab')
......@@ -33,7 +33,7 @@ describe 'Project > Members > Invite group and members', :js do
shared_examples 'the project cannot be shared with groups and members' do
it 'no tabs or share content exists' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).not_to have_selector('#invite-member-tab')
expect(page).not_to have_selector('#invite-group-tab')
......@@ -44,7 +44,7 @@ describe 'Project > Members > Invite group and members', :js do
shared_examples 'the project can be shared with groups and members' do
it 'both member and group tabs exist' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).not_to have_selector('.invite-member')
expect(page).not_to have_selector('.invite-group')
......@@ -67,7 +67,7 @@ describe 'Project > Members > Invite group and members', :js do
it_behaves_like 'the project can be shared with groups and members'
it 'the project can be shared with another group' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
click_on 'invite-group-tab'
......
......@@ -56,8 +56,8 @@ describe '[EE] Internal Project Access' do
it { is_expected.to be_allowed_for(:auditor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:auditor) }
end
......
......@@ -56,8 +56,8 @@ describe '[EE] Private Project Access' do
it { is_expected.to be_allowed_for(:auditor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:auditor) }
end
......
......@@ -56,8 +56,8 @@ describe '[EE] Public Project Access' do
it { is_expected.to be_allowed_for(:auditor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:auditor) }
end
......
......@@ -229,6 +229,7 @@ module QA
autoload :Show, 'qa/page/project/show'
autoload :Activity, 'qa/page/project/activity'
autoload :Menu, 'qa/page/project/menu'
autoload :Members, 'qa/page/project/members'
module Branches
autoload :Show, 'qa/page/project/branches/show'
......@@ -265,7 +266,6 @@ module QA
autoload :CiVariables, 'qa/page/project/settings/ci_variables'
autoload :Runners, 'qa/page/project/settings/runners'
autoload :MergeRequest, 'qa/page/project/settings/merge_request'
autoload :Members, 'qa/page/project/settings/members'
autoload :MirroringRepositories, 'qa/page/project/settings/mirroring_repositories'
autoload :VisibilityFeaturesPermissions, 'qa/page/project/settings/visibility_features_permissions'
......
......@@ -8,9 +8,9 @@ module QA
def add_member(project:, username:)
project.visit!
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Menu.perform(&:click_members)
Page::Project::Settings::Members.perform do |member_settings|
Page::Project::Members.perform do |member_settings|
member_settings.add_member(username)
end
end
......
# frozen_string_literal: true
module QA
module Page
module Project
class Members < Page::Base
include QA::Page::Component::Select2
view 'app/views/shared/members/_invite_member.html.haml' do
element :member_select_field
element :invite_member_button
end
view 'app/views/projects/project_members/_team.html.haml' do
element :members_list
end
view 'app/views/projects/project_members/index.html.haml' do
element :invite_group_tab
end
view 'app/views/shared/members/_invite_group.html.haml' do
element :group_select_field
element :invite_group_button
end
view 'app/views/shared/members/_group.html.haml' do
element :group_row
element :delete_group_access_link
end
def select_group(group_name)
click_element :group_select_field
search_and_select(group_name)
end
def invite_group(group_name)
click_element :invite_group_tab
select_group(group_name)
click_element :invite_group_button
end
def add_member(username)
click_element :member_select_field
search_and_select username
click_element :invite_member_button
end
def remove_group(group_name)
click_element :invite_group_tab
page.accept_alert do
within_element(:group_row, text: group_name) do
click_element :delete_group_access_link
end
end
end
end
end
end
end
......@@ -17,6 +17,7 @@ module QA
element :merge_requests_link
element :wiki_link
element :snippets_link
element :members_link
end
def click_merge_requests
......@@ -42,6 +43,12 @@ module QA
click_element(:snippets_link)
end
end
def click_members
within_sidebar do
click_element(:members_link)
end
end
end
end
end
......
# frozen_string_literal: true
module QA
module Page
module Project
module Settings
class Members < Page::Base
include QA::Page::Component::Select2
view 'app/views/shared/members/_invite_member.html.haml' do
element :member_select_field
element :invite_member_button
end
view 'app/views/projects/project_members/_team.html.haml' do
element :members_list
end
view 'app/views/projects/project_members/index.html.haml' do
element :invite_group_tab
end
view 'app/views/shared/members/_invite_group.html.haml' do
element :group_select_field
element :invite_group_button
end
view 'app/views/shared/members/_group.html.haml' do
element :group_row
element :delete_group_access_link
end
def select_group(group_name)
click_element :group_select_field
search_and_select(group_name)
end
def invite_group(group_name)
click_element :invite_group_tab
select_group(group_name)
click_element :invite_group_button
end
def add_member(username)
click_element :member_select_field
search_and_select username
click_element :invite_member_button
end
def remove_group(group_name)
click_element :invite_group_tab
page.accept_alert do
within_element(:group_row, text: group_name) do
click_element :delete_group_access_link
end
end
end
end
end
end
end
end
......@@ -15,7 +15,6 @@ module QA
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :settings_item
element :link_members_settings
element :general_settings_link
element :integrations_settings_link
element :operations_settings_link
......@@ -31,14 +30,6 @@ module QA
end
end
def go_to_members_settings
hover_settings do
within_submenu do
click_element :link_members_settings
end
end
end
def go_to_repository_settings
hover_settings do
within_submenu do
......
......@@ -12,8 +12,8 @@ module QA
project.name = 'add-member-project'
end.visit!
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |members|
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
members.add_member(user.username)
end
......
......@@ -113,13 +113,13 @@ module QA
sign_in
project.visit!
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |members|
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
members.invite_group(@group.path)
end
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |members|
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
members.remove_group(@group.path)
end
......
......@@ -39,8 +39,8 @@ module QA
before do
project.visit!
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |members|
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members|
members.add_member(user.username)
end
end
......
......@@ -28,8 +28,8 @@ module QA
end
@project.visit!
Page::Project::Menu.perform(&:go_to_members_settings)
Page::Project::Settings::Members.perform do |members_page|
Page::Project::Menu.perform(&:click_members)
Page::Project::Members.perform do |members_page|
members_page.add_member(@user.username)
members_page.add_member(@user2.username)
end
......
......@@ -21,7 +21,7 @@ describe 'Projects members' do
context 'with a group invitee' do
before do
group_invitee
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
it 'does not appear in the project members page' do
......@@ -70,7 +70,7 @@ describe 'Projects members' do
before do
group_invitee
project_invitee
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
it 'shows the project invitee, the project developer, and the group owner' do
......@@ -91,7 +91,7 @@ describe 'Projects members' do
context 'with a group requester' do
before do
group.request_access(group_requester)
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
it 'does not appear in the project members page' do
......@@ -105,7 +105,7 @@ describe 'Projects members' do
before do
group.request_access(group_requester)
project.request_access(project_requester)
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
it 'shows the project requester, the project developer, and the group owner' do
......@@ -129,7 +129,7 @@ describe 'Projects members' do
it_behaves_like 'showing user status' do
let(:user_with_status) { developer }
subject { visit project_settings_members_path(project) }
subject { visit project_project_members_path(project) }
end
end
end
......@@ -12,7 +12,7 @@ describe 'Projects > Members > Groups with access list', :js do
@group_link = create(:project_group_link, project: project, group: group)
sign_in(user)
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
it 'updates group access level' do
......@@ -24,7 +24,7 @@ describe 'Projects > Members > Groups with access list', :js do
wait_for_requests
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(first('.group_member')).to have_content('Guest')
end
......
......@@ -11,14 +11,14 @@ describe 'Project > Members > Invite group', :js do
describe 'Share with group lock' do
shared_examples 'the project can be shared with groups' do
it 'the "Invite group" tab exists' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).to have_selector('#invite-group-tab')
end
end
shared_examples 'the project cannot be shared with groups' do
it 'the "Invite group" tab does not exist' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
expect(page).not_to have_selector('#invite-group-tab')
end
end
......@@ -37,7 +37,7 @@ describe 'Project > Members > Invite group', :js do
it_behaves_like 'the project can be shared with groups'
it 'the project can be shared with another group' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
click_on 'invite-group-tab'
......@@ -118,7 +118,7 @@ describe 'Project > Members > Invite group', :js do
group.add_guest(maintainer)
sign_in(maintainer)
visit project_settings_members_path(project)
visit project_project_members_path(project)
click_on 'invite-group-tab'
......@@ -151,7 +151,7 @@ describe 'Project > Members > Invite group', :js do
create(:group).add_owner(maintainer)
create(:group).add_owner(maintainer)
visit project_settings_members_path(project)
visit project_project_members_path(project)
click_link 'Invite group'
......@@ -184,7 +184,7 @@ describe 'Project > Members > Invite group', :js do
end
it 'the groups dropdown does not show ancestors' do
visit project_settings_members_path(project)
visit project_project_members_path(project)
click_on 'invite-group-tab'
click_link 'Search for a group'
......
......@@ -113,6 +113,6 @@ describe 'Project members list' do
end
def visit_members_page
visit project_settings_members_path(project)
visit project_project_members_path(project)
end
end
......@@ -85,8 +85,8 @@ describe "Internal Project Access" do
it { is_expected.to be_denied_for(:visitor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
......
......@@ -85,8 +85,8 @@ describe "Private Project Access" do
it { is_expected.to be_denied_for(:visitor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
......
......@@ -85,8 +85,8 @@ describe "Public Project Access" do
it { is_expected.to be_allowed_for(:visitor) }
end
describe "GET /:project_path/-/settings/members" do
subject { project_settings_members_path(project) }
describe "GET /:project_path/-/project_members" do
subject { project_project_members_path(project) }
it { is_expected.to be_allowed_for(:admin) }
it { is_expected.to be_allowed_for(:owner).of(project) }
......
......@@ -482,8 +482,6 @@ describe 'project routing' do
let(:controller) { 'project_members' }
let(:controller_path) { '/-/project_members' }
end
it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/-/settings/members", "/gitlab/gitlabhq/-/project_members"
end
# project_milestones GET /:project_id/milestones(.:format) milestones#index
......
......@@ -79,11 +79,14 @@ RSpec.shared_context 'project navbar structure' do
nav_item: _('Snippets'),
nav_sub_items: []
},
{
nav_item: _('Members'),
nav_sub_items: []
},
{
nav_item: _('Settings'),
nav_sub_items: [
_('General'),
_('Members'),
_('Integrations'),
_('Webhooks'),
_('Access Tokens'),
......
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