Merge pull request #18318 from bforbis/dynamic-missing-annotation

Add dynamic yaml example to MissingAnnotation component
This commit is contained in:
Patrik Oldsberg
2023-09-26 14:18:04 +02:00
committed by GitHub
5 changed files with 58 additions and 35 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
MissingAnnotationEmptyState component can now dynamically generate a YAML example based off the current entity being used.
+2
View File
@@ -33,9 +33,11 @@
"start": "backstage-cli package start"
},
"dependencies": {
"@backstage/catalog-model": "workspace:^",
"@backstage/config": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/plugin-catalog-react": "workspace:^",
"@backstage/theme": "workspace:^",
"@backstage/version-bridge": "workspace:^",
"@date-io/core": "^1.3.13",
@@ -25,23 +25,8 @@ import { CodeSnippet } from '../CodeSnippet';
import { Link } from '../Link';
import { EmptyState } from './EmptyState';
const COMPONENT_YAML_TEMPLATE = `apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: example
description: example.com
annotations:
ANNOTATION: value
spec:
type: website
lifecycle: production
owner: user:guest`;
const ANNOTATION_REGEXP = /^.*ANNOTATION.*$/m;
const ANNOTATION_YAML = COMPONENT_YAML_TEMPLATE.match(ANNOTATION_REGEXP)![0];
const ANNOTATION_LINE = COMPONENT_YAML_TEMPLATE.split('\n').findIndex(line =>
ANNOTATION_REGEXP.test(line),
);
import { useEntity } from '@backstage/plugin-catalog-react';
import { Entity } from '@backstage/catalog-model';
type Props = {
annotation: string | string[];
@@ -62,19 +47,38 @@ const useStyles = makeStyles<BackstageTheme>(
{ name: 'BackstageMissingAnnotationEmptyState' },
);
function generateLineNumbers(lineCount: number) {
return Array.from(Array(lineCount + 1).keys(), i => i + ANNOTATION_LINE);
function generateYamlExample(
annotations: string[],
entity?: Entity,
): { yamlText: string; lineNumbers: number[] } {
const kind = entity?.kind || 'Component';
const name = entity?.metadata.name || 'example';
const type = entity?.spec?.type || 'website';
const owner = entity?.spec?.owner || 'user:default/guest';
const yamlText = `apiVersion: backstage.io/v1alpha1
kind: ${kind}
metadata:
name: ${name}
annotations:${annotations.map(ann => `\n ${ann}: value`).join('')}
spec:
type: ${type}
owner: ${owner}`;
let line = 6; // Line 6 is the line number that annotations are added to.
const lineNumbers: number[] = [];
annotations.forEach(() => {
lineNumbers.push(line);
line++;
});
return {
yamlText,
lineNumbers,
};
}
function generateComponentYaml(annotations: string[]) {
const annotationYaml = annotations
.map(ann => ANNOTATION_YAML.replace('ANNOTATION', ann))
.join('\n');
return COMPONENT_YAML_TEMPLATE.replace(ANNOTATION_YAML, annotationYaml);
}
function generateDescription(annotations: string[]) {
function generateDescription(annotations: string[], entityKind = 'Component') {
const isSingular = annotations.length <= 1;
return (
<>
@@ -87,13 +91,21 @@ function generateDescription(annotations: string[]) {
</>
))}{' '}
{isSingular ? 'is' : 'are'} missing. You need to add the{' '}
{isSingular ? 'annotation' : 'annotations'} to your component if you want
to enable this tool.
{isSingular ? 'annotation' : 'annotations'} to your {entityKind} if you
want to enable this tool.
</>
);
}
export function MissingAnnotationEmptyState(props: Props) {
let entity: Entity | undefined;
try {
const entityContext = useEntity();
entity = entityContext.entity;
} catch (err) {
// ignore when entity context doesnt exist
}
const { annotation, readMoreUrl } = props;
const annotations = Array.isArray(annotation) ? annotation : [annotation];
const url =
@@ -101,23 +113,25 @@ export function MissingAnnotationEmptyState(props: Props) {
'https://backstage.io/docs/features/software-catalog/well-known-annotations';
const classes = useStyles();
const entityKind = entity?.kind || 'Component';
const { yamlText, lineNumbers } = generateYamlExample(annotations, entity);
return (
<EmptyState
missing="field"
title="Missing Annotation"
description={generateDescription(annotations)}
description={generateDescription(annotations, entityKind)}
action={
<>
<Typography variant="body1">
Add the annotation to your component YAML as shown in the
Add the annotation to your {entityKind} YAML as shown in the
highlighted example below:
</Typography>
<Box className={classes.code}>
<CodeSnippet
text={generateComponentYaml(annotations)}
text={yamlText}
language="yaml"
showLineNumbers
highlightedNumbers={generateLineNumbers(annotations.length)}
highlightedNumbers={lineNumbers}
customStyle={{ background: 'inherit', fontSize: '115%' }}
/>
</Box>
@@ -46,7 +46,7 @@ describe('EntityVaultCard', () => {
</EntityProvider>,
);
expect(
rendered.getByText(/Add the annotation to your component YAML/),
rendered.getByText(/Add the annotation to your Component YAML/),
).toBeInTheDocument();
});
});
+2
View File
@@ -3973,11 +3973,13 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/core-components@workspace:packages/core-components"
dependencies:
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"
"@backstage/core-app-api": "workspace:^"
"@backstage/core-plugin-api": "workspace:^"
"@backstage/errors": "workspace:^"
"@backstage/plugin-catalog-react": "workspace:^"
"@backstage/test-utils": "workspace:^"
"@backstage/theme": "workspace:^"
"@backstage/version-bridge": "workspace:^"