From fb46b6e9b08dc2f0a68895e6dad2e29732b80245 Mon Sep 17 00:00:00 2001
From: Peter Hegman <phegman@gitlab.com>
Date: Tue, 25 Oct 2022 12:12:28 -0700
Subject: [PATCH 1/2] Prevent search for when under 3 characters

To align with API restrictions
---
 .../groups/components/overview_tabs.vue       |  4 +-
 .../groups/components/overview_tabs_spec.js   | 48 +++++++++++++++----
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
index d0c5846ac8846069..c7e85f92c46789bf 100644
--- a/app/assets/javascripts/groups/components/overview_tabs.vue
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -136,7 +136,9 @@ export default {
     handleSearchInput(value) {
       this.search = value;
 
-      this.debouncedSearch();
+      if (this.search.length === 0 || this.search.length >= 3) {
+        this.debouncedSearch();
+      }
     },
     debouncedSearch: debounce(async function debouncedSearch() {
       this.handleSearchOrSortChange();
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index 93e087e10f2e79b3..b615679dcc597990 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -67,6 +67,7 @@ describe('OverviewTabs', () => {
   const findTabPanels = () => wrapper.findAllComponents(GlTab);
   const findTab = (name) => wrapper.findByRole('tab', { name });
   const findSelectedTab = () => wrapper.findByRole('tab', { selected: true });
+  const findSearchInput = () => wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder);
 
   beforeEach(() => {
     axiosMock = new AxiosMockAdapter(axios);
@@ -244,18 +245,39 @@ describe('OverviewTabs', () => {
     };
 
     describe('when search is typed in', () => {
-      const search = 'Foo bar';
+      describe('when search is greater than or equal to 3 characters', () => {
+        const search = 'Foo bar';
 
-      beforeEach(async () => {
-        await setup();
-        await wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder).setValue(search);
-      });
+        beforeEach(async () => {
+          await setup();
+          await findSearchInput().setValue(search);
+        });
 
-      it('updates query string with `filter` key', () => {
-        expect(routerMock.push).toHaveBeenCalledWith({ query: { filter: search } });
+        it('updates query string with `filter` key', () => {
+          expect(routerMock.push).toHaveBeenCalledWith({ query: { filter: search } });
+        });
+
+        sharedAssertions({ search, sort: defaultProvide.initialSort });
       });
 
-      sharedAssertions({ search, sort: defaultProvide.initialSort });
+      describe('when search is less than 3 characters', () => {
+        const search = 'Fo';
+
+        beforeEach(async () => {
+          await setup();
+          await findSearchInput().setValue(search);
+        });
+
+        it('does not emit `fetchFilteredAndSortedGroups` event from `eventHub`', () => {
+          expect(eventHub.$emit).not.toHaveBeenCalledWith(
+            `${ACTIVE_TAB_SUBGROUPS_AND_PROJECTS}fetchFilteredAndSortedGroups`,
+            {
+              filterGroupsBy: search,
+              sortBy: defaultProvide.initialSort,
+            },
+          );
+        });
+      });
     });
 
     describe('when sort is changed', () => {
@@ -308,6 +330,16 @@ describe('OverviewTabs', () => {
         ).toBe('Foo bar');
       });
 
+      describe('when search is cleared', () => {
+        it('removes `filter` key from query string', async () => {
+          await findSearchInput().setValue('');
+
+          expect(routerMock.push).toHaveBeenCalledWith({
+            query: { sort: SORTING_ITEM_UPDATED.desc },
+          });
+        });
+      });
+
       it('sets sort dropdown', () => {
         expect(wrapper.findComponent(GlSorting).props()).toMatchObject({
           text: SORTING_ITEM_UPDATED.label,
-- 
GitLab


From d85a7bd9cf69bf333d51abc132bf18c1d7a52857 Mon Sep 17 00:00:00 2001
From: Peter Hegman <phegman@gitlab.com>
Date: Thu, 27 Oct 2022 12:36:00 -0700
Subject: [PATCH 2/2] Move number to constant

Per reviewer suggestion
---
 app/assets/javascripts/groups/components/overview_tabs.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
index c7e85f92c46789bf..46ab30367a0e38aa 100644
--- a/app/assets/javascripts/groups/components/overview_tabs.vue
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -15,6 +15,7 @@ import eventHub from '../event_hub';
 import GroupsApp from './app.vue';
 
 const [SORTING_ITEM_NAME] = OVERVIEW_TABS_SORTING_ITEMS;
+const MIN_SEARCH_LENGTH = 3;
 
 export default {
   components: { GlTabs, GlTab, GroupsApp, GlSearchBoxByType, GlSorting, GlSortingItem },
@@ -136,7 +137,7 @@ export default {
     handleSearchInput(value) {
       this.search = value;
 
-      if (this.search.length === 0 || this.search.length >= 3) {
+      if (!this.search || this.search.length >= MIN_SEARCH_LENGTH) {
         this.debouncedSearch();
       }
     },
-- 
GitLab