Merge pull request #9690 from backstage/jhaals/deprecate-useEntityKinds

catalog-react: deprecate useEntityKinds
This commit is contained in:
Johan Haals
2022-02-21 13:25:36 +01:00
committed by GitHub
8 changed files with 110 additions and 73 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Deprecated the `useEntityKinds` hook due to low usage and utility value.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/plugin-catalog': patch
'@backstage/plugin-catalog-graph': patch
---
Remove use of deprecated `useEntityKinds` hook.
@@ -13,63 +13,63 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useApi as useApiMocked } from '@backstage/core-plugin-api';
import { useEntityKinds as useEntityKindsMocked } from '@backstage/plugin-catalog-react';
import { render, waitFor } from '@testing-library/react';
import { GetEntityFacetsResponse } from '@backstage/catalog-client';
import { ApiProvider } from '@backstage/core-app-api';
import { AlertApi, alertApiRef } from '@backstage/core-plugin-api';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils';
import { waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { SelectedKindsFilter } from './SelectedKindsFilter';
jest.mock('@backstage/core-plugin-api');
jest.mock('@backstage/plugin-catalog-react');
const useApi = useApiMocked as jest.Mock<ReturnType<typeof useApiMocked>>;
const useEntityKinds = useEntityKindsMocked as jest.Mock<
ReturnType<typeof useEntityKindsMocked>
>;
const catalogApi = {
getEntityFacets: jest.fn().mockResolvedValue({
facets: {
kind: [
{ value: 'Component', count: 2 },
{ value: 'System', count: 1 },
{ value: 'API', count: 1 },
{ value: 'Resource', count: 1 },
],
},
} as GetEntityFacetsResponse),
};
const apis = TestApiRegistry.from(
[catalogApiRef, catalogApi],
[alertApiRef, {} as AlertApi],
);
describe('<SelectedKindsFilter/>', () => {
beforeEach(() => {
useApi.mockReturnValue({});
useEntityKinds.mockReturnValue({
loading: false,
kinds: ['API', 'Component', 'System', 'Domain', 'Resource'],
error: undefined,
});
it('should not explode while loading', async () => {
const rendered = await renderWithEffects(
<ApiProvider apis={apis}>
<SelectedKindsFilter value={['api', 'component']} onChange={() => {}} />
</ApiProvider>,
);
expect(rendered.baseElement).toBeInTheDocument();
});
afterEach(() => jest.resetAllMocks());
test('should not explode while loading', () => {
useEntityKinds.mockReturnValue({
loading: true,
kinds: undefined,
error: undefined,
});
const { baseElement } = render(
<SelectedKindsFilter value={['api', 'component']} onChange={() => {}} />,
it('should render current value', async () => {
const rendered = await renderWithEffects(
<ApiProvider apis={apis}>
<SelectedKindsFilter value={['api', 'component']} onChange={() => {}} />
</ApiProvider>,
);
expect(baseElement).toBeInTheDocument();
expect(rendered.getByText('API')).toBeInTheDocument();
expect(rendered.getByText('Component')).toBeInTheDocument();
});
test('should render current value', () => {
const { getByText } = render(
<SelectedKindsFilter value={['api', 'component']} onChange={() => {}} />,
);
expect(getByText('API')).toBeInTheDocument();
expect(getByText('Component')).toBeInTheDocument();
});
test('should select value', async () => {
it('should select value', async () => {
const onChange = jest.fn();
const { getByText, getByLabelText } = render(
<SelectedKindsFilter value={['api', 'component']} onChange={onChange} />,
const { getByLabelText, getByText } = await renderWithEffects(
<ApiProvider apis={apis}>
<SelectedKindsFilter value={['api', 'component']} onChange={onChange} />
</ApiProvider>,
);
userEvent.click(getByLabelText('Open'));
await waitFor(() => expect(getByText('System')).toBeInTheDocument());
userEvent.click(getByText('System'));
@@ -79,15 +79,16 @@ describe('<SelectedKindsFilter/>', () => {
});
});
test('should return undefined if all values are selected', async () => {
it('should return undefined if all values are selected', async () => {
const onChange = jest.fn();
const { getByText, getByLabelText } = render(
<SelectedKindsFilter
value={['api', 'component', 'system', 'domain']}
onChange={onChange}
/>,
const { getByLabelText, getByText } = await renderWithEffects(
<ApiProvider apis={apis}>
<SelectedKindsFilter
value={['api', 'component', 'system', 'domain']}
onChange={onChange}
/>
</ApiProvider>,
);
userEvent.click(getByLabelText('Open'));
await waitFor(() => expect(getByText('Resource')).toBeInTheDocument());
@@ -99,10 +100,12 @@ describe('<SelectedKindsFilter/>', () => {
});
});
test('should return all values when cleared', async () => {
it('should return all values when cleared', async () => {
const onChange = jest.fn();
const { getByRole } = render(
<SelectedKindsFilter value={[]} onChange={onChange} />,
const { getByRole } = await renderWithEffects(
<ApiProvider apis={apis}>
<SelectedKindsFilter value={[]} onChange={onChange} />
</ApiProvider>,
);
userEvent.click(getByRole('combobox'));
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
import { useEntityKinds } from '@backstage/plugin-catalog-react';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import {
Box,
Checkbox,
@@ -28,6 +28,7 @@ import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Autocomplete } from '@material-ui/lab';
import React, { useCallback, useEffect, useMemo } from 'react';
import useAsync from 'react-use/lib/useAsync';
const useStyles = makeStyles({
formControl: {
@@ -43,7 +44,13 @@ export type Props = {
export const SelectedKindsFilter = ({ value, onChange }: Props) => {
const classes = useStyles();
const alertApi = useApi(alertApiRef);
const { error, kinds } = useEntityKinds();
const catalogApi = useApi(catalogApiRef);
const { error, value: kinds } = useAsync(async () => {
return await catalogApi
.getEntityFacets({ facets: ['kind'] })
.then(response => response.facets.kind?.map(f => f.value).sort() || []);
});
useEffect(() => {
if (error) {
+1 -1
View File
@@ -551,7 +551,7 @@ export const useEntityCompoundName: () => {
// @public @deprecated (undocumented)
export const useEntityFromUrl: () => EntityLoadingStatus;
// @public
// @public @deprecated
export function useEntityKinds(): {
error: Error | undefined;
loading: boolean;
@@ -21,6 +21,7 @@ import { catalogApiRef } from '../api';
/**
* Retrieve a list of unique entity kinds present in the catalog
* @public
* @deprecated and will be removed due to low utility value.
*/
export function useEntityKinds() {
const catalogApi = useApi(catalogApiRef);
@@ -24,8 +24,13 @@ import {
MockEntityListContextProvider,
} from '@backstage/plugin-catalog-react';
import { ApiProvider } from '@backstage/core-app-api';
import { renderWithEffects, TestApiRegistry } from '@backstage/test-utils';
import {
MockErrorApi,
renderWithEffects,
TestApiRegistry,
} from '@backstage/test-utils';
import { CatalogKindHeader } from './CatalogKindHeader';
import { errorApiRef } from '@backstage/core-plugin-api';
const entities: Entity[] = [
{
@@ -57,21 +62,24 @@ const entities: Entity[] = [
},
},
];
const apis = TestApiRegistry.from([
catalogApiRef,
{
getEntityFacets: jest.fn().mockResolvedValue({
facets: {
kind: [
{ value: 'Component', count: 2 },
{ value: 'Template', count: 1 },
{ value: 'System', count: 1 },
],
},
} as GetEntityFacetsResponse),
},
]);
const errorApi = new MockErrorApi();
const apis = TestApiRegistry.from(
[
catalogApiRef,
{
getEntityFacets: jest.fn().mockResolvedValue({
facets: {
kind: [
{ value: 'Component', count: 2 },
{ value: 'Template', count: 1 },
{ value: 'System', count: 1 },
],
},
} as GetEntityFacetsResponse),
},
],
[errorApiRef, errorApi],
);
describe('<CatalogKindHeader />', () => {
it('renders available kinds', async () => {
@@ -25,10 +25,12 @@ import {
Theme,
} from '@material-ui/core';
import {
catalogApiRef,
EntityKindFilter,
useEntityKinds,
useEntityListProvider,
} from '@backstage/plugin-catalog-react';
import useAsync from 'react-use/lib/useAsync';
import { useApi } from '@backstage/core-plugin-api';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -51,7 +53,12 @@ export interface CatalogKindHeaderProps {
export function CatalogKindHeader(props: CatalogKindHeaderProps) {
const { initialFilter = 'component' } = props;
const classes = useStyles();
const { kinds: allKinds = [] } = useEntityKinds();
const catalogApi = useApi(catalogApiRef);
const { value: allKinds } = useAsync(async () => {
return await catalogApi
.getEntityFacets({ facets: ['kind'] })
.then(response => response.facets.kind?.map(f => f.value).sort() || []);
});
const { updateFilters, queryParameters } = useEntityListProvider();
const [selectedKind, setSelectedKind] = useState(
@@ -72,7 +79,7 @@ export function CatalogKindHeader(props: CatalogKindHeaderProps) {
// including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the
// more proper catalog kind if it exists.
const options = [capitalize(selectedKind)]
.concat(allKinds)
.concat(allKinds ?? [])
.sort()
.reduce((acc, kind) => {
acc[kind.toLocaleLowerCase('en-US')] = kind;