From 5bc78a5284773b43c5b35fa40bcc341c1ec116a5 Mon Sep 17 00:00:00 2001 From: Brian Fletcher Date: Tue, 13 Dec 2022 11:42:29 +0000 Subject: [PATCH] more review comments Signed-off-by: Brian Fletcher --- plugins/catalog-react/api-report.md | 9 +- .../EntityPeekAheadPopover.stories.tsx | 45 ++++++-- .../EntityPeekAheadPopover.test.tsx | 44 +++++--- .../EntityPeekAheadPopover.tsx | 106 +++++++++++------- .../EntityRefLink/EntityRefLink.tsx | 2 +- 5 files changed, 131 insertions(+), 75 deletions(-) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index 9d30d84bb2..82f8326a17 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -255,14 +255,13 @@ export class EntityOwnerFilter implements EntityFilter { export const EntityOwnerPicker: () => JSX.Element | null; // @public -export const EntityPeekAheadPopover: ({ - entityRef, - children, -}: EntityPeekAheadPopoverProps) => JSX.Element; +export const EntityPeekAheadPopover: ( + props: EntityPeekAheadPopoverProps, +) => JSX.Element; // @public export type EntityPeekAheadPopoverProps = PropsWithChildren<{ - entityRef: CompoundEntityRef; + entityRef: string; }>; // @public (undocumented) diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.stories.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.stories.tsx index c31e5320ef..c44a31a743 100644 --- a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.stories.tsx +++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.stories.tsx @@ -60,16 +60,27 @@ const mockCatalogApi = { }, }; } + if ( + entityRef.namespace === 'default' && + entityRef.name === 'slow.catalog.item' && + entityRef.kind === 'component' + ) { + await new Promise(resolve => setTimeout(resolve, 3000)); + return { + kind: 'Component', + metadata: { + name: 'slow.catalog.item', + namespace: 'default', + description: 'Details about the slow.catalog.item service', + }, + }; + } return undefined; }, }; const defaultArgs = { - entityRef: { - namespace: 'default', - name: 'playback', - kind: 'component', - }, + entityRef: 'component:default/playback', }; export default { @@ -106,9 +117,23 @@ export const User = (args: EntityPeekAheadPopoverProps) => ( ); User.args = { - entityRef: { - kind: 'user', - namespace: 'default', - name: 'fname.lname', - }, + entityRef: 'user:default/fname.lname', +}; + +export const NotFound = (args: EntityPeekAheadPopoverProps) => ( + + + +); +NotFound.args = { + entityRef: 'user:default/doesnt.exist', +}; + +export const SlowCatalogItem = (args: EntityPeekAheadPopoverProps) => ( + + + +); +SlowCatalogItem.args = { + entityRef: 'component:default/slow.catalog.item', }; diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx index 7053969a09..f7c4d1cffa 100644 --- a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx +++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.test.tsx @@ -14,22 +14,25 @@ * limitations under the License. */ -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, screen } from '@testing-library/react'; import React from 'react'; import { EntityPeekAheadPopover } from './EntityPeekAheadPopover'; import { ApiProvider } from '@backstage/core-app-api'; -import { TestApiRegistry } from '@backstage/test-utils'; +import { TestApiRegistry, renderInTestApp } from '@backstage/test-utils'; import { catalogApiRef } from '../../api'; import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; import { CatalogApi } from '@backstage/catalog-client'; +import { Button } from '@material-ui/core'; +import { entityRouteRef } from '../../routes'; const catalogApi: Partial = { getEntityByRef: async ( entityRef: CompoundEntityRef, ): Promise => { if ( - entityRef === - { name: 'service1', namespace: 'default', kind: 'component ' } + entityRef.name === 'service1' && + entityRef.namespace === 'default' && + entityRef.kind === 'component' ) { return { apiVersion: '', @@ -51,22 +54,31 @@ const apis = TestApiRegistry.from([catalogApiRef, catalogApi]); describe('', () => { it('renders all owners', async () => { - render( + renderInTestApp( - -
asdf
+ + + + +
, + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, ); - expect(screen.getByText('asdf')).toBeInTheDocument(); + expect(screen.getByText('s1')).toBeInTheDocument(); expect(screen.queryByText('service1')).toBeNull(); - fireEvent.mouseOver(screen.getByTestId('popover')); - expect(screen.getByText('service1')).toBeInTheDocument(); + fireEvent.mouseOver(screen.getByTestId('popover1')); + expect(await screen.findByText('service1')).toBeInTheDocument(); + + expect(screen.getByText('s2')).toBeInTheDocument(); + expect(screen.queryByText('service2')).toBeNull(); + fireEvent.mouseOver(screen.getByTestId('popover2')); + expect( + await screen.findByText(/service2 was not found/), + ).toBeInTheDocument(); }); }); diff --git a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx index bd41dd5b92..6e5b75ed58 100644 --- a/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx +++ b/plugins/catalog-react/src/components/EntityPeekAheadPopover/EntityPeekAheadPopover.tsx @@ -34,17 +34,17 @@ import { Tooltip, Typography, } from '@material-ui/core'; -import { Alert, Skeleton } from '@material-ui/lab'; +import { Alert } from '@material-ui/lab'; import EmailIcon from '@material-ui/icons/Email'; import InfoIcon from '@material-ui/icons/Info'; import { useApiHolder, useRouteRef } from '@backstage/core-plugin-api'; import { - CompoundEntityRef, isUserEntity, isGroupEntity, UserEntity, GroupEntity, Entity, + parseEntityRef, } from '@backstage/catalog-model'; import { Link, Progress } from '@backstage/core-components'; @@ -54,11 +54,14 @@ import { Link, Progress } from '@backstage/core-components'; * @public */ export type EntityPeekAheadPopoverProps = PropsWithChildren<{ - entityRef: CompoundEntityRef; + entityRef: string; }>; const useStyles = makeStyles(() => { return { + trigger: { + display: 'inline-block', + }, popoverPaper: { width: '30em', }, @@ -130,33 +133,53 @@ const EntityCardActions = ({ entity }: { entity: Entity }) => { ); }; +const EntityNotFoundCard = ({ + entityRef, + error, +}: { + entityRef: string; + error?: Error; +}) => { + return ( + + + + {entityRef} was not found {error?.message} + + + + ); +}; + /** * Shows an entity popover on hover of a component. * * @public */ -export const EntityPeekAheadPopover = ({ - entityRef, - children, -}: EntityPeekAheadPopoverProps) => { +export const EntityPeekAheadPopover = (props: EntityPeekAheadPopoverProps) => { + const { entityRef, children } = props; + const classes = useStyles(); const apiHolder = useApiHolder(); const popupState = usePopupState({ variant: 'popover', popupId: 'entity-peek-ahead', }); + const compoundEntityRef = parseEntityRef(entityRef); const [{ loading, error, value: entity }, load] = useAsyncFn(async () => { const catalogApi = apiHolder.get(catalogApiRef); if (catalogApi) { - const retrievedEntity = await catalogApi.getEntityByRef(entityRef); + const retrievedEntity = await catalogApi.getEntityByRef( + compoundEntityRef, + ); if (!retrievedEntity) { - throw new Error(`${entityRef.name} was not found`); + throw new Error(`${compoundEntityRef.name} was not found`); } return retrievedEntity; } return undefined; - }, [apiHolder, entityRef]); + }, [apiHolder, compoundEntityRef]); useEffect(() => { if (popupState.isOpen && !entity && !error && !loading) { @@ -166,9 +189,9 @@ export const EntityPeekAheadPopover = ({ return ( <> -
+ {children} -
+ - + <> {loading && } - - {entityRef.namespace} - - {entityRef.name} - - {error && {error.message}} - {entity ? ( - <> + {!entity && !loading && ( + + )} + {entity && ( + + + + {compoundEntityRef.namespace} + + + {compoundEntityRef.name} + {entity.kind} {entity.metadata.description} @@ -202,35 +229,28 @@ export const EntityPeekAheadPopover = ({ {(entity.metadata.tags || []) .slice(0, maxTagChips) .map(tag => { - return ; + return ; })} {entity.metadata.tags?.length && entity.metadata.tags?.length > maxTagChips && ( - + )} - - ) : ( - <> - - - - - - )} - - - {entity && ( - <> - {isUserEntity(entity) && } - {isGroupEntity(entity) && } - - - )} - - + + + <> + {isUserEntity(entity) && } + {isGroupEntity(entity) && ( + + )} + + + + + )} + ); diff --git a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx index 813195cb70..de94866bb6 100644 --- a/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx +++ b/plugins/catalog-react/src/components/EntityRefLink/EntityRefLink.tsx @@ -77,7 +77,7 @@ export const EntityRefLink = forwardRef( ); return ( - + {children} {!children && (title ?? formattedEntityRefTitle)}