@axis-backstage/plugin-readme 0.1.0

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/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # Readme plugin
2
+
3
+ Welcome to the readme plugin!
4
+
5
+ ![home](media/readme-card.png)
6
+
7
+ ## Introduction
8
+
9
+ The `README-plugin` enables easy access and viewing of the README.md file. By having information such as the project's purpose, usage instructions, or installation details as a central part of the EntityPage, we hope to improve the `onboarding and understanding of entities`.
10
+
11
+ The README.md file is always retrieved from the same directory as the `catalog-info.yaml file`, also known as the `entity source location`. If you wish to view the path where the plugin looks for your README.md file, you can find it in the backstage.io/source-location annotation in the catalog-info.yaml file (see the example below). This annotation is automatically added to your entity, so there is no need to add it manually.
12
+
13
+ ```yaml
14
+ annotations:
15
+ backstage.io/source-location: url:https://github.com/AxisCommunications/backstage-plugins/blob/main/
16
+ ```
17
+
18
+ Currently, placing your README.md file elsewhere than in the same directory as the `catalog-info.yaml file` repository is not supported.
19
+
20
+ The displays README files with one of the following file types:
21
+
22
+ ```ts
23
+ { name: 'README', type: 'text/plain' },
24
+ { name: 'README.md', type: 'text/markdown' },
25
+ { name: 'README.rst', type: 'text/plain' },
26
+ { name: 'README.txt', type: 'text/plain' },
27
+ { name: 'README.MD', type: 'text/markdown' },
28
+ ```
29
+
30
+ The plugin can also handle symlinks in the README file.
31
+
32
+ ## Note
33
+
34
+ You will **need** to also perform the installation instructions in [Readme Backend](https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/readme-backend) in order for this plugin to work.
35
+
36
+ ## Getting started
37
+
38
+ 1. First, install the plugin into your app:
39
+
40
+ ```bash
41
+ # From your Backstage root directory
42
+ yarn add --cwd packages/app @axis-backstage/plugin-readme
43
+ ```
44
+
45
+ 2. Then, modify your entity page in `EntityPage.tsx` to include the `ReadmeCard` component that is exported from the plugin to `overviewContent``.
46
+
47
+ ```tsx
48
+ // In packages/app/src/components/catalog/Entity.tsx
49
+ import { ReadmeCard } from '@axis-backstage/plugin-readme';
50
+
51
+ const overviewContent = (
52
+ ...
53
+ <Grid item md={6} sx={12}>
54
+ <ReadmeCard />
55
+ </Grid>
56
+ ...
57
+ )
58
+ ```
59
+
60
+ ## Layout
61
+
62
+ The readme card is located in the overview page on the entity page. From the card header it is also possible to open a dialog displaying the full README.md.
63
+
64
+ ![home](media/readme-card.png)
65
+
66
+ ![home](media/readme-dialog.png)
67
+
68
+ ### Troubleshooting
69
+
70
+ #### "No README.md file found at the source location..."
71
+
72
+ This message indicates that the backend cannot find your README.md file. Ensure that the README.md file is indeed located in the same directory as the `catalog-info.yaml file`. If you are still unable to locate it, try scheduling an entity refresh by clicking the "Schedule Entity Refresh" button in the AboutCard of the entity.
@@ -0,0 +1,75 @@
1
+ import { createRouteRef, createApiRef, createPlugin, createApiFactory, discoveryApiRef, fetchApiRef, identityApiRef, createRoutableExtension } from '@backstage/core-plugin-api';
2
+
3
+ const rootRouteRef = createRouteRef({
4
+ id: "readme"
5
+ });
6
+
7
+ const readmeApiRef = createApiRef({
8
+ id: "plugin.readme"
9
+ });
10
+
11
+ var __defProp = Object.defineProperty;
12
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
+ var __publicField = (obj, key, value) => {
14
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
15
+ return value;
16
+ };
17
+ class ReadmeClient {
18
+ constructor(options) {
19
+ __publicField(this, "discoveryApi");
20
+ __publicField(this, "fetchApi");
21
+ __publicField(this, "identityApi");
22
+ this.discoveryApi = options.discoveryApi;
23
+ this.fetchApi = options.fetchApi;
24
+ this.identityApi = options.identityApi;
25
+ }
26
+ async getReadmeContent(entityRef) {
27
+ const { token } = await this.identityApi.getCredentials();
28
+ const baseUrl = await this.discoveryApi.getBaseUrl("readme");
29
+ const resp = await this.fetchApi.fetch(
30
+ `${baseUrl}/${encodeURIComponent(entityRef)}`,
31
+ {
32
+ method: "GET",
33
+ headers: { Authorization: `Bearer ${token}` }
34
+ }
35
+ );
36
+ if (resp.ok) {
37
+ return [
38
+ await resp.text(),
39
+ resp.headers.get("Content-Type") || "text/plain"
40
+ ];
41
+ }
42
+ if (resp.status === 404) {
43
+ throw new Error("404");
44
+ }
45
+ throw new Error(`${resp.status}: ${resp.statusText}`);
46
+ }
47
+ }
48
+
49
+ const readmePlugin = createPlugin({
50
+ id: "readme",
51
+ apis: [
52
+ createApiFactory({
53
+ api: readmeApiRef,
54
+ deps: {
55
+ discoveryApi: discoveryApiRef,
56
+ fetchApi: fetchApiRef,
57
+ identityApi: identityApiRef
58
+ },
59
+ factory: ({ discoveryApi, fetchApi, identityApi }) => new ReadmeClient({ discoveryApi, fetchApi, identityApi })
60
+ })
61
+ ],
62
+ routes: {
63
+ root: rootRouteRef
64
+ }
65
+ });
66
+ const ReadmeCard = readmePlugin.provide(
67
+ createRoutableExtension({
68
+ name: "ReadmeCard",
69
+ component: () => import('./index-4c75dc93.esm.js').then((m) => m.ReadmeCard),
70
+ mountPoint: rootRouteRef
71
+ })
72
+ );
73
+
74
+ export { ReadmeCard as R, readmePlugin as a, readmeApiRef as r };
75
+ //# sourceMappingURL=index-0b47704b.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-0b47704b.esm.js","sources":["../../src/routes.ts","../../src/api/ReadmeApi.tsx","../../src/api/ReadmeClient.tsx","../../src/plugin.ts"],"sourcesContent":["import { createRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'readme',\n});\n","import { createApiRef } from '@backstage/core-plugin-api';\n\nexport const readmeApiRef = createApiRef<ReadmeApi>({\n id: 'plugin.readme',\n});\n\nexport type ReadmeApi = {\n getReadmeContent(entityRef: string): Promise<[string, string]>;\n};\n","import {\n DiscoveryApi,\n FetchApi,\n IdentityApi,\n} from '@backstage/core-plugin-api';\nimport { ReadmeApi } from './ReadmeApi';\n\nexport class ReadmeClient implements ReadmeApi {\n private readonly discoveryApi: DiscoveryApi;\n private readonly fetchApi: FetchApi;\n private readonly identityApi: IdentityApi;\n\n constructor(options: {\n discoveryApi: DiscoveryApi;\n fetchApi: FetchApi;\n identityApi: IdentityApi;\n }) {\n this.discoveryApi = options.discoveryApi;\n this.fetchApi = options.fetchApi;\n this.identityApi = options.identityApi;\n }\n\n async getReadmeContent(entityRef: string): Promise<[string, string]> {\n const { token } = await this.identityApi.getCredentials();\n const baseUrl = await this.discoveryApi.getBaseUrl('readme');\n\n const resp = await this.fetchApi.fetch(\n `${baseUrl}/${encodeURIComponent(entityRef)}`,\n {\n method: 'GET',\n headers: { Authorization: `Bearer ${token}` },\n },\n );\n if (resp.ok) {\n return [\n await resp.text(),\n resp.headers.get('Content-Type') || 'text/plain',\n ];\n }\n if (resp.status === 404) {\n throw new Error('404');\n }\n throw new Error(`${resp.status}: ${resp.statusText}`);\n }\n}\n","import {\n createApiFactory,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n identityApiRef,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef } from './routes';\nimport { readmeApiRef } from './api/ReadmeApi';\nimport { ReadmeClient } from './api/ReadmeClient';\n\n/**\n * Plugin that provides the Readme api\n * @public */\nexport const readmePlugin = createPlugin({\n id: 'readme',\n apis: [\n createApiFactory({\n api: readmeApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, fetchApi, identityApi }) =>\n new ReadmeClient({ discoveryApi, fetchApi, identityApi }),\n }),\n ],\n routes: {\n root: rootRouteRef,\n },\n});\n\n/**\n * Readme card exported from the Readme plugin\n * @public */\nexport const ReadmeCard = readmePlugin.provide(\n createRoutableExtension({\n name: 'ReadmeCard',\n component: () => import('./components/ReadmeCard').then(m => m.ReadmeCard),\n mountPoint: rootRouteRef,\n }),\n);\n"],"names":[],"mappings":";;AAEO,MAAM,eAAe,cAAe,CAAA;AAAA,EACzC,EAAI,EAAA,QAAA;AACN,CAAC,CAAA;;ACFM,MAAM,eAAe,YAAwB,CAAA;AAAA,EAClD,EAAI,EAAA,eAAA;AACN,CAAC;;;;;;;;ACGM,MAAM,YAAkC,CAAA;AAAA,EAK7C,YAAY,OAIT,EAAA;AARH,IAAiB,aAAA,CAAA,IAAA,EAAA,cAAA,CAAA,CAAA;AACjB,IAAiB,aAAA,CAAA,IAAA,EAAA,UAAA,CAAA,CAAA;AACjB,IAAiB,aAAA,CAAA,IAAA,EAAA,aAAA,CAAA,CAAA;AAOf,IAAA,IAAA,CAAK,eAAe,OAAQ,CAAA,YAAA,CAAA;AAC5B,IAAA,IAAA,CAAK,WAAW,OAAQ,CAAA,QAAA,CAAA;AACxB,IAAA,IAAA,CAAK,cAAc,OAAQ,CAAA,WAAA,CAAA;AAAA,GAC7B;AAAA,EAEA,MAAM,iBAAiB,SAA8C,EAAA;AACnE,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAA,CAAK,YAAY,cAAe,EAAA,CAAA;AACxD,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,YAAA,CAAa,WAAW,QAAQ,CAAA,CAAA;AAE3D,IAAM,MAAA,IAAA,GAAO,MAAM,IAAA,CAAK,QAAS,CAAA,KAAA;AAAA,MAC/B,CAAG,EAAA,OAAO,CAAI,CAAA,EAAA,kBAAA,CAAmB,SAAS,CAAC,CAAA,CAAA;AAAA,MAC3C;AAAA,QACE,MAAQ,EAAA,KAAA;AAAA,QACR,OAAS,EAAA,EAAE,aAAe,EAAA,CAAA,OAAA,EAAU,KAAK,CAAG,CAAA,EAAA;AAAA,OAC9C;AAAA,KACF,CAAA;AACA,IAAA,IAAI,KAAK,EAAI,EAAA;AACX,MAAO,OAAA;AAAA,QACL,MAAM,KAAK,IAAK,EAAA;AAAA,QAChB,IAAK,CAAA,OAAA,CAAQ,GAAI,CAAA,cAAc,CAAK,IAAA,YAAA;AAAA,OACtC,CAAA;AAAA,KACF;AACA,IAAI,IAAA,IAAA,CAAK,WAAW,GAAK,EAAA;AACvB,MAAM,MAAA,IAAI,MAAM,KAAK,CAAA,CAAA;AAAA,KACvB;AACA,IAAM,MAAA,IAAI,MAAM,CAAG,EAAA,IAAA,CAAK,MAAM,CAAK,EAAA,EAAA,IAAA,CAAK,UAAU,CAAE,CAAA,CAAA,CAAA;AAAA,GACtD;AACF;;AC5BO,MAAM,eAAe,YAAa,CAAA;AAAA,EACvC,EAAI,EAAA,QAAA;AAAA,EACJ,IAAM,EAAA;AAAA,IACJ,gBAAiB,CAAA;AAAA,MACf,GAAK,EAAA,YAAA;AAAA,MACL,IAAM,EAAA;AAAA,QACJ,YAAc,EAAA,eAAA;AAAA,QACd,QAAU,EAAA,WAAA;AAAA,QACV,WAAa,EAAA,cAAA;AAAA,OACf;AAAA,MACA,OAAS,EAAA,CAAC,EAAE,YAAA,EAAc,QAAU,EAAA,WAAA,EAClC,KAAA,IAAI,YAAa,CAAA,EAAE,YAAc,EAAA,QAAA,EAAU,aAAa,CAAA;AAAA,KAC3D,CAAA;AAAA,GACH;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,YAAA;AAAA,GACR;AACF,CAAC,EAAA;AAKM,MAAM,aAAa,YAAa,CAAA,OAAA;AAAA,EACrC,uBAAwB,CAAA;AAAA,IACtB,IAAM,EAAA,YAAA;AAAA,IACN,SAAA,EAAW,MAAM,OAAO,yBAAyB,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,UAAU,CAAA;AAAA,IACzE,UAAY,EAAA,YAAA;AAAA,GACb,CAAA;AACH;;;;"}
@@ -0,0 +1,103 @@
1
+ import React, { useState } from 'react';
2
+ import { Box, Typography, Dialog, DialogTitle, DialogContent, DialogActions, Button, IconButton } from '@material-ui/core';
3
+ import { Progress, Link, ErrorPanel, MarkdownContent, CodeSnippet, InfoCard } from '@backstage/core-components';
4
+ import { useEntity } from '@backstage/plugin-catalog-react';
5
+ import { useApi } from '@backstage/core-plugin-api';
6
+ import useAsync from 'react-use/lib/useAsync';
7
+ import { r as readmeApiRef } from './index-0b47704b.esm.js';
8
+ import { getEntitySourceLocation, stringifyEntityRef } from '@backstage/catalog-model';
9
+ import OpenInNewIcon from '@material-ui/icons/OpenInNew';
10
+
11
+ const FetchComponent = () => {
12
+ var _a;
13
+ const { entity } = useEntity();
14
+ const readmeApi = useApi(readmeApiRef);
15
+ let location;
16
+ try {
17
+ const { target } = getEntitySourceLocation(entity);
18
+ location = target != null ? target : target;
19
+ } catch (err) {
20
+ location = ": Unknown";
21
+ }
22
+ const {
23
+ value: content,
24
+ loading,
25
+ error
26
+ } = useAsync(
27
+ async () => await readmeApi.getReadmeContent(stringifyEntityRef(entity)),
28
+ [entity]
29
+ );
30
+ if (loading) {
31
+ return /* @__PURE__ */ React.createElement(Progress, null);
32
+ }
33
+ if ((error == null ? void 0 : error.message) === "404") {
34
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2", style: { paddingBottom: 15 } }, "No README.md file found at source location:", " ", location && /* @__PURE__ */ React.createElement("strong", null, location)), /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, "Need help? Go to our", " ", /* @__PURE__ */ React.createElement(Link, { to: "https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/readme/README.md" }, "documentation")));
35
+ }
36
+ if (error) {
37
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { error });
38
+ }
39
+ if (!content) {
40
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { error: Error("Unknown error") });
41
+ }
42
+ if (!content[1] || content[1] === "error") {
43
+ return /* @__PURE__ */ React.createElement(ErrorPanel, { error: Error((_a = content[1]) != null ? _a : "Unknown error") });
44
+ } else if (content[1].startsWith("text/markdown")) {
45
+ return /* @__PURE__ */ React.createElement(MarkdownContent, { content: content[0] });
46
+ }
47
+ return /* @__PURE__ */ React.createElement("div", { "data-testid": "readme-content" }, /* @__PURE__ */ React.createElement(CodeSnippet, { text: content[0], language: "plaintext" }));
48
+ };
49
+
50
+ const ReadmeDialog = ({ open, onClose }) => {
51
+ return /* @__PURE__ */ React.createElement(
52
+ Dialog,
53
+ {
54
+ maxWidth: "md",
55
+ open,
56
+ onClose,
57
+ "data-testid": "content-dialog"
58
+ },
59
+ /* @__PURE__ */ React.createElement(DialogTitle, null, "README"),
60
+ /* @__PURE__ */ React.createElement(DialogContent, { dividers: true }, /* @__PURE__ */ React.createElement(FetchComponent, null)),
61
+ /* @__PURE__ */ React.createElement(DialogActions, null, /* @__PURE__ */ React.createElement(
62
+ Button,
63
+ {
64
+ variant: "contained",
65
+ color: "primary",
66
+ "aria-label": "close",
67
+ onClick: onClose
68
+ },
69
+ "Close"
70
+ ))
71
+ );
72
+ };
73
+
74
+ const ReadmeCard = () => {
75
+ const [displayDialog, setDisplayDialog] = useState(false);
76
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
77
+ InfoCard,
78
+ {
79
+ title: "README",
80
+ variant: "flex",
81
+ action: /* @__PURE__ */ React.createElement(
82
+ IconButton,
83
+ {
84
+ onClick: () => setDisplayDialog(true),
85
+ "aria-label": "open dialog",
86
+ role: "button",
87
+ title: "Open in dialog"
88
+ },
89
+ /* @__PURE__ */ React.createElement(OpenInNewIcon, null)
90
+ )
91
+ },
92
+ /* @__PURE__ */ React.createElement("div", { style: { overflow: "auto" } }, /* @__PURE__ */ React.createElement(Box, { sx: { maxHeight: 235 } }, /* @__PURE__ */ React.createElement(FetchComponent, null)))
93
+ ), /* @__PURE__ */ React.createElement(
94
+ ReadmeDialog,
95
+ {
96
+ open: displayDialog,
97
+ onClose: () => setDisplayDialog(false)
98
+ }
99
+ ));
100
+ };
101
+
102
+ export { ReadmeCard };
103
+ //# sourceMappingURL=index-4c75dc93.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-4c75dc93.esm.js","sources":["../../src/components/FetchComponent/FetchComponent.tsx","../../src/components/ReadmeDialog/ReadmeDialog.tsx","../../src/components/ReadmeCard/ReadmeCard.tsx"],"sourcesContent":["import React from 'react';\nimport { useEntity } from '@backstage/plugin-catalog-react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport {\n CodeSnippet,\n ErrorPanel,\n Link,\n MarkdownContent,\n Progress,\n} from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { readmeApiRef } from '../../api/ReadmeApi';\nimport { stringifyEntityRef } from '@backstage/catalog-model';\nimport { getEntitySourceLocation } from '@backstage/catalog-model';\nimport { Box, Typography } from '@material-ui/core';\n\nexport const FetchComponent = () => {\n const { entity } = useEntity();\n const readmeApi = useApi(readmeApiRef);\n let location;\n\n try {\n const { target } = getEntitySourceLocation(entity);\n location = target ?? target;\n } catch (err) {\n location = ': Unknown';\n }\n\n const {\n value: content,\n loading,\n error,\n } = useAsync(\n async (): Promise<string[]> =>\n await readmeApi.getReadmeContent(stringifyEntityRef(entity)),\n [entity],\n );\n\n if (loading) {\n return <Progress />;\n }\n if (error?.message === '404') {\n return (\n <Box>\n <Typography variant=\"body2\" style={{ paddingBottom: 15 }}>\n No README.md file found at source location:{' '}\n {location && <strong>{location}</strong>}\n </Typography>\n <Typography variant=\"body2\">\n Need help? Go to our{' '}\n <Link to=\"https://github.com/AxisCommunications/backstage-plugins/blob/main/plugins/readme/README.md\">\n documentation\n </Link>\n </Typography>\n </Box>\n );\n }\n\n if (error) {\n return <ErrorPanel error={error} />;\n }\n if (!content) {\n return <ErrorPanel error={Error('Unknown error')} />;\n }\n if (!content[1] || content[1] === 'error') {\n return <ErrorPanel error={Error(content[1] ?? 'Unknown error')} />;\n } else if (content[1].startsWith('text/markdown')) {\n return <MarkdownContent content={content[0]} />;\n }\n // probably text/plain\n return (\n <div data-testid=\"readme-content\">\n <CodeSnippet text={content[0]} language=\"plaintext\" />\n </div>\n );\n};\n","import React from 'react';\nimport {\n Button,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n} from '@material-ui/core';\nimport { FetchComponent } from '../FetchComponent';\n\ntype Props = {\n open: boolean;\n onClose: () => void;\n};\n\nexport const ReadmeDialog = ({ open, onClose }: Props) => {\n return (\n <Dialog\n maxWidth=\"md\"\n open={open}\n onClose={onClose}\n data-testid=\"content-dialog\"\n >\n <DialogTitle>README</DialogTitle>\n <DialogContent dividers>\n <FetchComponent />\n </DialogContent>\n <DialogActions>\n <Button\n variant=\"contained\"\n color=\"primary\"\n aria-label=\"close\"\n onClick={onClose}\n >\n Close\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n","import React, { useState } from 'react';\nimport { Box, IconButton } from '@material-ui/core';\nimport { InfoCard } from '@backstage/core-components';\nimport { FetchComponent } from '../FetchComponent';\nimport OpenInNewIcon from '@material-ui/icons/OpenInNew';\nimport { ReadmeDialog } from '../ReadmeDialog/ReadmeDialog';\n\nexport const ReadmeCard = () => {\n const [displayDialog, setDisplayDialog] = useState(false);\n\n return (\n <>\n <InfoCard\n title=\"README\"\n variant=\"flex\"\n action={\n <IconButton\n onClick={() => setDisplayDialog(true)}\n aria-label=\"open dialog\"\n role=\"button\"\n title=\"Open in dialog\"\n >\n <OpenInNewIcon />\n </IconButton>\n }\n >\n <div style={{ overflow: 'auto' }}>\n <Box sx={{ maxHeight: 235 }}>\n <FetchComponent />\n </Box>\n </div>\n </InfoCard>\n\n <ReadmeDialog\n open={displayDialog}\n onClose={() => setDisplayDialog(false)}\n />\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import * as react from 'react';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+
5
+ /**
6
+ * Plugin that provides the Readme api
7
+ * @public */
8
+ declare const readmePlugin: _backstage_core_plugin_api.BackstagePlugin<{
9
+ root: _backstage_core_plugin_api.RouteRef<undefined>;
10
+ }, {}, {}>;
11
+ /**
12
+ * Readme card exported from the Readme plugin
13
+ * @public */
14
+ declare const ReadmeCard: () => react.JSX.Element;
15
+
16
+ export { ReadmeCard, readmePlugin };
@@ -0,0 +1,3 @@
1
+ export { R as ReadmeCard, a as readmePlugin } from './esm/index-0b47704b.esm.js';
2
+ import '@backstage/core-plugin-api';
3
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@axis-backstage/plugin-readme",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.esm.js",
5
+ "types": "dist/index.d.ts",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "backstage": {
13
+ "role": "frontend-plugin"
14
+ },
15
+ "sideEffects": false,
16
+ "scripts": {
17
+ "start": "backstage-cli package start",
18
+ "build": "backstage-cli package build",
19
+ "lint": "backstage-cli package lint",
20
+ "test": "backstage-cli package test",
21
+ "clean": "backstage-cli package clean",
22
+ "prepack": "backstage-cli package prepack",
23
+ "postpack": "backstage-cli package postpack"
24
+ },
25
+ "dependencies": {
26
+ "@backstage/catalog-model": "^1.4.3",
27
+ "@backstage/core-components": "^0.13.6",
28
+ "@backstage/core-plugin-api": "^1.7.0",
29
+ "@backstage/plugin-catalog-react": "^1.9.0",
30
+ "@backstage/theme": "^0.4.3",
31
+ "@material-ui/core": "^4.12.2",
32
+ "@material-ui/icons": "^4.9.1",
33
+ "@material-ui/lab": "4.0.0-alpha.61",
34
+ "react-use": "^17.2.4"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^16.13.1 || ^17.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@backstage/cli": "^0.23.0",
41
+ "@backstage/core-app-api": "^1.11.0",
42
+ "@backstage/dev-utils": "^1.0.22",
43
+ "@backstage/test-utils": "^1.4.4",
44
+ "@testing-library/jest-dom": "^5.10.1",
45
+ "@testing-library/react": "^12.1.3",
46
+ "@testing-library/user-event": "^14.0.0",
47
+ "msw": "^1.0.0"
48
+ },
49
+ "files": [
50
+ "dist"
51
+ ],
52
+ "module": "./dist/index.esm.js"
53
+ }