catalog-react: deprecate useEntityKinds

Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2022-02-21 10:09:49 +01:00
parent 60c97f6707
commit a8331830f1
7 changed files with 109 additions and 72 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) {
@@ -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;