From 5172a9247bc4fc7b5192247db7dfd27be4d94dce Mon Sep 17 00:00:00 2001 From: Andrew Fontaine <afontaine@gitlab.com> Date: Tue, 26 Mar 2024 18:51:52 +0000 Subject: [PATCH] Add search functionality to sub group autocomplete Before this, the group access dropdown had a search input that was not configured to filter results. Here we fetch new results on query change, passing that query value down to the GroupsFinder, where the search functionality already exists. Changelog: fixed EE: true --- .../settings/api/access_dropdown_api.js | 9 ++- .../settings/components/access_dropdown.vue | 8 ++- .../autocomplete/group_subgroups_finder.rb | 7 ++- .../group_subgroups_finder_spec.rb | 11 ++++ .../components/access_dropdown_spec.js | 60 +++++++++++++++++++ 5 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 spec/frontend/groups/settings/components/access_dropdown_spec.js 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 e232b1977f0a2..5b43096325247 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 327f73b88c20b..e47092b896bfa 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 36bbd05248001..1b51da15f0060 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 ac416291199a8..64366749ba9c3 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 0000000000000..67a514ef35dbe --- /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, + }); + }); + }); +}); -- GitLab