Merge pull request #10201 from backstage/rugvip/use-entity

catalog-react: remove deprecated loading state of useEntity
This commit is contained in:
Ben Lambert
2022-03-15 13:15:58 +01:00
committed by GitHub
6 changed files with 30 additions and 37 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': minor
---
**BREAKING**: The `useEntity` hook no longer returns loading or error states, and will throw an error if the entity is not immediately available. In practice this means that `useEntity` can only be used in contexts where the entity is guaranteed to have been loaded, for example inside an `EntityLayout`. To access the loading state of the entity, use `useAsyncEntity` instead.
-3
View File
@@ -472,9 +472,6 @@ export function useAsyncEntity<
// @public
export function useEntity<TEntity extends Entity = Entity>(): {
entity: TEntity;
loading: boolean;
error?: Error;
refresh?: VoidFunction;
};
// @public
@@ -16,19 +16,21 @@
import React from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { useEntity, EntityProvider, AsyncEntityProvider } from './useEntity';
import {
useEntity,
useAsyncEntity,
EntityProvider,
AsyncEntityProvider,
} from './useEntity';
import { Entity } from '@backstage/catalog-model';
describe('EntityProvider', () => {
it('should provide no entity', async () => {
describe('useEntity', () => {
it('should throw if no entity is provided', async () => {
const { result } = renderHook(() => useEntity(), {
wrapper: ({ children }) => <EntityProvider children={children} />,
});
expect(result.current.entity).toBe(undefined);
expect(result.current.loading).toBe(true);
expect(result.current.error).toBe(undefined);
expect(result.current.refresh).toBe(undefined);
expect(result.error?.message).toMatch(/entity has not been loaded/);
});
it('should provide an entity', async () => {
@@ -40,15 +42,12 @@ describe('EntityProvider', () => {
});
expect(result.current.entity).toBe(entity);
expect(result.current.loading).toBe(false);
expect(result.current.error).toBe(undefined);
expect(result.current.refresh).toBe(undefined);
});
});
describe('AsyncEntityProvider', () => {
describe('useAsyncEntity', () => {
it('should provide no entity', async () => {
const { result } = renderHook(() => useEntity(), {
const { result } = renderHook(() => useAsyncEntity(), {
wrapper: ({ children }) => (
<AsyncEntityProvider loading={false} children={children} />
),
@@ -63,7 +62,7 @@ describe('AsyncEntityProvider', () => {
it('should provide an entity', async () => {
const entity = { kind: 'MyEntity' } as Entity;
const refresh = () => {};
const { result } = renderHook(() => useEntity(), {
const { result } = renderHook(() => useAsyncEntity(), {
wrapper: ({ children }) => (
<AsyncEntityProvider
loading={false}
@@ -82,7 +81,7 @@ describe('AsyncEntityProvider', () => {
it('should provide an error', async () => {
const error = new Error('oh no');
const { result } = renderHook(() => useEntity(), {
const { result } = renderHook(() => useAsyncEntity(), {
wrapper: ({ children }) => (
<AsyncEntityProvider
loading={false}
+3 -15
View File
@@ -103,12 +103,6 @@ export const EntityProvider = ({ entity, children }: EntityProviderProps) => (
*/
export function useEntity<TEntity extends Entity = Entity>(): {
entity: TEntity;
/** @deprecated use {@link useAsyncEntity} instead */
loading: boolean;
/** @deprecated use {@link useAsyncEntity} instead */
error?: Error;
/** @deprecated use {@link useAsyncEntity} instead */
refresh?: VoidFunction;
} {
const versionedHolder =
useVersionedContext<{ 1: EntityLoadingStatus }>('entity-context');
@@ -123,18 +117,12 @@ export function useEntity<TEntity extends Entity = Entity>(): {
}
if (!value.entity) {
// Once we have removed the additional fields from being returned we can drop this deprecation
// and move to the error instead.
// throw new Error('useEntity hook is being called outside of an EntityLayout where the entity has not been loaded. If this is intentional, please use useAsyncEntity instead.');
// eslint-disable-next-line no-console
console.warn(
'DEPRECATION: useEntity hook is being called outside of an EntityLayout where the entity has not been loaded. If this is intentional, please use useAsyncEntity instead. This warning will be replaced with an error in future releases.',
throw new Error(
'useEntity hook is being called outside of an EntityLayout where the entity has not been loaded. If this is intentional, please use useAsyncEntity instead.',
);
}
const { entity, loading, error, refresh } = value;
return { entity: entity as TEntity, loading, error, refresh };
return { entity: value.entity as TEntity };
}
/**
@@ -17,18 +17,18 @@
import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common';
import { renderHook } from '@testing-library/react-hooks';
import { useEntityPermission } from './useEntityPermission';
import { useEntity } from './useEntity';
import { useAsyncEntity } from './useEntity';
import { usePermission } from '@backstage/plugin-permission-react';
jest.mock('./useEntity', () => ({
...jest.requireActual('./useEntity'),
useEntity: jest.fn(),
useAsyncEntity: jest.fn(),
}));
jest.mock('@backstage/plugin-permission-react', () => ({
...jest.requireActual('@backstage/plugin-permission-react'),
usePermission: jest.fn(),
}));
const useEntityMock = useEntity as jest.Mock;
const useEntityMock = useAsyncEntity as jest.Mock;
const usePermissionMock = usePermission as jest.Mock;
describe('useEntityPermission', () => {
@@ -17,7 +17,7 @@
import { stringifyEntityRef } from '@backstage/catalog-model';
import { Permission } from '@backstage/plugin-permission-common';
import { usePermission } from '@backstage/plugin-permission-react';
import { useEntity } from './useEntity';
import { useAsyncEntity } from './useEntity';
/**
* A thin wrapper around the
@@ -35,7 +35,11 @@ export function useEntityPermission(permission: Permission): {
allowed: boolean;
error?: Error;
} {
const { entity, loading: loadingEntity, error: entityError } = useEntity();
const {
entity,
loading: loadingEntity,
error: entityError,
} = useAsyncEntity();
const {
allowed,
loading: loadingPermission,