From 24d302fce045e45a7cc20c43f146efe6e315371b Mon Sep 17 00:00:00 2001 From: Zach Hammer Date: Wed, 20 Mar 2024 12:55:33 -0400 Subject: [PATCH 1/4] Only hide EntityAutocompletePicker if there are no options Signed-off-by: Zach Hammer --- .../EntityAutocompletePicker.test.tsx | 50 +++++++++++++++++++ .../EntityAutocompletePicker.tsx | 4 +- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx index 94af52f374..0516267041 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx @@ -88,6 +88,56 @@ describe('', () => { }); }); + it('hides filter if there are no available options', async () => { + const mockCatalogApiNoOptions: Partial> = { + getEntityFacets: jest.fn().mockResolvedValue({ + facets: { + 'spec.options': [], + }, + }), + }; + render( + + + + label="Options" + path="spec.options" + name="options" + Filter={EntityOptionFilter} + /> + + , + ); + await waitFor(() => { + expect(screen.queryByText('Options')).not.toBeInTheDocument(); + }); + }); + + it('renders filter if there is one available option', async () => { + const mockCatalogApiOneOption: Partial> = { + getEntityFacets: jest.fn().mockResolvedValue({ + facets: { + 'spec.options': [{ value: 'option1', count: 1 }], + }, + }), + }; + render( + + + + label="Options" + path="spec.options" + name="options" + Filter={EntityOptionFilter} + /> + + , + ); + await waitFor(() => { + expect(screen.queryByText('Options')).toBeInTheDocument(); + }); + }); + it('renders unique options in alphabetical order', async () => { render( diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx index 5e5bedaceb..a9b96f7e70 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx @@ -144,8 +144,8 @@ export function EntityAutocompletePicker< return null; } - // Hide if there are 1 or fewer options; nothing to pick from - if (availableOptions.length <= 1) return null; + // Hide if there are no options; nothing to pick from + if (availableOptions.length === 0) return null; return ( From b863830aaa060c913b6424c1ff572a1b5dd0394b Mon Sep 17 00:00:00 2001 From: Zach Hammer Date: Wed, 20 Mar 2024 13:00:10 -0400 Subject: [PATCH 2/4] Add changeset Signed-off-by: Zach Hammer --- .changeset/moody-rice-jump.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/moody-rice-jump.md diff --git a/.changeset/moody-rice-jump.md b/.changeset/moody-rice-jump.md new file mode 100644 index 0000000000..00e71aa2af --- /dev/null +++ b/.changeset/moody-rice-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Change behavior in EntityAutoCompletePicker to only hide filter if there are no available options. Previously the filter was hidden if there were <= 1 available options. From dd6b3f01c8ea4a7e849e433642dd520fa406d2cf Mon Sep 17 00:00:00 2001 From: Zach Hammer Date: Mon, 1 Apr 2024 17:01:08 -0400 Subject: [PATCH 3/4] remove redundant line Signed-off-by: Zach Hammer --- .../EntityAutocompletePicker/EntityAutocompletePicker.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx index a9b96f7e70..590a896a06 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx @@ -144,9 +144,6 @@ export function EntityAutocompletePicker< return null; } - // Hide if there are no options; nothing to pick from - if (availableOptions.length === 0) return null; - return ( From fecdba04d0f6b451bccdc217fc9e4896fd9378a8 Mon Sep 17 00:00:00 2001 From: Zach Hammer Date: Mon, 1 Apr 2024 17:09:50 -0400 Subject: [PATCH 4/4] refactor mock catalog api gen into function Signed-off-by: Zach Hammer --- .../EntityAutocompletePicker.test.tsx | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx index 0516267041..26dee40ec3 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.test.tsx @@ -30,7 +30,7 @@ interface EntityFilters extends DefaultEntityFilters { options?: EntityOptionFilter; } -const options = ['option1', 'option2', 'option3', 'option4']; +const defaultOptions = ['option1', 'option2', 'option3', 'option4']; class EntityOptionFilter implements EntityFilter { constructor(readonly values: string[]) {} @@ -46,20 +46,25 @@ class EntityOptionFilter implements EntityFilter { } } -describe('', () => { - const mockCatalogApi: Partial> = { +const makeMockCatalogApi = ( + opts: string[] = defaultOptions, +): Partial> => { + return { getEntityFacets: jest.fn().mockResolvedValue({ facets: { - 'spec.options': options.map((value, idx) => ({ value, count: idx })), + 'spec.options': opts.map((value, idx) => ({ value, count: idx })), }, }), }; +}; +describe('', () => { beforeEach(() => { jest.clearAllMocks(); }); it('renders all options', async () => { + const mockCatalogApi = makeMockCatalogApi(); render( @@ -83,21 +88,15 @@ describe('', () => { }); fireEvent.click(screen.getByTestId('options-picker-expand')); - options.forEach(option => { + defaultOptions.forEach(option => { expect(screen.getByText(option)).toBeInTheDocument(); }); }); it('hides filter if there are no available options', async () => { - const mockCatalogApiNoOptions: Partial> = { - getEntityFacets: jest.fn().mockResolvedValue({ - facets: { - 'spec.options': [], - }, - }), - }; + const mockCatalogApi = makeMockCatalogApi([]); render( - + label="Options" @@ -114,15 +113,9 @@ describe('', () => { }); it('renders filter if there is one available option', async () => { - const mockCatalogApiOneOption: Partial> = { - getEntityFacets: jest.fn().mockResolvedValue({ - facets: { - 'spec.options': [{ value: 'option1', count: 1 }], - }, - }), - }; + const mockCatalogApi = makeMockCatalogApi(['option1']); render( - + label="Options" @@ -139,6 +132,7 @@ describe('', () => { }); it('renders unique options in alphabetical order', async () => { + const mockCatalogApi = makeMockCatalogApi(); render( @@ -166,6 +160,7 @@ describe('', () => { }); it('renders options with counts', async () => { + const mockCatalogApi = makeMockCatalogApi(); render( @@ -194,6 +189,7 @@ describe('', () => { }); it('respects the query parameter filter value', async () => { + const mockCatalogApi = makeMockCatalogApi(); const updateFilters = jest.fn(); const queryParameters = { options: ['option3'] }; render( @@ -222,6 +218,7 @@ describe('', () => { }); it('adds options to filters', async () => { + const mockCatalogApi = makeMockCatalogApi(); const updateFilters = jest.fn(); render( @@ -251,6 +248,7 @@ describe('', () => { }); it('removes options from filters', async () => { + const mockCatalogApi = makeMockCatalogApi(); const updateFilters = jest.fn(); render( @@ -284,6 +282,7 @@ describe('', () => { }); it('responds to external queryParameters changes', async () => { + const mockCatalogApi = makeMockCatalogApi(); const updateFilters = jest.fn(); const rendered = render( @@ -330,6 +329,7 @@ describe('', () => { }); it('filters available values by kind as default', async () => { + const mockCatalogApi = makeMockCatalogApi(); render( ', () => { }); it('can be supplied with filters for available values', async () => { + const mockCatalogApi = makeMockCatalogApi(); render(