badges: use new error api. revert css layout tweak for CodeSnippet. add basic frontend test. improve doc.
Signed-off-by: Andreas Stenius <andreas.stenius@svenskaspel.se>
This commit is contained in:
committed by
Fredrik Adelöw
parent
022610b7b7
commit
97836e51f1
@@ -1,6 +1,7 @@
|
||||
# Badges Backend
|
||||
|
||||
Backend plugin for serving badges. Default implementation uses
|
||||
Backend plugin for serving badges to the `@backstage/plugin-badges` plugin.
|
||||
Default implementation uses
|
||||
[badge-maker](https://www.npmjs.com/package/badge-maker) for creating the
|
||||
badges, in SVG.
|
||||
|
||||
@@ -8,10 +9,35 @@ Currently, only entity badges are implemented. i.e. badges that may have entity
|
||||
specific information in them, and as such, are served from a entity specific
|
||||
endpoint.
|
||||
|
||||
## Setup
|
||||
## Installation
|
||||
|
||||
The list of all badges to offer are passed as an object with badge factories to
|
||||
the badges-backend `createRouter()` during plugin registration.
|
||||
Install the `@backstage/plugin-badges-backend` package in your backend packages,
|
||||
and then integrate the plugin using the following default setup for
|
||||
`src/plugins/badges.ts`:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createRouter,
|
||||
createDefaultBadgeFactories,
|
||||
} from '@backstage/plugin-badges-backend';
|
||||
import { PluginEnvironment } from '../types';
|
||||
|
||||
export default async function createPlugin({
|
||||
config,
|
||||
discovery,
|
||||
}: PluginEnvironment) {
|
||||
return await createRouter({
|
||||
config,
|
||||
discovery,
|
||||
badgeFactories: createDefaultBadgeFactories(),
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The `createDefaultBadgeFactories()` returns an object with badge factories to
|
||||
the badges-backend `createRouter()` to forward to the default badge builder. To
|
||||
customize the available badges, provide a custom set of badge factories. See
|
||||
further down for an example of a custom badge factories function.
|
||||
|
||||
## Badge builder
|
||||
|
||||
@@ -28,6 +54,30 @@ as examples.
|
||||
Additional badges may be provided in your application by defining custom badge
|
||||
factories, and provide them to the badge builder.
|
||||
|
||||
### Custom badges
|
||||
|
||||
To provide custom badges, create a badges factories function, and use that when
|
||||
creating the badges backend router.
|
||||
|
||||
```ts
|
||||
import type { Badge, BadgeContext, BadgeFactories } from '@backstage/plugin-badges-backend';
|
||||
export const createMyCustomBadgeFactories = (): BadgeFactories => ({
|
||||
<custom-badge-id>: {
|
||||
createBadge: (context: BadgeContext): Badge | null => {
|
||||
// ...
|
||||
return {
|
||||
label: 'my-badge',
|
||||
message: 'custom stuff',
|
||||
// ...
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
// optional: include the default badges
|
||||
// ...createDefaultBadgeFactories(),
|
||||
});
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
The badges backend api exposes two main endpoints for entity badges. (the
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
"@backstage/catalog-client": "^0.3.6",
|
||||
"@backstage/catalog-model": "^0.7.3",
|
||||
"@backstage/config": "^0.1.3",
|
||||
"@backstage/errors": "^0.1.1",
|
||||
"@types/express": "^4.17.6",
|
||||
"badge-maker": "^3.3.0",
|
||||
"cors": "^2.8.5",
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
} from '@backstage/backend-common';
|
||||
import { CatalogApi, CatalogClient } from '@backstage/catalog-client';
|
||||
import { Config } from '@backstage/config';
|
||||
import { NotFoundError } from '@backstage/errors';
|
||||
import { BadgeBuilder, DefaultBadgeBuilder } from '../lib/BadgeBuilder';
|
||||
import { BadgeContext, BadgeFactories } from '../types';
|
||||
|
||||
@@ -50,8 +51,9 @@ export async function createRouter(
|
||||
const { namespace, kind, name } = req.params;
|
||||
const entity = await catalog.getEntityByName({ namespace, kind, name });
|
||||
if (!entity) {
|
||||
res.status(404).send(`Unknown entity`);
|
||||
return;
|
||||
throw new NotFoundError(
|
||||
`No ${kind} entity in ${namespace} named "${name}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const context: BadgeContext = {
|
||||
@@ -86,8 +88,9 @@ export async function createRouter(
|
||||
const { namespace, kind, name, badgeId } = req.params;
|
||||
const entity = await catalog.getEntityByName({ namespace, kind, name });
|
||||
if (!entity) {
|
||||
res.status(404).send(`Unknown entity`);
|
||||
return;
|
||||
throw new NotFoundError(
|
||||
`No ${kind} entity in ${namespace} named "${name}"`,
|
||||
);
|
||||
}
|
||||
|
||||
let format =
|
||||
@@ -109,11 +112,11 @@ export async function createRouter(
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
res.status(404).send(`Unknown entity badge "${badgeId}"`);
|
||||
} else {
|
||||
res.setHeader('Content-Type', format);
|
||||
res.status(200).send(data);
|
||||
throw new NotFoundError(`Unknown badge "${badgeId}" for ${kind} entity.`);
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', format);
|
||||
res.status(200).send(data);
|
||||
});
|
||||
|
||||
router.use(errorHandler());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Badges
|
||||
# @backstage/plugin-badges
|
||||
|
||||
The badges plugin offers a set of badges that can be used outside of
|
||||
your backstage deployment, showing information related to data from
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2021 Spotify AB
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
ApiProvider,
|
||||
ApiRegistry,
|
||||
ErrorApi,
|
||||
errorApiRef,
|
||||
} from '@backstage/core';
|
||||
import { renderWithEffects } from '@backstage/test-utils';
|
||||
import { BadgesApi, badgesApiRef } from '../api';
|
||||
import { EntityBadgesDialog } from './EntityBadgesDialog';
|
||||
|
||||
describe('EntityBadgesDialog', () => {
|
||||
it('should render', async () => {
|
||||
const mockApi: jest.Mocked<BadgesApi> = {
|
||||
getEntityBadgeSpecs: jest.fn().mockResolvedValue([
|
||||
{
|
||||
id: 'testbadge',
|
||||
badge: {
|
||||
label: 'test',
|
||||
message: 'badge',
|
||||
},
|
||||
url: 'http://127.0.0.1/badges/entity/.../testbadge',
|
||||
markdown: '',
|
||||
},
|
||||
]),
|
||||
};
|
||||
const mockEntity = { metadata: { name: 'mock' } } as Entity;
|
||||
|
||||
const rendered = await renderWithEffects(
|
||||
<ApiProvider
|
||||
apis={ApiRegistry.with(badgesApiRef, mockApi).with(
|
||||
errorApiRef,
|
||||
{} as ErrorApi,
|
||||
)}
|
||||
>
|
||||
<EntityBadgesDialog open entity={mockEntity} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
await expect(
|
||||
rendered.findByText('testbadge badge'),
|
||||
).resolves.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -35,14 +35,11 @@ import { badgesApiRef } from '../api';
|
||||
|
||||
type Props = {
|
||||
open: boolean;
|
||||
onClose: () => any;
|
||||
onClose?: () => any;
|
||||
entity: Entity;
|
||||
};
|
||||
|
||||
const useStyles = makeStyles({
|
||||
content: {
|
||||
overflowX: 'hidden',
|
||||
},
|
||||
codeBlock: {
|
||||
'& code': {
|
||||
whiteSpace: 'pre-wrap',
|
||||
@@ -85,7 +82,7 @@ export const EntityBadgesDialog = ({ open, onClose, entity }: Props) => {
|
||||
<Dialog fullScreen={fullScreen} open={open} onClose={onClose}>
|
||||
<DialogTitle id="badges-dialog-title">Entity Badges</DialogTitle>
|
||||
|
||||
<DialogContent className={classes.content}>
|
||||
<DialogContent>
|
||||
{loading ? <Progress /> : null}
|
||||
|
||||
{error ? (
|
||||
|
||||
Reference in New Issue
Block a user