@backstage-community/plugin-badges 0.2.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1581 -0
- package/README.md +204 -0
- package/dist/esm/EntityBadgesDialog-DwRwuts8.esm.js +43 -0
- package/dist/esm/EntityBadgesDialog-DwRwuts8.esm.js.map +1 -0
- package/dist/esm/index-R_9uVcjC.esm.js +116 -0
- package/dist/esm/index-R_9uVcjC.esm.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.esm.js +6 -0
- package/dist/index.esm.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# @backstage-community/plugin-badges
|
|
2
|
+
|
|
3
|
+
The badges plugin offers a set of badges that can be used outside of
|
|
4
|
+
your backstage deployment, showing information related to data from
|
|
5
|
+
the catalog, such as entity owner and lifecycle data for instance.
|
|
6
|
+
|
|
7
|
+
The available badges are setup in the `badges-backend` plugin, see
|
|
8
|
+
link below for more details.
|
|
9
|
+
|
|
10
|
+
## Entity badges
|
|
11
|
+
|
|
12
|
+
To get markdown code for the entity badges, access the `Badges` context menu
|
|
13
|
+
(three dots in the upper right corner) of an entity page like this:
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
This will popup a badges dialog showing all available badges for that entity like this:
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## Badge obfuscation
|
|
22
|
+
|
|
23
|
+
The badges plugin supports obfuscating the badge URL to prevent it from being enumerated if the badges are used in a public context (like in Github repositories).
|
|
24
|
+
|
|
25
|
+
To enable obfuscation, set the `obfuscate` option to `true` in the `app.badges` section of your `app-config.yaml`:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
app:
|
|
29
|
+
badges:
|
|
30
|
+
obfuscate: true
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Please note that if you have already set badges in your repositories and you activate the obfuscation you will need to update the badges in your repositories to use the new obfuscated URLs.
|
|
34
|
+
|
|
35
|
+
Please note that the backend part needs to be configured to support obfuscation. See the [backend plugin documentation](../badges-backend/README.md) for more details.
|
|
36
|
+
|
|
37
|
+
Also, you need to allow your frontend to access the configuration see <https://backstage.io/docs/conf/defining/#visibility> :
|
|
38
|
+
|
|
39
|
+
Example implementation would be in : `packages/app/src/config.d.ts`
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
export interface Config {
|
|
43
|
+
app: {
|
|
44
|
+
... some code
|
|
45
|
+
badges: {
|
|
46
|
+
/**
|
|
47
|
+
* badges obfuscate
|
|
48
|
+
* @visibility frontend
|
|
49
|
+
*/
|
|
50
|
+
obfuscate?: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
then include in the `packages/app/package.json` :
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
"files": [
|
|
60
|
+
"dist",
|
|
61
|
+
"config.d.ts"
|
|
62
|
+
],
|
|
63
|
+
"configSchema": "config.d.ts",
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Sample Badges
|
|
67
|
+
|
|
68
|
+
Here are some samples of badges for the `artists-lookup` service in the Demo Backstage site:
|
|
69
|
+
|
|
70
|
+
- Component: [](https://demo.backstage.io/catalog/default/component/artist-lookup)
|
|
71
|
+
- Lifecycle: [](https://demo.backstage.io/catalog/default/component/artist-lookup)
|
|
72
|
+
- Owner: [](https://demo.backstage.io/catalog/default/component/artist-lookup)
|
|
73
|
+
- Docs: [](https://demo.backstage.io/catalog/default/component/artist-lookup/docs)
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
### Install the package
|
|
78
|
+
|
|
79
|
+
Install the `@backstage-community/plugin-badges` package in your frontend app package:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# From your Backstage root directory
|
|
83
|
+
yarn --cwd packages/app add @backstage-community/plugin-badges
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Register plugin
|
|
87
|
+
|
|
88
|
+
This plugin requires explicit registration, so you will need to add it to your App's `plugins.ts` file:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { badgesPlugin } from '@backstage-community/plugin-badges';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If you don't have a `plugins.ts` file see: [troubleshooting](#troubleshooting)
|
|
95
|
+
|
|
96
|
+
### Update your EntityPage
|
|
97
|
+
|
|
98
|
+
In your `EntityPage.tsx` file located in `packages\app\src\components\catalog` we'll need to make a few changes to get the Badges context menu added to the UI.
|
|
99
|
+
|
|
100
|
+
First we need to add the following imports:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { EntityBadgesDialog } from '@backstage-community/plugin-badges';
|
|
104
|
+
import BadgeIcon from '@material-ui/icons/CallToAction';
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Next we'll update the React import that looks like this:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import React from 'react';
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
To look like this:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import React, { ReactNode, useMemo, useState } from 'react';
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then we have to add this chunk of code after all the imports but before any of the other code:
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const EntityLayoutWrapper = (props: { children?: ReactNode }) => {
|
|
123
|
+
const [badgesDialogOpen, setBadgesDialogOpen] = useState(false);
|
|
124
|
+
|
|
125
|
+
const extraMenuItems = useMemo(() => {
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
title: 'Badges',
|
|
129
|
+
Icon: BadgeIcon,
|
|
130
|
+
onClick: () => setBadgesDialogOpen(true),
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<>
|
|
137
|
+
<EntityLayout UNSTABLE_extraContextMenuItems={extraMenuItems}>
|
|
138
|
+
{props.children}
|
|
139
|
+
</EntityLayout>
|
|
140
|
+
<EntityBadgesDialog
|
|
141
|
+
open={badgesDialogOpen}
|
|
142
|
+
onClose={() => setBadgesDialogOpen(false)}
|
|
143
|
+
/>
|
|
144
|
+
</>
|
|
145
|
+
);
|
|
146
|
+
};
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The last step is to wrap all the entity pages in the `EntityLayoutWrapper` like this:
|
|
150
|
+
|
|
151
|
+
```diff
|
|
152
|
+
const defaultEntityPage = (
|
|
153
|
+
+ <EntityLayoutWrapper>
|
|
154
|
+
<EntityLayout.Route path="/" title="Overview">
|
|
155
|
+
{overviewContent}
|
|
156
|
+
</EntityLayout.Route>
|
|
157
|
+
|
|
158
|
+
<EntityLayout.Route path="/docs" title="Docs">
|
|
159
|
+
<EntityTechdocsContent />
|
|
160
|
+
</EntityLayout.Route>
|
|
161
|
+
|
|
162
|
+
<EntityLayout.Route path="/todos" title="TODOs">
|
|
163
|
+
<EntityTodoContent />
|
|
164
|
+
</EntityLayout.Route>
|
|
165
|
+
+ </EntityLayoutWrapper>
|
|
166
|
+
);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Note: the above only shows an example for the `defaultEntityPage` for a full example of this you can look at [this EntityPage](https://github.com/backstage/backstage/blob/1fd9e6f601cabe42af8eb20b5d200ad1988ba309/packages/app/src/components/catalog/EntityPage.tsx#L318)
|
|
170
|
+
|
|
171
|
+
## Troubleshooting
|
|
172
|
+
|
|
173
|
+
If you don't have a `plugins.ts` file, you can create it with the path `packages/app/src/plugins.ts` and then import it into your `App.tsx`:
|
|
174
|
+
|
|
175
|
+
```diff
|
|
176
|
+
+ import * as plugins from './plugins';
|
|
177
|
+
|
|
178
|
+
const app = createApp({
|
|
179
|
+
apis,
|
|
180
|
+
+ plugins: Object.values(plugins),
|
|
181
|
+
bindRoutes({ bind }) {
|
|
182
|
+
/* ... */
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Or simply edit `App.tsx` with:
|
|
188
|
+
|
|
189
|
+
```diff
|
|
190
|
+
+ import { badgesPlugin } from '@backstage-community/plugin-badges'
|
|
191
|
+
|
|
192
|
+
const app = createApp({
|
|
193
|
+
apis,
|
|
194
|
+
+ plugins: [badgesPlugin],
|
|
195
|
+
bindRoutes({ bind }) {
|
|
196
|
+
/* ... */
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Links
|
|
202
|
+
|
|
203
|
+
- [Backend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/badges-backend)
|
|
204
|
+
- [The Backstage homepage](https://backstage.io)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useAsyncEntity } from '@backstage/plugin-catalog-react';
|
|
2
|
+
import Box from '@material-ui/core/Box';
|
|
3
|
+
import Button from '@material-ui/core/Button';
|
|
4
|
+
import Dialog from '@material-ui/core/Dialog';
|
|
5
|
+
import DialogActions from '@material-ui/core/DialogActions';
|
|
6
|
+
import DialogContent from '@material-ui/core/DialogContent';
|
|
7
|
+
import DialogContentText from '@material-ui/core/DialogContentText';
|
|
8
|
+
import DialogTitle from '@material-ui/core/DialogTitle';
|
|
9
|
+
import useMediaQuery from '@material-ui/core/useMediaQuery';
|
|
10
|
+
import { useTheme } from '@material-ui/core/styles';
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import useAsync from 'react-use/esm/useAsync';
|
|
13
|
+
import 'react-router-dom';
|
|
14
|
+
import '@backstage/errors';
|
|
15
|
+
import '@backstage/catalog-model';
|
|
16
|
+
import { b as badgesApiRef } from './index-R_9uVcjC.esm.js';
|
|
17
|
+
import { CodeSnippet, Progress, ResponseErrorPanel } from '@backstage/core-components';
|
|
18
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
19
|
+
|
|
20
|
+
const EntityBadgesDialog = (props) => {
|
|
21
|
+
const { open, onClose } = props;
|
|
22
|
+
const theme = useTheme();
|
|
23
|
+
const { entity } = useAsyncEntity();
|
|
24
|
+
const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
|
|
25
|
+
const badgesApi = useApi(badgesApiRef);
|
|
26
|
+
const {
|
|
27
|
+
value: badges,
|
|
28
|
+
loading,
|
|
29
|
+
error
|
|
30
|
+
} = useAsync(async () => {
|
|
31
|
+
if (open && entity) {
|
|
32
|
+
return await badgesApi.getEntityBadgeSpecs(entity);
|
|
33
|
+
}
|
|
34
|
+
return [];
|
|
35
|
+
}, [badgesApi, entity, open]);
|
|
36
|
+
const content = (badges || []).map(
|
|
37
|
+
({ badge: { description }, id, url, markdown }) => /* @__PURE__ */ React.createElement(Box, { marginTop: 4, key: id }, /* @__PURE__ */ React.createElement(DialogContentText, { component: "div" }, /* @__PURE__ */ React.createElement("img", { alt: description || id, src: url }), /* @__PURE__ */ React.createElement(CodeSnippet, { language: "markdown", text: markdown, showCopyCodeButton: true })))
|
|
38
|
+
);
|
|
39
|
+
return /* @__PURE__ */ React.createElement(Dialog, { fullScreen, open, onClose }, /* @__PURE__ */ React.createElement(DialogTitle, null, "Entity Badges"), /* @__PURE__ */ React.createElement(DialogContent, null, /* @__PURE__ */ React.createElement(DialogContentText, null, "Embed badges in other web sites that link back to this entity. Copy the relevant snippet of Markdown code to use the badge."), loading && /* @__PURE__ */ React.createElement(Progress, null), error && /* @__PURE__ */ React.createElement(ResponseErrorPanel, { error }), content), /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(Button, { onClick: onClose, color: "primary" }, "Close")));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export { EntityBadgesDialog };
|
|
43
|
+
//# sourceMappingURL=EntityBadgesDialog-DwRwuts8.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityBadgesDialog-DwRwuts8.esm.js","sources":["../../src/components/EntityBadgesDialog.tsx"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { useAsyncEntity } from '@backstage/plugin-catalog-react';\nimport Box from '@material-ui/core/Box';\nimport Button from '@material-ui/core/Button';\nimport Dialog from '@material-ui/core/Dialog';\nimport DialogActions from '@material-ui/core/DialogActions';\nimport DialogContent from '@material-ui/core/DialogContent';\nimport DialogContentText from '@material-ui/core/DialogContentText';\nimport DialogTitle from '@material-ui/core/DialogTitle';\nimport useMediaQuery from '@material-ui/core/useMediaQuery';\nimport { useTheme } from '@material-ui/core/styles';\nimport React from 'react';\nimport useAsync from 'react-use/esm/useAsync';\nimport { badgesApiRef } from '../api';\n\nimport {\n CodeSnippet,\n Progress,\n ResponseErrorPanel,\n} from '@backstage/core-components';\nimport { useApi } from '@backstage/core-plugin-api';\n\nexport const EntityBadgesDialog = (props: {\n open: boolean;\n onClose?: () => any;\n}) => {\n const { open, onClose } = props;\n const theme = useTheme();\n const { entity } = useAsyncEntity();\n const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));\n const badgesApi = useApi(badgesApiRef);\n\n const {\n value: badges,\n loading,\n error,\n } = useAsync(async () => {\n if (open && entity) {\n return await badgesApi.getEntityBadgeSpecs(entity);\n }\n return [];\n }, [badgesApi, entity, open]);\n\n const content = (badges || []).map(\n ({ badge: { description }, id, url, markdown }) => (\n <Box marginTop={4} key={id}>\n <DialogContentText component=\"div\">\n <img alt={description || id} src={url} />\n <CodeSnippet language=\"markdown\" text={markdown} showCopyCodeButton />\n </DialogContentText>\n </Box>\n ),\n );\n\n return (\n <Dialog fullScreen={fullScreen} open={open} onClose={onClose}>\n <DialogTitle>Entity Badges</DialogTitle>\n <DialogContent>\n <DialogContentText>\n Embed badges in other web sites that link back to this entity. Copy\n the relevant snippet of Markdown code to use the badge.\n </DialogContentText>\n\n {loading && <Progress />}\n {error && <ResponseErrorPanel error={error} />}\n\n {content}\n </DialogContent>\n\n <DialogActions>\n <Button onClick={onClose} color=\"primary\">\n Close\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAqCa,MAAA,kBAAA,GAAqB,CAAC,KAG7B,KAAA;AACJ,EAAM,MAAA,EAAE,IAAM,EAAA,OAAA,EAAY,GAAA,KAAA,CAAA;AAC1B,EAAA,MAAM,QAAQ,QAAS,EAAA,CAAA;AACvB,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,cAAe,EAAA,CAAA;AAClC,EAAA,MAAM,aAAa,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAC7D,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA,CAAA;AAErC,EAAM,MAAA;AAAA,IACJ,KAAO,EAAA,MAAA;AAAA,IACP,OAAA;AAAA,IACA,KAAA;AAAA,GACF,GAAI,SAAS,YAAY;AACvB,IAAA,IAAI,QAAQ,MAAQ,EAAA;AAClB,MAAO,OAAA,MAAM,SAAU,CAAA,mBAAA,CAAoB,MAAM,CAAA,CAAA;AAAA,KACnD;AACA,IAAA,OAAO,EAAC,CAAA;AAAA,GACP,EAAA,CAAC,SAAW,EAAA,MAAA,EAAQ,IAAI,CAAC,CAAA,CAAA;AAE5B,EAAM,MAAA,OAAA,GAAA,CAAW,MAAU,IAAA,EAAI,EAAA,GAAA;AAAA,IAC7B,CAAC,EAAE,KAAA,EAAO,EAAE,WAAA,IAAe,EAAI,EAAA,GAAA,EAAK,QAAS,EAAA,yCAC1C,GAAI,EAAA,EAAA,SAAA,EAAW,CAAG,EAAA,GAAA,EAAK,sBACrB,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,SAAU,EAAA,KAAA,EAAA,sCAC1B,KAAI,EAAA,EAAA,GAAA,EAAK,WAAe,IAAA,EAAA,EAAI,KAAK,GAAK,EAAA,CAAA,kBACtC,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,UAAS,UAAW,EAAA,IAAA,EAAM,UAAU,kBAAkB,EAAA,IAAA,EAAC,CACtE,CACF,CAAA;AAAA,GAEJ,CAAA;AAEA,EAAA,2CACG,MAAO,EAAA,EAAA,UAAA,EAAwB,IAAY,EAAA,OAAA,EAAA,sCACzC,WAAY,EAAA,IAAA,EAAA,eAAa,CAC1B,kBAAA,KAAA,CAAA,aAAA,CAAC,qCACE,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,IAAA,EAAkB,6HAGnB,CAAA,EAEC,2BAAY,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAS,CACrB,EAAA,KAAA,wCAAU,kBAAmB,EAAA,EAAA,KAAA,EAAc,CAE3C,EAAA,OACH,mBAEC,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAO,SAAS,OAAS,EAAA,KAAA,EAAM,SAAU,EAAA,EAAA,OAE1C,CACF,CACF,CAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { generatePath } from 'react-router-dom';
|
|
2
|
+
import { ResponseError } from '@backstage/errors';
|
|
3
|
+
import { DEFAULT_NAMESPACE } from '@backstage/catalog-model';
|
|
4
|
+
import { createApiRef, createPlugin, createApiFactory, fetchApiRef, discoveryApiRef, configApiRef, createComponentExtension } from '@backstage/core-plugin-api';
|
|
5
|
+
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __publicField = (obj, key, value) => {
|
|
9
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
10
|
+
return value;
|
|
11
|
+
};
|
|
12
|
+
class BadgesClient {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
__publicField(this, "discoveryApi");
|
|
15
|
+
__publicField(this, "fetchApi");
|
|
16
|
+
__publicField(this, "configApi");
|
|
17
|
+
this.discoveryApi = options.discoveryApi;
|
|
18
|
+
this.fetchApi = options.fetchApi;
|
|
19
|
+
this.configApi = options.configApi;
|
|
20
|
+
}
|
|
21
|
+
static fromConfig(options) {
|
|
22
|
+
return new BadgesClient(options);
|
|
23
|
+
}
|
|
24
|
+
async getEntityBadgeSpecs(entity) {
|
|
25
|
+
const obfuscate = this.configApi.getOptionalBoolean("app.badges.obfuscate");
|
|
26
|
+
if (obfuscate) {
|
|
27
|
+
const entityUuidUrl = await this.getEntityUuidUrl(entity);
|
|
28
|
+
const entityUuid = await this.getEntityUuid(entityUuidUrl).then((data) => {
|
|
29
|
+
return data.uuid;
|
|
30
|
+
});
|
|
31
|
+
const entityUuidBadgeSpecsUrl = await this.getEntityUuidBadgeSpecsUrl(
|
|
32
|
+
entityUuid
|
|
33
|
+
);
|
|
34
|
+
const response2 = await this.fetchApi.fetch(entityUuidBadgeSpecsUrl);
|
|
35
|
+
if (!response2.ok) {
|
|
36
|
+
throw await ResponseError.fromResponse(response2);
|
|
37
|
+
}
|
|
38
|
+
return await response2.json();
|
|
39
|
+
}
|
|
40
|
+
const entityBadgeSpecsUrl = await this.getEntityBadgeSpecsUrl(entity);
|
|
41
|
+
const response = await this.fetchApi.fetch(entityBadgeSpecsUrl);
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
throw await ResponseError.fromResponse(response);
|
|
44
|
+
}
|
|
45
|
+
return await response.json();
|
|
46
|
+
}
|
|
47
|
+
async getEntityUuidUrl(entity) {
|
|
48
|
+
const routeParams = this.getEntityRouteParams(entity);
|
|
49
|
+
const path = generatePath(`:namespace/:kind/:name`, routeParams);
|
|
50
|
+
const baseUrl = await this.discoveryApi.getBaseUrl("badges");
|
|
51
|
+
const obfuscatedEntityUrl = `${baseUrl}/entity/${path}/obfuscated`;
|
|
52
|
+
return obfuscatedEntityUrl;
|
|
53
|
+
}
|
|
54
|
+
async getEntityUuid(entityUuidUrl) {
|
|
55
|
+
const responseEntityUuid = await this.fetchApi.fetch(entityUuidUrl);
|
|
56
|
+
if (!responseEntityUuid.ok) {
|
|
57
|
+
throw await ResponseError.fromResponse(responseEntityUuid);
|
|
58
|
+
}
|
|
59
|
+
return await responseEntityUuid.json();
|
|
60
|
+
}
|
|
61
|
+
async getEntityUuidBadgeSpecsUrl(entityUuid) {
|
|
62
|
+
const baseUrl = await this.discoveryApi.getBaseUrl("badges");
|
|
63
|
+
return `${baseUrl}/entity/${entityUuid}/badge-specs`;
|
|
64
|
+
}
|
|
65
|
+
async getEntityBadgeSpecsUrl(entity) {
|
|
66
|
+
const routeParams = this.getEntityRouteParams(entity);
|
|
67
|
+
const path = generatePath(`:namespace/:kind/:name`, routeParams);
|
|
68
|
+
const baseUrl = await this.discoveryApi.getBaseUrl("badges");
|
|
69
|
+
return `${baseUrl}/entity/${path}/badge-specs`;
|
|
70
|
+
}
|
|
71
|
+
// This function is used to generate the route parameters using the entity kind, namespace and name
|
|
72
|
+
getEntityRouteParams(entity) {
|
|
73
|
+
var _a, _b;
|
|
74
|
+
return {
|
|
75
|
+
kind: entity.kind.toLocaleLowerCase("en-US"),
|
|
76
|
+
namespace: (_b = (_a = entity.metadata.namespace) == null ? void 0 : _a.toLocaleLowerCase("en-US")) != null ? _b : DEFAULT_NAMESPACE,
|
|
77
|
+
name: entity.metadata.name
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const badgesApiRef = createApiRef({
|
|
83
|
+
id: "plugin.badges.client"
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const badgesPlugin = createPlugin({
|
|
87
|
+
id: "badges",
|
|
88
|
+
apis: [
|
|
89
|
+
createApiFactory({
|
|
90
|
+
api: badgesApiRef,
|
|
91
|
+
deps: {
|
|
92
|
+
fetchApi: fetchApiRef,
|
|
93
|
+
discoveryApi: discoveryApiRef,
|
|
94
|
+
configApi: configApiRef
|
|
95
|
+
},
|
|
96
|
+
factory: ({ fetchApi, discoveryApi, configApi }) => new BadgesClient({
|
|
97
|
+
fetchApi,
|
|
98
|
+
discoveryApi,
|
|
99
|
+
configApi
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
const EntityBadgesDialog = badgesPlugin.provide(
|
|
105
|
+
createComponentExtension({
|
|
106
|
+
name: "EntityBadgesDialog",
|
|
107
|
+
component: {
|
|
108
|
+
lazy: () => import('./EntityBadgesDialog-DwRwuts8.esm.js').then(
|
|
109
|
+
(m) => m.EntityBadgesDialog
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
export { EntityBadgesDialog as E, badgesPlugin as a, badgesApiRef as b };
|
|
116
|
+
//# sourceMappingURL=index-R_9uVcjC.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-R_9uVcjC.esm.js","sources":["../../src/api/BadgesClient.ts","../../src/api/types.ts","../../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { generatePath } from 'react-router-dom';\nimport { ResponseError } from '@backstage/errors';\nimport { Entity, DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport { BadgesApi, BadgeSpec } from './types';\nimport { ConfigApi, DiscoveryApi, FetchApi } from '@backstage/core-plugin-api';\n\nexport class BadgesClient implements BadgesApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private readonly configApi: ConfigApi;\n\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n configApi: ConfigApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n this.configApi = options.configApi;\n }\n\n static fromConfig(options: {\n fetchApi: FetchApi;\n discoveryApi: DiscoveryApi;\n configApi: ConfigApi;\n }) {\n return new BadgesClient(options);\n }\n\n public async getEntityBadgeSpecs(entity: Entity): Promise<BadgeSpec[]> {\n // Check if obfuscation is enabled in the configuration\n const obfuscate = this.configApi.getOptionalBoolean('app.badges.obfuscate');\n\n if (obfuscate) {\n const entityUuidUrl = await this.getEntityUuidUrl(entity);\n const entityUuid = await this.getEntityUuid(entityUuidUrl).then(data => {\n return data.uuid;\n });\n const entityUuidBadgeSpecsUrl = await this.getEntityUuidBadgeSpecsUrl(\n entityUuid,\n );\n\n const response = await this.fetchApi.fetch(entityUuidBadgeSpecsUrl);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n // If obfuscation is disabled, get the badge specs directly as the previous implementation\n const entityBadgeSpecsUrl = await this.getEntityBadgeSpecsUrl(entity);\n const response = await this.fetchApi.fetch(entityBadgeSpecsUrl);\n if (!response.ok) {\n throw await ResponseError.fromResponse(response);\n }\n\n return await response.json();\n }\n\n private async getEntityUuidUrl(entity: Entity): Promise<string> {\n const routeParams = this.getEntityRouteParams(entity);\n const path = generatePath(`:namespace/:kind/:name`, routeParams);\n const baseUrl = await this.discoveryApi.getBaseUrl('badges');\n const obfuscatedEntityUrl = `${baseUrl}/entity/${path}/obfuscated`;\n\n return obfuscatedEntityUrl;\n }\n\n private async getEntityUuid(entityUuidUrl: string): Promise<any> {\n const responseEntityUuid = await this.fetchApi.fetch(entityUuidUrl);\n\n if (!responseEntityUuid.ok) {\n throw await ResponseError.fromResponse(responseEntityUuid);\n }\n return await responseEntityUuid.json();\n }\n\n private async getEntityUuidBadgeSpecsUrl(entityUuid: {\n uuid: string;\n }): Promise<string> {\n const baseUrl = await this.discoveryApi.getBaseUrl('badges');\n return `${baseUrl}/entity/${entityUuid}/badge-specs`;\n }\n\n private async getEntityBadgeSpecsUrl(entity: Entity): Promise<string> {\n const routeParams = this.getEntityRouteParams(entity);\n const path = generatePath(`:namespace/:kind/:name`, routeParams);\n const baseUrl = await this.discoveryApi.getBaseUrl('badges');\n return `${baseUrl}/entity/${path}/badge-specs`;\n }\n\n // This function is used to generate the route parameters using the entity kind, namespace and name\n private getEntityRouteParams(entity: Entity) {\n return {\n kind: entity.kind.toLocaleLowerCase('en-US'),\n namespace:\n entity.metadata.namespace?.toLocaleLowerCase('en-US') ??\n DEFAULT_NAMESPACE,\n name: entity.metadata.name,\n };\n }\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Entity } from '@backstage/catalog-model';\nimport { createApiRef } from '@backstage/core-plugin-api';\n\nexport const badgesApiRef = createApiRef<BadgesApi>({\n id: 'plugin.badges.client',\n});\n\nexport type BadgeStyle =\n | 'plastic'\n | 'flat'\n | 'flat-square'\n | 'for-the-badge'\n | 'social';\n\ninterface Badge {\n color?: string;\n description?: string;\n kind?: 'entity';\n label: string;\n labelColor?: string;\n link?: string;\n message: string;\n style?: BadgeStyle;\n}\n\nexport interface BadgeSpec {\n /** Badge id */\n id: string;\n\n /** Badge data */\n badge: Badge;\n\n /** The URL to the badge image */\n url: string;\n\n /** The markdown code to use the badge */\n markdown: string;\n}\n\nexport interface BadgesApi {\n getEntityBadgeSpecs(entity: Entity): Promise<BadgeSpec[]>;\n}\n","/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { badgesApiRef, BadgesClient } from './api';\nimport {\n configApiRef,\n createApiFactory,\n createComponentExtension,\n createPlugin,\n fetchApiRef,\n discoveryApiRef,\n} from '@backstage/core-plugin-api';\n\n/** @public */\nexport const badgesPlugin = createPlugin({\n id: 'badges',\n apis: [\n createApiFactory({\n api: badgesApiRef,\n deps: {\n fetchApi: fetchApiRef,\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n },\n factory: ({ fetchApi, discoveryApi, configApi }) =>\n new BadgesClient({\n fetchApi,\n discoveryApi,\n configApi,\n }),\n }),\n ],\n});\n\n/** @public */\nexport const EntityBadgesDialog = badgesPlugin.provide(\n createComponentExtension({\n name: 'EntityBadgesDialog',\n component: {\n lazy: () =>\n import('./components/EntityBadgesDialog').then(\n m => m.EntityBadgesDialog,\n ),\n },\n }),\n);\n"],"names":["response"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
|
|
4
|
+
|
|
5
|
+
/** @public */
|
|
6
|
+
declare const badgesPlugin: _backstage_core_plugin_api.BackstagePlugin<{}, {}, {}>;
|
|
7
|
+
/** @public */
|
|
8
|
+
declare const EntityBadgesDialog: (props: {
|
|
9
|
+
open: boolean;
|
|
10
|
+
onClose?: (() => any) | undefined;
|
|
11
|
+
}) => react.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { EntityBadgesDialog, badgesPlugin };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@backstage-community/plugin-badges",
|
|
3
|
+
"version": "0.2.59",
|
|
4
|
+
"description": "A Backstage plugin that generates README badges for your entities",
|
|
5
|
+
"backstage": {
|
|
6
|
+
"role": "frontend-plugin"
|
|
7
|
+
},
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"main": "dist/index.esm.js",
|
|
11
|
+
"types": "dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://backstage.io",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/backstage/community-plugins",
|
|
17
|
+
"directory": "workspaces/badges/plugins/badges"
|
|
18
|
+
},
|
|
19
|
+
"license": "Apache-2.0",
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"main": "dist/index.esm.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "backstage-cli package build",
|
|
28
|
+
"clean": "backstage-cli package clean",
|
|
29
|
+
"lint": "backstage-cli package lint",
|
|
30
|
+
"prepack": "backstage-cli package prepack",
|
|
31
|
+
"postpack": "backstage-cli package postpack",
|
|
32
|
+
"start": "backstage-cli package start",
|
|
33
|
+
"test": "backstage-cli package test"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@backstage/catalog-model": "^1.4.5",
|
|
37
|
+
"@backstage/core-components": "^0.14.4",
|
|
38
|
+
"@backstage/core-plugin-api": "^1.9.2",
|
|
39
|
+
"@backstage/errors": "^1.2.4",
|
|
40
|
+
"@backstage/plugin-catalog-react": "^1.11.3",
|
|
41
|
+
"@material-ui/core": "^4.12.2",
|
|
42
|
+
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
43
|
+
"react-use": "^17.2.4"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@backstage/cli": "^0.26.3",
|
|
47
|
+
"@backstage/dev-utils": "^1.0.31",
|
|
48
|
+
"@backstage/test-utils": "^1.5.4",
|
|
49
|
+
"@testing-library/dom": "^10.0.0",
|
|
50
|
+
"@testing-library/jest-dom": "^6.0.0",
|
|
51
|
+
"@testing-library/react": "^15.0.0",
|
|
52
|
+
"@types/react-dom": "^18.2.19",
|
|
53
|
+
"canvas": "^2.11.2",
|
|
54
|
+
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
55
|
+
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
56
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
60
|
+
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
|
61
|
+
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
|
62
|
+
},
|
|
63
|
+
"module": "./dist/index.esm.js"
|
|
64
|
+
}
|