badges: load default badges from code rather than config. #4457.
Signed-off-by: Andreas Stenius <git@astekk.se>
This commit is contained in:
committed by
Fredrik Adelöw
parent
ce4897ff37
commit
ac17aeb35d
Vendored
-27
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export interface Config {
|
||||
// defined with doc in badges-backend
|
||||
badges?: {
|
||||
[badgeId: string]: {
|
||||
/**
|
||||
* @visibility frontend
|
||||
*/
|
||||
kind?: 'entity';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -45,8 +45,6 @@
|
||||
"msw": "^0.21.2"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"config.d.ts"
|
||||
],
|
||||
"configSchema": "config.d.ts"
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -15,58 +15,33 @@
|
||||
*/
|
||||
|
||||
import { generatePath } from 'react-router';
|
||||
import { ConfigApi, DiscoveryApi } from '@backstage/core';
|
||||
import { DiscoveryApi } from '@backstage/core';
|
||||
import { Entity, ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';
|
||||
import { entityRoute } from '@backstage/plugin-catalog-react';
|
||||
import { Badge, BadgesApi, BadgeConfig, BadgeSpec } from './types';
|
||||
import { BadgesApi, BadgeSpec } from './types';
|
||||
|
||||
export class BadgesClient implements BadgesApi {
|
||||
private readonly configApi: ConfigApi;
|
||||
private readonly discoveryApi: DiscoveryApi;
|
||||
|
||||
constructor(options: { configApi: ConfigApi; discoveryApi: DiscoveryApi }) {
|
||||
this.configApi = options.configApi;
|
||||
constructor(options: { discoveryApi: DiscoveryApi }) {
|
||||
this.discoveryApi = options.discoveryApi;
|
||||
}
|
||||
|
||||
public async getDefinedEntityBadges(entity: Entity): Promise<Badge[]> {
|
||||
const badges = [];
|
||||
const badgesConfig = this.configApi.getOptional('badges') ?? {};
|
||||
const entityBadgeUri = await this.getEntityBadgeUri(entity);
|
||||
public async getEntityBadgeSpecs(entity: Entity): Promise<BadgeSpec[]> {
|
||||
const entityBadgeSpecsUrl = await this.getEntityBadgeSpecsUrl(entity);
|
||||
const specs = (await (
|
||||
await fetch(entityBadgeSpecsUrl)
|
||||
).json()) as BadgeSpec[];
|
||||
|
||||
for (const [badgeId, badge] of Object.entries(badgesConfig)) {
|
||||
if (!badge.kind || badge.kind === 'entity') {
|
||||
const info = await this.getBadgeInfo(entityBadgeUri, badgeId);
|
||||
if (info) {
|
||||
badges.push(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return badges;
|
||||
return specs;
|
||||
}
|
||||
|
||||
private async getBadgeInfo(
|
||||
entityBadgeUri: string,
|
||||
badgeId: string,
|
||||
): Promise<Badge> {
|
||||
const badgeUrl = `${entityBadgeUri}/${badgeId}`;
|
||||
const spec = (await (
|
||||
await fetch(`${badgeUrl}?format=json`)
|
||||
).json()) as BadgeSpec;
|
||||
|
||||
return {
|
||||
id: badgeId,
|
||||
markdown: this.getBadgeMarkdownCode(badgeUrl, spec.badge),
|
||||
spec,
|
||||
url: badgeUrl,
|
||||
};
|
||||
}
|
||||
|
||||
private async getEntityBadgeUri(entity: Entity): Promise<string> {
|
||||
private async getEntityBadgeSpecsUrl(entity: Entity): Promise<string> {
|
||||
const routeParams = this.getEntityRouteParams(entity);
|
||||
const path = generatePath(entityRoute.path, routeParams);
|
||||
return `${await this.discoveryApi.getBaseUrl('badges')}/entity/${path}`;
|
||||
return `${await this.discoveryApi.getBaseUrl(
|
||||
'badges',
|
||||
)}/entity/${path}/badge-specs`;
|
||||
}
|
||||
|
||||
private getEntityRouteParams(entity: Entity) {
|
||||
@@ -77,13 +52,4 @@ export class BadgesClient implements BadgesApi {
|
||||
name: entity.metadata.name,
|
||||
};
|
||||
}
|
||||
|
||||
private getBadgeMarkdownCode(badgeUrl: string, badge: BadgeConfig): string {
|
||||
const title = badge.title ? ` "${badge.title}"` : '';
|
||||
const img = ``;
|
||||
if (!badge.link) {
|
||||
return img;
|
||||
}
|
||||
return `[${img}](${badge.link})`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,35 +29,42 @@ export type BadgeStyle =
|
||||
| 'for-the-badge'
|
||||
| 'social';
|
||||
|
||||
// should probably have this in a "badges-common" package
|
||||
export interface BadgeConfig {
|
||||
interface BadgeParams {
|
||||
color?: string;
|
||||
description?: string;
|
||||
kind?: 'entity';
|
||||
label: string;
|
||||
message: string;
|
||||
color?: string;
|
||||
labelColor?: string;
|
||||
style?: BadgeStyle;
|
||||
title?: string;
|
||||
description?: string;
|
||||
link?: string;
|
||||
message: string;
|
||||
style?: BadgeStyle;
|
||||
}
|
||||
|
||||
interface Badge extends BadgeParams {
|
||||
markdown: string;
|
||||
}
|
||||
|
||||
interface BadgeConfig extends BadgeParams {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface BadgeSpec {
|
||||
/** The rendered data */
|
||||
badge: BadgeConfig;
|
||||
/** The rendered fields, markdown code */
|
||||
badge: Badge;
|
||||
|
||||
/** The configuration data, with placeholders and all */
|
||||
config: BadgeConfig;
|
||||
/** The context used when rendering config -> badge */
|
||||
context: object;
|
||||
}
|
||||
|
||||
export interface Badge {
|
||||
id: string;
|
||||
markdown: string;
|
||||
spec: BadgeSpec;
|
||||
url: string;
|
||||
/** The context used when rendering config -> badge */
|
||||
context: {
|
||||
// here is more, but only badge_url we care about
|
||||
badge_url: string;
|
||||
};
|
||||
|
||||
format: 'json'; // or 'svg', but we'll never see that as structured
|
||||
// data, only as an svg element
|
||||
}
|
||||
|
||||
export interface BadgesApi {
|
||||
getDefinedEntityBadges(entity: Entity): Promise<Badge[]>;
|
||||
getEntityBadgeSpecs(entity: Entity): Promise<BadgeSpec[]>;
|
||||
}
|
||||
|
||||
@@ -55,26 +55,32 @@ export const EntityBadgesDialog = ({ open, onClose, entity }: Props) => {
|
||||
|
||||
const { value: badges, loading, error } = useAsync(async () => {
|
||||
if (open) {
|
||||
return await badgesApi.getDefinedEntityBadges(entity);
|
||||
return await badgesApi.getEntityBadgeSpecs(entity);
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [badgesApi, entity, open]);
|
||||
|
||||
const content = (badges || []).map(({ id, markdown, spec, url }) => (
|
||||
<div key={id}>
|
||||
<DialogContentText>
|
||||
{spec.badge.title || spec.badge.description || id}
|
||||
<br />
|
||||
<img alt={spec.badge.description} src={url} />
|
||||
</DialogContentText>
|
||||
<Typography component="div" className={classes.codeBlock}>
|
||||
Copy the following snippet of markdown code for the badge:
|
||||
<CodeSnippet language="markdown" text={markdown} showCopyCodeButton />
|
||||
</Typography>
|
||||
<hr />
|
||||
</div>
|
||||
));
|
||||
const content = (badges || []).map(
|
||||
({
|
||||
badge: { description, markdown },
|
||||
config: { id },
|
||||
context: { badge_url },
|
||||
}) => (
|
||||
<div key={id}>
|
||||
<DialogContentText>
|
||||
{description}
|
||||
<br />
|
||||
<img alt={description} src={badge_url} />
|
||||
</DialogContentText>
|
||||
<Typography component="div" className={classes.codeBlock}>
|
||||
Copy the following snippet of markdown code for the badge:
|
||||
<CodeSnippet language="markdown" text={markdown} showCopyCodeButton />
|
||||
</Typography>
|
||||
<hr />
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog fullScreen={fullScreen} open={open} onClose={onClose}>
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
createApiFactory,
|
||||
createComponentExtension,
|
||||
createPlugin,
|
||||
configApiRef,
|
||||
discoveryApiRef,
|
||||
} from '@backstage/core';
|
||||
import { badgesApiRef, BadgesClient } from './api';
|
||||
@@ -27,9 +26,8 @@ export const badgesPlugin = createPlugin({
|
||||
apis: [
|
||||
createApiFactory({
|
||||
api: badgesApiRef,
|
||||
deps: { configApi: configApiRef, discoveryApi: discoveryApiRef },
|
||||
factory: ({ configApi, discoveryApi }) =>
|
||||
new BadgesClient({ configApi, discoveryApi }),
|
||||
deps: { discoveryApi: discoveryApiRef },
|
||||
factory: ({ discoveryApi }) => new BadgesClient({ discoveryApi }),
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user