Merge pull request #28825 from annervisser/fix-update-entityautocompletepicker-selected-options-when-value-changes
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
update EntityAutocompletePicker selected options when filter value is changed externally
|
||||
+30
-30
@@ -14,16 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { fireEvent, render, waitFor, screen } from '@testing-library/react';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import {
|
||||
MockEntityListContextProvider,
|
||||
catalogApiMock,
|
||||
MockEntityListContextProvider,
|
||||
} from '@backstage/plugin-catalog-react/testUtils';
|
||||
import { EntityAutocompletePicker } from './EntityAutocompletePicker';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { catalogApiRef } from '../../api';
|
||||
import { DefaultEntityFilters } from '../../hooks';
|
||||
import { DefaultEntityFilters, useEntityList } from '../../hooks';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { EntityFilter } from '../../types';
|
||||
import { EntityKindFilter, EntityTypeFilter } from '../../filters';
|
||||
@@ -281,15 +281,28 @@ describe('<EntityAutocompletePicker/>', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('responds to external queryParameters changes', async () => {
|
||||
it('responds to external filter changes', async () => {
|
||||
const mockCatalogApi = makeMockCatalogApi();
|
||||
const updateFilters = jest.fn();
|
||||
const rendered = render(
|
||||
const ChangeFilterButton = () => {
|
||||
const { updateFilters } = useEntityList<EntityFilters>();
|
||||
|
||||
return (
|
||||
<button
|
||||
data-testid="external-filter-change-button"
|
||||
onClick={() =>
|
||||
updateFilters({ options: new EntityOptionFilter(['option3']) })
|
||||
}
|
||||
>
|
||||
Trigger external filter change
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
render(
|
||||
<TestApiProvider apis={[[catalogApiRef, mockCatalogApi]]}>
|
||||
<MockEntityListContextProvider<EntityFilters>
|
||||
value={{
|
||||
updateFilters,
|
||||
queryParameters: { options: ['option1'] },
|
||||
filters: { options: new EntityOptionFilter(['option2']) },
|
||||
}}
|
||||
>
|
||||
<EntityAutocompletePicker<EntityFilters>
|
||||
@@ -298,34 +311,21 @@ describe('<EntityAutocompletePicker/>', () => {
|
||||
name="options"
|
||||
Filter={EntityOptionFilter}
|
||||
/>
|
||||
<ChangeFilterButton />
|
||||
</MockEntityListContextProvider>
|
||||
</TestApiProvider>,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(updateFilters).toHaveBeenLastCalledWith({
|
||||
options: new EntityOptionFilter(['option1']),
|
||||
}),
|
||||
expect(screen.queryByText('Options')).toBeInTheDocument(),
|
||||
);
|
||||
rendered.rerender(
|
||||
<TestApiProvider apis={[[catalogApiRef, mockCatalogApi]]}>
|
||||
<MockEntityListContextProvider<EntityFilters>
|
||||
value={{
|
||||
updateFilters,
|
||||
queryParameters: { options: ['option2'] },
|
||||
}}
|
||||
>
|
||||
<EntityAutocompletePicker<EntityFilters>
|
||||
label="Options"
|
||||
path="spec.options"
|
||||
name="options"
|
||||
Filter={EntityOptionFilter}
|
||||
/>
|
||||
</MockEntityListContextProvider>
|
||||
</TestApiProvider>,
|
||||
expect(screen.queryByText('option2')).toBeInTheDocument();
|
||||
|
||||
screen.getByTestId('external-filter-change-button').click();
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByText('option3')).toBeInTheDocument(),
|
||||
);
|
||||
expect(updateFilters).toHaveBeenLastCalledWith({
|
||||
options: new EntityOptionFilter(['option2']),
|
||||
});
|
||||
expect(screen.queryByText('option2')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('filters available values by kind as default', async () => {
|
||||
|
||||
+19
-2
@@ -29,6 +29,7 @@ import {
|
||||
import { EntityFilter } from '../../types';
|
||||
import { reduceBackendCatalogFilters } from '../../utils/filters';
|
||||
import { CatalogAutocomplete } from '../CatalogAutocomplete';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
/** @public */
|
||||
export type AllowedEntityFilters<T extends DefaultEntityFilters> = {
|
||||
@@ -116,11 +117,13 @@ export function EntityAutocompletePicker<
|
||||
[queryParameter],
|
||||
);
|
||||
|
||||
const filteredOptions = (filters[name] as unknown as { values: string[] })
|
||||
?.values;
|
||||
|
||||
const [selectedOptions, setSelectedOptions] = useState(
|
||||
queryParameters.length
|
||||
? queryParameters
|
||||
: (filters[name] as unknown as { values: string[] })?.values ??
|
||||
initialSelectedOptions,
|
||||
: filteredOptions ?? initialSelectedOptions,
|
||||
);
|
||||
|
||||
// Set selected options on query parameter updates; this happens at initial page load and from
|
||||
@@ -134,12 +137,26 @@ export function EntityAutocompletePicker<
|
||||
const availableOptions = Object.keys(availableValues ?? {});
|
||||
const shouldAddFilter = selectedOptions.length && availableOptions.length;
|
||||
|
||||
// Update filter value when selectedOptions change
|
||||
useEffect(() => {
|
||||
updateFilters({
|
||||
[name]: shouldAddFilter ? new Filter(selectedOptions) : undefined,
|
||||
} as Partial<T>);
|
||||
}, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);
|
||||
|
||||
// Update selected options when filter value changes
|
||||
useEffect(() => {
|
||||
if (!shouldAddFilter) return;
|
||||
|
||||
const newSelectedOptions = filteredOptions ?? [];
|
||||
|
||||
// Check value is actually different (not just a different reference) to prevent selectedOptions <> filters loop
|
||||
if (!isEqual(newSelectedOptions, selectedOptions)) {
|
||||
setSelectedOptions(newSelectedOptions);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- Don't re-set filter value when selectedOptions changes
|
||||
}, [filteredOptions]);
|
||||
|
||||
const filter = filters[name];
|
||||
if (
|
||||
(filter && typeof filter === 'object' && !('values' in filter)) ||
|
||||
|
||||
Reference in New Issue
Block a user