From 0fc2a84352930da4c2166dc80536e7792767bb6c Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 13 Feb 2021 11:37:41 +0000 Subject: [PATCH] Update CatalogTable actions to support custom URLs --- .../src/components/AboutCard/AboutCard.tsx | 2 +- .../CatalogTable/CatalogTable.test.tsx | 67 +++++++++++++++++++ .../components/CatalogTable/CatalogTable.tsx | 13 ++-- .../{createEditLink.ts => actions.ts} | 24 ++++++- yarn.lock | 3 +- 5 files changed, 99 insertions(+), 10 deletions(-) rename plugins/catalog/src/components/{createEditLink.ts => actions.ts} (80%) diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index 2d6cd6bca8..0f2d55295b 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -35,7 +35,7 @@ import ExtensionIcon from '@material-ui/icons/Extension'; import GitHubIcon from '@material-ui/icons/GitHub'; import React from 'react'; import { findLocationForEntityMeta } from '../../data/utils'; -import { createEditLink, determineUrlType } from '../createEditLink'; +import { createEditLink, determineUrlType } from '../actions'; import { AboutContent } from './AboutContent'; const useStyles = makeStyles({ diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index 16c91c0d6c..5cb776746d 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -15,6 +15,7 @@ */ import { Entity } from '@backstage/catalog-model'; +import { act, fireEvent } from '@testing-library/react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import * as React from 'react'; import { CatalogTable } from './CatalogTable'; @@ -38,6 +39,14 @@ const entities: Entity[] = [ ]; describe('CatalogTable component', () => { + beforeEach(() => { + window.open = jest.fn(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + it('should render error message when error is passed in props', async () => { const rendered = await renderWithEffects( wrapInTestApp( @@ -70,4 +79,62 @@ describe('CatalogTable component', () => { expect(rendered.getByText(/component2/)).toBeInTheDocument(); expect(rendered.getByText(/component3/)).toBeInTheDocument(); }); + + it('should use specified edit URL if in annotation', async () => { + const entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'component1', + annotations: { 'backstage.io/browser-edit-url': 'https://other.place' }, + }, + }; + + const { getByTitle } = await renderWithEffects( + wrapInTestApp( + , + ), + ); + + const editButton = getByTitle('Edit'); + + await act(async () => { + fireEvent.click(editButton); + }); + + expect(window.open).toHaveBeenCalledWith('https://other.place', '_blank'); + }); + + it('should use specified view URL if in annotation', async () => { + const entity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'component1', + annotations: { 'backstage.io/browser-view-url': 'https://other.place' }, + }, + }; + + const { getByTitle } = await renderWithEffects( + wrapInTestApp( + , + ), + ); + + const viewButton = getByTitle('View'); + + await act(async () => { + fireEvent.click(viewButton); + }); + + expect(window.open).toHaveBeenCalledWith('https://other.place', '_blank'); + }); }); diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index 12d97e91a6..ca40648ecb 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -34,13 +34,12 @@ import { getEntityRelations, useStarredEntities, } from '@backstage/plugin-catalog-react'; - import { Chip } from '@material-ui/core'; import Edit from '@material-ui/icons/Edit'; import OpenInNew from '@material-ui/icons/OpenInNew'; import React from 'react'; import { findLocationForEntityMeta } from '../../data/utils'; -import { createEditLink } from '../createEditLink'; +import { findViewUrl, findEditUrl } from '../actions'; import { favouriteEntityIcon, favouriteEntityTooltip, @@ -154,23 +153,25 @@ export const CatalogTable = ({ const actions: TableProps['actions'] = [ ({ entity }) => { const location = findLocationForEntityMeta(entity.metadata); + const url = findViewUrl(entity, location); return { icon: () => , tooltip: 'View', onClick: () => { - if (!location) return; - window.open(location.target, '_blank'); + if (!url) return; + window.open(url, '_blank'); }, }; }, ({ entity }) => { const location = findLocationForEntityMeta(entity.metadata); + const url = findEditUrl(entity, location); return { icon: () => , tooltip: 'Edit', onClick: () => { - if (!location) return; - window.open(createEditLink(location), '_blank'); + if (!url) return; + window.open(url, '_blank'); }, }; }, diff --git a/plugins/catalog/src/components/createEditLink.ts b/plugins/catalog/src/components/actions.ts similarity index 80% rename from plugins/catalog/src/components/createEditLink.ts rename to plugins/catalog/src/components/actions.ts index 57fc876704..10ee9f38a4 100644 --- a/plugins/catalog/src/components/createEditLink.ts +++ b/plugins/catalog/src/components/actions.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { LocationSpec } from '@backstage/catalog-model'; +import { LocationSpec, Entity } from '@backstage/catalog-model'; import parseGitUrl from 'git-url-parse'; /** @@ -75,3 +75,25 @@ export const determineUrlType = (url: string): string => { } return 'url'; }; + +export const findEditUrl = ( + { metadata }: Entity, + location?: LocationSpec, +): string | undefined => { + const annotations = metadata.annotations || {}; + + const editUrl = annotations['backstage.io/browser-edit-url']; + + if (editUrl) return editUrl; + + return location && createEditLink(location); +}; + +export const findViewUrl = ( + { metadata }: Entity, + location?: LocationSpec, +): string | undefined => { + const annotations = metadata.annotations || {}; + + return annotations['backstage.io/browser-view-url'] || location?.target; +}; diff --git a/yarn.lock b/yarn.lock index c32766faa3..90e7e8bb14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1874,7 +1874,6 @@ "@backstage/catalog-model" "^0.7.1" "@backstage/core" "^0.6.2" "@backstage/plugin-catalog-react" "^0.0.4" - "@backstage/plugin-scaffolder" "^0.5.1" "@backstage/theme" "^0.2.3" "@material-ui/core" "^4.11.0" "@material-ui/icons" "^4.9.1" @@ -18238,7 +18237,7 @@ modify-values@^1.0.0: resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@^2.19.3, moment@^2.25.3, moment@^2.26.0, moment@^2.27.0: +moment@^2.19.3, moment@^2.25.3, moment@^2.27.0: version "2.29.1" resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==