diff --git a/app/assets/javascripts/groups/settings/api/access_dropdown_api.js b/app/assets/javascripts/groups/settings/api/access_dropdown_api.js index e232b1977f0a2a1ce66eb6a9d13c68d4f5f42a62..5b43096325247e244a30ab6d12855378c40b626c 100644 --- a/app/assets/javascripts/groups/settings/api/access_dropdown_api.js +++ b/app/assets/javascripts/groups/settings/api/access_dropdown_api.js @@ -7,16 +7,21 @@ const buildUrl = (urlRoot, url) => { return joinPaths(urlRoot, url); }; -const defaultOptions = { includeParentDescendants: false, includeParentSharedGroups: false }; +const defaultOptions = { + includeParentDescendants: false, + includeParentSharedGroups: false, + search: '', +}; export const getSubGroups = (options = defaultOptions) => { - const { includeParentDescendants, includeParentSharedGroups } = options; + const { includeParentDescendants, includeParentSharedGroups, search } = options; return axios.get(buildUrl(gon.relative_url_root || '', GROUP_SUBGROUPS_PATH), { params: { group_id: gon.current_group_id, include_parent_descendants: includeParentDescendants, include_parent_shared_groups: includeParentSharedGroups, + search, }, }); }; diff --git a/app/assets/javascripts/groups/settings/components/access_dropdown.vue b/app/assets/javascripts/groups/settings/components/access_dropdown.vue index 327f73b88c20bb4fd9222d5ebb0db8565756ebad..e47092b896bfa487b0b2c35f195e86185aa6af8c 100644 --- a/app/assets/javascripts/groups/settings/components/access_dropdown.vue +++ b/app/assets/javascripts/groups/settings/components/access_dropdown.vue @@ -94,9 +94,11 @@ export default { if (this.hasLicense) { Promise.all([ - this.groups.length - ? Promise.resolve({ data: this.groups }) - : getSubGroups({ includeParentDescendants: true, includeParentSharedGroups: true }), + getSubGroups({ + includeParentDescendants: true, + includeParentSharedGroups: true, + search: this.query, + }), ]) .then(([groupsResponse]) => { this.consolidateData(groupsResponse.data); diff --git a/ee/app/finders/autocomplete/group_subgroups_finder.rb b/ee/app/finders/autocomplete/group_subgroups_finder.rb index 36bbd0524800113b0f226dfe072476f89af2edbc..1b51da15f00606affee3ea41c998ed8597d846a2 100644 --- a/ee/app/finders/autocomplete/group_subgroups_finder.rb +++ b/ee/app/finders/autocomplete/group_subgroups_finder.rb @@ -23,12 +23,17 @@ def group_id params[:group_id] end + def search + params[:search] + end + # rubocop: disable CodeReuse/Finder def execute group = ::Autocomplete::GroupFinder.new(current_user, nil, group_id: group_id).execute GroupsFinder.new(current_user, parent: group, include_parent_descendants: include_parent_descendants?, - include_parent_shared_groups: include_parent_shared_groups?).execute.limit(LIMIT) + include_parent_shared_groups: include_parent_shared_groups?, + search: search).execute.limit(LIMIT) end # rubocop: enable CodeReuse/Finder end diff --git a/ee/spec/finders/autocomplete/group_subgroups_finder_spec.rb b/ee/spec/finders/autocomplete/group_subgroups_finder_spec.rb index ac416291199a88e54080323cf3e643226550dad3..64366749ba9c34555b7a2f8915d3667934d5a2a3 100644 --- a/ee/spec/finders/autocomplete/group_subgroups_finder_spec.rb +++ b/ee/spec/finders/autocomplete/group_subgroups_finder_spec.rb @@ -55,6 +55,17 @@ end end + context 'when a search param is added' do + before do + params[:search] = subgroup_1.name + end + + it 'returns only the searched for subgroups' do + expect(subject.count).to eq(1) + expect(subject).to contain_exactly(subgroup_1) + end + end + context 'when the number of groups exceeds the limit' do before do stub_const("#{described_class}::LIMIT", 1) diff --git a/spec/frontend/groups/settings/components/access_dropdown_spec.js b/spec/frontend/groups/settings/components/access_dropdown_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..67a514ef35dbef740740bd637406c2644b841653 --- /dev/null +++ b/spec/frontend/groups/settings/components/access_dropdown_spec.js @@ -0,0 +1,60 @@ +import { GlDropdown, GlSearchBoxByType } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import { getSubGroups } from '~/groups/settings/api/access_dropdown_api'; +import AccessDropdown from '~/groups/settings/components/access_dropdown.vue'; + +jest.mock('~/groups/settings/api/access_dropdown_api', () => ({ + getSubGroups: jest.fn().mockResolvedValue({ + data: [ + { id: 4, name: 'group4' }, + { id: 5, name: 'group5' }, + { id: 6, name: 'group6' }, + ], + }), +})); + +describe('Access Level Dropdown', () => { + let wrapper; + const createComponent = ({ ...optionalProps } = {}) => { + wrapper = shallowMount(AccessDropdown, { + propsData: { + ...optionalProps, + }, + stubs: { + GlDropdown, + }, + }); + }; + + const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + + describe('data request', () => { + it('should make an api call for sub-groups', () => { + createComponent(); + expect(getSubGroups).toHaveBeenCalledWith({ + includeParentDescendants: true, + includeParentSharedGroups: true, + search: '', + }); + }); + + it('should not make an API call sub groups when user does not have a license', () => { + createComponent({ hasLicense: false }); + expect(getSubGroups).not.toHaveBeenCalled(); + }); + + it('should make api calls when search query is updated', async () => { + createComponent(); + const search = 'root'; + + findSearchBox().vm.$emit('input', search); + await nextTick(); + expect(getSubGroups).toHaveBeenCalledWith({ + includeParentDescendants: true, + includeParentSharedGroups: true, + search, + }); + }); + }); +});