feat: add entity metadata links

This commit is contained in:
Andrew Thauer
2021-01-27 21:38:02 -05:00
parent 8b57797896
commit 6e612ce252
10 changed files with 93 additions and 1167 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/catalog-model': minor
---
Adds a new optional `links` metadata field to the Entity class within the `catalog-model` package (as discussed in [[RFC] Entity Links](https://github.com/backstage/backstage/issues/3787)). This PR adds support for the entity links only. Follow up PR's will introduce the UI component to display them.
@@ -314,6 +314,34 @@ This field is optional, and currently has no special semantics.
Each tag must be sequences of `[a-z0-9]` separated by `-`, at most 63 characters
in total.
### `links` [optional]
A list of external hyperlinks related to the entity. Links can provide
additional contextual information that may be located outside of backstage
itself. For example, an admin dashboard or external CMS page.
Users may add links to descriptor YAML files to provide additional reference
information to external content & resources. Links are not intended to drive any
additional functionality within backstage, which is best left to `annotations`
and `labels`. It is recommended to use links only when an equivalent well-known
`annotation` does not cover a similar use case.
Fields of a link are:
| Field | Type | Description |
| ------- | ------ | ------------------------------------------------------------------------------------ |
| `url` | String | [Required] A `url` in a standard `uri` format (e.g. `https://example.com/some/page`) |
| `title` | String | [Optional] A user friendly display name for the link. |
| `icon` | String | [Optional] A key representing a visual icon to be displayed in the UI. |
_NOTE_: The `icon` field value is meant to be a semantic key that will map to a
specific icon that may be provided by an icon library (e.g. `material-ui`
icons). These keys should a sequence of `[a-z0-9A-Z]` and possibly separated by
one of `[-_.]`. Backstage may support some basic icons out of the box, but the
backstage integrator will ultimately be left to provide the appropriate icon
component mappings. A generic fallback icon would be provided if a mapping
cannot be resolved.
## Common to All Kinds: Relations
The `relations` root field is a read-only list of relations, between the current
@@ -3,6 +3,9 @@ kind: Group
metadata:
name: acme-corp
description: The acme-corp organization
links:
- url: http://www.acme.com/
name: Website
spec:
type: organization
profile:
@@ -5,6 +5,10 @@ metadata:
description: The Smartylighting Streetlights API allows you to remotely manage the city lights.
tags:
- mqtt
links:
- url: https://github.com/asyncapi/asyncapi/blob/master/examples/1.2.0/streetlights.yml
title: Source Code
icon: code
spec:
type: asyncapi
lifecycle: production
File diff suppressed because it is too large Load Diff
@@ -3,6 +3,10 @@ kind: Component
metadata:
name: petstore
description: Petstore
links:
- url: https://github.com/swagger-api/swagger-petstore
title: GitHub Repo
icon: github
spec:
type: service
lifecycle: experimental
@@ -3,5 +3,8 @@ kind: Domain
metadata:
name: artists
description: Everything related to artists
links:
- url: http://example.com/domain/readme
title: Artists Domain Readme
spec:
owner: team-a
@@ -125,6 +125,11 @@ export type EntityMeta = JsonObject & {
* various ways.
*/
tags?: string[];
/**
* A list of external hyperlinks related to the entity.
*/
links?: EntityLink[];
};
/**
@@ -161,3 +166,23 @@ export type EntityRelationSpec = {
*/
target: EntityName;
};
/**
* A link to external information that is related to the entity.
*/
export type EntityLink = {
/**
* The url to the external site, document, etc.
*/
url: string;
/**
* An optional descriptive title for the link.
*/
title?: string;
/**
* An optional semantic key that represents a visual icon.
*/
icon?: string;
};
@@ -38,6 +38,10 @@ describe('FieldFormatEntityPolicy', () => {
tags:
- java
- data-service
links:
- url: https://example.org
title: Website
icon: website
spec:
custom: stuff
`);
@@ -110,4 +114,9 @@ describe('FieldFormatEntityPolicy', () => {
data.metadata.tags.push('Hello World');
await expect(policy.enforce(data)).rejects.toThrow(/tags.*"Hello World"/i);
});
it('rejects bad link icon value', async () => {
data.metadata.links.push({ url: 'https://foo', icon: 'some icon' });
await expect(policy.enforce(data)).rejects.toThrow(/links.*"some icon"/i);
});
});
@@ -134,6 +134,12 @@ export class FieldFormatEntityPolicy implements EntityPolicy {
require(`tags.${i}`, tags[i], this.validators.isValidTag);
}
const links = entity.metadata.links ?? [];
for (let i = 0; i < links.length; ++i) {
optional(`links.${i}`, links[i]?.icon, this.validators.isValidEntityName);
}
return entity;
}
}