diff --git a/packages/core/src/components/HeaderIconLinkRow/IconLinkVertical.tsx b/packages/core/src/components/HeaderIconLinkRow/IconLinkVertical.tsx index 3ea7981aa5..c3c817362a 100644 --- a/packages/core/src/components/HeaderIconLinkRow/IconLinkVertical.tsx +++ b/packages/core/src/components/HeaderIconLinkRow/IconLinkVertical.tsx @@ -20,12 +20,13 @@ import LinkIcon from '@material-ui/icons/Link'; import { Link as RouterLink } from '../Link'; export type IconLinkVerticalProps = { - icon?: React.ReactNode; - href?: string; - onClick?: React.MouseEventHandler; - disabled?: boolean; - label: string; color?: 'primary' | 'secondary'; + disabled?: boolean; + href?: string; + icon?: React.ReactNode; + label: string; + onClick?: React.MouseEventHandler; + title?: string; }; const useIconStyles = makeStyles(theme => ({ @@ -53,18 +54,20 @@ const useIconStyles = makeStyles(theme => ({ })); export function IconLinkVertical({ - icon = , - href = '#', - disabled = false, color = 'primary', + disabled = false, + href = '#', + icon = , label, onClick, + title, }: IconLinkVerticalProps) { const classes = useIconStyles(); if (disabled) { return ( @@ -76,6 +79,7 @@ export function IconLinkVertical({ return ( GitHub', () => { - it('renders info and "view source" link', () => { + it('renders info and "view source" link', async () => { const entity = { apiVersion: 'v1', kind: 'Component', @@ -41,7 +41,7 @@ describe(' GitHub', () => { lifecycle: 'production', }, }; - const { getByText } = render( + const { getByText, getByTitle } = render( , @@ -51,15 +51,21 @@ describe(' GitHub', () => { 'href', 'https://github.com/backstage/backstage/blob/master/software.yaml', ); - expect(getByText('View Source').closest('a')).toHaveAttribute( - 'edithref', - 'https://github.com/backstage/backstage/edit/master/software.yaml', + + const editButton = getByTitle('Edit Metadata'); + window.open = jest.fn(); + await act(async () => { + fireEvent.click(editButton); + }); + expect(window.open).toHaveBeenCalledWith( + `https://github.com/backstage/backstage/edit/master/software.yaml`, + '_blank', ); }); }); describe(' GitLab', () => { - it('renders info and "view source" link', () => { + it('renders info and "view source" link', async () => { const entity = { apiVersion: 'v1', kind: 'Component', @@ -76,25 +82,32 @@ describe(' GitLab', () => { lifecycle: 'production', }, }; - const { getByText } = render( + const { getByText, getByTitle } = render( , ); + expect(getByText('service')).toBeInTheDocument(); expect(getByText('View Source').closest('a')).toHaveAttribute( 'href', 'https://gitlab.com/backstage/backstage/-/blob/master/software.yaml', ); - expect(getByText('View Source').closest('a')).toHaveAttribute( - 'edithref', - 'https://gitlab.com/backstage/backstage/-/edit/master/software.yaml', + + const editButton = getByTitle('Edit Metadata'); + window.open = jest.fn(); + await act(async () => { + fireEvent.click(editButton); + }); + expect(window.open).toHaveBeenCalledWith( + `https://gitlab.com/backstage/backstage/-/edit/master/software.yaml`, + '_blank', ); }); }); describe(' BitBucket', () => { - it('renders info and "view source" link', () => { + it('renders info and "view source" link', async () => { const entity = { apiVersion: 'v1', kind: 'Component', @@ -111,7 +124,7 @@ describe(' BitBucket', () => { lifecycle: 'production', }, }; - const { getByText } = render( + const { getByText, getByTitle } = render( , @@ -121,15 +134,21 @@ describe(' BitBucket', () => { 'href', 'https://bitbucket.org/backstage/backstage/src/master/software.yaml', ); - expect(getByText('View Source').closest('a')).toHaveAttribute( - 'edithref', - 'https://bitbucket.org/backstage/backstage/src/master/software.yaml?mode=edit&spa=0&at=master', + + const editButton = getByTitle('Edit Metadata'); + window.open = jest.fn(); + await act(async () => { + fireEvent.click(editButton); + }); + expect(window.open).toHaveBeenCalledWith( + `https://bitbucket.org/backstage/backstage/src/master/software.yaml?mode=edit&spa=0&at=master`, + '_blank', ); }); }); describe(' custom links', () => { - it('renders info and "view source" link', () => { + it('renders info and "view source" link', async () => { const entity = { apiVersion: 'v1', kind: 'Component', @@ -149,7 +168,7 @@ describe(' custom links', () => { lifecycle: 'production', }, }; - const { getByText } = render( + const { getByText, getByTitle } = render( , @@ -159,9 +178,12 @@ describe(' custom links', () => { 'href', 'https://another.place/backstage.git', ); - expect(getByText('View Source').closest('a')).toHaveAttribute( - 'edithref', - 'https://another.place', - ); + + const editButton = getByTitle('Edit Metadata'); + window.open = jest.fn(); + await act(async () => { + fireEvent.click(editButton); + }); + expect(window.open).toHaveBeenCalledWith(`https://another.place`, '_blank'); }); }); diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index 64564f5ec4..ff411f80d4 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -21,7 +21,7 @@ import { SOURCE_LOCATION_ANNOTATION, RELATION_PROVIDES_API, } from '@backstage/catalog-model'; -import { HeaderIconLinkRow } from '@backstage/core'; +import { HeaderIconLinkRow, IconLinkVerticalProps } from '@backstage/core'; import { useEntity } from '@backstage/plugin-catalog-react'; import { Card, @@ -105,11 +105,12 @@ export function AboutCard({ variant }: AboutCardProps) { const codeLink = getCodeLinkInfo(entity); // TODO: Also support RELATION_CONSUMES_API here const hasApis = entity.relations?.some(r => r.type === RELATION_PROVIDES_API); - const viewInSource = { + const viewInSource: IconLinkVerticalProps = { label: 'View Source', - ...codeLink, + href: codeLink.href, + icon: codeLink.icon, }; - const viewInTechDocs = { + const viewInTechDocs: IconLinkVerticalProps = { label: 'View TechDocs', disabled: !entity.metadata.annotations?.['backstage.io/techdocs-ref'], icon: , @@ -117,7 +118,7 @@ export function AboutCard({ variant }: AboutCardProps) { entity.kind }/${entity.metadata.name}`, }; - const viewApi = { + const viewApi: IconLinkVerticalProps = { title: hasApis ? '' : 'No APIs available', label: 'View API', disabled: !hasApis,