Commit 2bef64c0 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '229830-move-groups-members-pending-in-to-tabs' into 'master'

Reorganize group member management into tabs

See merge request gitlab-org/gitlab!38344
parents 1856178c b568ca05
...@@ -25,8 +25,12 @@ ...@@ -25,8 +25,12 @@
} }
.form-control { .form-control {
width: 100%;
padding-right: 35px; padding-right: 35px;
}
.search-control-wrap,
.form-control {
width: 100%;
@include media-breakpoint-up(sm) { @include media-breakpoint-up(sm) {
width: 250px; width: 250px;
......
.gl-px-3.gl-py-3.gl-display-flex.gl-flex-direction-column.gl-md-flex-direction-row
= yield
.gl-display-flex.gl-md-align-items-center.gl-flex-direction-column.gl-md-flex-direction-row.row-content-block.second-block
= yield
%span.gl-flex-grow-1.gl-py-3.gl-pr-3
= yield
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
= search_field_tag :search, params[:search], { placeholder: _('Find existing members by name'), class: 'form-control', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: _('Find existing members by name'), class: 'form-control', spellcheck: false }
%button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") } %button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") }
= icon("search") = icon("search")
= label_tag :sort_by, _('Sort by'), class: 'col-form-label label-bold px-2'
= render 'shared/members/sort_dropdown' = render 'shared/members/sort_dropdown'
%ul.content-list.members-list{ data: { qa_selector: 'members_list' } } %ul.content-list.members-list{ data: { qa_selector: 'members_list' } }
= render partial: 'shared/members/member', collection: members, as: :member = render partial: 'shared/members/member', collection: members, as: :member
- filter = params[:two_factor] || 'everyone' - filter = params[:two_factor] || 'everyone'
- filter_options = { 'everyone' => _('Everyone'), 'enabled' => _('Enabled'), 'disabled' => _('Disabled') } - filter_options = { 'everyone' => _('Everyone'), 'enabled' => _('Enabled'), 'disabled' => _('Disabled') }
.dropdown.inline.member-filter-2fa-dropdown.pr-md-2 .dropdown.inline.member-filter-2fa-dropdown
= dropdown_toggle(filter_options[filter], { toggle: 'dropdown' }) = dropdown_toggle(filter_options[filter], { toggle: 'dropdown' })
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
%li.dropdown-header %li.dropdown-header
......
- name = local_assigns.fetch(:name, :search)
.search-control-wrap.gl-relative
= search_field_tag name, params[name], { placeholder: _('Search'), class: 'form-control', spellcheck: false }
%button.user-search-btn.border-left.gl-display-flex.gl-align-items-center.gl-justify-content-center{ type: 'submit', 'aria': { label: _('Submit search') } }
= sprite_icon('search')
= label_tag :sort_by, 'Sort by', class: 'col-form-label label-bold px-2'
.dropdown.inline.qa-user-sort-dropdown .dropdown.inline.qa-user-sort-dropdown
= dropdown_toggle(member_sort_options_hash[@sort], { toggle: 'dropdown' }) = dropdown_toggle(member_sort_options_hash[@sort], { toggle: 'dropdown' })
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable %ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
......
---
title: Reorganize group member management into tabs
merge_request: 38344
author:
type: changed
...@@ -1237,6 +1237,9 @@ msgstr "" ...@@ -1237,6 +1237,9 @@ msgstr ""
msgid "Access forbidden. Check your access level." msgid "Access forbidden. Check your access level."
msgstr "" msgstr ""
msgid "Access requests"
msgstr ""
msgid "Access to '%{classification_label}' not allowed" msgid "Access to '%{classification_label}' not allowed"
msgstr "" msgstr ""
...@@ -9926,9 +9929,6 @@ msgstr "" ...@@ -9926,9 +9929,6 @@ msgstr ""
msgid "Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project." msgid "Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project."
msgstr "" msgstr ""
msgid "Existing shares"
msgstr ""
msgid "Existing sign in methods may be removed" msgid "Existing sign in methods may be removed"
msgstr "" msgstr ""
...@@ -13264,6 +13264,9 @@ msgstr "" ...@@ -13264,6 +13264,9 @@ msgstr ""
msgid "Invite teammates (optional)" msgid "Invite teammates (optional)"
msgstr "" msgstr ""
msgid "Invited"
msgstr ""
msgid "Invited users will be added with developer level permissions. You can always change this later." msgid "Invited users will be added with developer level permissions. You can always change this later."
msgstr "" msgstr ""
...@@ -14864,6 +14867,9 @@ msgstr "" ...@@ -14864,6 +14867,9 @@ msgstr ""
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}" msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr "" msgstr ""
msgid "Members invited to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
msgid "Members of %{strong_open}%{project_name}%{strong_close}" msgid "Members of %{strong_open}%{project_name}%{strong_close}"
msgstr "" msgstr ""
...@@ -14873,9 +14879,6 @@ msgstr "" ...@@ -14873,9 +14879,6 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}" msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr "" msgstr ""
msgid "Members with pending access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
msgid "Memory Usage" msgid "Memory Usage"
msgstr "" msgstr ""
...@@ -26700,6 +26703,9 @@ msgstr "" ...@@ -26700,6 +26703,9 @@ msgstr ""
msgid "Users requesting access to" msgid "Users requesting access to"
msgstr "" msgstr ""
msgid "Users requesting access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
msgid "Users were successfully added." msgid "Users were successfully added."
msgstr "" msgstr ""
......
...@@ -25,6 +25,7 @@ module QA ...@@ -25,6 +25,7 @@ module QA
view 'app/views/groups/group_members/index.html.haml' do view 'app/views/groups/group_members/index.html.haml' do
element :invite_group_tab element :invite_group_tab
element :groups_list_tab
element :groups_list element :groups_list
end end
...@@ -71,6 +72,8 @@ module QA ...@@ -71,6 +72,8 @@ module QA
end end
def has_existing_group_share?(group_name) def has_existing_group_share?(group_name)
click_element :groups_list_tab
within_element(:groups_list) do within_element(:groups_list) do
has_element?(:group_row, text: group_name) has_element?(:group_row, text: group_name)
end end
......
...@@ -20,26 +20,28 @@ RSpec.describe 'Groups > Members > Manage groups', :js do ...@@ -20,26 +20,28 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
add_group(shared_with_group.id, 'Reporter') add_group(shared_with_group.id, 'Reporter')
click_groups_tab
page.within(first_row) do page.within(first_row) do
expect(page).to have_content(shared_with_group.name) expect(page).to have_content(shared_with_group.name)
expect(page).to have_content('Reporter') expect(page).to have_content('Reporter')
end end
end end
it 'remove user from group' do it 'remove group from group' do
create(:group_group_link, shared_group: shared_group, create(:group_group_link, shared_group: shared_group,
shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER)
visit group_group_members_path(shared_group) visit group_group_members_path(shared_group)
click_groups_tab
expect(page).to have_content(shared_with_group.name) expect(page).to have_content(shared_with_group.name)
accept_confirm do accept_confirm do
find(:css, '#existing_shares li', text: shared_with_group.name).find(:css, 'a.btn-remove').click find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-remove').click
end end
wait_for_requests
expect(page).not_to have_content(shared_with_group.name) expect(page).not_to have_content(shared_with_group.name)
end end
...@@ -49,6 +51,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do ...@@ -49,6 +51,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
visit group_group_members_path(shared_group) visit group_group_members_path(shared_group)
click_groups_tab
page.within(first_row) do page.within(first_row) do
click_button('Developer') click_button('Developer')
click_link('Maintainer') click_link('Maintainer')
...@@ -67,4 +71,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do ...@@ -67,4 +71,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
click_button "Invite" click_button "Invite"
end end
end end
def click_groups_tab
click_link "Groups"
end
end end
...@@ -101,7 +101,7 @@ RSpec.describe 'Groups > Members > Manage members' do ...@@ -101,7 +101,7 @@ RSpec.describe 'Groups > Members > Manage members' do
add_user('test@example.com', 'Reporter') add_user('test@example.com', 'Reporter')
click_link('Pending') click_link('Invited')
page.within('.content-list.members-list') do page.within('.content-list.members-list') do
expect(page).to have_content('test@example.com') expect(page).to have_content('test@example.com')
......
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Groups > Members > Maintainer manages access requests' do RSpec.describe 'Groups > Members > Maintainer manages access requests' do
it_behaves_like 'Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do
let(:has_tabs) { true }
let(:entity) { create(:group, :public) } let(:entity) { create(:group, :public) }
let(:members_page_path) { group_group_members_path(entity) } let(:members_page_path) { group_group_members_path(entity) }
end end
......
...@@ -19,7 +19,7 @@ RSpec.describe 'Search group member' do ...@@ -19,7 +19,7 @@ RSpec.describe 'Search group member' do
end end
it 'renders member users' do it 'renders member users' do
page.within '.user-search-form' do page.within '[data-testid="user-search-form"]' do
fill_in 'search', with: member.name fill_in 'search', with: member.name
find('.user-search-btn').click find('.user-search-btn').click
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Groups > Members > Tabs' do
using RSpec::Parameterized::TableSyntax
shared_examples 'active "Members" tab' do
it 'displays "Members" tab' do
expect(page).to have_selector('.nav-link.active', text: 'Members')
end
end
shared_examples 'active "Invited" tab' do
it 'displays "Invited" tab' do
expect(page).to have_selector('.nav-link.active', text: 'Invited')
end
end
let(:owner) { create(:user) }
let(:group) { create(:group) }
before do
stub_const('Groups::GroupMembersController::MEMBER_PER_PAGE_LIMIT', 1)
allow_any_instance_of(Member).to receive(:send_request).and_return(true)
group.add_owner(owner)
sign_in(owner)
create_list(:group_member, 2, group: group)
create_list(:group_member, 2, :invited, group: group)
create_list(:group_group_link, 2, shared_group: group)
create_list(:group_member, 2, :access_request, group: group)
end
where(:tab, :count) do
'Members' | 3
'Invited' | 2
'Groups' | 2
'Access requests' | 2
end
with_them do
it "renders #{params[:tab]} tab" do
visit group_group_members_path(group)
expect(page).to have_selector('.nav-link', text: "#{tab} #{count}")
end
end
context 'displays "Members" tab by default' do
before do
visit group_group_members_path(group)
end
it_behaves_like 'active "Members" tab'
end
context 'when searching "Invited"', :js do
before do
visit group_group_members_path(group)
click_link 'Invited'
page.within '[data-testid="user-search-form"]' do
fill_in 'search_invited', with: 'email'
find('button[type="submit"]').click
end
end
it_behaves_like 'active "Invited" tab'
context 'and then searching "Members"' do
before do
click_link 'Members'
page.within '[data-testid="user-search-form"]' do
fill_in 'search', with: 'test'
find('button[type="submit"]').click
end
end
it_behaves_like 'active "Members" tab'
end
end
context 'when using "Invited" pagination', :js do
before do
visit group_group_members_path(group)
click_link 'Invited'
page.within '.pagination' do
click_link '2'
end
end
it_behaves_like 'active "Invited" tab'
context 'and then using "Members" pagination' do
before do
click_link 'Members'
page.within '.pagination' do
click_link '2'
end
end
it_behaves_like 'active "Members" tab'
end
end
end
...@@ -4,6 +4,7 @@ require 'spec_helper' ...@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Projects > Members > Maintainer manages access requests' do RSpec.describe 'Projects > Members > Maintainer manages access requests' do
it_behaves_like 'Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do
let(:has_tabs) { false }
let(:entity) { create(:project, :public) } let(:entity) { create(:project, :public) }
let(:members_page_path) { project_project_members_path(entity) } let(:members_page_path) { project_project_members_path(entity) }
end end
......
...@@ -8,17 +8,18 @@ RSpec.shared_examples 'Maintainer manages access requests' do ...@@ -8,17 +8,18 @@ RSpec.shared_examples 'Maintainer manages access requests' do
entity.request_access(user) entity.request_access(user)
entity.respond_to?(:add_owner) ? entity.add_owner(maintainer) : entity.add_maintainer(maintainer) entity.respond_to?(:add_owner) ? entity.add_owner(maintainer) : entity.add_maintainer(maintainer)
sign_in(maintainer) sign_in(maintainer)
end
it 'maintainer can see access requests' do
visit members_page_path visit members_page_path
if has_tabs
click_on 'Access requests'
end
end
it 'maintainer can see access requests', :js do
expect_visible_access_request(entity, user) expect_visible_access_request(entity, user)
end end
it 'maintainer can grant access', :js do it 'maintainer can grant access', :js do
visit members_page_path
expect_visible_access_request(entity, user) expect_visible_access_request(entity, user)
click_on 'Grant access' click_on 'Grant access'
...@@ -31,8 +32,6 @@ RSpec.shared_examples 'Maintainer manages access requests' do ...@@ -31,8 +32,6 @@ RSpec.shared_examples 'Maintainer manages access requests' do
end end
it 'maintainer can deny access', :js do it 'maintainer can deny access', :js do
visit members_page_path
expect_visible_access_request(entity, user) expect_visible_access_request(entity, user)
# Open modal # Open modal
...@@ -47,7 +46,13 @@ RSpec.shared_examples 'Maintainer manages access requests' do ...@@ -47,7 +46,13 @@ RSpec.shared_examples 'Maintainer manages access requests' do
end end
def expect_visible_access_request(entity, user) def expect_visible_access_request(entity, user)
expect(page).to have_content "Users requesting access to #{entity.name} 1" if has_tabs
expect(page).to have_content "Access requests 1"
expect(page).to have_content "Users requesting access to #{entity.name}"
else
expect(page).to have_content "Users requesting access to #{entity.name} 1"
end
expect(page).to have_content user.name expect(page).to have_content user.name
end end
......
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