Commit 70e36862 authored by Jason Goodman's avatar Jason Goodman

Use group hierarchy share setting to filter search results for invite

No behavior changes because setting cannot be changed yet
parent bc6d1e35
...@@ -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