Commit bbce77eb authored by Vitaly Slobodin's avatar Vitaly Slobodin

Merge branch 'hide-groups-outside-hierarchy-from-search' into 'master'

Use Group Hierarchy Share Setting to Filter Search Results for Invite

See merge request gitlab-org/gitlab!63336
parents 9f5f1405 70e36862
...@@ -18,6 +18,7 @@ const Api = { ...@@ -18,6 +18,7 @@ const Api = {
groupMembersPath: '/api/:version/groups/:id/members', groupMembersPath: '/api/:version/groups/:id/members',
groupMilestonesPath: '/api/:version/groups/:id/milestones', groupMilestonesPath: '/api/:version/groups/:id/milestones',
subgroupsPath: '/api/:version/groups/:id/subgroups', subgroupsPath: '/api/:version/groups/:id/subgroups',
descendantGroupsPath: '/api/:version/groups/:id/descendant_groups',
namespacesPath: '/api/:version/namespaces.json', namespacesPath: '/api/:version/namespaces.json',
groupInvitationsPath: '/api/:version/groups/:id/invitations', groupInvitationsPath: '/api/:version/groups/:id/invitations',
groupPackagesPath: '/api/:version/groups/:id/packages', groupPackagesPath: '/api/:version/groups/:id/packages',
......
...@@ -5,6 +5,17 @@ import Api from './api'; ...@@ -5,6 +5,17 @@ import Api from './api';
import { loadCSSFile } from './lib/utils/css_utils'; import { loadCSSFile } from './lib/utils/css_utils';
import { select2AxiosTransport } from './lib/utils/select2_utils'; import { select2AxiosTransport } from './lib/utils/select2_utils';
const groupsPath = (groupsFilter, parentGroupID) => {
switch (groupsFilter) {
case 'descendant_groups':
return Api.descendantGroupsPath.replace(':id', parentGroupID);
case 'subgroups':
return Api.subgroupsPath.replace(':id', parentGroupID);
default:
return Api.groupsPath;
}
};
const groupsSelect = () => { const groupsSelect = () => {
loadCSSFile(gon.select2_css_path) loadCSSFile(gon.select2_css_path)
.then(() => { .then(() => {
...@@ -16,9 +27,7 @@ const groupsSelect = () => { ...@@ -16,9 +27,7 @@ const groupsSelect = () => {
const allAvailable = $select.data('allAvailable'); const allAvailable = $select.data('allAvailable');
const skipGroups = $select.data('skipGroups') || []; const skipGroups = $select.data('skipGroups') || [];
const parentGroupID = $select.data('parentId'); const parentGroupID = $select.data('parentId');
const groupsPath = parentGroupID const groupsFilter = $select.data('groupsFilter');
? Api.subgroupsPath.replace(':id', parentGroupID)
: Api.groupsPath;
$select.select2({ $select.select2({
placeholder: __('Search for a group'), placeholder: __('Search for a group'),
...@@ -26,7 +35,7 @@ const groupsSelect = () => { ...@@ -26,7 +35,7 @@ const groupsSelect = () => {
multiple: $select.hasClass('multiselect'), multiple: $select.hasClass('multiselect'),
minimumInputLength: 0, minimumInputLength: 0,
ajax: { ajax: {
url: Api.buildUrl(groupsPath), url: Api.buildUrl(groupsPath(groupsFilter, parentGroupID)),
dataType: 'json', dataType: 'json',
quietMillis: 250, quietMillis: 250,
transport: select2AxiosTransport, transport: select2AxiosTransport,
......
- add_page_specific_style 'page_bundles/members' - add_page_specific_style 'page_bundles/members'
- page_title _('Group members') - page_title _('Group members')
- groups_select_tag_data = @group.root_ancestor.namespace_settings.prevent_sharing_groups_outside_hierarchy ? { groups_filter: 'descendant_groups', parent_id: @group.root_ancestor.id, skip_groups: @skip_groups } : { skip_groups: @skip_groups }
.js-remove-member-modal .js-remove-member-modal
.row.gl-mt-3 .row.gl-mt-3
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
.tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' } .tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' }
= render_invite_member_for_group(@group, @group_member.access_level) = render_invite_member_for_group(@group, @group_member.access_level)
.tab-pane{ id: 'invite-group-pane', role: 'tabpanel' } .tab-pane{ id: 'invite-group-pane', role: 'tabpanel' }
= render 'shared/members/invite_group', submit_url: group_group_links_path(@group), access_levels: GroupMember.access_level_roles, default_access_level: @group_member.access_level, group_link_field: 'shared_with_group_id', group_access_field: 'shared_group_access' = render 'shared/members/invite_group', submit_url: group_group_links_path(@group), access_levels: GroupMember.access_level_roles, default_access_level: @group_member.access_level, group_link_field: 'shared_with_group_id', group_access_field: 'shared_group_access', groups_select_tag_data: groups_select_tag_data
= render_if_exists 'groups/group_members/ldap_sync' = render_if_exists 'groups/group_members/ldap_sync'
......
...@@ -51,11 +51,11 @@ ...@@ -51,11 +51,11 @@
.tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' } .tab-pane.active{ id: 'invite-member-pane', role: 'tabpanel' }
= render 'shared/members/invite_member', submit_url: project_project_members_path(@project), access_levels: ProjectMember.access_level_roles, default_access_level: @project_member.access_level, can_import_members?: can_import_members?, import_path: import_project_project_members_path(@project) = render 'shared/members/invite_member', submit_url: project_project_members_path(@project), access_levels: ProjectMember.access_level_roles, default_access_level: @project_member.access_level, can_import_members?: can_import_members?, import_path: import_project_project_members_path(@project)
.tab-pane{ id: 'invite-group-pane', role: 'tabpanel', class: ('active' if membership_locked?) } .tab-pane{ id: 'invite-group-pane', role: 'tabpanel', class: ('active' if membership_locked?) }
= render 'shared/members/invite_group', submit_url: project_group_links_path(@project), access_levels: ProjectGroupLink.access_options, default_access_level: ProjectGroupLink.default_access, group_link_field: 'link_group_id', group_access_field: 'link_group_access' = render 'shared/members/invite_group', submit_url: project_group_links_path(@project), access_levels: ProjectGroupLink.access_options, default_access_level: ProjectGroupLink.default_access, group_link_field: 'link_group_id', group_access_field: 'link_group_access', groups_select_tag_data: { skip_groups: @skip_groups }
- elsif !membership_locked? - elsif !membership_locked?
.invite-member= render 'shared/members/invite_member', submit_url: project_project_members_path(@project), access_levels: ProjectMember.access_level_roles, default_access_level: @project_member.access_level, can_import_members?: can_import_members?, import_path: import_project_project_members_path(@project) .invite-member= render 'shared/members/invite_member', submit_url: project_project_members_path(@project), access_levels: ProjectMember.access_level_roles, default_access_level: @project_member.access_level, can_import_members?: can_import_members?, import_path: import_project_project_members_path(@project)
- elsif @project.allowed_to_share_with_group? - elsif @project.allowed_to_share_with_group?
.invite-group= render 'shared/members/invite_group', access_levels: ProjectGroupLink.access_options, default_access_level: ProjectGroupLink.default_access, submit_url: project_group_links_path(@project), group_link_field: 'link_group_id', group_access_field: 'link_group_access' .invite-group= render 'shared/members/invite_group', access_levels: ProjectGroupLink.access_options, default_access_level: ProjectGroupLink.default_access, submit_url: project_group_links_path(@project), group_link_field: 'link_group_id', group_access_field: 'link_group_access', groups_select_tag_data: { skip_groups: @skip_groups }
.js-project-members-list-app{ data: { members_data: project_members_app_data_json(@project, .js-project-members-list-app{ data: { members_data: project_members_app_data_json(@project,
members: @project_members, members: @project_members,
group_links: @group_links, group_links: @group_links,
......
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
- submit_url = local_assigns[:submit_url] - submit_url = local_assigns[:submit_url]
- group_link_field = local_assigns[:group_link_field] - group_link_field = local_assigns[:group_link_field]
- group_access_field = local_assigns[:group_access_field] - group_access_field = local_assigns[:group_access_field]
- groups_select_tag_data = local_assigns[:groups_select_tag_data]
.row .row
.col-sm-12 .col-sm-12
= form_tag submit_url, class: 'invite-group-form js-requires-input', method: :post do = form_tag submit_url, class: 'invite-group-form js-requires-input', method: :post do
.form-group .form-group
= label_tag group_link_field, _("Select a group to invite"), class: "label-bold" = label_tag group_link_field, _("Select a group to invite"), class: "label-bold"
= groups_select_tag(group_link_field, data: { skip_groups: @skip_groups }, class: 'input-clamp qa-group-select-field', required: true) = groups_select_tag(group_link_field, data: groups_select_tag_data, class: 'input-clamp qa-group-select-field', required: true)
.form-text.text-muted.gl-mb-3 .form-text.text-muted.gl-mb-3
= _('Group sharing provides access to all group members (including members who inherited group membership from a parent group).') = _('Group sharing provides access to all group members (including members who inherited group membership from a parent group).')
.form-group .form-group
......
...@@ -19,6 +19,6 @@ ...@@ -19,6 +19,6 @@
.form-group .form-group
= f.label :custom_project_templates_group_id, class: 'label-bold' do = f.label :custom_project_templates_group_id, class: 'label-bold' do
= _('Custom project templates') = _('Custom project templates')
= groups_select_tag('group[custom_project_templates_group_id]', data: { parent_id: @group.id }, selected: @group.custom_project_templates_group_id, class: 'input-clamp allowClear qa-custom-project-template-select', multiple: false) = groups_select_tag('group[custom_project_templates_group_id]', data: { groups_filter: 'subgroups', parent_id: @group.id }, selected: @group.custom_project_templates_group_id, class: 'input-clamp allowClear qa-custom-project-template-select', multiple: false)
= f.submit _('Save changes'), class: 'btn gl-button btn-success qa-save-changes-button' = f.submit _('Save changes'), class: 'btn gl-button btn-success qa-save-changes-button'
...@@ -143,6 +143,58 @@ RSpec.describe 'Groups > Members > Manage groups', :js do ...@@ -143,6 +143,58 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
end end
end end
describe 'group search results' do
let_it_be(:group, refind: true) { create(:group) }
let_it_be(:group_within_hierarchy) { create(:group, parent: group) }
let_it_be(:group_outside_hierarchy) { create(:group) }
before_all do
group.add_owner(user)
group_within_hierarchy.add_owner(user)
group_outside_hierarchy.add_owner(user)
end
context 'when sharing with groups outside the hierarchy is enabled' do
context 'when the invite members group modal is disabled' do
before do
stub_feature_flags(invite_members_group_modal: false)
end
it 'shows groups within and outside the hierarchy in search results' do
visit group_group_members_path(group)
click_on 'Invite group'
click_on 'Search for a group'
expect(page).to have_text group_within_hierarchy.name
expect(page).to have_text group_outside_hierarchy.name
end
end
end
context 'when sharing with groups outside the hierarchy is disabled' do
before do
group.namespace_settings.update!(prevent_sharing_groups_outside_hierarchy: true)
end
context 'when the invite members group modal is disabled' do
before do
stub_feature_flags(invite_members_group_modal: false)
end
it 'shows only groups within the hierarchy in search results' do
visit group_group_members_path(group)
click_on 'Invite group'
click_on 'Search for a group'
expect(page).to have_text group_within_hierarchy.name
expect(page).not_to have_text group_outside_hierarchy.name
end
end
end
end
def add_group(id, role) def add_group(id, role)
page.click_link 'Invite group' page.click_link 'Invite group'
page.within ".invite-group-form" do page.within ".invite-group-form" do
......
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