From 0fc2a84352930da4c2166dc80536e7792767bb6c Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 13 Feb 2021 11:37:41 +0000 Subject: [PATCH 1/8] 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== From a51094aac81785c077c7a1f778618afbb5a67986 Mon Sep 17 00:00:00 2001 From: James Turley Date: Tue, 16 Feb 2021 15:40:32 +0000 Subject: [PATCH 2/8] Allow custom edit and view source links on AboutCard --- .../components/AboutCard/AboutCard.test.tsx | 38 +++++++++++++++++++ .../src/components/AboutCard/AboutCard.tsx | 17 +++++---- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index ada827115d..dfca528716 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -123,3 +123,41 @@ describe(' BitBucket', () => { ); }); }); + +describe(' custom links', () => { + it('renders info and "view source" link', () => { + const entity = { + apiVersion: 'v1', + kind: 'Component', + metadata: { + name: 'software', + annotations: { + 'backstage.io/managed-by-location': + 'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml', + 'backstage.io/browser-edit-url': 'https://another.place', + 'backstage.io/browser-source-url': + 'https://another.place/backstage.git', + }, + }, + spec: { + owner: 'guest', + type: 'service', + lifecycle: 'production', + }, + }; + const { getByText } = render( + + + , + ); + expect(getByText('service')).toBeInTheDocument(); + expect(getByText('View Source').closest('a')).toHaveAttribute( + 'href', + 'https://another.place/backstage.git', + ); + expect(getByText('View Source').closest('a')).toHaveAttribute( + 'edithref', + 'https://another.place', + ); + }); +}); diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index 0f2d55295b..ee42281d31 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 '../actions'; +import { findEditUrl, determineUrlType } from '../actions'; import { AboutContent } from './AboutContent'; const useStyles = makeStyles({ @@ -61,19 +61,22 @@ type CodeLinkInfo = { }; function getCodeLinkInfo(entity: Entity): CodeLinkInfo { + let sourceUrl = + entity.metadata?.annotations?.['backstage.io/browser-source-url']; const location = findLocationForEntityMeta(entity?.metadata); + const editUrl = findEditUrl(entity, location); + if (location) { + sourceUrl = sourceUrl || location.target; const type = - location.type === 'url' - ? determineUrlType(location.target) - : location.type; + location.type === 'url' ? determineUrlType(sourceUrl) : location.type; return { + edithref: editUrl, icon: iconMap[type], - edithref: createEditLink(location), - href: location.target, + href: sourceUrl, }; } - return {}; + return { edithref: editUrl, href: sourceUrl }; } type AboutCardProps = { From a4f863f8f859b19e4010a5833e1883fb8bbbdb62 Mon Sep 17 00:00:00 2001 From: James Turley Date: Thu, 18 Feb 2021 14:27:09 +0000 Subject: [PATCH 3/8] Document browser URL annotations --- .github/styles/vocab.txt | 1 + .../well-known-annotations.md | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt index 41ec95e9aa..2a8854b8a2 100644 --- a/.github/styles/vocab.txt +++ b/.github/styles/vocab.txt @@ -166,6 +166,7 @@ interop jq js json +jsonnet jsx kubectl kubernetes diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 2cbb829554..795bf15621 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -70,6 +70,25 @@ The value of this annotation is a location reference string (see above). If this annotation is specified, it is expected to point to a repository that the TechDocs system can read and generate docs from. +### backstage.io/browser-view-url, backstage.io/browser-edit-url, backstage.io/browser-source-url + +```yaml +# Example: +metadata: + annotations: + backstage.io/browser-view-url: https://some.website/catalog-info.yaml + backstage.io/browser-edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet + backstage.io/browser-source-url: https://github.com/my-org/my-service +``` + +These annotations allow customising links from the catalog pages. The view URL +should point to the canonical metadata YAML that governs this entity. The edit +URL should point to the source file for the metadata. The source URL should +point to the source code of the entity itself (where relevant, i.e. when the +entity is a `Component`). In the example above, `my-org` generates its catalog +data from Jsonnet files in a monorepo, and so for the `my-service` component, we +need three custom links. + ### jenkins.io/github-folder ```yaml From e337085d3840d3d9c5e2e9934893ceade3e6fa6f Mon Sep 17 00:00:00 2001 From: James Turley Date: Fri, 19 Feb 2021 12:17:35 +0000 Subject: [PATCH 4/8] Use proper location ref for custom source location --- .../well-known-annotations.md | 24 +++++++++++----- .../catalog-model/src/location/annotation.ts | 2 ++ packages/catalog-model/src/location/index.ts | 6 +++- .../components/AboutCard/AboutCard.test.tsx | 5 ++-- .../src/components/AboutCard/AboutCard.tsx | 28 ++++++++++++++----- plugins/catalog/src/data/utils.ts | 10 +++++-- 6 files changed, 55 insertions(+), 20 deletions(-) diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 795bf15621..3c8f836aed 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -70,7 +70,7 @@ The value of this annotation is a location reference string (see above). If this annotation is specified, it is expected to point to a repository that the TechDocs system can read and generate docs from. -### backstage.io/browser-view-url, backstage.io/browser-edit-url, backstage.io/browser-source-url +### backstage.io/browser-view-url, backstage.io/browser-edit-url ```yaml # Example: @@ -78,16 +78,26 @@ metadata: annotations: backstage.io/browser-view-url: https://some.website/catalog-info.yaml backstage.io/browser-edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet - backstage.io/browser-source-url: https://github.com/my-org/my-service ``` These annotations allow customising links from the catalog pages. The view URL should point to the canonical metadata YAML that governs this entity. The edit -URL should point to the source file for the metadata. The source URL should -point to the source code of the entity itself (where relevant, i.e. when the -entity is a `Component`). In the example above, `my-org` generates its catalog -data from Jsonnet files in a monorepo, and so for the `my-service` component, we -need three custom links. +URL should point to the source file for the metadata. In the example above, +`my-org` generates its catalog data from Jsonnet files in a monorepo, so the +view and edit links need changing. + +### backstage.io/source-location + +```yaml +# Example: +metadata: + annotations: + backstage.io/source-location: github:https://github.com/my-org/my-service +``` + +A `Location` reference that points to the source code of the entity (typically a +`Component`). Useful when catalog files do not get ingested from the source code +repository itself. ### jenkins.io/github-folder diff --git a/packages/catalog-model/src/location/annotation.ts b/packages/catalog-model/src/location/annotation.ts index 93f2fabea4..ba875c3edf 100644 --- a/packages/catalog-model/src/location/annotation.ts +++ b/packages/catalog-model/src/location/annotation.ts @@ -17,3 +17,5 @@ export const LOCATION_ANNOTATION = 'backstage.io/managed-by-location'; export const ORIGIN_LOCATION_ANNOTATION = 'backstage.io/managed-by-origin-location'; + +export const SOURCE_LOCATION_ANNOTATION = 'backstage.io/source-location'; diff --git a/packages/catalog-model/src/location/index.ts b/packages/catalog-model/src/location/index.ts index 8fd516120a..6cfb074613 100644 --- a/packages/catalog-model/src/location/index.ts +++ b/packages/catalog-model/src/location/index.ts @@ -20,4 +20,8 @@ export { locationSpecSchema, analyzeLocationSchema, } from './validation'; -export { LOCATION_ANNOTATION, ORIGIN_LOCATION_ANNOTATION } from './annotation'; +export { + LOCATION_ANNOTATION, + ORIGIN_LOCATION_ANNOTATION, + SOURCE_LOCATION_ANNOTATION, +} from './annotation'; diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index dfca528716..e99ec056d2 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -15,6 +15,7 @@ */ import { EntityProvider } from '@backstage/plugin-catalog-react'; +import { SOURCE_LOCATION_ANNOTATION } from '@backstage/catalog-model'; import { render } from '@testing-library/react'; import React from 'react'; import { AboutCard } from './AboutCard'; @@ -135,8 +136,8 @@ describe(' custom links', () => { 'backstage.io/managed-by-location': 'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml', 'backstage.io/browser-edit-url': 'https://another.place', - 'backstage.io/browser-source-url': - 'https://another.place/backstage.git', + [SOURCE_LOCATION_ANNOTATION]: + 'url:https://another.place/backstage.git', }, }, spec: { diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index ee42281d31..6a13d78d14 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -16,7 +16,9 @@ import { Entity, + LocationSpec, ENTITY_DEFAULT_NAMESPACE, + SOURCE_LOCATION_ANNOTATION, RELATION_PROVIDES_API, } from '@backstage/catalog-model'; import { HeaderIconLinkRow } from '@backstage/core'; @@ -34,7 +36,7 @@ import EditIcon from '@material-ui/icons/Edit'; import ExtensionIcon from '@material-ui/icons/Extension'; import GitHubIcon from '@material-ui/icons/GitHub'; import React from 'react'; -import { findLocationForEntityMeta } from '../../data/utils'; +import { findLocationForEntityMeta, parseLocation } from '../../data/utils'; import { findEditUrl, determineUrlType } from '../actions'; import { AboutContent } from './AboutContent'; @@ -60,23 +62,35 @@ type CodeLinkInfo = { href?: string; }; +function getSourceLocationForEntity( + entity: Entity, + location?: LocationSpec, +): LocationSpec | undefined { + const annotation = entity.metadata?.annotations?.[SOURCE_LOCATION_ANNOTATION]; + const parsed = annotation && parseLocation(annotation); + + return parsed || location; +} + function getCodeLinkInfo(entity: Entity): CodeLinkInfo { - let sourceUrl = - entity.metadata?.annotations?.['backstage.io/browser-source-url']; const location = findLocationForEntityMeta(entity?.metadata); const editUrl = findEditUrl(entity, location); + let sourceLocation = getSourceLocationForEntity(entity, location); if (location) { - sourceUrl = sourceUrl || location.target; + sourceLocation = sourceLocation || location; const type = - location.type === 'url' ? determineUrlType(sourceUrl) : location.type; + sourceLocation.type === 'url' + ? determineUrlType(sourceLocation.target) + : sourceLocation.type; return { edithref: editUrl, icon: iconMap[type], - href: sourceUrl, + href: sourceLocation.target, }; } - return { edithref: editUrl, href: sourceUrl }; + + return { edithref: editUrl, href: sourceLocation?.target }; } type AboutCardProps = { diff --git a/plugins/catalog/src/data/utils.ts b/plugins/catalog/src/data/utils.ts index df14875092..ec63d94754 100644 --- a/plugins/catalog/src/data/utils.ts +++ b/plugins/catalog/src/data/utils.ts @@ -32,13 +32,17 @@ export function findLocationForEntityMeta( return undefined; } - const separatorIndex = annotation.indexOf(':'); + return parseLocation(annotation); +} + +export function parseLocation(reference: string): LocationSpec | undefined { + const separatorIndex = reference.indexOf(':'); if (separatorIndex === -1) { return undefined; } return { - type: annotation.substring(0, separatorIndex), - target: annotation.substring(separatorIndex + 1), + type: reference.substring(0, separatorIndex), + target: reference.substring(separatorIndex + 1), }; } From 9c521c53a7e8a44bedc3561ff3e62ab55c80b275 Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 20 Feb 2021 11:07:08 +0000 Subject: [PATCH 5/8] Rename view/edit annotations --- docs/features/software-catalog/well-known-annotations.md | 6 +++--- plugins/catalog/src/components/AboutCard/AboutCard.test.tsx | 2 +- .../src/components/CatalogTable/CatalogTable.test.tsx | 4 ++-- plugins/catalog/src/components/actions.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md index 3c8f836aed..8ec4813799 100644 --- a/docs/features/software-catalog/well-known-annotations.md +++ b/docs/features/software-catalog/well-known-annotations.md @@ -70,14 +70,14 @@ The value of this annotation is a location reference string (see above). If this annotation is specified, it is expected to point to a repository that the TechDocs system can read and generate docs from. -### backstage.io/browser-view-url, backstage.io/browser-edit-url +### backstage.io/view-url, backstage.io/edit-url ```yaml # Example: metadata: annotations: - backstage.io/browser-view-url: https://some.website/catalog-info.yaml - backstage.io/browser-edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet + backstage.io/view-url: https://some.website/catalog-info.yaml + backstage.io/edit-url: https://github.com/my-org/catalog/edit/master/my-service.jsonnet ``` These annotations allow customising links from the catalog pages. The view URL diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index e99ec056d2..393f3f2576 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -135,7 +135,7 @@ describe(' custom links', () => { annotations: { 'backstage.io/managed-by-location': 'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml', - 'backstage.io/browser-edit-url': 'https://another.place', + 'backstage.io/edit-url': 'https://another.place', [SOURCE_LOCATION_ANNOTATION]: 'url:https://another.place/backstage.git', }, diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index 5cb776746d..b77dd2b8a0 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -86,7 +86,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { 'backstage.io/browser-edit-url': 'https://other.place' }, + annotations: { 'backstage.io/edit-url': 'https://other.place' }, }, }; @@ -115,7 +115,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { 'backstage.io/browser-view-url': 'https://other.place' }, + annotations: { 'backstage.io/view-url': 'https://other.place' }, }, }; diff --git a/plugins/catalog/src/components/actions.ts b/plugins/catalog/src/components/actions.ts index 10ee9f38a4..c7fbfac8e2 100644 --- a/plugins/catalog/src/components/actions.ts +++ b/plugins/catalog/src/components/actions.ts @@ -82,7 +82,7 @@ export const findEditUrl = ( ): string | undefined => { const annotations = metadata.annotations || {}; - const editUrl = annotations['backstage.io/browser-edit-url']; + const editUrl = annotations['backstage.io/edit-url']; if (editUrl) return editUrl; @@ -95,5 +95,5 @@ export const findViewUrl = ( ): string | undefined => { const annotations = metadata.annotations || {}; - return annotations['backstage.io/browser-view-url'] || location?.target; + return annotations['backstage.io/view-url'] || location?.target; }; From dcdb9f06518e481a09a4e396ed9c0320b5224199 Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 20 Feb 2021 11:26:37 +0000 Subject: [PATCH 6/8] Extract view/edit annotations to constants --- packages/catalog-model/src/entity/constants.ts | 6 ++++++ packages/catalog-model/src/entity/index.ts | 2 ++ .../src/components/AboutCard/AboutCard.test.tsx | 7 +++++-- .../src/components/CatalogTable/CatalogTable.test.tsx | 10 +++++++--- plugins/catalog/src/components/actions.ts | 11 ++++++++--- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/catalog-model/src/entity/constants.ts b/packages/catalog-model/src/entity/constants.ts index 42ea2ae8ba..c8f88e3b0c 100644 --- a/packages/catalog-model/src/entity/constants.ts +++ b/packages/catalog-model/src/entity/constants.ts @@ -27,3 +27,9 @@ export const ENTITY_META_GENERATED_FIELDS = [ 'etag', 'generation', ] as const; + +/** + * Annotations for linking to entity from catalog pages. + */ +export const VIEW_URL_ANNOTATION = 'backstage.io/view-url'; +export const EDIT_URL_ANNOTATION = 'backstage.io/edit-url'; diff --git a/packages/catalog-model/src/entity/index.ts b/packages/catalog-model/src/entity/index.ts index e80e14f7a4..e267c607e1 100644 --- a/packages/catalog-model/src/entity/index.ts +++ b/packages/catalog-model/src/entity/index.ts @@ -17,6 +17,8 @@ export { ENTITY_DEFAULT_NAMESPACE, ENTITY_META_GENERATED_FIELDS, + VIEW_URL_ANNOTATION, + EDIT_URL_ANNOTATION, } from './constants'; export type { Entity, diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx index 393f3f2576..449d3c1fc9 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.test.tsx @@ -15,7 +15,10 @@ */ import { EntityProvider } from '@backstage/plugin-catalog-react'; -import { SOURCE_LOCATION_ANNOTATION } from '@backstage/catalog-model'; +import { + SOURCE_LOCATION_ANNOTATION, + EDIT_URL_ANNOTATION, +} from '@backstage/catalog-model'; import { render } from '@testing-library/react'; import React from 'react'; import { AboutCard } from './AboutCard'; @@ -135,7 +138,7 @@ describe(' custom links', () => { annotations: { 'backstage.io/managed-by-location': 'bitbucket:https://bitbucket.org/backstage/backstage/src/master/software.yaml', - 'backstage.io/edit-url': 'https://another.place', + [EDIT_URL_ANNOTATION]: 'https://another.place', [SOURCE_LOCATION_ANNOTATION]: 'url:https://another.place/backstage.git', }, diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index b77dd2b8a0..ffd5f3d190 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import { + Entity, + VIEW_URL_ANNOTATION, + EDIT_URL_ANNOTATION, +} from '@backstage/catalog-model'; import { act, fireEvent } from '@testing-library/react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import * as React from 'react'; @@ -86,7 +90,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { 'backstage.io/edit-url': 'https://other.place' }, + annotations: { [EDIT_URL_ANNOTATION]: 'https://other.place' }, }, }; @@ -115,7 +119,7 @@ describe('CatalogTable component', () => { kind: 'Component', metadata: { name: 'component1', - annotations: { 'backstage.io/view-url': 'https://other.place' }, + annotations: { [VIEW_URL_ANNOTATION]: 'https://other.place' }, }, }; diff --git a/plugins/catalog/src/components/actions.ts b/plugins/catalog/src/components/actions.ts index c7fbfac8e2..13e235d46e 100644 --- a/plugins/catalog/src/components/actions.ts +++ b/plugins/catalog/src/components/actions.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { LocationSpec, Entity } from '@backstage/catalog-model'; +import { + LocationSpec, + Entity, + EDIT_URL_ANNOTATION, + VIEW_URL_ANNOTATION, +} from '@backstage/catalog-model'; import parseGitUrl from 'git-url-parse'; /** @@ -82,7 +87,7 @@ export const findEditUrl = ( ): string | undefined => { const annotations = metadata.annotations || {}; - const editUrl = annotations['backstage.io/edit-url']; + const editUrl = annotations[EDIT_URL_ANNOTATION]; if (editUrl) return editUrl; @@ -95,5 +100,5 @@ export const findViewUrl = ( ): string | undefined => { const annotations = metadata.annotations || {}; - return annotations['backstage.io/view-url'] || location?.target; + return annotations[VIEW_URL_ANNOTATION] || location?.target; }; From 302fd47cac2227926d7481c25f6f1ce0854e7f3f Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 20 Feb 2021 11:36:56 +0000 Subject: [PATCH 7/8] Simplify URL lookup functions --- .../catalog/src/components/AboutCard/AboutCard.tsx | 2 +- .../src/components/CatalogTable/CatalogTable.tsx | 7 ++----- plugins/catalog/src/components/actions.ts | 14 ++++++-------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index 6a13d78d14..64564f5ec4 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -74,7 +74,7 @@ function getSourceLocationForEntity( function getCodeLinkInfo(entity: Entity): CodeLinkInfo { const location = findLocationForEntityMeta(entity?.metadata); - const editUrl = findEditUrl(entity, location); + const editUrl = findEditUrl(entity); let sourceLocation = getSourceLocationForEntity(entity, location); if (location) { diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index ca40648ecb..7d693d1bc8 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -38,7 +38,6 @@ 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 { findViewUrl, findEditUrl } from '../actions'; import { favouriteEntityIcon, @@ -152,8 +151,7 @@ export const CatalogTable = ({ const actions: TableProps['actions'] = [ ({ entity }) => { - const location = findLocationForEntityMeta(entity.metadata); - const url = findViewUrl(entity, location); + const url = findViewUrl(entity); return { icon: () => , tooltip: 'View', @@ -164,8 +162,7 @@ export const CatalogTable = ({ }; }, ({ entity }) => { - const location = findLocationForEntityMeta(entity.metadata); - const url = findEditUrl(entity, location); + const url = findEditUrl(entity); return { icon: () => , tooltip: 'Edit', diff --git a/plugins/catalog/src/components/actions.ts b/plugins/catalog/src/components/actions.ts index 13e235d46e..72e1bf67ec 100644 --- a/plugins/catalog/src/components/actions.ts +++ b/plugins/catalog/src/components/actions.ts @@ -20,6 +20,7 @@ import { EDIT_URL_ANNOTATION, VIEW_URL_ANNOTATION, } from '@backstage/catalog-model'; +import { findLocationForEntityMeta } from '../data/utils'; import parseGitUrl from 'git-url-parse'; /** @@ -81,24 +82,21 @@ export const determineUrlType = (url: string): string => { return 'url'; }; -export const findEditUrl = ( - { metadata }: Entity, - location?: LocationSpec, -): string | undefined => { +export const findEditUrl = ({ metadata }: Entity): string | undefined => { const annotations = metadata.annotations || {}; const editUrl = annotations[EDIT_URL_ANNOTATION]; if (editUrl) return editUrl; + const location = findLocationForEntityMeta(metadata); + return location && createEditLink(location); }; -export const findViewUrl = ( - { metadata }: Entity, - location?: LocationSpec, -): string | undefined => { +export const findViewUrl = ({ metadata }: Entity): string | undefined => { const annotations = metadata.annotations || {}; + const location = findLocationForEntityMeta(metadata); return annotations[VIEW_URL_ANNOTATION] || location?.target; }; From bad21a085411106557164de0b51a4ffc5b62e6d6 Mon Sep 17 00:00:00 2001 From: James Turley Date: Sat, 20 Feb 2021 11:38:41 +0000 Subject: [PATCH 8/8] Changeset for catalog packages --- .changeset/honest-hounds-exist.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/honest-hounds-exist.md diff --git a/.changeset/honest-hounds-exist.md b/.changeset/honest-hounds-exist.md new file mode 100644 index 0000000000..8aadd84a95 --- /dev/null +++ b/.changeset/honest-hounds-exist.md @@ -0,0 +1,6 @@ +--- +'@backstage/catalog-model': patch +'@backstage/plugin-catalog': patch +--- + +Implement annotations for customising Entity URLs in the Catalog pages.