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==