@backstage/plugin-catalog 0.7.5 → 0.7.9-next.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/CHANGELOG.md +52 -0
- package/dist/esm/{index-96cd0b79.esm.js → index-8f8224b0.esm.js} +3 -3
- package/dist/esm/index-8f8224b0.esm.js.map +1 -0
- package/dist/esm/{index-66d685f8.esm.js → index-948ef81a.esm.js} +36 -51
- package/dist/esm/index-948ef81a.esm.js.map +1 -0
- package/dist/esm/{index-00a86fa7.esm.js → index-a149773d.esm.js} +3 -3
- package/dist/esm/index-a149773d.esm.js.map +1 -0
- package/dist/esm/{index-c9b0afd8.esm.js → index-d363820f.esm.js} +2 -2
- package/dist/esm/index-d363820f.esm.js.map +1 -0
- package/dist/index.d.ts +8 -3
- package/dist/index.esm.js +2 -2
- package/package.json +13 -13
- package/dist/esm/index-00a86fa7.esm.js.map +0 -1
- package/dist/esm/index-66d685f8.esm.js.map +0 -1
- package/dist/esm/index-96cd0b79.esm.js.map +0 -1
- package/dist/esm/index-c9b0afd8.esm.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @backstage/plugin-catalog
|
|
2
2
|
|
|
3
|
+
## 0.7.9-next.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7ba416be78: **@backstage/plugin-user-settings:** Hide Header on mobile screens to improve the UI & give more space to the content. Furthermore, the "Pin Sidebar" setting is removed on mobile screens, as the mobile sidebar is always pinned to the bottom.
|
|
8
|
+
|
|
9
|
+
**Other plugins:** Smaller style adjustments across plugins to improve the UI on mobile devices.
|
|
10
|
+
|
|
11
|
+
- 51fbedc445: Migrated usage of deprecated `IdentityApi` methods.
|
|
12
|
+
- 2b27e49eb1: Internal update to match status field changes in `@backstage/catalog-model`.
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
- @backstage/core-components@0.8.5-next.0
|
|
15
|
+
- @backstage/core-plugin-api@0.6.0-next.0
|
|
16
|
+
- @backstage/plugin-catalog-react@0.6.12-next.0
|
|
17
|
+
- @backstage/catalog-model@0.9.10-next.0
|
|
18
|
+
- @backstage/integration-react@0.1.19-next.0
|
|
19
|
+
- @backstage/catalog-client@0.5.5-next.0
|
|
20
|
+
|
|
21
|
+
## 0.7.8
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- Updated dependencies
|
|
26
|
+
- @backstage/core-components@0.8.4
|
|
27
|
+
- @backstage/core-plugin-api@0.5.0
|
|
28
|
+
- @backstage/plugin-catalog-react@0.6.11
|
|
29
|
+
- @backstage/errors@0.2.0
|
|
30
|
+
- @backstage/catalog-client@0.5.4
|
|
31
|
+
- @backstage/catalog-model@0.9.9
|
|
32
|
+
- @backstage/integration-react@0.1.18
|
|
33
|
+
|
|
34
|
+
## 0.7.7
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
|
39
|
+
- 11b81683a9: Support customizing index page layouts via outlets
|
|
40
|
+
- e195390974: Allow entities from `file` locations to be manually refreshed through the UI
|
|
41
|
+
- Updated dependencies
|
|
42
|
+
- @backstage/core-plugin-api@0.4.1
|
|
43
|
+
- @backstage/plugin-catalog-react@0.6.10
|
|
44
|
+
- @backstage/core-components@0.8.3
|
|
45
|
+
|
|
46
|
+
## 0.7.6
|
|
47
|
+
|
|
48
|
+
### Patch Changes
|
|
49
|
+
|
|
50
|
+
- 7d4b4e937c: Uptake changes to the GitHub Credentials Provider interface.
|
|
51
|
+
- Updated dependencies
|
|
52
|
+
- @backstage/plugin-catalog-react@0.6.9
|
|
53
|
+
- @backstage/integration-react@0.1.17
|
|
54
|
+
|
|
3
55
|
## 0.7.5
|
|
4
56
|
|
|
5
57
|
### Patch Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AboutCard, a as AboutContent, b as AboutField } from './index-
|
|
1
|
+
export { A as AboutCard, a as AboutContent, b as AboutField } from './index-948ef81a.esm.js';
|
|
2
2
|
import '@backstage/catalog-model';
|
|
3
3
|
import '@backstage/core-components';
|
|
4
4
|
import '@backstage/core-plugin-api';
|
|
@@ -18,8 +18,8 @@ import '@material-ui/icons/Cancel';
|
|
|
18
18
|
import '@material-ui/icons/MoreVert';
|
|
19
19
|
import '@backstage/errors';
|
|
20
20
|
import '@backstage/catalog-client';
|
|
21
|
-
import 'react-use';
|
|
21
|
+
import 'react-use/lib/useAsync';
|
|
22
22
|
import 'react-helmet';
|
|
23
23
|
import '@material-ui/icons/FilterList';
|
|
24
24
|
import '../components/EntityNotFound/Illo/illo.svg';
|
|
25
|
-
//# sourceMappingURL=index-
|
|
25
|
+
//# sourceMappingURL=index-8f8224b0.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-8f8224b0.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -11,13 +11,13 @@ import React, { useCallback, useState, useEffect, useMemo, useContext } from 're
|
|
|
11
11
|
import OpenInNew from '@material-ui/icons/OpenInNew';
|
|
12
12
|
import { capitalize as capitalize$1 } from 'lodash';
|
|
13
13
|
import { Alert } from '@material-ui/lab';
|
|
14
|
-
import { useNavigate, useParams, Navigate, matchRoutes, useRoutes, Routes, Route as Route$1 } from 'react-router';
|
|
14
|
+
import { useNavigate, useParams, Navigate, matchRoutes, useRoutes, useOutlet, Routes, Route as Route$1 } from 'react-router';
|
|
15
15
|
import { makeStyles as makeStyles$1 } from '@material-ui/core/styles';
|
|
16
16
|
import Cancel from '@material-ui/icons/Cancel';
|
|
17
17
|
import MoreVert from '@material-ui/icons/MoreVert';
|
|
18
18
|
import { assertError } from '@backstage/errors';
|
|
19
19
|
import { ENTITY_STATUS_CATALOG_PROCESSING_TYPE, CatalogClient } from '@backstage/catalog-client';
|
|
20
|
-
import
|
|
20
|
+
import useAsync from 'react-use/lib/useAsync';
|
|
21
21
|
import { Helmet } from 'react-helmet';
|
|
22
22
|
import FilterListIcon from '@material-ui/icons/FilterList';
|
|
23
23
|
import IlloSvgUrl from '../components/EntityNotFound/Illo/illo.svg';
|
|
@@ -28,64 +28,40 @@ class CatalogClientWrapper {
|
|
|
28
28
|
this.identityApi = options.identityApi;
|
|
29
29
|
}
|
|
30
30
|
async getLocationById(id, options) {
|
|
31
|
-
|
|
32
|
-
return await this.client.getLocationById(id, {
|
|
33
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
34
|
-
});
|
|
31
|
+
return await this.client.getLocationById(id, await this.getCredentials(options));
|
|
35
32
|
}
|
|
36
33
|
async getEntities(request, options) {
|
|
37
|
-
|
|
38
|
-
return await this.client.getEntities(request, {
|
|
39
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
40
|
-
});
|
|
34
|
+
return await this.client.getEntities(request, await this.getCredentials(options));
|
|
41
35
|
}
|
|
42
36
|
async getEntityByName(compoundName, options) {
|
|
43
|
-
|
|
44
|
-
return await this.client.getEntityByName(compoundName, {
|
|
45
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
46
|
-
});
|
|
37
|
+
return await this.client.getEntityByName(compoundName, await this.getCredentials(options));
|
|
47
38
|
}
|
|
48
39
|
async addLocation(request, options) {
|
|
49
|
-
|
|
50
|
-
return await this.client.addLocation(request, {
|
|
51
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
52
|
-
});
|
|
40
|
+
return await this.client.addLocation(request, await this.getCredentials(options));
|
|
53
41
|
}
|
|
54
42
|
async getOriginLocationByEntity(entity, options) {
|
|
55
|
-
|
|
56
|
-
return await this.client.getOriginLocationByEntity(entity, {
|
|
57
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
58
|
-
});
|
|
43
|
+
return await this.client.getOriginLocationByEntity(entity, await this.getCredentials(options));
|
|
59
44
|
}
|
|
60
45
|
async getLocationByEntity(entity, options) {
|
|
61
|
-
|
|
62
|
-
return await this.client.getLocationByEntity(entity, {
|
|
63
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
64
|
-
});
|
|
46
|
+
return await this.client.getLocationByEntity(entity, await this.getCredentials(options));
|
|
65
47
|
}
|
|
66
48
|
async removeLocationById(id, options) {
|
|
67
|
-
|
|
68
|
-
return await this.client.removeLocationById(id, {
|
|
69
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
70
|
-
});
|
|
49
|
+
return await this.client.removeLocationById(id, await this.getCredentials(options));
|
|
71
50
|
}
|
|
72
51
|
async removeEntityByUid(uid, options) {
|
|
73
|
-
|
|
74
|
-
return await this.client.removeEntityByUid(uid, {
|
|
75
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
76
|
-
});
|
|
52
|
+
return await this.client.removeEntityByUid(uid, await this.getCredentials(options));
|
|
77
53
|
}
|
|
78
54
|
async refreshEntity(entityRef, options) {
|
|
79
|
-
|
|
80
|
-
return await this.client.refreshEntity(entityRef, {
|
|
81
|
-
token: (_a = options == null ? void 0 : options.token) != null ? _a : await this.identityApi.getIdToken()
|
|
82
|
-
});
|
|
55
|
+
return await this.client.refreshEntity(entityRef, await this.getCredentials(options));
|
|
83
56
|
}
|
|
84
57
|
async getEntityAncestors(request, options) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
58
|
+
return await this.client.getEntityAncestors(request, await this.getCredentials(options));
|
|
59
|
+
}
|
|
60
|
+
async getCredentials(options) {
|
|
61
|
+
if (options == null ? void 0 : options.token) {
|
|
62
|
+
return { token: options == null ? void 0 : options.token };
|
|
63
|
+
}
|
|
64
|
+
return this.identityApi.getCredentials();
|
|
89
65
|
}
|
|
90
66
|
}
|
|
91
67
|
|
|
@@ -233,7 +209,7 @@ const useStyles$5 = makeStyles({
|
|
|
233
209
|
}
|
|
234
210
|
});
|
|
235
211
|
function AboutCard({ variant }) {
|
|
236
|
-
var _a, _b
|
|
212
|
+
var _a, _b;
|
|
237
213
|
const classes = useStyles$5();
|
|
238
214
|
const { entity } = useEntity();
|
|
239
215
|
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
|
@@ -272,7 +248,8 @@ function AboutCard({ variant }) {
|
|
|
272
248
|
} else if (variant === "fullHeight") {
|
|
273
249
|
cardContentClass = classes.fullHeightCardContent;
|
|
274
250
|
}
|
|
275
|
-
const
|
|
251
|
+
const entityLocation = (_b = entity.metadata.annotations) == null ? void 0 : _b[LOCATION_ANNOTATION];
|
|
252
|
+
const allowRefresh = (entityLocation == null ? void 0 : entityLocation.startsWith("url:")) || (entityLocation == null ? void 0 : entityLocation.startsWith("file:"));
|
|
276
253
|
const refreshEntity = useCallback(async () => {
|
|
277
254
|
await catalogApi.refreshEntity(stringifyEntityRef(entity));
|
|
278
255
|
alertApi.post({ message: "Refresh scheduled", severity: "info" });
|
|
@@ -281,7 +258,7 @@ function AboutCard({ variant }) {
|
|
|
281
258
|
className: cardClass
|
|
282
259
|
}, /* @__PURE__ */ React.createElement(CardHeader, {
|
|
283
260
|
title: "About",
|
|
284
|
-
action: /* @__PURE__ */ React.createElement(React.Fragment, null,
|
|
261
|
+
action: /* @__PURE__ */ React.createElement(React.Fragment, null, allowRefresh && /* @__PURE__ */ React.createElement(IconButton, {
|
|
285
262
|
"aria-label": "Refresh",
|
|
286
263
|
title: "Schedule entity refresh",
|
|
287
264
|
onClick: refreshEntity
|
|
@@ -343,6 +320,7 @@ const useStyles$3 = makeStyles({
|
|
|
343
320
|
},
|
|
344
321
|
itemText: {
|
|
345
322
|
width: "100%",
|
|
323
|
+
wordBreak: "break-all",
|
|
346
324
|
marginBottom: "1rem"
|
|
347
325
|
}
|
|
348
326
|
});
|
|
@@ -1119,7 +1097,7 @@ const EntityListContainer = ({ children }) => /* @__PURE__ */ React.createElemen
|
|
|
1119
1097
|
lg: 10
|
|
1120
1098
|
}, children);
|
|
1121
1099
|
|
|
1122
|
-
const
|
|
1100
|
+
const DefaultCatalogPage = ({
|
|
1123
1101
|
columns,
|
|
1124
1102
|
actions,
|
|
1125
1103
|
initiallySelectedFilter = "owned"
|
|
@@ -1143,6 +1121,13 @@ const CatalogPage = ({
|
|
|
1143
1121
|
}))))));
|
|
1144
1122
|
};
|
|
1145
1123
|
|
|
1124
|
+
const CatalogPage = (props) => {
|
|
1125
|
+
const outlet = useOutlet();
|
|
1126
|
+
return outlet || /* @__PURE__ */ React.createElement(DefaultCatalogPage, {
|
|
1127
|
+
...props
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1146
1131
|
const useStyles$1 = makeStyles((theme) => ({
|
|
1147
1132
|
illo: {
|
|
1148
1133
|
maxWidth: "60%",
|
|
@@ -1287,7 +1272,7 @@ const catalogPlugin = createPlugin({
|
|
|
1287
1272
|
});
|
|
1288
1273
|
const CatalogIndexPage = catalogPlugin.provide(createRoutableExtension({
|
|
1289
1274
|
name: "CatalogIndexPage",
|
|
1290
|
-
component: () => import('./index-
|
|
1275
|
+
component: () => import('./index-a149773d.esm.js').then((m) => m.CatalogPage),
|
|
1291
1276
|
mountPoint: catalogRouteRef
|
|
1292
1277
|
}));
|
|
1293
1278
|
const CatalogEntityPage = catalogPlugin.provide(createRoutableExtension({
|
|
@@ -1298,7 +1283,7 @@ const CatalogEntityPage = catalogPlugin.provide(createRoutableExtension({
|
|
|
1298
1283
|
const EntityAboutCard = catalogPlugin.provide(createComponentExtension({
|
|
1299
1284
|
name: "EntityAboutCard",
|
|
1300
1285
|
component: {
|
|
1301
|
-
lazy: () => import('./index-
|
|
1286
|
+
lazy: () => import('./index-8f8224b0.esm.js').then((m) => m.AboutCard)
|
|
1302
1287
|
}
|
|
1303
1288
|
}));
|
|
1304
1289
|
const EntityLinksCard = catalogPlugin.provide(createComponentExtension({
|
|
@@ -1352,9 +1337,9 @@ const EntityDependsOnResourcesCard = catalogPlugin.provide(createComponentExtens
|
|
|
1352
1337
|
const EntitySystemDiagramCard = catalogPlugin.provide(createComponentExtension({
|
|
1353
1338
|
name: "EntitySystemDiagramCard",
|
|
1354
1339
|
component: {
|
|
1355
|
-
lazy: () => import('./index-
|
|
1340
|
+
lazy: () => import('./index-d363820f.esm.js').then((m) => m.SystemDiagramCard)
|
|
1356
1341
|
}
|
|
1357
1342
|
}));
|
|
1358
1343
|
|
|
1359
|
-
export { AboutCard as A, EntityOrphanWarning as B, CatalogPage as C,
|
|
1360
|
-
//# sourceMappingURL=index-
|
|
1344
|
+
export { AboutCard as A, EntityOrphanWarning as B, CatalogPage as C, DefaultCatalogPage as D, EntityAboutCard as E, isOrphan as F, EntityProcessingErrorsPanel as G, hasCatalogProcessingErrors as H, EntityPageLayout as I, EntitySwitch as J, isKind as K, isNamespace as L, isComponentType as M, FilteredEntityLayout as N, FilterContainer as O, EntityListContainer as P, Router as R, AboutContent as a, AboutField as b, CatalogClientWrapper as c, CatalogTable as d, CatalogEntityPage as e, CatalogIndexPage as f, catalogPlugin as g, EntityDependencyOfComponentsCard as h, EntityDependsOnComponentsCard as i, EntityDependsOnResourcesCard as j, EntityHasComponentsCard as k, EntityHasResourcesCard as l, EntityHasSubcomponentsCard as m, EntityHasSystemsCard as n, EntityLinksCard as o, EntitySystemDiagramCard as p, CatalogKindHeader as q, CatalogResultListItem as r, createNameColumn as s, createSystemColumn as t, createOwnerColumn as u, createSpecTypeColumn as v, createSpecLifecycleColumn as w, createMetadataDescriptionColumn as x, createTagsColumn as y, EntityLayout as z };
|
|
1345
|
+
//# sourceMappingURL=index-948ef81a.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-948ef81a.esm.js","sources":["../../src/CatalogClientWrapper.ts","../../src/routes.ts","../../src/components/AboutCard/AboutField.tsx","../../src/components/AboutCard/AboutContent.tsx","../../src/components/AboutCard/AboutCard.tsx","../../src/components/CatalogKindHeader/CatalogKindHeader.tsx","../../src/components/CatalogResultListItem/CatalogResultListItem.tsx","../../src/components/CatalogTable/columns.tsx","../../src/components/CatalogTable/CatalogTable.tsx","../../src/components/EntityContextMenu/EntityContextMenu.tsx","../../src/components/EntityLayout/EntityLayout.tsx","../../src/components/EntityOrphanWarning/DeleteEntityDialog.tsx","../../src/components/EntityOrphanWarning/EntityOrphanWarning.tsx","../../src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx","../../src/components/EntityPageLayout/Tabbed/Tabbed.tsx","../../src/components/EntityPageLayout/EntityPageLayout.tsx","../../src/components/EntitySwitch/EntitySwitch.tsx","../../src/components/EntitySwitch/conditions.ts","../../src/components/FilteredEntityLayout/FilteredEntityLayout.tsx","../../src/components/FilteredEntityLayout/FilterContainer.tsx","../../src/components/FilteredEntityLayout/EntityListContainer.tsx","../../src/components/CatalogPage/DefaultCatalogPage.tsx","../../src/components/CatalogPage/CatalogPage.tsx","../../src/components/EntityNotFound/Illo/Illo.tsx","../../src/components/EntityNotFound/EntityNotFound.tsx","../../src/components/Router.tsx","../../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2020 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, EntityName, Location } from '@backstage/catalog-model';\nimport {\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogClient,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from '@backstage/catalog-client';\nimport { IdentityApi } from '@backstage/core-plugin-api';\n\n/**\n * CatalogClient wrapper that injects identity token for all requests\n *\n * @deprecated The default catalog client now uses the `fetchApiRef`\n * implementation, which in turn by default issues tokens just the same as this\n * class used to assist in doing. If you use a custom `fetchApiRef`\n * implementation that does NOT issue tokens, or use a custom `catalogApiRef`\n * implementation which does not use the default `fetchApiRef`, you can wrap\n * your catalog API in this class to get back the old behavior.\n */\nexport class CatalogClientWrapper implements CatalogApi {\n private readonly identityApi: IdentityApi;\n private readonly client: CatalogClient;\n\n constructor(options: { client: CatalogClient; identityApi: IdentityApi }) {\n this.client = options.client;\n this.identityApi = options.identityApi;\n }\n\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getLocationById(\n id,\n await this.getCredentials(options),\n );\n }\n\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n return await this.client.getEntities(\n request,\n await this.getCredentials(options),\n );\n }\n\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n return await this.client.getEntityByName(\n compoundName,\n await this.getCredentials(options),\n );\n }\n\n async addLocation(\n request: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n return await this.client.addLocation(\n request,\n await this.getCredentials(options),\n );\n }\n\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getOriginLocationByEntity(\n entity,\n await this.getCredentials(options),\n );\n }\n\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getLocationByEntity(\n entity,\n await this.getCredentials(options),\n );\n }\n\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.removeLocationById(\n id,\n await this.getCredentials(options),\n );\n }\n\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.removeEntityByUid(\n uid,\n await this.getCredentials(options),\n );\n }\n\n async refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.refreshEntity(\n entityRef,\n await this.getCredentials(options),\n );\n }\n\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n return await this.client.getEntityAncestors(\n request,\n await this.getCredentials(options),\n );\n }\n\n private async getCredentials(\n options?: CatalogRequestOptions,\n ): Promise<{ token?: string }> {\n if (options?.token) {\n return { token: options?.token };\n }\n return this.identityApi.getCredentials();\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 { createExternalRouteRef } from '@backstage/core-plugin-api';\n\nexport const createComponentRouteRef = createExternalRouteRef({\n id: 'create-component',\n optional: true,\n});\n\nexport const viewTechDocRouteRef = createExternalRouteRef({\n id: 'view-techdoc',\n optional: true,\n params: ['namespace', 'kind', 'name'],\n});\n","/*\n * Copyright 2020 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 { useElementFilter } from '@backstage/core-plugin-api';\nimport { Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\n\nconst useStyles = makeStyles(theme => ({\n value: {\n fontWeight: 'bold',\n overflow: 'hidden',\n lineHeight: '24px',\n wordBreak: 'break-word',\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontSize: '10px',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n },\n}));\n\ntype Props = {\n label: string;\n value?: string;\n gridSizes?: Record<string, number>;\n children?: React.ReactNode;\n};\n\nexport const AboutField = ({ label, value, gridSizes, children }: Props) => {\n const classes = useStyles();\n\n const childElements = useElementFilter(children, c => c.getElements());\n\n // Content is either children or a string prop `value`\n const content =\n childElements.length > 0 ? (\n childElements\n ) : (\n <Typography variant=\"body2\" className={classes.value}>\n {value || `unknown`}\n </Typography>\n );\n return (\n <Grid item {...gridSizes}>\n <Typography variant=\"subtitle2\" className={classes.label}>\n {label}\n </Typography>\n {content}\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { Chip, Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\nimport { AboutField } from './AboutField';\n\nconst useStyles = makeStyles({\n description: {\n wordBreak: 'break-word',\n },\n});\n\ntype Props = {\n entity: Entity;\n};\n\nexport const AboutContent = ({ entity }: Props) => {\n const classes = useStyles();\n const isSystem = entity.kind.toLocaleLowerCase('en-US') === 'system';\n const isResource = entity.kind.toLocaleLowerCase('en-US') === 'resource';\n const isComponent = entity.kind.toLocaleLowerCase('en-US') === 'component';\n const isAPI = entity.kind.toLocaleLowerCase('en-US') === 'api';\n const isTemplate = entity.kind.toLocaleLowerCase('en-US') === 'template';\n const isLocation = entity.kind.toLocaleLowerCase('en-US') === 'location';\n const isGroup = entity.kind.toLocaleLowerCase('en-US') === 'group';\n\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const partOfComponentRelations = getEntityRelations(\n entity,\n RELATION_PART_OF,\n {\n kind: 'component',\n },\n );\n const partOfDomainRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'domain',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n <Grid container>\n <AboutField label=\"Description\" gridSizes={{ xs: 12 }}>\n <Typography variant=\"body2\" paragraph className={classes.description}>\n {entity?.metadata?.description || 'No description'}\n </Typography>\n </AboutField>\n <AboutField\n label=\"Owner\"\n value=\"No Owner\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {ownedByRelations.length > 0 && (\n <EntityRefLinks entityRefs={ownedByRelations} defaultKind=\"group\" />\n )}\n </AboutField>\n {(isSystem || partOfDomainRelations.length > 0) && (\n <AboutField\n label=\"Domain\"\n value=\"No Domain\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {partOfDomainRelations.length > 0 && (\n <EntityRefLinks\n entityRefs={partOfDomainRelations}\n defaultKind=\"domain\"\n />\n )}\n </AboutField>\n )}\n {(isAPI ||\n isComponent ||\n isResource ||\n partOfSystemRelations.length > 0) && (\n <AboutField\n label=\"System\"\n value=\"No System\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {partOfSystemRelations.length > 0 && (\n <EntityRefLinks\n entityRefs={partOfSystemRelations}\n defaultKind=\"system\"\n />\n )}\n </AboutField>\n )}\n {isComponent && partOfComponentRelations.length > 0 && (\n <AboutField\n label=\"Parent Component\"\n value=\"No Parent Component\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n <EntityRefLinks\n entityRefs={partOfComponentRelations}\n defaultKind=\"component\"\n />\n </AboutField>\n )}\n {(isAPI ||\n isComponent ||\n isResource ||\n isTemplate ||\n isGroup ||\n isLocation ||\n typeof entity?.spec?.type === 'string') && (\n <AboutField\n label=\"Type\"\n value={entity?.spec?.type as string}\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n />\n )}\n {(isAPI ||\n isComponent ||\n typeof entity?.spec?.lifecycle === 'string') && (\n <AboutField\n label=\"Lifecycle\"\n value={entity?.spec?.lifecycle as string}\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n />\n )}\n <AboutField\n label=\"Tags\"\n value=\"No Tags\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {(entity?.metadata?.tags || []).map(t => (\n <Chip key={t} size=\"small\" label={t} />\n ))}\n </AboutField>\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n LOCATION_ANNOTATION,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n HeaderIconLinkRow,\n IconLinkVerticalProps,\n InfoCardVariants,\n Link,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n ScmIntegrationIcon,\n scmIntegrationsApiRef,\n} from '@backstage/integration-react';\nimport {\n catalogApiRef,\n getEntityMetadataEditUrl,\n getEntitySourceLocation,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport {\n Card,\n CardContent,\n CardHeader,\n Divider,\n IconButton,\n makeStyles,\n} from '@material-ui/core';\nimport CachedIcon from '@material-ui/icons/Cached';\nimport DocsIcon from '@material-ui/icons/Description';\nimport EditIcon from '@material-ui/icons/Edit';\nimport React, { useCallback } from 'react';\nimport { viewTechDocRouteRef } from '../../routes';\nimport { AboutContent } from './AboutContent';\n\nconst useStyles = makeStyles({\n gridItemCard: {\n display: 'flex',\n flexDirection: 'column',\n height: 'calc(100% - 10px)', // for pages without content header\n marginBottom: '10px',\n },\n fullHeightCard: {\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n },\n gridItemCardContent: {\n flex: 1,\n },\n fullHeightCardContent: {\n flex: 1,\n },\n});\n\ntype AboutCardProps = {\n /** @deprecated The entity is now grabbed from context instead */\n entity?: Entity;\n variant?: InfoCardVariants;\n};\n\nexport function AboutCard({ variant }: AboutCardProps) {\n const classes = useStyles();\n const { entity } = useEntity();\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n const viewTechdocLink = useRouteRef(viewTechDocRouteRef);\n\n const entitySourceLocation = getEntitySourceLocation(\n entity,\n scmIntegrationsApi,\n );\n const entityMetadataEditUrl = getEntityMetadataEditUrl(entity);\n\n const viewInSource: IconLinkVerticalProps = {\n label: 'View Source',\n disabled: !entitySourceLocation,\n icon: <ScmIntegrationIcon type={entitySourceLocation?.integrationType} />,\n href: entitySourceLocation?.locationTargetUrl,\n };\n const viewInTechDocs: IconLinkVerticalProps = {\n label: 'View TechDocs',\n disabled:\n !entity.metadata.annotations?.['backstage.io/techdocs-ref'] ||\n !viewTechdocLink,\n icon: <DocsIcon />,\n href:\n viewTechdocLink &&\n viewTechdocLink({\n namespace: entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE,\n kind: entity.kind,\n name: entity.metadata.name,\n }),\n };\n\n let cardClass = '';\n if (variant === 'gridItem') {\n cardClass = classes.gridItemCard;\n } else if (variant === 'fullHeight') {\n cardClass = classes.fullHeightCard;\n }\n\n let cardContentClass = '';\n if (variant === 'gridItem') {\n cardContentClass = classes.gridItemCardContent;\n } else if (variant === 'fullHeight') {\n cardContentClass = classes.fullHeightCardContent;\n }\n\n const entityLocation = entity.metadata.annotations?.[LOCATION_ANNOTATION];\n // Limiting the ability to manually refresh to the less expensive locations\n const allowRefresh =\n entityLocation?.startsWith('url:') || entityLocation?.startsWith('file:');\n const refreshEntity = useCallback(async () => {\n await catalogApi.refreshEntity(stringifyEntityRef(entity));\n alertApi.post({ message: 'Refresh scheduled', severity: 'info' });\n }, [catalogApi, alertApi, entity]);\n\n return (\n <Card className={cardClass}>\n <CardHeader\n title=\"About\"\n action={\n <>\n {allowRefresh && (\n <IconButton\n aria-label=\"Refresh\"\n title=\"Schedule entity refresh\"\n onClick={refreshEntity}\n >\n <CachedIcon />\n </IconButton>\n )}\n <IconButton\n component={Link}\n aria-label=\"Edit\"\n disabled={!entityMetadataEditUrl}\n title=\"Edit Metadata\"\n to={entityMetadataEditUrl ?? '#'}\n >\n <EditIcon />\n </IconButton>\n </>\n }\n subheader={<HeaderIconLinkRow links={[viewInSource, viewInTechDocs]} />}\n />\n <Divider />\n <CardContent className={cardContentClass}>\n <AboutContent entity={entity} />\n </CardContent>\n </Card>\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 React, { useEffect, useState } from 'react';\nimport {\n capitalize,\n createStyles,\n InputBase,\n makeStyles,\n MenuItem,\n Select,\n Theme,\n} from '@material-ui/core';\nimport {\n EntityKindFilter,\n useEntityKinds,\n useEntityListProvider,\n} from '@backstage/plugin-catalog-react';\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n ...theme.typography.h4,\n },\n }),\n);\n\ntype CatalogKindHeaderProps = {\n initialFilter?: string;\n};\n\nexport const CatalogKindHeader = ({\n initialFilter = 'component',\n}: CatalogKindHeaderProps) => {\n const classes = useStyles();\n const { kinds: allKinds = [] } = useEntityKinds();\n const { updateFilters, queryParameters } = useEntityListProvider();\n\n const [selectedKind, setSelectedKind] = useState(\n ([queryParameters.kind].flat()[0] ?? initialFilter).toLocaleLowerCase(\n 'en-US',\n ),\n );\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined,\n });\n }, [selectedKind, updateFilters]);\n\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n const options = [capitalize(selectedKind)]\n .concat(allKinds)\n .sort()\n .reduce((acc, kind) => {\n acc[kind.toLocaleLowerCase('en-US')] = kind;\n return acc;\n }, {} as Record<string, string>);\n\n return (\n <Select\n input={<InputBase value={selectedKind} />}\n value={selectedKind}\n onChange={e => setSelectedKind(e.target.value as string)}\n classes={classes}\n >\n {Object.keys(options).map(kind => (\n <MenuItem value={kind} key={kind}>\n {`${options[kind]}s`}\n </MenuItem>\n ))}\n </Select>\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 React from 'react';\nimport {\n Box,\n Chip,\n Divider,\n ListItem,\n ListItemText,\n makeStyles,\n} from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\n\nconst useStyles = makeStyles({\n flexContainer: {\n flexWrap: 'wrap',\n },\n itemText: {\n width: '100%',\n wordBreak: 'break-all',\n marginBottom: '1rem',\n },\n});\n\nexport const CatalogResultListItem = ({ result }: any) => {\n const classes = useStyles();\n return (\n <Link to={result.location}>\n <ListItem alignItems=\"flex-start\" className={classes.flexContainer}>\n <ListItemText\n className={classes.itemText}\n primaryTypographyProps={{ variant: 'h6' }}\n primary={result.title}\n secondary={result.text}\n />\n <Box>\n {result.kind && <Chip label={`Kind: ${result.kind}`} size=\"small\" />}\n {result.lifecycle && (\n <Chip label={`Lifecycle: ${result.lifecycle}`} size=\"small\" />\n )}\n </Box>\n </ListItem>\n <Divider component=\"li\" />\n </Link>\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 */\nimport React from 'react';\nimport {\n formatEntityRefTitle,\n EntityRefLink,\n EntityRefLinks,\n} from '@backstage/plugin-catalog-react';\nimport { Chip } from '@material-ui/core';\nimport { EntityRow } from './types';\nimport { OverflowTooltip, TableColumn } from '@backstage/core-components';\nimport { Entity } from '@backstage/catalog-model';\n\ntype NameColumnProps = {\n defaultKind?: string;\n};\n\nexport function createNameColumn(\n props?: NameColumnProps,\n): TableColumn<EntityRow> {\n function formatContent(entity: Entity): string {\n return (\n entity.metadata?.title ||\n formatEntityRefTitle(entity, {\n defaultKind: props?.defaultKind,\n })\n );\n }\n\n return {\n title: 'Name',\n field: 'resolved.name',\n highlight: true,\n customSort({ entity: entity1 }, { entity: entity2 }) {\n // TODO: We could implement this more efficiently by comparing field by field.\n // This has similar issues as above.\n return formatContent(entity1).localeCompare(formatContent(entity2));\n },\n render: ({ entity }) => (\n <EntityRefLink\n entityRef={entity}\n defaultKind={props?.defaultKind || 'Component'}\n title={entity.metadata?.title}\n />\n ),\n };\n}\n\nexport function createSystemColumn(): TableColumn<EntityRow> {\n return {\n title: 'System',\n field: 'resolved.partOfSystemRelationTitle',\n render: ({ resolved }) => (\n <EntityRefLinks\n entityRefs={resolved.partOfSystemRelations}\n defaultKind=\"system\"\n />\n ),\n };\n}\n\nexport function createOwnerColumn(): TableColumn<EntityRow> {\n return {\n title: 'Owner',\n field: 'resolved.ownedByRelationsTitle',\n render: ({ resolved }) => (\n <EntityRefLinks\n entityRefs={resolved.ownedByRelations}\n defaultKind=\"group\"\n />\n ),\n };\n}\n\nexport function createSpecTypeColumn(): TableColumn<EntityRow> {\n return {\n title: 'Type',\n field: 'entity.spec.type',\n hidden: true,\n };\n}\n\nexport function createSpecLifecycleColumn(): TableColumn<EntityRow> {\n return {\n title: 'Lifecycle',\n field: 'entity.spec.lifecycle',\n };\n}\n\nexport function createMetadataDescriptionColumn(): TableColumn<EntityRow> {\n return {\n title: 'Description',\n field: 'entity.metadata.description',\n render: ({ entity }) => (\n <OverflowTooltip\n text={entity.metadata.description}\n placement=\"bottom-start\"\n />\n ),\n width: 'auto',\n };\n}\n\nexport function createTagsColumn(): TableColumn<EntityRow> {\n return {\n title: 'Tags',\n field: 'entity.metadata.tags',\n cellStyle: {\n padding: '0px 16px 0px 20px',\n },\n render: ({ entity }) => (\n <>\n {entity.metadata.tags &&\n entity.metadata.tags.map(t => (\n <Chip\n key={t}\n label={t}\n size=\"small\"\n variant=\"outlined\"\n style={{ marginBottom: '0px' }}\n />\n ))}\n </>\n ),\n };\n}\n","/*\n * Copyright 2020 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 { RELATION_OWNED_BY, RELATION_PART_OF } from '@backstage/catalog-model';\nimport {\n favoriteEntityIcon,\n favoriteEntityTooltip,\n formatEntityRefTitle,\n getEntityMetadataEditUrl,\n getEntityMetadataViewUrl,\n getEntityRelations,\n useEntityListProvider,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport Edit from '@material-ui/icons/Edit';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport { capitalize } from 'lodash';\nimport React, { useMemo } from 'react';\nimport * as columnFactories from './columns';\nimport { EntityRow } from './types';\nimport {\n CodeSnippet,\n Table,\n TableColumn,\n TableProps,\n WarningPanel,\n} from '@backstage/core-components';\n\ntype CatalogTableProps = {\n columns?: TableColumn<EntityRow>[];\n actions?: TableProps<EntityRow>['actions'];\n};\n\nexport const CatalogTable = ({ columns, actions }: CatalogTableProps) => {\n const { isStarredEntity, toggleStarredEntity } = useStarredEntities();\n const { loading, error, entities, filters } = useEntityListProvider();\n\n const defaultColumns: TableColumn<EntityRow>[] = useMemo(\n () => [\n columnFactories.createNameColumn({ defaultKind: filters.kind?.value }),\n columnFactories.createSystemColumn(),\n columnFactories.createOwnerColumn(),\n columnFactories.createSpecTypeColumn(),\n columnFactories.createSpecLifecycleColumn(),\n columnFactories.createMetadataDescriptionColumn(),\n columnFactories.createTagsColumn(),\n ],\n [filters.kind?.value],\n );\n\n const showTypeColumn = filters.type === undefined;\n // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar\n const titlePreamble = capitalize(filters.user?.value ?? 'all');\n\n if (error) {\n return (\n <div>\n <WarningPanel\n severity=\"error\"\n title=\"Could not fetch catalog entities.\"\n >\n <CodeSnippet language=\"text\" text={error.toString()} />\n </WarningPanel>\n </div>\n );\n }\n\n const defaultActions: TableProps<EntityRow>['actions'] = [\n ({ entity }) => {\n const url = getEntityMetadataViewUrl(entity);\n return {\n icon: () => <OpenInNew aria-label=\"View\" fontSize=\"small\" />,\n tooltip: 'View',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const url = getEntityMetadataEditUrl(entity);\n return {\n icon: () => <Edit aria-label=\"Edit\" fontSize=\"small\" />,\n tooltip: 'Edit',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const isStarred = isStarredEntity(entity);\n return {\n cellStyle: { paddingLeft: '1em' },\n icon: () => favoriteEntityIcon(isStarred),\n tooltip: favoriteEntityTooltip(isStarred),\n onClick: () => toggleStarredEntity(entity),\n };\n },\n ];\n\n const rows = entities.map(entity => {\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return {\n entity,\n resolved: {\n name: formatEntityRefTitle(entity, {\n defaultKind: 'Component',\n }),\n ownedByRelationsTitle: ownedByRelations\n .map(r => formatEntityRefTitle(r, { defaultKind: 'group' }))\n .join(', '),\n ownedByRelations,\n partOfSystemRelationTitle: partOfSystemRelations\n .map(r =>\n formatEntityRefTitle(r, {\n defaultKind: 'system',\n }),\n )\n .join(', '),\n partOfSystemRelations,\n },\n };\n });\n\n const typeColumn = (columns || defaultColumns).find(c => c.title === 'Type');\n if (typeColumn) {\n typeColumn.hidden = !showTypeColumn;\n }\n const showPagination = rows.length > 20;\n\n return (\n <Table<EntityRow>\n isLoading={loading}\n columns={columns || defaultColumns}\n options={{\n paging: showPagination,\n pageSize: 20,\n actionsColumnIndex: -1,\n loadingType: 'linear',\n showEmptyDataSourceMessage: !loading,\n padding: 'dense',\n pageSizeOptions: [20, 50, 100],\n }}\n title={`${titlePreamble} (${entities.length})`}\n data={rows}\n actions={actions || defaultActions}\n />\n );\n};\n\nCatalogTable.columns = columnFactories;\n","/*\n * Copyright 2020 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 {\n Divider,\n IconButton,\n ListItemIcon,\n ListItemText,\n MenuItem,\n MenuList,\n Popover,\n} from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Cancel from '@material-ui/icons/Cancel';\nimport MoreVert from '@material-ui/icons/MoreVert';\nimport React, { useState } from 'react';\nimport { IconComponent } from '@backstage/core-plugin-api';\n\n// TODO(freben): It should probably instead be the case that Header sets the theme text color to white inside itself unconditionally instead\nconst useStyles = makeStyles({\n button: {\n color: 'white',\n },\n});\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype Props = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n onUnregisterEntity: () => void;\n};\n\nexport const EntityContextMenu = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n onUnregisterEntity,\n}: Props) => {\n const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();\n const classes = useStyles();\n\n const onOpen = (event: React.SyntheticEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const onClose = () => {\n setAnchorEl(undefined);\n };\n\n const extraItems = UNSTABLE_extraContextMenuItems && [\n ...UNSTABLE_extraContextMenuItems.map(item => (\n <MenuItem\n key={item.title}\n onClick={() => {\n onClose();\n item.onClick();\n }}\n >\n <ListItemIcon>\n <item.Icon fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary={item.title} />\n </MenuItem>\n )),\n <Divider key=\"the divider is here!\" />,\n ];\n\n const disableUnregister =\n UNSTABLE_contextMenuOptions?.disableUnregister ?? false;\n\n return (\n <>\n <IconButton\n aria-label=\"more\"\n aria-controls=\"long-menu\"\n aria-haspopup=\"true\"\n onClick={onOpen}\n data-testid=\"menu-button\"\n className={classes.button}\n >\n <MoreVert />\n </IconButton>\n <Popover\n open={Boolean(anchorEl)}\n onClose={onClose}\n anchorEl={anchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n >\n <MenuList>\n {extraItems}\n <MenuItem\n onClick={() => {\n onClose();\n onUnregisterEntity();\n }}\n disabled={disableUnregister}\n >\n <ListItemIcon>\n <Cancel fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Unregister entity\" />\n </MenuItem>\n </MenuList>\n </Popover>\n </>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n RoutedTabs,\n WarningPanel,\n} from '@backstage/core-components';\nimport {\n attachComponentData,\n IconComponent,\n useElementFilter,\n} from '@backstage/core-plugin-api';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box, TabProps } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\n\ntype SubRoute = {\n path: string;\n title: string;\n children: JSX.Element;\n if?: (entity: Entity) => boolean;\n tabProps?: TabProps<React.ElementType, { component?: React.ElementType }>;\n};\n\nconst dataKey = 'plugin.catalog.entityLayoutRoute';\n\nconst Route: (props: SubRoute) => null = () => null;\nattachComponentData(Route, dataKey, true);\n\n// This causes all mount points that are discovered within this route to use the path of the route itself\nattachComponentData(Route, 'core.gatherMountPoints', true);\n\nconst EntityLayoutTitle = ({\n entity,\n title,\n}: {\n title: string;\n entity: Entity | undefined;\n}) => {\n return (\n <Box display=\"inline-flex\" alignItems=\"center\" height=\"1em\" maxWidth=\"100%\">\n <Box\n component=\"span\"\n textOverflow=\"ellipsis\"\n whiteSpace=\"nowrap\"\n overflow=\"hidden\"\n >\n {title}\n </Box>\n {entity && <FavoriteEntity entity={entity} />}\n </Box>\n );\n};\n\nconst headerProps = (\n paramKind: string | undefined,\n paramNamespace: string | undefined,\n paramName: string | undefined,\n entity: Entity | undefined,\n): { headerTitle: string; headerType: string } => {\n const kind = paramKind ?? entity?.kind ?? '';\n const namespace = paramNamespace ?? entity?.metadata.namespace ?? '';\n const name =\n entity?.metadata.title ?? paramName ?? entity?.metadata.name ?? '';\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec as { type: string }).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\nconst EntityLabels = ({ entity }: { entity: Entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label=\"Owner\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel label=\"Lifecycle\" value={entity.spec.lifecycle} />\n )}\n </>\n );\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype EntityLayoutProps = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n children?: React.ReactNode;\n};\n\n/**\n * EntityLayout is a compound component, which allows you to define a layout for\n * entities using a sub-navigation mechanism.\n *\n * Consists of two parts: EntityLayout and EntityLayout.Route\n *\n * @example\n * ```jsx\n * <EntityLayout>\n * <EntityLayout.Route path=\"/example\" title=\"Example tab\">\n * <div>This is rendered under /example/anything-here route</div>\n * </EntityLayout.Route>\n * </EntityLayout>\n * ```\n */\nexport const EntityLayout = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n children,\n}: EntityLayoutProps) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const routes = useElementFilter(\n children,\n elements =>\n elements\n .selectByComponentData({\n key: dataKey,\n withStrictError:\n 'Child of EntityLayout must be an EntityLayout.Route',\n })\n .getElements<SubRoute>() // all nodes, element data, maintain structure or not?\n .flatMap(({ props }) => {\n if (props.if && entity && !props.if(entity)) {\n return [];\n }\n\n return [\n {\n path: props.path,\n title: props.title,\n children: props.children,\n tabProps: props.tabProps,\n },\n ];\n }),\n [entity],\n );\n\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n <Page themeId={entity?.spec?.type?.toString() ?? 'home'}>\n <Header\n title={<EntityLayoutTitle title={headerTitle} entity={entity!} />}\n pageTitleOverride={headerTitle}\n type={headerType}\n >\n {entity && (\n <>\n <EntityLabels entity={entity} />\n <EntityContextMenu\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n onUnregisterEntity={showRemovalDialog}\n />\n </>\n )}\n </Header>\n\n {loading && <Progress />}\n\n {entity && <RoutedTabs routes={routes} />}\n\n {error && (\n <Content>\n <Alert severity=\"error\">{error.toString()}</Alert>\n </Content>\n )}\n\n {!loading && !error && !entity && (\n <Content>\n <WarningPanel title=\"Entity not found\">\n There is no {kind} with the requested{' '}\n <Link to=\"https://backstage.io/docs/features/software-catalog/references\">\n kind, namespace, and name\n </Link>\n .\n </WarningPanel>\n </Content>\n )}\n\n <UnregisterEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\n </Page>\n );\n};\n\nEntityLayout.Route = Route;\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 { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core';\nimport React, { useState } from 'react';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { assertError } from '@backstage/errors';\n\ntype Props = {\n open: boolean;\n onClose: () => any;\n onConfirm: () => any;\n entity: Entity;\n};\n\nexport const DeleteEntityDialog = ({\n open,\n onClose,\n onConfirm,\n entity,\n}: Props) => {\n const [busy, setBusy] = useState(false);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n\n const onDelete = async () => {\n setBusy(true);\n try {\n const uid = entity.metadata.uid;\n await catalogApi.removeEntityByUid(uid!);\n onConfirm();\n } catch (err) {\n assertError(err);\n alertApi.post({ message: err.message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={onClose}>\n <DialogTitle id=\"responsive-dialog-title\">\n Are you sure you want to delete this entity?\n </DialogTitle>\n <DialogActions>\n <Button\n variant=\"contained\"\n color=\"secondary\"\n disabled={busy}\n onClick={onDelete}\n >\n Delete\n </Button>\n <Button onClick={onClose} color=\"primary\">\n Cancel\n </Button>\n </DialogActions>\n </Dialog>\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 { catalogRouteRef, useEntity } from '@backstage/plugin-catalog-react';\nimport { Alert } from '@material-ui/lab';\nimport React, { useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { DeleteEntityDialog } from './DeleteEntityDialog';\nimport { useRouteRef } from '@backstage/core-plugin-api';\n\nexport const isOrphan = (entity: Entity) =>\n entity?.metadata?.annotations?.['backstage.io/orphan'] === 'true';\n\n/**\n * Displays a warning alert if the entity is marked as orphan with the ability to delete said entity.\n */\nexport const EntityOrphanWarning = () => {\n const navigate = useNavigate();\n const catalogLink = useRouteRef(catalogRouteRef);\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const { entity } = useEntity();\n\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate(catalogLink());\n };\n\n return (\n <>\n <Alert severity=\"warning\" onClick={() => setConfirmationDialogOpen(true)}>\n This entity is not referenced by any location and is therefore not\n receiving updates. Click here to delete.\n </Alert>\n <DeleteEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\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 {\n Entity,\n AlphaEntity,\n stringifyEntityRef,\n EntityStatusItem,\n compareEntityToRef,\n} from '@backstage/catalog-model';\nimport {\n catalogApiRef,\n EntityRefLink,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React from 'react';\nimport { ResponseErrorPanel } from '@backstage/core-components';\nimport {\n CatalogApi,\n ENTITY_STATUS_CATALOG_PROCESSING_TYPE,\n} from '@backstage/catalog-client';\nimport { useApi, ApiHolder } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { SerializedError } from '@backstage/errors';\n\nconst errorFilter = (i: EntityStatusItem) =>\n i.error &&\n i.level === 'error' &&\n i.type === ENTITY_STATUS_CATALOG_PROCESSING_TYPE;\n\ntype GetOwnAndAncestorsErrorsResponse = {\n items: {\n errors: SerializedError[];\n entity: Entity;\n }[];\n};\n\nasync function getOwnAndAncestorsErrors(\n entityRef: string,\n catalogApi: CatalogApi,\n): Promise<GetOwnAndAncestorsErrorsResponse> {\n const ancestors = await catalogApi.getEntityAncestors({ entityRef });\n const items = ancestors.items\n .map(item => {\n const statuses = (item.entity as AlphaEntity).status?.items ?? [];\n const errors = statuses\n .filter(errorFilter)\n .map(e => e.error)\n .filter((e): e is SerializedError => Boolean(e));\n return { errors: errors, entity: item.entity };\n })\n .filter(item => item.errors.length > 0);\n return { items };\n}\n\nexport const hasCatalogProcessingErrors = async (\n entity: Entity,\n context: { apis: ApiHolder },\n) => {\n const catalogApi = context.apis.get(catalogApiRef);\n if (!catalogApi) {\n throw new Error(`No implementation available for ${catalogApiRef}`);\n }\n\n const errors = await getOwnAndAncestorsErrors(\n stringifyEntityRef(entity),\n catalogApi,\n );\n return errors.items.length > 0;\n};\n\n/**\n * Displays a list of errors from the ancestors of the current entity.\n */\nexport const EntityProcessingErrorsPanel = () => {\n const { entity } = useEntity();\n const entityRef = stringifyEntityRef(entity);\n const catalogApi = useApi(catalogApiRef);\n const { loading, error, value } = useAsync(async () => {\n return getOwnAndAncestorsErrors(entityRef, catalogApi);\n }, [entityRef, catalogApi]);\n\n if (error) {\n return (\n <Box mb={1}>\n <ResponseErrorPanel error={error} />\n </Box>\n );\n }\n\n if (loading || !value) {\n return null;\n }\n\n return (\n <>\n {value.items.map((ancestorError, index) => (\n <Box key={index} mb={1}>\n {!compareEntityToRef(\n entity,\n stringifyEntityRef(ancestorError.entity),\n ) && (\n <Box p={1}>\n The error below originates from{' '}\n <EntityRefLink entityRef={ancestorError.entity} />\n </Box>\n )}\n {ancestorError.errors.map((e, i) => (\n <ResponseErrorPanel key={i} error={e} />\n ))}\n </Box>\n ))}\n </>\n );\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport {\n useParams,\n useNavigate,\n PartialRouteObject,\n matchRoutes,\n RouteObject,\n useRoutes,\n Navigate,\n RouteMatch,\n} from 'react-router';\nimport { Helmet } from 'react-helmet';\nimport { Tab, HeaderTabs, Content } from '@backstage/core-components';\n\nconst getSelectedIndexOrDefault = (\n matchedRoute: RouteMatch,\n tabs: Tab[],\n defaultIndex = 0,\n) => {\n if (!matchedRoute) return defaultIndex;\n const tabIndex = tabs.findIndex(t => t.id === matchedRoute.route.path);\n return ~tabIndex ? tabIndex : defaultIndex;\n};\n\n/**\n * Compound component, which allows you to define layout\n * for EntityPage using Tabs as a sub-navigation mechanism\n * Consists of 2 parts: Tabbed.Layout and Tabbed.Content.\n * Takes care of: tabs, routes, document titles, spacing around content\n *\n * @example\n * ```jsx\n * <Tabbed.Layout>\n * <Tabbed.Content\n * title=\"Example tab\"\n * route=\"/example/*\"\n * element={<div>This is rendered under /example/anything-here route</div>}\n * />\n * </TabbedLayout>\n * ```\n */\nexport const Tabbed = {\n Layout: ({ children }: { children: React.ReactNode }) => {\n const routes: PartialRouteObject[] = [];\n const tabs: Tab[] = [];\n const params = useParams();\n const navigate = useNavigate();\n\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) {\n // Skip conditionals resolved to falses/nulls/undefineds etc\n return;\n }\n if (child.type !== Tabbed.Content) {\n throw new Error(\n 'This component only accepts Content elements as direct children. Check the code of the EntityPage.',\n );\n }\n const pathAndId = (child as JSX.Element).props.path;\n\n // Child here must be then always a functional component without any wrappers\n tabs.push({\n id: pathAndId,\n label: (child as JSX.Element).props.title,\n });\n\n routes.push({\n path: pathAndId,\n element: child.props.element,\n });\n });\n\n // Add catch-all for incorrect sub-routes\n if ((routes?.[0]?.path ?? '') !== '')\n routes.push({\n path: '/*',\n element: <Navigate to={routes[0].path!} />,\n });\n\n const [matchedRoute] =\n matchRoutes(routes as RouteObject[], `/${params['*']}`) ?? [];\n const selectedIndex = getSelectedIndexOrDefault(matchedRoute, tabs);\n const currentTab = tabs[selectedIndex];\n const title = currentTab?.label;\n\n const onTabChange = (index: number) =>\n // Remove trailing /*\n // And remove leading / for relative navigation\n // Note! route resolves relative to the position in the React tree,\n // not relative to current location\n navigate(tabs[index].id.replace(/\\/\\*$/, '').replace(/^\\//, ''));\n\n const currentRouteElement = useRoutes(routes);\n\n if (!currentTab) return null;\n return (\n <>\n <HeaderTabs\n tabs={tabs}\n selectedIndex={selectedIndex}\n onChange={onTabChange}\n />\n <Content>\n <Helmet title={title} />\n {currentRouteElement}\n </Content>\n </>\n );\n },\n Content: (_props: { path: string; title: string; element: JSX.Element }) =>\n null,\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\nimport { Tabbed } from './Tabbed';\n\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n ResponseErrorPanel,\n WarningPanel,\n} from '@backstage/core-components';\n\nimport { IconComponent } from '@backstage/core-plugin-api';\n\nconst EntityPageTitle = ({\n entity,\n title,\n}: {\n title: string;\n entity: Entity | undefined;\n}) => (\n <Box display=\"inline-flex\" alignItems=\"center\" height=\"1em\">\n {title}\n {entity && <FavoriteEntity entity={entity} />}\n </Box>\n);\n\nconst EntityLabels = ({ entity }: { entity: Entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label=\"Owner\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel label=\"Lifecycle\" value={entity.spec.lifecycle} />\n )}\n </>\n );\n};\n\nconst headerProps = (\n kind: string,\n namespace: string | undefined,\n name: string,\n entity: Entity | undefined,\n): { headerTitle: string; headerType: string } => {\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec as { type: string }).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype EntityPageLayoutProps = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n children?: React.ReactNode;\n};\n\nexport const EntityPageLayout = ({\n children,\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n}: EntityPageLayoutProps) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity!,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n <Page themeId={entity?.spec?.type?.toString() ?? 'home'}>\n <Header\n title={<EntityPageTitle title={headerTitle} entity={entity!} />}\n pageTitleOverride={headerTitle}\n type={headerType}\n >\n {/* TODO: Make entity labels configurable for entity kind / type */}\n {entity && (\n <>\n <EntityLabels entity={entity} />\n <EntityContextMenu\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n onUnregisterEntity={showRemovalDialog}\n />\n </>\n )}\n </Header>\n\n {loading && (\n <Content>\n <Progress />\n </Content>\n )}\n\n {entity && <Tabbed.Layout>{children}</Tabbed.Layout>}\n\n {error && (\n <Content>\n <ResponseErrorPanel error={error} />\n </Content>\n )}\n\n {!loading && !error && !entity && (\n <Content>\n <WarningPanel title=\"Entity not found\">\n There is no {kind} with the requested{' '}\n <Link to=\"https://backstage.io/docs/features/software-catalog/references\">\n kind, namespace, and name\n </Link>\n .\n </WarningPanel>\n </Content>\n )}\n\n <UnregisterEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\n </Page>\n );\n};\n\nEntityPageLayout.Content = Tabbed.Content;\n","/*\n * Copyright 2020 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 { useEntity } from '@backstage/plugin-catalog-react';\nimport React, { PropsWithChildren, ReactNode } from 'react';\nimport {\n attachComponentData,\n useApiHolder,\n useElementFilter,\n ApiHolder,\n} from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\n\nconst ENTITY_SWITCH_KEY = 'core.backstage.entitySwitch';\n\nconst EntitySwitchCase = (_: {\n if?: (\n entity: Entity,\n context: { apis: ApiHolder },\n ) => boolean | Promise<boolean>;\n children: ReactNode;\n}) => null;\n\nattachComponentData(EntitySwitchCase, ENTITY_SWITCH_KEY, true);\n\ntype SwitchCase = {\n if?: (\n entity: Entity,\n context: { apis: ApiHolder },\n ) => boolean | Promise<boolean>;\n children: JSX.Element;\n};\n\ntype SwitchCaseResult = {\n if: boolean | Promise<boolean>;\n children: JSX.Element;\n};\n\nexport const EntitySwitch = ({ children }: PropsWithChildren<{}>) => {\n const { entity } = useEntity();\n const apis = useApiHolder();\n const results = useElementFilter(\n children,\n collection =>\n collection\n .selectByComponentData({\n key: ENTITY_SWITCH_KEY,\n withStrictError: 'Child of EntitySwitch is not an EntitySwitch.Case',\n })\n .getElements()\n .flatMap<SwitchCaseResult>((element: React.ReactElement) => {\n const { if: condition, children: elementsChildren } =\n element.props as SwitchCase;\n return [\n {\n if: condition?.(entity, { apis }) ?? true,\n children: elementsChildren,\n },\n ];\n }),\n [apis, entity],\n );\n const hasAsyncCases = results.some(\n r => typeof r.if === 'object' && 'then' in r.if,\n );\n\n if (hasAsyncCases) {\n return <AsyncEntitySwitch results={results} />;\n }\n\n return results.find(r => r.if)?.children ?? null;\n};\n\nfunction AsyncEntitySwitch({ results }: { results: SwitchCaseResult[] }) {\n const { loading, value } = useAsync(async () => {\n const promises = results.map(\n async ({ if: condition, children: output }) => {\n try {\n if (await condition) {\n return output;\n }\n } catch {\n /* ignored */\n }\n\n return null;\n },\n );\n return (await Promise.all(promises)).find(Boolean) ?? null;\n }, [results]);\n\n if (loading || !value) {\n return null;\n }\n\n return value;\n}\n\nEntitySwitch.Case = EntitySwitchCase;\n","/*\n * Copyright 2020 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, ComponentEntity } from '@backstage/catalog-model';\n\nfunction strCmp(a: string | undefined, b: string | undefined): boolean {\n return Boolean(\n a && a?.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'),\n );\n}\n\nexport function isKind(kind: string) {\n return (entity: Entity) => strCmp(entity?.kind, kind);\n}\n\nexport function isComponentType(type: string) {\n return (entity: Entity) => {\n if (!strCmp(entity?.kind, 'component')) {\n return false;\n }\n const componentEntity = entity as ComponentEntity;\n return strCmp(componentEntity.spec.type, type);\n };\n}\n\nexport function isNamespace(namespace: string) {\n return (entity: Entity) => strCmp(entity?.metadata?.namespace, namespace);\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 { Grid } from '@material-ui/core';\nimport React, { PropsWithChildren } from 'react';\n\nexport const FilteredEntityLayout = ({ children }: PropsWithChildren<{}>) => (\n <Grid container style={{ position: 'relative' }}>\n {children}\n </Grid>\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 { BackstageTheme } from '@backstage/theme';\nimport {\n Box,\n Button,\n Drawer,\n Grid,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@material-ui/core';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport React, { useState, PropsWithChildren } from 'react';\n\nexport const FilterContainer = ({ children }: PropsWithChildren<{}>) => {\n const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>\n theme.breakpoints.down('md'),\n );\n const theme = useTheme<BackstageTheme>();\n const [filterDrawerOpen, setFilterDrawerOpen] = useState<boolean>(false);\n\n return isMidSizeScreen ? (\n <>\n <Button\n style={{ marginTop: theme.spacing(1), marginLeft: theme.spacing(1) }}\n onClick={() => setFilterDrawerOpen(true)}\n startIcon={<FilterListIcon />}\n >\n Filters\n </Button>\n <Drawer\n open={filterDrawerOpen}\n onClose={() => setFilterDrawerOpen(false)}\n anchor=\"left\"\n disableAutoFocus\n keepMounted\n variant=\"temporary\"\n >\n <Box m={2}>\n <Typography\n variant=\"h6\"\n component=\"h2\"\n style={{ marginBottom: theme.spacing(1) }}\n >\n Filters\n </Typography>\n {children}\n </Box>\n </Drawer>\n </>\n ) : (\n <Grid item lg={2}>\n {children}\n </Grid>\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 { Grid } from '@material-ui/core';\nimport React, { PropsWithChildren } from 'react';\n\nexport const EntityListContainer = ({ children }: PropsWithChildren<{}>) => (\n <Grid item xs={12} lg={10}>\n {children}\n </Grid>\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 {\n Content,\n ContentHeader,\n CreateButton,\n PageWithHeader,\n SupportButton,\n TableColumn,\n TableProps,\n} from '@backstage/core-components';\nimport { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n EntityLifecyclePicker,\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n EntityTypePicker,\n UserListFilterKind,\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport React from 'react';\nimport { createComponentRouteRef } from '../../routes';\nimport { CatalogTable } from '../CatalogTable';\nimport { EntityRow } from '../CatalogTable/types';\nimport {\n FilteredEntityLayout,\n EntityListContainer,\n FilterContainer,\n} from '../FilteredEntityLayout';\nimport { CatalogKindHeader } from '../CatalogKindHeader';\n\n/**\n * DefaultCatalogPageProps\n * @public\n */\nexport type DefaultCatalogPageProps = {\n initiallySelectedFilter?: UserListFilterKind;\n columns?: TableColumn<EntityRow>[];\n actions?: TableProps<EntityRow>['actions'];\n};\n\nexport const DefaultCatalogPage = ({\n columns,\n actions,\n initiallySelectedFilter = 'owned',\n}: DefaultCatalogPageProps) => {\n const orgName =\n useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage';\n const createComponentLink = useRouteRef(createComponentRouteRef);\n\n return (\n <PageWithHeader title={`${orgName} Catalog`} themeId=\"home\">\n <EntityListProvider>\n <Content>\n <ContentHeader titleComponent={<CatalogKindHeader />}>\n <CreateButton\n title=\"Create Component\"\n to={createComponentLink && createComponentLink()}\n />\n <SupportButton>All your software catalog entities</SupportButton>\n </ContentHeader>\n <FilteredEntityLayout>\n <FilterContainer>\n <EntityTypePicker />\n <UserListPicker initialFilter={initiallySelectedFilter} />\n <EntityOwnerPicker />\n <EntityLifecyclePicker />\n <EntityTagPicker />\n </FilterContainer>\n <EntityListContainer>\n <CatalogTable columns={columns} actions={actions} />\n </EntityListContainer>\n </FilteredEntityLayout>\n </Content>\n </EntityListProvider>\n </PageWithHeader>\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 React from 'react';\nimport { useOutlet } from 'react-router';\nimport {\n DefaultCatalogPage,\n DefaultCatalogPageProps,\n} from './DefaultCatalogPage';\n\nexport const CatalogPage = (props: DefaultCatalogPageProps) => {\n const outlet = useOutlet();\n\n return outlet || <DefaultCatalogPage {...props} />;\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport { makeStyles } from '@material-ui/core';\nimport IlloSvgUrl from './illo.svg';\n\nconst useStyles = makeStyles(theme => ({\n illo: {\n maxWidth: '60%',\n top: 100,\n right: 20,\n position: 'absolute',\n [theme.breakpoints.down('xs')]: {\n maxWidth: '96%',\n position: 'relative',\n top: 'unset',\n right: 'unset',\n margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,\n },\n },\n}));\n\nexport const Illo = () => {\n const classes = useStyles();\n return (\n <img\n src={IlloSvgUrl}\n className={classes.illo}\n alt=\"Illustration on entity not found page\"\n />\n );\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport { Grid, Button, Typography } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { BackstageTheme } from '@backstage/theme';\n\nimport { Illo } from './Illo';\n\nconst useStyles = makeStyles<BackstageTheme>(theme => ({\n container: {\n paddingTop: theme.spacing(24),\n paddingLeft: theme.spacing(8),\n [theme.breakpoints.down('xs')]: {\n padding: theme.spacing(2),\n },\n },\n title: {\n paddingBottom: theme.spacing(2),\n [theme.breakpoints.down('xs')]: {\n fontSize: 32,\n },\n },\n body: {\n paddingBottom: theme.spacing(6),\n [theme.breakpoints.down('xs')]: {\n paddingBottom: theme.spacing(5),\n },\n },\n}));\n\nexport const EntityNotFound = () => {\n const classes = useStyles();\n\n return (\n <Grid container spacing={0} className={classes.container}>\n <Illo />\n <Grid item xs={12} sm={6}>\n <Typography variant=\"h2\" className={classes.title}>\n Entity was not found\n </Typography>\n <Typography variant=\"body1\" className={classes.body}>\n Want to help us build this? Check out our Getting Started\n documentation.\n </Typography>\n <Button\n variant=\"contained\"\n color=\"primary\"\n href=\"https://backstage.io/docs\"\n >\n DOCS\n </Button>\n </Grid>\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport {\n AsyncEntityProvider,\n useEntity,\n useEntityFromUrl,\n} from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\nimport React, { ComponentType, ReactNode } from 'react';\nimport { Navigate, Route, Routes, useParams } from 'react-router';\nimport { CatalogPage } from './CatalogPage';\nimport { EntityNotFound } from './EntityNotFound';\nimport { EntityPageLayout } from './EntityPageLayout';\nimport { Content, Link } from '@backstage/core-components';\n\nconst DefaultEntityPage = () => (\n <EntityPageLayout>\n <EntityPageLayout.Content\n path=\"/\"\n title=\"Overview\"\n element={\n <Content>\n <Typography variant=\"h2\">This is the default entity page.</Typography>\n <Typography variant=\"body1\">\n To override this component with your custom implementation, read\n docs on{' '}\n <Link to=\"https://backstage.io/docs\">backstage.io/docs</Link>\n </Typography>\n </Content>\n }\n />\n </EntityPageLayout>\n);\n\nconst EntityPageSwitch = ({ EntityPage }: { EntityPage: ComponentType }) => {\n const { entity, loading, error } = useEntity();\n // Loading and error states\n if (loading) return <EntityPageLayout />;\n if (error || !entity) return <EntityNotFound />;\n\n // Otherwise EntityPage provided from the App\n // Note that EntityPage will include EntityPageLayout already\n return <EntityPage />;\n};\n\nconst OldEntityRouteRedirect = () => {\n const { optionalNamespaceAndName, '*': rest } = useParams() as any;\n const [name, namespace] = optionalNamespaceAndName.split(':').reverse();\n const namespaceLower =\n namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE;\n const restWithSlash = rest ? `/${rest}` : '';\n return (\n <Navigate\n to={`../../${namespaceLower}/component/${name}${restWithSlash}`}\n />\n );\n};\n\nexport const EntityLoader = (props: { children: ReactNode }) => (\n <AsyncEntityProvider {...useEntityFromUrl()} {...props} />\n);\n\n/**\n * @deprecated Use plugin extensions instead\n * */\nexport const Router = ({\n EntityPage = DefaultEntityPage,\n}: {\n EntityPage?: ComponentType;\n}) => (\n <Routes>\n <Route path=\"/\" element={<CatalogPage />} />\n <Route\n path=\"/:namespace/:kind/:name\"\n element={\n <EntityLoader>\n <EntityPageSwitch EntityPage={EntityPage} />\n </EntityLoader>\n }\n />\n <Route\n path=\"Component/:optionalNamespaceAndName/*\"\n element={<OldEntityRouteRedirect />}\n />\n </Routes>\n);\n","/*\n * Copyright 2020 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 { CatalogClient } from '@backstage/catalog-client';\nimport {\n catalogApiRef,\n catalogRouteRef,\n DefaultStarredEntitiesApi,\n entityRouteRef,\n starredEntitiesApiRef,\n} from '@backstage/plugin-catalog-react';\nimport { createComponentRouteRef, viewTechDocRouteRef } from './routes';\nimport {\n createApiFactory,\n createComponentExtension,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n storageApiRef,\n} from '@backstage/core-plugin-api';\n\nexport const catalogPlugin = createPlugin({\n id: 'catalog',\n apis: [\n createApiFactory({\n api: catalogApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new CatalogClient({ discoveryApi, fetchApi }),\n }),\n createApiFactory({\n api: starredEntitiesApiRef,\n deps: { storageApi: storageApiRef },\n factory: ({ storageApi }) =>\n new DefaultStarredEntitiesApi({ storageApi }),\n }),\n ],\n routes: {\n catalogIndex: catalogRouteRef,\n catalogEntity: entityRouteRef,\n },\n externalRoutes: {\n createComponent: createComponentRouteRef,\n viewTechDoc: viewTechDocRouteRef,\n },\n});\n\nexport const CatalogIndexPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogIndexPage',\n component: () =>\n import('./components/CatalogPage').then(m => m.CatalogPage),\n mountPoint: catalogRouteRef,\n }),\n);\n\nexport const CatalogEntityPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogEntityPage',\n component: () =>\n import('./components/CatalogEntityPage').then(m => m.CatalogEntityPage),\n mountPoint: entityRouteRef,\n }),\n);\n\nexport const EntityAboutCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityAboutCard',\n component: {\n lazy: () => import('./components/AboutCard').then(m => m.AboutCard),\n },\n }),\n);\n\nexport const EntityLinksCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityLinksCard',\n component: {\n lazy: () =>\n import('./components/EntityLinksCard').then(m => m.EntityLinksCard),\n },\n }),\n);\n\nexport const EntityHasSystemsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSystemsCard',\n component: {\n lazy: () =>\n import('./components/HasSystemsCard').then(m => m.HasSystemsCard),\n },\n }),\n);\n\nexport const EntityHasComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasComponentsCard',\n component: {\n lazy: () =>\n import('./components/HasComponentsCard').then(m => m.HasComponentsCard),\n },\n }),\n);\n\nexport const EntityHasSubcomponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSubcomponentsCard',\n component: {\n lazy: () =>\n import('./components/HasSubcomponentsCard').then(\n m => m.HasSubcomponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityHasResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasResourcesCard',\n component: {\n lazy: () =>\n import('./components/HasResourcesCard').then(m => m.HasResourcesCard),\n },\n }),\n);\n\nexport const EntityDependsOnComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependsOnComponentsCard').then(\n m => m.DependsOnComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependencyOfComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependencyOfComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependencyOfComponentsCard').then(\n m => m.DependencyOfComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependsOnResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnResourcesCard',\n component: {\n lazy: () =>\n import('./components/DependsOnResourcesCard').then(\n m => m.DependsOnResourcesCard,\n ),\n },\n }),\n);\n\nexport const EntitySystemDiagramCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntitySystemDiagramCard',\n component: {\n lazy: () =>\n import('./components/SystemDiagramCard').then(m => m.SystemDiagramCard),\n },\n }),\n);\n"],"names":["useStyles","columnFactories.createNameColumn","columnFactories.createSystemColumn","columnFactories.createOwnerColumn","columnFactories.createSpecTypeColumn","columnFactories.createSpecLifecycleColumn","columnFactories.createMetadataDescriptionColumn","columnFactories.createTagsColumn","capitalize","Edit","makeStyles","headerProps","EntityLabels","Route"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CatalogPage } from './index-
|
|
1
|
+
export { C as CatalogPage, D as DefaultCatalogPage } from './index-948ef81a.esm.js';
|
|
2
2
|
import '@backstage/catalog-model';
|
|
3
3
|
import '@backstage/core-components';
|
|
4
4
|
import '@backstage/core-plugin-api';
|
|
@@ -18,8 +18,8 @@ import '@material-ui/icons/Cancel';
|
|
|
18
18
|
import '@material-ui/icons/MoreVert';
|
|
19
19
|
import '@backstage/errors';
|
|
20
20
|
import '@backstage/catalog-client';
|
|
21
|
-
import 'react-use';
|
|
21
|
+
import 'react-use/lib/useAsync';
|
|
22
22
|
import 'react-helmet';
|
|
23
23
|
import '@material-ui/icons/FilterList';
|
|
24
24
|
import '../components/EntityNotFound/Illo/illo.svg';
|
|
25
|
-
//# sourceMappingURL=index-
|
|
25
|
+
//# sourceMappingURL=index-a149773d.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-a149773d.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -3,7 +3,7 @@ import { useEntity, catalogApiRef, getEntityRelations, entityRouteRef } from '@b
|
|
|
3
3
|
import { makeStyles, useTheme, Box, Typography } from '@material-ui/core';
|
|
4
4
|
import ZoomOutMap from '@material-ui/icons/ZoomOutMap';
|
|
5
5
|
import React from 'react';
|
|
6
|
-
import
|
|
6
|
+
import useAsync from 'react-use/lib/useAsync';
|
|
7
7
|
import { Progress, ResponseErrorPanel, InfoCard, DependencyGraph, DependencyGraphTypes, Link } from '@backstage/core-components';
|
|
8
8
|
import { useApi, useRouteRef } from '@backstage/core-plugin-api';
|
|
9
9
|
|
|
@@ -179,4 +179,4 @@ function SystemDiagramCard() {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
export { SystemDiagramCard };
|
|
182
|
-
//# sourceMappingURL=index-
|
|
182
|
+
//# sourceMappingURL=index-d363820f.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-d363820f.esm.js","sources":["../../src/components/SystemDiagramCard/SystemDiagramCard.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 {\n Entity,\n RELATION_DEPENDS_ON,\n RELATION_PROVIDES_API,\n RELATION_PART_OF,\n stringifyEntityRef,\n ENTITY_DEFAULT_NAMESPACE,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport {\n catalogApiRef,\n entityRouteRef,\n getEntityRelations,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Box, makeStyles, Typography, useTheme } from '@material-ui/core';\nimport ZoomOutMap from '@material-ui/icons/ZoomOutMap';\nimport React from 'react';\nimport useAsync from 'react-use/lib/useAsync';\nimport { BackstageTheme } from '@backstage/theme';\n\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n InfoCard,\n Progress,\n ResponseErrorPanel,\n Link,\n} from '@backstage/core-components';\n\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\n\n/** @public */\nexport type SystemDiagramCardClassKey =\n | 'domainNode'\n | 'systemNode'\n | 'componentNode'\n | 'apiNode'\n | 'resourceNode';\n\nconst useStyles = makeStyles(\n (theme: BackstageTheme) => ({\n domainNode: {\n fill: theme.palette.primary.main,\n stroke: theme.palette.border,\n },\n systemNode: {\n fill: 'coral',\n stroke: theme.palette.border,\n },\n componentNode: {\n fill: 'yellowgreen',\n stroke: theme.palette.border,\n },\n apiNode: {\n fill: theme.palette.gold,\n stroke: theme.palette.border,\n },\n resourceNode: {\n fill: 'grey',\n stroke: theme.palette.border,\n },\n }),\n { name: 'PluginCatalogSystemDiagramCard' },\n);\n\n// Simplifies the diagram output by hiding the default namespace and kind\nfunction readableEntityName(\n ref:\n | Entity\n | {\n kind: string;\n namespace?: string;\n name: string;\n },\n): string {\n return stringifyEntityRef(ref)\n .toLocaleLowerCase('en-US')\n .replace(`:${ENTITY_DEFAULT_NAMESPACE}/`, ':')\n .split(':')[1];\n}\n\nfunction RenderNode(props: DependencyGraphTypes.RenderNodeProps<any>) {\n const classes = useStyles();\n const catalogEntityRoute = useRouteRef(entityRouteRef);\n const kind = props.node.kind || 'Component';\n const ref = parseEntityRef(props.node.id);\n const MAX_NAME_LENGTH = 20;\n const truncatedNodeName =\n props.node.name.length < MAX_NAME_LENGTH\n ? props.node.name\n : `${props.node.name.slice(0, MAX_NAME_LENGTH)}...`;\n let nodeClass = classes.componentNode;\n\n switch (kind) {\n case 'Domain':\n nodeClass = classes.domainNode;\n break;\n case 'System':\n nodeClass = classes.systemNode;\n break;\n case 'Component':\n nodeClass = classes.componentNode;\n break;\n case 'API':\n nodeClass = classes.apiNode;\n break;\n case 'Resource':\n nodeClass = classes.resourceNode;\n break;\n default:\n nodeClass = classes.componentNode;\n }\n\n return (\n <g>\n <rect width={200} height={100} rx={20} className={nodeClass} />\n <Link\n to={catalogEntityRoute({\n kind: kind,\n namespace: ref.namespace,\n name: ref.name,\n })}\n >\n <text\n x={100}\n y={45}\n textAnchor=\"middle\"\n alignmentBaseline=\"baseline\"\n style={{ fontWeight: 'bold' }}\n >\n {truncatedNodeName}\n </text>\n </Link>\n\n <text x={100} y={65} textAnchor=\"middle\" alignmentBaseline=\"hanging\">\n {props.node.kind}\n </text>\n </g>\n );\n}\n\n/**\n * Dynamically generates a diagram of a system, its assigned entities,\n * and relationships of those entities.\n */\nexport function SystemDiagramCard() {\n const { entity } = useEntity();\n const theme = useTheme();\n const currentSystemName = entity.metadata.name;\n const currentSystemNode = stringifyEntityRef(entity);\n const systemNodes = new Array<{ id: string; kind: string; name: string }>();\n const systemEdges = new Array<{ from: string; to: string; label: string }>();\n\n const catalogApi = useApi(catalogApiRef);\n const {\n loading,\n error,\n value: catalogResponse,\n } = useAsync(() => {\n return catalogApi.getEntities({\n filter: {\n kind: ['Component', 'API', 'Resource', 'System', 'Domain'],\n 'spec.system': [\n currentSystemName,\n `${\n entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE\n }/${currentSystemName}`,\n ],\n },\n });\n }, [catalogApi, currentSystemName]);\n\n // pick out the system itself\n systemNodes.push({\n id: currentSystemNode,\n kind: 'System',\n name: readableEntityName(entity),\n });\n\n // check if the system has an assigned domain\n // even if the domain object doesn't exist in the catalog, display it in the map\n const catalogItemDomain = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'Domain',\n });\n catalogItemDomain.forEach(foundDomain =>\n systemNodes.push({\n id: stringifyEntityRef(foundDomain),\n kind: foundDomain.kind,\n name: readableEntityName(foundDomain),\n }),\n );\n catalogItemDomain.forEach(foundDomain =>\n systemEdges.push({\n from: currentSystemNode,\n to: stringifyEntityRef(foundDomain),\n label: 'part of',\n }),\n );\n\n if (catalogResponse && catalogResponse.items) {\n for (const catalogItem of catalogResponse.items) {\n systemNodes.push({\n id: stringifyEntityRef(catalogItem),\n kind: catalogItem.kind,\n name: readableEntityName(catalogItem),\n });\n\n // Check relations of the entity assigned to this system to see\n // if it relates to other entities.\n // Note those relations may, or may not, be explicitly\n // assigned to the system.\n const catalogItemRelations_partOf = getEntityRelations(\n catalogItem,\n RELATION_PART_OF,\n );\n catalogItemRelations_partOf.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'part of',\n }),\n );\n\n const catalogItemRelations_providesApi = getEntityRelations(\n catalogItem,\n RELATION_PROVIDES_API,\n );\n catalogItemRelations_providesApi.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'provides',\n }),\n );\n\n const catalogItemRelations_dependsOn = getEntityRelations(\n catalogItem,\n RELATION_DEPENDS_ON,\n );\n catalogItemRelations_dependsOn.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'depends on',\n }),\n );\n }\n }\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <InfoCard title=\"System Diagram\">\n <DependencyGraph\n nodes={systemNodes}\n edges={systemEdges}\n nodeMargin={10}\n direction={DependencyGraphTypes.Direction.BOTTOM_TOP}\n renderNode={RenderNode}\n paddingX={theme.spacing(4)}\n paddingY={theme.spacing(4)}\n />\n <Box m={1} />\n <Typography\n variant=\"caption\"\n style={{ display: 'block', textAlign: 'right' }}\n >\n <ZoomOutMap style={{ verticalAlign: 'bottom' }} /> Use pinch & zoom\n to move around the diagram.\n </Typography>\n </InfoCard>\n );\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ declare class CatalogClientWrapper implements CatalogApi {
|
|
|
38
38
|
removeEntityByUid(uid: string, options?: CatalogRequestOptions): Promise<void>;
|
|
39
39
|
refreshEntity(entityRef: string, options?: CatalogRequestOptions): Promise<void>;
|
|
40
40
|
getEntityAncestors(request: CatalogEntityAncestorsRequest, options?: CatalogRequestOptions): Promise<CatalogEntityAncestorsResponse>;
|
|
41
|
+
private getCredentials;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
declare type AboutCardProps = {
|
|
@@ -246,7 +247,11 @@ declare const Router: ({ EntityPage, }: {
|
|
|
246
247
|
EntityPage?: React.ComponentType<{}> | undefined;
|
|
247
248
|
}) => JSX.Element;
|
|
248
249
|
|
|
249
|
-
|
|
250
|
+
/**
|
|
251
|
+
* DefaultCatalogPageProps
|
|
252
|
+
* @public
|
|
253
|
+
*/
|
|
254
|
+
declare type DefaultCatalogPageProps = {
|
|
250
255
|
initiallySelectedFilter?: UserListFilterKind;
|
|
251
256
|
columns?: TableColumn<EntityRow>[];
|
|
252
257
|
actions?: TableProps<EntityRow>['actions'];
|
|
@@ -267,7 +272,7 @@ declare const catalogPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
|
267
272
|
namespace: string;
|
|
268
273
|
}, true>;
|
|
269
274
|
}>;
|
|
270
|
-
declare const CatalogIndexPage: (
|
|
275
|
+
declare const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element;
|
|
271
276
|
declare const CatalogEntityPage: () => JSX.Element;
|
|
272
277
|
declare const EntityAboutCard: typeof AboutCard;
|
|
273
278
|
declare const EntityLinksCard: ({ cols, variant }: {
|
|
@@ -300,4 +305,4 @@ declare const EntityDependsOnResourcesCard: ({ variant }: {
|
|
|
300
305
|
}) => JSX.Element;
|
|
301
306
|
declare const EntitySystemDiagramCard: typeof SystemDiagramCard;
|
|
302
307
|
|
|
303
|
-
export { AboutCard, AboutContent, AboutField, BackstageOverrides, CatalogClientWrapper, CatalogEntityPage, CatalogIndexPage, CatalogKindHeader, CatalogResultListItem, CatalogTable, EntityRow as CatalogTableRow, EntityAboutCard, EntityDependencyOfComponentsCard, EntityDependsOnComponentsCard, EntityDependsOnResourcesCard, EntityHasComponentsCard, EntityHasResourcesCard, EntityHasSubcomponentsCard, EntityHasSystemsCard, EntityLayout, EntityLinksCard, EntityLinksEmptyStateClassKey, EntityListContainer, EntityOrphanWarning, EntityPageLayout, EntityProcessingErrorsPanel, EntitySwitch, EntitySystemDiagramCard, FilterContainer, FilteredEntityLayout, PluginCatalogComponentsNameToClassKey, Router, SystemDiagramCardClassKey, catalogPlugin, createMetadataDescriptionColumn, createNameColumn, createOwnerColumn, createSpecLifecycleColumn, createSpecTypeColumn, createSystemColumn, createTagsColumn, hasCatalogProcessingErrors, isComponentType, isKind, isNamespace, isOrphan, catalogPlugin as plugin };
|
|
308
|
+
export { AboutCard, AboutContent, AboutField, BackstageOverrides, CatalogClientWrapper, CatalogEntityPage, CatalogIndexPage, CatalogKindHeader, CatalogResultListItem, CatalogTable, EntityRow as CatalogTableRow, DefaultCatalogPageProps, EntityAboutCard, EntityDependencyOfComponentsCard, EntityDependsOnComponentsCard, EntityDependsOnResourcesCard, EntityHasComponentsCard, EntityHasResourcesCard, EntityHasSubcomponentsCard, EntityHasSystemsCard, EntityLayout, EntityLinksCard, EntityLinksEmptyStateClassKey, EntityListContainer, EntityOrphanWarning, EntityPageLayout, EntityProcessingErrorsPanel, EntitySwitch, EntitySystemDiagramCard, FilterContainer, FilteredEntityLayout, PluginCatalogComponentsNameToClassKey, Router, SystemDiagramCardClassKey, catalogPlugin, createMetadataDescriptionColumn, createNameColumn, createOwnerColumn, createSpecLifecycleColumn, createSpecTypeColumn, createSystemColumn, createTagsColumn, hasCatalogProcessingErrors, isComponentType, isKind, isNamespace, isOrphan, catalogPlugin as plugin };
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AboutCard, a as AboutContent, b as AboutField, c as CatalogClientWrapper, e as CatalogEntityPage, f as CatalogIndexPage, q as CatalogKindHeader, r as CatalogResultListItem, d as CatalogTable, E as EntityAboutCard, h as EntityDependencyOfComponentsCard, i as EntityDependsOnComponentsCard, j as EntityDependsOnResourcesCard, k as EntityHasComponentsCard, l as EntityHasResourcesCard, m as EntityHasSubcomponentsCard, n as EntityHasSystemsCard, z as EntityLayout, o as EntityLinksCard,
|
|
1
|
+
export { A as AboutCard, a as AboutContent, b as AboutField, c as CatalogClientWrapper, e as CatalogEntityPage, f as CatalogIndexPage, q as CatalogKindHeader, r as CatalogResultListItem, d as CatalogTable, E as EntityAboutCard, h as EntityDependencyOfComponentsCard, i as EntityDependsOnComponentsCard, j as EntityDependsOnResourcesCard, k as EntityHasComponentsCard, l as EntityHasResourcesCard, m as EntityHasSubcomponentsCard, n as EntityHasSystemsCard, z as EntityLayout, o as EntityLinksCard, P as EntityListContainer, B as EntityOrphanWarning, I as EntityPageLayout, G as EntityProcessingErrorsPanel, J as EntitySwitch, p as EntitySystemDiagramCard, O as FilterContainer, N as FilteredEntityLayout, R as Router, g as catalogPlugin, x as createMetadataDescriptionColumn, s as createNameColumn, u as createOwnerColumn, w as createSpecLifecycleColumn, v as createSpecTypeColumn, t as createSystemColumn, y as createTagsColumn, H as hasCatalogProcessingErrors, M as isComponentType, K as isKind, L as isNamespace, F as isOrphan, g as plugin } from './esm/index-948ef81a.esm.js';
|
|
2
2
|
import '@backstage/catalog-model';
|
|
3
3
|
import '@backstage/core-components';
|
|
4
4
|
import '@backstage/core-plugin-api';
|
|
@@ -18,7 +18,7 @@ import '@material-ui/icons/Cancel';
|
|
|
18
18
|
import '@material-ui/icons/MoreVert';
|
|
19
19
|
import '@backstage/errors';
|
|
20
20
|
import '@backstage/catalog-client';
|
|
21
|
-
import 'react-use';
|
|
21
|
+
import 'react-use/lib/useAsync';
|
|
22
22
|
import 'react-helmet';
|
|
23
23
|
import '@material-ui/icons/FilterList';
|
|
24
24
|
import './components/EntityNotFound/Illo/illo.svg';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-catalog",
|
|
3
3
|
"description": "The Backstage plugin for browsing the Backstage catalog",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.9-next.0",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"clean": "backstage-cli clean"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@backstage/catalog-client": "^0.5.
|
|
35
|
-
"@backstage/catalog-model": "^0.9.
|
|
36
|
-
"@backstage/core-components": "^0.8.
|
|
37
|
-
"@backstage/core-plugin-api": "^0.
|
|
38
|
-
"@backstage/errors": "^0.
|
|
39
|
-
"@backstage/integration-react": "^0.1.
|
|
40
|
-
"@backstage/plugin-catalog-react": "^0.6.
|
|
34
|
+
"@backstage/catalog-client": "^0.5.5-next.0",
|
|
35
|
+
"@backstage/catalog-model": "^0.9.10-next.0",
|
|
36
|
+
"@backstage/core-components": "^0.8.5-next.0",
|
|
37
|
+
"@backstage/core-plugin-api": "^0.6.0-next.0",
|
|
38
|
+
"@backstage/errors": "^0.2.0",
|
|
39
|
+
"@backstage/integration-react": "^0.1.19-next.0",
|
|
40
|
+
"@backstage/plugin-catalog-react": "^0.6.12-next.0",
|
|
41
41
|
"@backstage/theme": "^0.2.14",
|
|
42
42
|
"@material-ui/core": "^4.12.2",
|
|
43
43
|
"@material-ui/icons": "^4.9.1",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"react": "^16.13.1 || ^17.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@backstage/cli": "^0.
|
|
57
|
-
"@backstage/core-app-api": "^0.
|
|
58
|
-
"@backstage/dev-utils": "^0.2.
|
|
59
|
-
"@backstage/test-utils": "^0.2.0",
|
|
56
|
+
"@backstage/cli": "^0.12.0-next.0",
|
|
57
|
+
"@backstage/core-app-api": "^0.5.0-next.0",
|
|
58
|
+
"@backstage/dev-utils": "^0.2.18-next.0",
|
|
59
|
+
"@backstage/test-utils": "^0.2.3-next.0",
|
|
60
60
|
"@testing-library/jest-dom": "^5.10.1",
|
|
61
61
|
"@testing-library/react": "^11.2.5",
|
|
62
62
|
"@testing-library/user-event": "^13.1.8",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"files": [
|
|
67
67
|
"dist"
|
|
68
68
|
],
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "31184691d5a38cb78b091c8f7ad6db80604519a6"
|
|
70
70
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-00a86fa7.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-66d685f8.esm.js","sources":["../../src/CatalogClientWrapper.ts","../../src/routes.ts","../../src/components/AboutCard/AboutField.tsx","../../src/components/AboutCard/AboutContent.tsx","../../src/components/AboutCard/AboutCard.tsx","../../src/components/CatalogKindHeader/CatalogKindHeader.tsx","../../src/components/CatalogResultListItem/CatalogResultListItem.tsx","../../src/components/CatalogTable/columns.tsx","../../src/components/CatalogTable/CatalogTable.tsx","../../src/components/EntityContextMenu/EntityContextMenu.tsx","../../src/components/EntityLayout/EntityLayout.tsx","../../src/components/EntityOrphanWarning/DeleteEntityDialog.tsx","../../src/components/EntityOrphanWarning/EntityOrphanWarning.tsx","../../src/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.tsx","../../src/components/EntityPageLayout/Tabbed/Tabbed.tsx","../../src/components/EntityPageLayout/EntityPageLayout.tsx","../../src/components/EntitySwitch/EntitySwitch.tsx","../../src/components/EntitySwitch/conditions.ts","../../src/components/FilteredEntityLayout/FilteredEntityLayout.tsx","../../src/components/FilteredEntityLayout/FilterContainer.tsx","../../src/components/FilteredEntityLayout/EntityListContainer.tsx","../../src/components/CatalogPage/CatalogPage.tsx","../../src/components/EntityNotFound/Illo/Illo.tsx","../../src/components/EntityNotFound/EntityNotFound.tsx","../../src/components/Router.tsx","../../src/plugin.ts"],"sourcesContent":["/*\n * Copyright 2020 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, EntityName, Location } from '@backstage/catalog-model';\nimport {\n AddLocationRequest,\n AddLocationResponse,\n CatalogApi,\n CatalogClient,\n CatalogEntitiesRequest,\n CatalogListResponse,\n CatalogRequestOptions,\n CatalogEntityAncestorsRequest,\n CatalogEntityAncestorsResponse,\n} from '@backstage/catalog-client';\nimport { IdentityApi } from '@backstage/core-plugin-api';\n\n/**\n * CatalogClient wrapper that injects identity token for all requests\n *\n * @deprecated The default catalog client now uses the `fetchApiRef`\n * implementation, which in turn by default issues tokens just the same as this\n * class used to assist in doing. If you use a custom `fetchApiRef`\n * implementation that does NOT issue tokens, or use a custom `catalogApiRef`\n * implementation which does not use the default `fetchApiRef`, you can wrap\n * your catalog API in this class to get back the old behavior.\n */\nexport class CatalogClientWrapper implements CatalogApi {\n private readonly identityApi: IdentityApi;\n private readonly client: CatalogClient;\n\n constructor(options: { client: CatalogClient; identityApi: IdentityApi }) {\n this.client = options.client;\n this.identityApi = options.identityApi;\n }\n\n async getLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getLocationById(id, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async getEntities(\n request?: CatalogEntitiesRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogListResponse<Entity>> {\n return await this.client.getEntities(request, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async getEntityByName(\n compoundName: EntityName,\n options?: CatalogRequestOptions,\n ): Promise<Entity | undefined> {\n return await this.client.getEntityByName(compoundName, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async addLocation(\n request: AddLocationRequest,\n options?: CatalogRequestOptions,\n ): Promise<AddLocationResponse> {\n return await this.client.addLocation(request, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async getOriginLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getOriginLocationByEntity(entity, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async getLocationByEntity(\n entity: Entity,\n options?: CatalogRequestOptions,\n ): Promise<Location | undefined> {\n return await this.client.getLocationByEntity(entity, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async removeLocationById(\n id: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.removeLocationById(id, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async removeEntityByUid(\n uid: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.removeEntityByUid(uid, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async refreshEntity(\n entityRef: string,\n options?: CatalogRequestOptions,\n ): Promise<void> {\n return await this.client.refreshEntity(entityRef, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\n });\n }\n\n async getEntityAncestors(\n request: CatalogEntityAncestorsRequest,\n options?: CatalogRequestOptions,\n ): Promise<CatalogEntityAncestorsResponse> {\n return await this.client.getEntityAncestors(request, {\n token: options?.token ?? (await this.identityApi.getIdToken()),\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 { createExternalRouteRef } from '@backstage/core-plugin-api';\n\nexport const createComponentRouteRef = createExternalRouteRef({\n id: 'create-component',\n optional: true,\n});\n\nexport const viewTechDocRouteRef = createExternalRouteRef({\n id: 'view-techdoc',\n optional: true,\n params: ['namespace', 'kind', 'name'],\n});\n","/*\n * Copyright 2020 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 { useElementFilter } from '@backstage/core-plugin-api';\nimport { Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\n\nconst useStyles = makeStyles(theme => ({\n value: {\n fontWeight: 'bold',\n overflow: 'hidden',\n lineHeight: '24px',\n wordBreak: 'break-word',\n },\n label: {\n color: theme.palette.text.secondary,\n textTransform: 'uppercase',\n fontSize: '10px',\n fontWeight: 'bold',\n letterSpacing: 0.5,\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n },\n}));\n\ntype Props = {\n label: string;\n value?: string;\n gridSizes?: Record<string, number>;\n children?: React.ReactNode;\n};\n\nexport const AboutField = ({ label, value, gridSizes, children }: Props) => {\n const classes = useStyles();\n\n const childElements = useElementFilter(children, c => c.getElements());\n\n // Content is either children or a string prop `value`\n const content =\n childElements.length > 0 ? (\n childElements\n ) : (\n <Typography variant=\"body2\" className={classes.value}>\n {value || `unknown`}\n </Typography>\n );\n return (\n <Grid item {...gridSizes}>\n <Typography variant=\"subtitle2\" className={classes.label}>\n {label}\n </Typography>\n {content}\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n RELATION_OWNED_BY,\n RELATION_PART_OF,\n} from '@backstage/catalog-model';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { Chip, Grid, makeStyles, Typography } from '@material-ui/core';\nimport React from 'react';\nimport { AboutField } from './AboutField';\n\nconst useStyles = makeStyles({\n description: {\n wordBreak: 'break-word',\n },\n});\n\ntype Props = {\n entity: Entity;\n};\n\nexport const AboutContent = ({ entity }: Props) => {\n const classes = useStyles();\n const isSystem = entity.kind.toLocaleLowerCase('en-US') === 'system';\n const isResource = entity.kind.toLocaleLowerCase('en-US') === 'resource';\n const isComponent = entity.kind.toLocaleLowerCase('en-US') === 'component';\n const isAPI = entity.kind.toLocaleLowerCase('en-US') === 'api';\n const isTemplate = entity.kind.toLocaleLowerCase('en-US') === 'template';\n const isLocation = entity.kind.toLocaleLowerCase('en-US') === 'location';\n const isGroup = entity.kind.toLocaleLowerCase('en-US') === 'group';\n\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const partOfComponentRelations = getEntityRelations(\n entity,\n RELATION_PART_OF,\n {\n kind: 'component',\n },\n );\n const partOfDomainRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'domain',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return (\n <Grid container>\n <AboutField label=\"Description\" gridSizes={{ xs: 12 }}>\n <Typography variant=\"body2\" paragraph className={classes.description}>\n {entity?.metadata?.description || 'No description'}\n </Typography>\n </AboutField>\n <AboutField\n label=\"Owner\"\n value=\"No Owner\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {ownedByRelations.length > 0 && (\n <EntityRefLinks entityRefs={ownedByRelations} defaultKind=\"group\" />\n )}\n </AboutField>\n {(isSystem || partOfDomainRelations.length > 0) && (\n <AboutField\n label=\"Domain\"\n value=\"No Domain\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {partOfDomainRelations.length > 0 && (\n <EntityRefLinks\n entityRefs={partOfDomainRelations}\n defaultKind=\"domain\"\n />\n )}\n </AboutField>\n )}\n {(isAPI ||\n isComponent ||\n isResource ||\n partOfSystemRelations.length > 0) && (\n <AboutField\n label=\"System\"\n value=\"No System\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {partOfSystemRelations.length > 0 && (\n <EntityRefLinks\n entityRefs={partOfSystemRelations}\n defaultKind=\"system\"\n />\n )}\n </AboutField>\n )}\n {isComponent && partOfComponentRelations.length > 0 && (\n <AboutField\n label=\"Parent Component\"\n value=\"No Parent Component\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n <EntityRefLinks\n entityRefs={partOfComponentRelations}\n defaultKind=\"component\"\n />\n </AboutField>\n )}\n {(isAPI ||\n isComponent ||\n isResource ||\n isTemplate ||\n isGroup ||\n isLocation ||\n typeof entity?.spec?.type === 'string') && (\n <AboutField\n label=\"Type\"\n value={entity?.spec?.type as string}\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n />\n )}\n {(isAPI ||\n isComponent ||\n typeof entity?.spec?.lifecycle === 'string') && (\n <AboutField\n label=\"Lifecycle\"\n value={entity?.spec?.lifecycle as string}\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n />\n )}\n <AboutField\n label=\"Tags\"\n value=\"No Tags\"\n gridSizes={{ xs: 12, sm: 6, lg: 4 }}\n >\n {(entity?.metadata?.tags || []).map(t => (\n <Chip key={t} size=\"small\" label={t} />\n ))}\n </AboutField>\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n LOCATION_ANNOTATION,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport {\n HeaderIconLinkRow,\n IconLinkVerticalProps,\n InfoCardVariants,\n Link,\n} from '@backstage/core-components';\nimport { alertApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n ScmIntegrationIcon,\n scmIntegrationsApiRef,\n} from '@backstage/integration-react';\nimport {\n catalogApiRef,\n getEntityMetadataEditUrl,\n getEntitySourceLocation,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport {\n Card,\n CardContent,\n CardHeader,\n Divider,\n IconButton,\n makeStyles,\n} from '@material-ui/core';\nimport CachedIcon from '@material-ui/icons/Cached';\nimport DocsIcon from '@material-ui/icons/Description';\nimport EditIcon from '@material-ui/icons/Edit';\nimport React, { useCallback } from 'react';\nimport { viewTechDocRouteRef } from '../../routes';\nimport { AboutContent } from './AboutContent';\n\nconst useStyles = makeStyles({\n gridItemCard: {\n display: 'flex',\n flexDirection: 'column',\n height: 'calc(100% - 10px)', // for pages without content header\n marginBottom: '10px',\n },\n fullHeightCard: {\n display: 'flex',\n flexDirection: 'column',\n height: '100%',\n },\n gridItemCardContent: {\n flex: 1,\n },\n fullHeightCardContent: {\n flex: 1,\n },\n});\n\ntype AboutCardProps = {\n /** @deprecated The entity is now grabbed from context instead */\n entity?: Entity;\n variant?: InfoCardVariants;\n};\n\nexport function AboutCard({ variant }: AboutCardProps) {\n const classes = useStyles();\n const { entity } = useEntity();\n const scmIntegrationsApi = useApi(scmIntegrationsApiRef);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n const viewTechdocLink = useRouteRef(viewTechDocRouteRef);\n\n const entitySourceLocation = getEntitySourceLocation(\n entity,\n scmIntegrationsApi,\n );\n const entityMetadataEditUrl = getEntityMetadataEditUrl(entity);\n\n const viewInSource: IconLinkVerticalProps = {\n label: 'View Source',\n disabled: !entitySourceLocation,\n icon: <ScmIntegrationIcon type={entitySourceLocation?.integrationType} />,\n href: entitySourceLocation?.locationTargetUrl,\n };\n const viewInTechDocs: IconLinkVerticalProps = {\n label: 'View TechDocs',\n disabled:\n !entity.metadata.annotations?.['backstage.io/techdocs-ref'] ||\n !viewTechdocLink,\n icon: <DocsIcon />,\n href:\n viewTechdocLink &&\n viewTechdocLink({\n namespace: entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE,\n kind: entity.kind,\n name: entity.metadata.name,\n }),\n };\n\n let cardClass = '';\n if (variant === 'gridItem') {\n cardClass = classes.gridItemCard;\n } else if (variant === 'fullHeight') {\n cardClass = classes.fullHeightCard;\n }\n\n let cardContentClass = '';\n if (variant === 'gridItem') {\n cardContentClass = classes.gridItemCardContent;\n } else if (variant === 'fullHeight') {\n cardContentClass = classes.fullHeightCardContent;\n }\n\n const isUrl =\n entity.metadata.annotations?.[LOCATION_ANNOTATION]?.startsWith('url:');\n const refreshEntity = useCallback(async () => {\n await catalogApi.refreshEntity(stringifyEntityRef(entity));\n alertApi.post({ message: 'Refresh scheduled', severity: 'info' });\n }, [catalogApi, alertApi, entity]);\n\n return (\n <Card className={cardClass}>\n <CardHeader\n title=\"About\"\n action={\n <>\n {isUrl && (\n <IconButton\n aria-label=\"Refresh\"\n title=\"Schedule entity refresh\"\n onClick={refreshEntity}\n >\n <CachedIcon />\n </IconButton>\n )}\n <IconButton\n component={Link}\n aria-label=\"Edit\"\n disabled={!entityMetadataEditUrl}\n title=\"Edit Metadata\"\n to={entityMetadataEditUrl ?? '#'}\n >\n <EditIcon />\n </IconButton>\n </>\n }\n subheader={<HeaderIconLinkRow links={[viewInSource, viewInTechDocs]} />}\n />\n <Divider />\n <CardContent className={cardContentClass}>\n <AboutContent entity={entity} />\n </CardContent>\n </Card>\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 React, { useEffect, useState } from 'react';\nimport {\n capitalize,\n createStyles,\n InputBase,\n makeStyles,\n MenuItem,\n Select,\n Theme,\n} from '@material-ui/core';\nimport {\n EntityKindFilter,\n useEntityKinds,\n useEntityListProvider,\n} from '@backstage/plugin-catalog-react';\n\nconst useStyles = makeStyles((theme: Theme) =>\n createStyles({\n root: {\n ...theme.typography.h4,\n },\n }),\n);\n\ntype CatalogKindHeaderProps = {\n initialFilter?: string;\n};\n\nexport const CatalogKindHeader = ({\n initialFilter = 'component',\n}: CatalogKindHeaderProps) => {\n const classes = useStyles();\n const { kinds: allKinds = [] } = useEntityKinds();\n const { updateFilters, queryParameters } = useEntityListProvider();\n\n const [selectedKind, setSelectedKind] = useState(\n ([queryParameters.kind].flat()[0] ?? initialFilter).toLocaleLowerCase(\n 'en-US',\n ),\n );\n\n useEffect(() => {\n updateFilters({\n kind: selectedKind ? new EntityKindFilter(selectedKind) : undefined,\n });\n }, [selectedKind, updateFilters]);\n\n // Before allKinds is loaded, or when a kind is entered manually in the URL, selectedKind may not\n // be present in allKinds. It should still be shown in the dropdown, but may not have the nice\n // enforced casing from the catalog-backend. This makes a key/value record for the Select options,\n // including selectedKind if it's unknown - but allows the selectedKind to get clobbered by the\n // more proper catalog kind if it exists.\n const options = [capitalize(selectedKind)]\n .concat(allKinds)\n .sort()\n .reduce((acc, kind) => {\n acc[kind.toLocaleLowerCase('en-US')] = kind;\n return acc;\n }, {} as Record<string, string>);\n\n return (\n <Select\n input={<InputBase value={selectedKind} />}\n value={selectedKind}\n onChange={e => setSelectedKind(e.target.value as string)}\n classes={classes}\n >\n {Object.keys(options).map(kind => (\n <MenuItem value={kind} key={kind}>\n {`${options[kind]}s`}\n </MenuItem>\n ))}\n </Select>\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 React from 'react';\nimport {\n Box,\n Chip,\n Divider,\n ListItem,\n ListItemText,\n makeStyles,\n} from '@material-ui/core';\nimport { Link } from '@backstage/core-components';\n\nconst useStyles = makeStyles({\n flexContainer: {\n flexWrap: 'wrap',\n },\n itemText: {\n width: '100%',\n marginBottom: '1rem',\n },\n});\n\nexport const CatalogResultListItem = ({ result }: any) => {\n const classes = useStyles();\n return (\n <Link to={result.location}>\n <ListItem alignItems=\"flex-start\" className={classes.flexContainer}>\n <ListItemText\n className={classes.itemText}\n primaryTypographyProps={{ variant: 'h6' }}\n primary={result.title}\n secondary={result.text}\n />\n <Box>\n {result.kind && <Chip label={`Kind: ${result.kind}`} size=\"small\" />}\n {result.lifecycle && (\n <Chip label={`Lifecycle: ${result.lifecycle}`} size=\"small\" />\n )}\n </Box>\n </ListItem>\n <Divider component=\"li\" />\n </Link>\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 */\nimport React from 'react';\nimport {\n formatEntityRefTitle,\n EntityRefLink,\n EntityRefLinks,\n} from '@backstage/plugin-catalog-react';\nimport { Chip } from '@material-ui/core';\nimport { EntityRow } from './types';\nimport { OverflowTooltip, TableColumn } from '@backstage/core-components';\nimport { Entity } from '@backstage/catalog-model';\n\ntype NameColumnProps = {\n defaultKind?: string;\n};\n\nexport function createNameColumn(\n props?: NameColumnProps,\n): TableColumn<EntityRow> {\n function formatContent(entity: Entity): string {\n return (\n entity.metadata?.title ||\n formatEntityRefTitle(entity, {\n defaultKind: props?.defaultKind,\n })\n );\n }\n\n return {\n title: 'Name',\n field: 'resolved.name',\n highlight: true,\n customSort({ entity: entity1 }, { entity: entity2 }) {\n // TODO: We could implement this more efficiently by comparing field by field.\n // This has similar issues as above.\n return formatContent(entity1).localeCompare(formatContent(entity2));\n },\n render: ({ entity }) => (\n <EntityRefLink\n entityRef={entity}\n defaultKind={props?.defaultKind || 'Component'}\n title={entity.metadata?.title}\n />\n ),\n };\n}\n\nexport function createSystemColumn(): TableColumn<EntityRow> {\n return {\n title: 'System',\n field: 'resolved.partOfSystemRelationTitle',\n render: ({ resolved }) => (\n <EntityRefLinks\n entityRefs={resolved.partOfSystemRelations}\n defaultKind=\"system\"\n />\n ),\n };\n}\n\nexport function createOwnerColumn(): TableColumn<EntityRow> {\n return {\n title: 'Owner',\n field: 'resolved.ownedByRelationsTitle',\n render: ({ resolved }) => (\n <EntityRefLinks\n entityRefs={resolved.ownedByRelations}\n defaultKind=\"group\"\n />\n ),\n };\n}\n\nexport function createSpecTypeColumn(): TableColumn<EntityRow> {\n return {\n title: 'Type',\n field: 'entity.spec.type',\n hidden: true,\n };\n}\n\nexport function createSpecLifecycleColumn(): TableColumn<EntityRow> {\n return {\n title: 'Lifecycle',\n field: 'entity.spec.lifecycle',\n };\n}\n\nexport function createMetadataDescriptionColumn(): TableColumn<EntityRow> {\n return {\n title: 'Description',\n field: 'entity.metadata.description',\n render: ({ entity }) => (\n <OverflowTooltip\n text={entity.metadata.description}\n placement=\"bottom-start\"\n />\n ),\n width: 'auto',\n };\n}\n\nexport function createTagsColumn(): TableColumn<EntityRow> {\n return {\n title: 'Tags',\n field: 'entity.metadata.tags',\n cellStyle: {\n padding: '0px 16px 0px 20px',\n },\n render: ({ entity }) => (\n <>\n {entity.metadata.tags &&\n entity.metadata.tags.map(t => (\n <Chip\n key={t}\n label={t}\n size=\"small\"\n variant=\"outlined\"\n style={{ marginBottom: '0px' }}\n />\n ))}\n </>\n ),\n };\n}\n","/*\n * Copyright 2020 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 { RELATION_OWNED_BY, RELATION_PART_OF } from '@backstage/catalog-model';\nimport {\n favoriteEntityIcon,\n favoriteEntityTooltip,\n formatEntityRefTitle,\n getEntityMetadataEditUrl,\n getEntityMetadataViewUrl,\n getEntityRelations,\n useEntityListProvider,\n useStarredEntities,\n} from '@backstage/plugin-catalog-react';\nimport Edit from '@material-ui/icons/Edit';\nimport OpenInNew from '@material-ui/icons/OpenInNew';\nimport { capitalize } from 'lodash';\nimport React, { useMemo } from 'react';\nimport * as columnFactories from './columns';\nimport { EntityRow } from './types';\nimport {\n CodeSnippet,\n Table,\n TableColumn,\n TableProps,\n WarningPanel,\n} from '@backstage/core-components';\n\ntype CatalogTableProps = {\n columns?: TableColumn<EntityRow>[];\n actions?: TableProps<EntityRow>['actions'];\n};\n\nexport const CatalogTable = ({ columns, actions }: CatalogTableProps) => {\n const { isStarredEntity, toggleStarredEntity } = useStarredEntities();\n const { loading, error, entities, filters } = useEntityListProvider();\n\n const defaultColumns: TableColumn<EntityRow>[] = useMemo(\n () => [\n columnFactories.createNameColumn({ defaultKind: filters.kind?.value }),\n columnFactories.createSystemColumn(),\n columnFactories.createOwnerColumn(),\n columnFactories.createSpecTypeColumn(),\n columnFactories.createSpecLifecycleColumn(),\n columnFactories.createMetadataDescriptionColumn(),\n columnFactories.createTagsColumn(),\n ],\n [filters.kind?.value],\n );\n\n const showTypeColumn = filters.type === undefined;\n // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar\n const titlePreamble = capitalize(filters.user?.value ?? 'all');\n\n if (error) {\n return (\n <div>\n <WarningPanel\n severity=\"error\"\n title=\"Could not fetch catalog entities.\"\n >\n <CodeSnippet language=\"text\" text={error.toString()} />\n </WarningPanel>\n </div>\n );\n }\n\n const defaultActions: TableProps<EntityRow>['actions'] = [\n ({ entity }) => {\n const url = getEntityMetadataViewUrl(entity);\n return {\n icon: () => <OpenInNew aria-label=\"View\" fontSize=\"small\" />,\n tooltip: 'View',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const url = getEntityMetadataEditUrl(entity);\n return {\n icon: () => <Edit aria-label=\"Edit\" fontSize=\"small\" />,\n tooltip: 'Edit',\n disabled: !url,\n onClick: () => {\n if (!url) return;\n window.open(url, '_blank');\n },\n };\n },\n ({ entity }) => {\n const isStarred = isStarredEntity(entity);\n return {\n cellStyle: { paddingLeft: '1em' },\n icon: () => favoriteEntityIcon(isStarred),\n tooltip: favoriteEntityTooltip(isStarred),\n onClick: () => toggleStarredEntity(entity),\n };\n },\n ];\n\n const rows = entities.map(entity => {\n const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'system',\n });\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n\n return {\n entity,\n resolved: {\n name: formatEntityRefTitle(entity, {\n defaultKind: 'Component',\n }),\n ownedByRelationsTitle: ownedByRelations\n .map(r => formatEntityRefTitle(r, { defaultKind: 'group' }))\n .join(', '),\n ownedByRelations,\n partOfSystemRelationTitle: partOfSystemRelations\n .map(r =>\n formatEntityRefTitle(r, {\n defaultKind: 'system',\n }),\n )\n .join(', '),\n partOfSystemRelations,\n },\n };\n });\n\n const typeColumn = (columns || defaultColumns).find(c => c.title === 'Type');\n if (typeColumn) {\n typeColumn.hidden = !showTypeColumn;\n }\n const showPagination = rows.length > 20;\n\n return (\n <Table<EntityRow>\n isLoading={loading}\n columns={columns || defaultColumns}\n options={{\n paging: showPagination,\n pageSize: 20,\n actionsColumnIndex: -1,\n loadingType: 'linear',\n showEmptyDataSourceMessage: !loading,\n padding: 'dense',\n pageSizeOptions: [20, 50, 100],\n }}\n title={`${titlePreamble} (${entities.length})`}\n data={rows}\n actions={actions || defaultActions}\n />\n );\n};\n\nCatalogTable.columns = columnFactories;\n","/*\n * Copyright 2020 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 {\n Divider,\n IconButton,\n ListItemIcon,\n ListItemText,\n MenuItem,\n MenuList,\n Popover,\n} from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport Cancel from '@material-ui/icons/Cancel';\nimport MoreVert from '@material-ui/icons/MoreVert';\nimport React, { useState } from 'react';\nimport { IconComponent } from '@backstage/core-plugin-api';\n\n// TODO(freben): It should probably instead be the case that Header sets the theme text color to white inside itself unconditionally instead\nconst useStyles = makeStyles({\n button: {\n color: 'white',\n },\n});\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype Props = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n onUnregisterEntity: () => void;\n};\n\nexport const EntityContextMenu = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n onUnregisterEntity,\n}: Props) => {\n const [anchorEl, setAnchorEl] = useState<HTMLButtonElement>();\n const classes = useStyles();\n\n const onOpen = (event: React.SyntheticEvent<HTMLButtonElement>) => {\n setAnchorEl(event.currentTarget);\n };\n\n const onClose = () => {\n setAnchorEl(undefined);\n };\n\n const extraItems = UNSTABLE_extraContextMenuItems && [\n ...UNSTABLE_extraContextMenuItems.map(item => (\n <MenuItem\n key={item.title}\n onClick={() => {\n onClose();\n item.onClick();\n }}\n >\n <ListItemIcon>\n <item.Icon fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary={item.title} />\n </MenuItem>\n )),\n <Divider key=\"the divider is here!\" />,\n ];\n\n const disableUnregister =\n UNSTABLE_contextMenuOptions?.disableUnregister ?? false;\n\n return (\n <>\n <IconButton\n aria-label=\"more\"\n aria-controls=\"long-menu\"\n aria-haspopup=\"true\"\n onClick={onOpen}\n data-testid=\"menu-button\"\n className={classes.button}\n >\n <MoreVert />\n </IconButton>\n <Popover\n open={Boolean(anchorEl)}\n onClose={onClose}\n anchorEl={anchorEl}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n transformOrigin={{ vertical: 'top', horizontal: 'right' }}\n >\n <MenuList>\n {extraItems}\n <MenuItem\n onClick={() => {\n onClose();\n onUnregisterEntity();\n }}\n disabled={disableUnregister}\n >\n <ListItemIcon>\n <Cancel fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText primary=\"Unregister entity\" />\n </MenuItem>\n </MenuList>\n </Popover>\n </>\n );\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n RoutedTabs,\n WarningPanel,\n} from '@backstage/core-components';\nimport {\n attachComponentData,\n IconComponent,\n useElementFilter,\n} from '@backstage/core-plugin-api';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box, TabProps } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\n\ntype SubRoute = {\n path: string;\n title: string;\n children: JSX.Element;\n if?: (entity: Entity) => boolean;\n tabProps?: TabProps<React.ElementType, { component?: React.ElementType }>;\n};\n\nconst dataKey = 'plugin.catalog.entityLayoutRoute';\n\nconst Route: (props: SubRoute) => null = () => null;\nattachComponentData(Route, dataKey, true);\n\n// This causes all mount points that are discovered within this route to use the path of the route itself\nattachComponentData(Route, 'core.gatherMountPoints', true);\n\nconst EntityLayoutTitle = ({\n entity,\n title,\n}: {\n title: string;\n entity: Entity | undefined;\n}) => {\n return (\n <Box display=\"inline-flex\" alignItems=\"center\" height=\"1em\" maxWidth=\"100%\">\n <Box\n component=\"span\"\n textOverflow=\"ellipsis\"\n whiteSpace=\"nowrap\"\n overflow=\"hidden\"\n >\n {title}\n </Box>\n {entity && <FavoriteEntity entity={entity} />}\n </Box>\n );\n};\n\nconst headerProps = (\n paramKind: string | undefined,\n paramNamespace: string | undefined,\n paramName: string | undefined,\n entity: Entity | undefined,\n): { headerTitle: string; headerType: string } => {\n const kind = paramKind ?? entity?.kind ?? '';\n const namespace = paramNamespace ?? entity?.metadata.namespace ?? '';\n const name =\n entity?.metadata.title ?? paramName ?? entity?.metadata.name ?? '';\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec as { type: string }).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\nconst EntityLabels = ({ entity }: { entity: Entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label=\"Owner\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel label=\"Lifecycle\" value={entity.spec.lifecycle} />\n )}\n </>\n );\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype EntityLayoutProps = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n children?: React.ReactNode;\n};\n\n/**\n * EntityLayout is a compound component, which allows you to define a layout for\n * entities using a sub-navigation mechanism.\n *\n * Consists of two parts: EntityLayout and EntityLayout.Route\n *\n * @example\n * ```jsx\n * <EntityLayout>\n * <EntityLayout.Route path=\"/example\" title=\"Example tab\">\n * <div>This is rendered under /example/anything-here route</div>\n * </EntityLayout.Route>\n * </EntityLayout>\n * ```\n */\nexport const EntityLayout = ({\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n children,\n}: EntityLayoutProps) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const routes = useElementFilter(\n children,\n elements =>\n elements\n .selectByComponentData({\n key: dataKey,\n withStrictError:\n 'Child of EntityLayout must be an EntityLayout.Route',\n })\n .getElements<SubRoute>() // all nodes, element data, maintain structure or not?\n .flatMap(({ props }) => {\n if (props.if && entity && !props.if(entity)) {\n return [];\n }\n\n return [\n {\n path: props.path,\n title: props.title,\n children: props.children,\n tabProps: props.tabProps,\n },\n ];\n }),\n [entity],\n );\n\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n <Page themeId={entity?.spec?.type?.toString() ?? 'home'}>\n <Header\n title={<EntityLayoutTitle title={headerTitle} entity={entity!} />}\n pageTitleOverride={headerTitle}\n type={headerType}\n >\n {entity && (\n <>\n <EntityLabels entity={entity} />\n <EntityContextMenu\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n onUnregisterEntity={showRemovalDialog}\n />\n </>\n )}\n </Header>\n\n {loading && <Progress />}\n\n {entity && <RoutedTabs routes={routes} />}\n\n {error && (\n <Content>\n <Alert severity=\"error\">{error.toString()}</Alert>\n </Content>\n )}\n\n {!loading && !error && !entity && (\n <Content>\n <WarningPanel title=\"Entity not found\">\n There is no {kind} with the requested{' '}\n <Link to=\"https://backstage.io/docs/features/software-catalog/references\">\n kind, namespace, and name\n </Link>\n .\n </WarningPanel>\n </Content>\n )}\n\n <UnregisterEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\n </Page>\n );\n};\n\nEntityLayout.Route = Route;\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 { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core';\nimport React, { useState } from 'react';\nimport { alertApiRef, useApi } from '@backstage/core-plugin-api';\nimport { assertError } from '@backstage/errors';\n\ntype Props = {\n open: boolean;\n onClose: () => any;\n onConfirm: () => any;\n entity: Entity;\n};\n\nexport const DeleteEntityDialog = ({\n open,\n onClose,\n onConfirm,\n entity,\n}: Props) => {\n const [busy, setBusy] = useState(false);\n const catalogApi = useApi(catalogApiRef);\n const alertApi = useApi(alertApiRef);\n\n const onDelete = async () => {\n setBusy(true);\n try {\n const uid = entity.metadata.uid;\n await catalogApi.removeEntityByUid(uid!);\n onConfirm();\n } catch (err) {\n assertError(err);\n alertApi.post({ message: err.message });\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={onClose}>\n <DialogTitle id=\"responsive-dialog-title\">\n Are you sure you want to delete this entity?\n </DialogTitle>\n <DialogActions>\n <Button\n variant=\"contained\"\n color=\"secondary\"\n disabled={busy}\n onClick={onDelete}\n >\n Delete\n </Button>\n <Button onClick={onClose} color=\"primary\">\n Cancel\n </Button>\n </DialogActions>\n </Dialog>\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 { catalogRouteRef, useEntity } from '@backstage/plugin-catalog-react';\nimport { Alert } from '@material-ui/lab';\nimport React, { useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { DeleteEntityDialog } from './DeleteEntityDialog';\nimport { useRouteRef } from '@backstage/core-plugin-api';\n\nexport const isOrphan = (entity: Entity) =>\n entity?.metadata?.annotations?.['backstage.io/orphan'] === 'true';\n\n/**\n * Displays a warning alert if the entity is marked as orphan with the ability to delete said entity.\n */\nexport const EntityOrphanWarning = () => {\n const navigate = useNavigate();\n const catalogLink = useRouteRef(catalogRouteRef);\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const { entity } = useEntity();\n\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate(catalogLink());\n };\n\n return (\n <>\n <Alert severity=\"warning\" onClick={() => setConfirmationDialogOpen(true)}>\n This entity is not referenced by any location and is therefore not\n receiving updates. Click here to delete.\n </Alert>\n <DeleteEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\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 {\n Entity,\n stringifyEntityRef,\n UNSTABLE_EntityStatusItem,\n compareEntityToRef,\n} from '@backstage/catalog-model';\nimport {\n catalogApiRef,\n EntityRefLink,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React from 'react';\nimport { ResponseErrorPanel } from '@backstage/core-components';\nimport {\n CatalogApi,\n ENTITY_STATUS_CATALOG_PROCESSING_TYPE,\n} from '@backstage/catalog-client';\nimport { useApi, ApiHolder } from '@backstage/core-plugin-api';\nimport { useAsync } from 'react-use';\nimport { SerializedError } from '@backstage/errors';\n\nconst errorFilter = (i: UNSTABLE_EntityStatusItem) =>\n i.error &&\n i.level === 'error' &&\n i.type === ENTITY_STATUS_CATALOG_PROCESSING_TYPE;\n\ntype GetOwnAndAncestorsErrorsResponse = {\n items: {\n errors: SerializedError[];\n entity: Entity;\n }[];\n};\n\nasync function getOwnAndAncestorsErrors(\n entityRef: string,\n catalogApi: CatalogApi,\n): Promise<GetOwnAndAncestorsErrorsResponse> {\n const ancestors = await catalogApi.getEntityAncestors({ entityRef });\n const items = ancestors.items\n .map(item => {\n const statuses = item.entity.status?.items ?? [];\n const errors = statuses\n .filter(errorFilter)\n .map(e => e.error)\n .filter((e): e is SerializedError => Boolean(e));\n return { errors: errors, entity: item.entity };\n })\n .filter(item => item.errors.length > 0);\n return { items };\n}\n\nexport const hasCatalogProcessingErrors = async (\n entity: Entity,\n context: { apis: ApiHolder },\n) => {\n const catalogApi = context.apis.get(catalogApiRef);\n if (!catalogApi) {\n throw new Error(`No implementation available for ${catalogApiRef}`);\n }\n\n const errors = await getOwnAndAncestorsErrors(\n stringifyEntityRef(entity),\n catalogApi,\n );\n return errors.items.length > 0;\n};\n\n/**\n * Displays a list of errors from the ancestors of the current entity.\n */\nexport const EntityProcessingErrorsPanel = () => {\n const { entity } = useEntity();\n const entityRef = stringifyEntityRef(entity);\n const catalogApi = useApi(catalogApiRef);\n const { loading, error, value } = useAsync(async () => {\n return getOwnAndAncestorsErrors(entityRef, catalogApi);\n }, [entityRef, catalogApi]);\n\n if (error) {\n return (\n <Box mb={1}>\n <ResponseErrorPanel error={error} />\n </Box>\n );\n }\n\n if (loading || !value) {\n return null;\n }\n\n return (\n <>\n {value.items.map((ancestorError, index) => (\n <Box key={index} mb={1}>\n {!compareEntityToRef(\n entity,\n stringifyEntityRef(ancestorError.entity),\n ) && (\n <Box p={1}>\n The error below originates from{' '}\n <EntityRefLink entityRef={ancestorError.entity} />\n </Box>\n )}\n {ancestorError.errors.map((e, i) => (\n <ResponseErrorPanel key={i} error={e} />\n ))}\n </Box>\n ))}\n </>\n );\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport {\n useParams,\n useNavigate,\n PartialRouteObject,\n matchRoutes,\n RouteObject,\n useRoutes,\n Navigate,\n RouteMatch,\n} from 'react-router';\nimport { Helmet } from 'react-helmet';\nimport { Tab, HeaderTabs, Content } from '@backstage/core-components';\n\nconst getSelectedIndexOrDefault = (\n matchedRoute: RouteMatch,\n tabs: Tab[],\n defaultIndex = 0,\n) => {\n if (!matchedRoute) return defaultIndex;\n const tabIndex = tabs.findIndex(t => t.id === matchedRoute.route.path);\n return ~tabIndex ? tabIndex : defaultIndex;\n};\n\n/**\n * Compound component, which allows you to define layout\n * for EntityPage using Tabs as a sub-navigation mechanism\n * Consists of 2 parts: Tabbed.Layout and Tabbed.Content.\n * Takes care of: tabs, routes, document titles, spacing around content\n *\n * @example\n * ```jsx\n * <Tabbed.Layout>\n * <Tabbed.Content\n * title=\"Example tab\"\n * route=\"/example/*\"\n * element={<div>This is rendered under /example/anything-here route</div>}\n * />\n * </TabbedLayout>\n * ```\n */\nexport const Tabbed = {\n Layout: ({ children }: { children: React.ReactNode }) => {\n const routes: PartialRouteObject[] = [];\n const tabs: Tab[] = [];\n const params = useParams();\n const navigate = useNavigate();\n\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) {\n // Skip conditionals resolved to falses/nulls/undefineds etc\n return;\n }\n if (child.type !== Tabbed.Content) {\n throw new Error(\n 'This component only accepts Content elements as direct children. Check the code of the EntityPage.',\n );\n }\n const pathAndId = (child as JSX.Element).props.path;\n\n // Child here must be then always a functional component without any wrappers\n tabs.push({\n id: pathAndId,\n label: (child as JSX.Element).props.title,\n });\n\n routes.push({\n path: pathAndId,\n element: child.props.element,\n });\n });\n\n // Add catch-all for incorrect sub-routes\n if ((routes?.[0]?.path ?? '') !== '')\n routes.push({\n path: '/*',\n element: <Navigate to={routes[0].path!} />,\n });\n\n const [matchedRoute] =\n matchRoutes(routes as RouteObject[], `/${params['*']}`) ?? [];\n const selectedIndex = getSelectedIndexOrDefault(matchedRoute, tabs);\n const currentTab = tabs[selectedIndex];\n const title = currentTab?.label;\n\n const onTabChange = (index: number) =>\n // Remove trailing /*\n // And remove leading / for relative navigation\n // Note! route resolves relative to the position in the React tree,\n // not relative to current location\n navigate(tabs[index].id.replace(/\\/\\*$/, '').replace(/^\\//, ''));\n\n const currentRouteElement = useRoutes(routes);\n\n if (!currentTab) return null;\n return (\n <>\n <HeaderTabs\n tabs={tabs}\n selectedIndex={selectedIndex}\n onChange={onTabChange}\n />\n <Content>\n <Helmet title={title} />\n {currentRouteElement}\n </Content>\n </>\n );\n },\n Content: (_props: { path: string; title: string; element: JSX.Element }) =>\n null,\n};\n","/*\n * Copyright 2020 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 {\n Entity,\n ENTITY_DEFAULT_NAMESPACE,\n RELATION_OWNED_BY,\n} from '@backstage/catalog-model';\nimport {\n EntityContext,\n EntityRefLinks,\n FavoriteEntity,\n getEntityRelations,\n UnregisterEntityDialog,\n useEntityCompoundName,\n} from '@backstage/plugin-catalog-react';\nimport { Box } from '@material-ui/core';\nimport React, { useContext, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { EntityContextMenu } from '../EntityContextMenu/EntityContextMenu';\nimport { Tabbed } from './Tabbed';\n\nimport {\n Content,\n Header,\n HeaderLabel,\n Link,\n Page,\n Progress,\n ResponseErrorPanel,\n WarningPanel,\n} from '@backstage/core-components';\n\nimport { IconComponent } from '@backstage/core-plugin-api';\n\nconst EntityPageTitle = ({\n entity,\n title,\n}: {\n title: string;\n entity: Entity | undefined;\n}) => (\n <Box display=\"inline-flex\" alignItems=\"center\" height=\"1em\">\n {title}\n {entity && <FavoriteEntity entity={entity} />}\n </Box>\n);\n\nconst EntityLabels = ({ entity }: { entity: Entity }) => {\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label=\"Owner\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel label=\"Lifecycle\" value={entity.spec.lifecycle} />\n )}\n </>\n );\n};\n\nconst headerProps = (\n kind: string,\n namespace: string | undefined,\n name: string,\n entity: Entity | undefined,\n): { headerTitle: string; headerType: string } => {\n return {\n headerTitle: `${name}${\n namespace && namespace !== ENTITY_DEFAULT_NAMESPACE\n ? ` in ${namespace}`\n : ''\n }`,\n headerType: (() => {\n let t = kind.toLocaleLowerCase('en-US');\n if (entity && entity.spec && 'type' in entity.spec) {\n t += ' — ';\n t += (entity.spec as { type: string }).type.toLocaleLowerCase('en-US');\n }\n return t;\n })(),\n };\n};\n\n// NOTE(freben): Intentionally not exported at this point, since it's part of\n// the unstable extra context menu items concept below\ntype ExtraContextMenuItem = {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n};\n\n// unstable context menu option, eg: disable the unregister entity menu\ntype contextMenuOptions = {\n disableUnregister: boolean;\n};\n\ntype EntityPageLayoutProps = {\n UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[];\n UNSTABLE_contextMenuOptions?: contextMenuOptions;\n children?: React.ReactNode;\n};\n\nexport const EntityPageLayout = ({\n children,\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n}: EntityPageLayoutProps) => {\n const { kind, namespace, name } = useEntityCompoundName();\n const { entity, loading, error } = useContext(EntityContext);\n const { headerTitle, headerType } = headerProps(\n kind,\n namespace,\n name,\n entity!,\n );\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n const navigate = useNavigate();\n const cleanUpAfterRemoval = async () => {\n setConfirmationDialogOpen(false);\n navigate('/');\n };\n\n const showRemovalDialog = () => setConfirmationDialogOpen(true);\n\n return (\n <Page themeId={entity?.spec?.type?.toString() ?? 'home'}>\n <Header\n title={<EntityPageTitle title={headerTitle} entity={entity!} />}\n pageTitleOverride={headerTitle}\n type={headerType}\n >\n {/* TODO: Make entity labels configurable for entity kind / type */}\n {entity && (\n <>\n <EntityLabels entity={entity} />\n <EntityContextMenu\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n onUnregisterEntity={showRemovalDialog}\n />\n </>\n )}\n </Header>\n\n {loading && (\n <Content>\n <Progress />\n </Content>\n )}\n\n {entity && <Tabbed.Layout>{children}</Tabbed.Layout>}\n\n {error && (\n <Content>\n <ResponseErrorPanel error={error} />\n </Content>\n )}\n\n {!loading && !error && !entity && (\n <Content>\n <WarningPanel title=\"Entity not found\">\n There is no {kind} with the requested{' '}\n <Link to=\"https://backstage.io/docs/features/software-catalog/references\">\n kind, namespace, and name\n </Link>\n .\n </WarningPanel>\n </Content>\n )}\n\n <UnregisterEntityDialog\n open={confirmationDialogOpen}\n entity={entity!}\n onConfirm={cleanUpAfterRemoval}\n onClose={() => setConfirmationDialogOpen(false)}\n />\n </Page>\n );\n};\n\nEntityPageLayout.Content = Tabbed.Content;\n","/*\n * Copyright 2020 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 { useEntity } from '@backstage/plugin-catalog-react';\nimport React, { PropsWithChildren, ReactNode } from 'react';\nimport {\n attachComponentData,\n useApiHolder,\n useElementFilter,\n ApiHolder,\n} from '@backstage/core-plugin-api';\nimport { useAsync } from 'react-use';\n\nconst ENTITY_SWITCH_KEY = 'core.backstage.entitySwitch';\n\nconst EntitySwitchCase = (_: {\n if?: (\n entity: Entity,\n context: { apis: ApiHolder },\n ) => boolean | Promise<boolean>;\n children: ReactNode;\n}) => null;\n\nattachComponentData(EntitySwitchCase, ENTITY_SWITCH_KEY, true);\n\ntype SwitchCase = {\n if?: (\n entity: Entity,\n context: { apis: ApiHolder },\n ) => boolean | Promise<boolean>;\n children: JSX.Element;\n};\n\ntype SwitchCaseResult = {\n if: boolean | Promise<boolean>;\n children: JSX.Element;\n};\n\nexport const EntitySwitch = ({ children }: PropsWithChildren<{}>) => {\n const { entity } = useEntity();\n const apis = useApiHolder();\n const results = useElementFilter(\n children,\n collection =>\n collection\n .selectByComponentData({\n key: ENTITY_SWITCH_KEY,\n withStrictError: 'Child of EntitySwitch is not an EntitySwitch.Case',\n })\n .getElements()\n .flatMap<SwitchCaseResult>((element: React.ReactElement) => {\n const { if: condition, children: elementsChildren } =\n element.props as SwitchCase;\n return [\n {\n if: condition?.(entity, { apis }) ?? true,\n children: elementsChildren,\n },\n ];\n }),\n [apis, entity],\n );\n const hasAsyncCases = results.some(\n r => typeof r.if === 'object' && 'then' in r.if,\n );\n\n if (hasAsyncCases) {\n return <AsyncEntitySwitch results={results} />;\n }\n\n return results.find(r => r.if)?.children ?? null;\n};\n\nfunction AsyncEntitySwitch({ results }: { results: SwitchCaseResult[] }) {\n const { loading, value } = useAsync(async () => {\n const promises = results.map(\n async ({ if: condition, children: output }) => {\n try {\n if (await condition) {\n return output;\n }\n } catch {\n /* ignored */\n }\n\n return null;\n },\n );\n return (await Promise.all(promises)).find(Boolean) ?? null;\n }, [results]);\n\n if (loading || !value) {\n return null;\n }\n\n return value;\n}\n\nEntitySwitch.Case = EntitySwitchCase;\n","/*\n * Copyright 2020 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, ComponentEntity } from '@backstage/catalog-model';\n\nfunction strCmp(a: string | undefined, b: string | undefined): boolean {\n return Boolean(\n a && a?.toLocaleLowerCase('en-US') === b?.toLocaleLowerCase('en-US'),\n );\n}\n\nexport function isKind(kind: string) {\n return (entity: Entity) => strCmp(entity?.kind, kind);\n}\n\nexport function isComponentType(type: string) {\n return (entity: Entity) => {\n if (!strCmp(entity?.kind, 'component')) {\n return false;\n }\n const componentEntity = entity as ComponentEntity;\n return strCmp(componentEntity.spec.type, type);\n };\n}\n\nexport function isNamespace(namespace: string) {\n return (entity: Entity) => strCmp(entity?.metadata?.namespace, namespace);\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 { Grid } from '@material-ui/core';\nimport React, { PropsWithChildren } from 'react';\n\nexport const FilteredEntityLayout = ({ children }: PropsWithChildren<{}>) => (\n <Grid container style={{ position: 'relative' }}>\n {children}\n </Grid>\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 { BackstageTheme } from '@backstage/theme';\nimport {\n Box,\n Button,\n Drawer,\n Grid,\n Typography,\n useMediaQuery,\n useTheme,\n} from '@material-ui/core';\nimport FilterListIcon from '@material-ui/icons/FilterList';\nimport React, { useState, PropsWithChildren } from 'react';\n\nexport const FilterContainer = ({ children }: PropsWithChildren<{}>) => {\n const isMidSizeScreen = useMediaQuery<BackstageTheme>(theme =>\n theme.breakpoints.down('md'),\n );\n const theme = useTheme<BackstageTheme>();\n const [filterDrawerOpen, setFilterDrawerOpen] = useState<boolean>(false);\n\n return isMidSizeScreen ? (\n <>\n <Button\n style={{ marginTop: theme.spacing(1), marginLeft: theme.spacing(1) }}\n onClick={() => setFilterDrawerOpen(true)}\n startIcon={<FilterListIcon />}\n >\n Filters\n </Button>\n <Drawer\n open={filterDrawerOpen}\n onClose={() => setFilterDrawerOpen(false)}\n anchor=\"left\"\n disableAutoFocus\n keepMounted\n variant=\"temporary\"\n >\n <Box m={2}>\n <Typography\n variant=\"h6\"\n component=\"h2\"\n style={{ marginBottom: theme.spacing(1) }}\n >\n Filters\n </Typography>\n {children}\n </Box>\n </Drawer>\n </>\n ) : (\n <Grid item lg={2}>\n {children}\n </Grid>\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 { Grid } from '@material-ui/core';\nimport React, { PropsWithChildren } from 'react';\n\nexport const EntityListContainer = ({ children }: PropsWithChildren<{}>) => (\n <Grid item xs={12} lg={10}>\n {children}\n </Grid>\n);\n","/*\n * Copyright 2020 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 {\n Content,\n ContentHeader,\n CreateButton,\n PageWithHeader,\n SupportButton,\n TableColumn,\n TableProps,\n} from '@backstage/core-components';\nimport { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api';\nimport {\n EntityLifecyclePicker,\n EntityListProvider,\n EntityOwnerPicker,\n EntityTagPicker,\n EntityTypePicker,\n UserListFilterKind,\n UserListPicker,\n} from '@backstage/plugin-catalog-react';\nimport React from 'react';\nimport { createComponentRouteRef } from '../../routes';\nimport { CatalogTable } from '../CatalogTable';\nimport { EntityRow } from '../CatalogTable/types';\nimport {\n FilteredEntityLayout,\n EntityListContainer,\n FilterContainer,\n} from '../FilteredEntityLayout';\nimport { CatalogKindHeader } from '../CatalogKindHeader';\n\nexport type CatalogPageProps = {\n initiallySelectedFilter?: UserListFilterKind;\n columns?: TableColumn<EntityRow>[];\n actions?: TableProps<EntityRow>['actions'];\n};\n\nexport const CatalogPage = ({\n columns,\n actions,\n initiallySelectedFilter = 'owned',\n}: CatalogPageProps) => {\n const orgName =\n useApi(configApiRef).getOptionalString('organization.name') ?? 'Backstage';\n const createComponentLink = useRouteRef(createComponentRouteRef);\n\n return (\n <PageWithHeader title={`${orgName} Catalog`} themeId=\"home\">\n <EntityListProvider>\n <Content>\n <ContentHeader titleComponent={<CatalogKindHeader />}>\n <CreateButton\n title=\"Create Component\"\n to={createComponentLink && createComponentLink()}\n />\n <SupportButton>All your software catalog entities</SupportButton>\n </ContentHeader>\n <FilteredEntityLayout>\n <FilterContainer>\n <EntityTypePicker />\n <UserListPicker initialFilter={initiallySelectedFilter} />\n <EntityOwnerPicker />\n <EntityLifecyclePicker />\n <EntityTagPicker />\n </FilterContainer>\n <EntityListContainer>\n <CatalogTable columns={columns} actions={actions} />\n </EntityListContainer>\n </FilteredEntityLayout>\n </Content>\n </EntityListProvider>\n </PageWithHeader>\n );\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport { makeStyles } from '@material-ui/core';\nimport IlloSvgUrl from './illo.svg';\n\nconst useStyles = makeStyles(theme => ({\n illo: {\n maxWidth: '60%',\n top: 100,\n right: 20,\n position: 'absolute',\n [theme.breakpoints.down('xs')]: {\n maxWidth: '96%',\n position: 'relative',\n top: 'unset',\n right: 'unset',\n margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,\n },\n },\n}));\n\nexport const Illo = () => {\n const classes = useStyles();\n return (\n <img\n src={IlloSvgUrl}\n className={classes.illo}\n alt=\"Illustration on entity not found page\"\n />\n );\n};\n","/*\n * Copyright 2020 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 React from 'react';\nimport { Grid, Button, Typography } from '@material-ui/core';\nimport { makeStyles } from '@material-ui/core/styles';\nimport { BackstageTheme } from '@backstage/theme';\n\nimport { Illo } from './Illo';\n\nconst useStyles = makeStyles<BackstageTheme>(theme => ({\n container: {\n paddingTop: theme.spacing(24),\n paddingLeft: theme.spacing(8),\n [theme.breakpoints.down('xs')]: {\n padding: theme.spacing(2),\n },\n },\n title: {\n paddingBottom: theme.spacing(2),\n [theme.breakpoints.down('xs')]: {\n fontSize: 32,\n },\n },\n body: {\n paddingBottom: theme.spacing(6),\n [theme.breakpoints.down('xs')]: {\n paddingBottom: theme.spacing(5),\n },\n },\n}));\n\nexport const EntityNotFound = () => {\n const classes = useStyles();\n\n return (\n <Grid container spacing={0} className={classes.container}>\n <Illo />\n <Grid item xs={12} sm={6}>\n <Typography variant=\"h2\" className={classes.title}>\n Entity was not found\n </Typography>\n <Typography variant=\"body1\" className={classes.body}>\n Want to help us build this? Check out our Getting Started\n documentation.\n </Typography>\n <Button\n variant=\"contained\"\n color=\"primary\"\n href=\"https://backstage.io/docs\"\n >\n DOCS\n </Button>\n </Grid>\n </Grid>\n );\n};\n","/*\n * Copyright 2020 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 { ENTITY_DEFAULT_NAMESPACE } from '@backstage/catalog-model';\nimport {\n AsyncEntityProvider,\n useEntity,\n useEntityFromUrl,\n} from '@backstage/plugin-catalog-react';\nimport { Typography } from '@material-ui/core';\nimport React, { ComponentType, ReactNode } from 'react';\nimport { Navigate, Route, Routes, useParams } from 'react-router';\nimport { CatalogPage } from './CatalogPage';\nimport { EntityNotFound } from './EntityNotFound';\nimport { EntityPageLayout } from './EntityPageLayout';\nimport { Content, Link } from '@backstage/core-components';\n\nconst DefaultEntityPage = () => (\n <EntityPageLayout>\n <EntityPageLayout.Content\n path=\"/\"\n title=\"Overview\"\n element={\n <Content>\n <Typography variant=\"h2\">This is the default entity page.</Typography>\n <Typography variant=\"body1\">\n To override this component with your custom implementation, read\n docs on{' '}\n <Link to=\"https://backstage.io/docs\">backstage.io/docs</Link>\n </Typography>\n </Content>\n }\n />\n </EntityPageLayout>\n);\n\nconst EntityPageSwitch = ({ EntityPage }: { EntityPage: ComponentType }) => {\n const { entity, loading, error } = useEntity();\n // Loading and error states\n if (loading) return <EntityPageLayout />;\n if (error || !entity) return <EntityNotFound />;\n\n // Otherwise EntityPage provided from the App\n // Note that EntityPage will include EntityPageLayout already\n return <EntityPage />;\n};\n\nconst OldEntityRouteRedirect = () => {\n const { optionalNamespaceAndName, '*': rest } = useParams() as any;\n const [name, namespace] = optionalNamespaceAndName.split(':').reverse();\n const namespaceLower =\n namespace?.toLocaleLowerCase('en-US') ?? ENTITY_DEFAULT_NAMESPACE;\n const restWithSlash = rest ? `/${rest}` : '';\n return (\n <Navigate\n to={`../../${namespaceLower}/component/${name}${restWithSlash}`}\n />\n );\n};\n\nexport const EntityLoader = (props: { children: ReactNode }) => (\n <AsyncEntityProvider {...useEntityFromUrl()} {...props} />\n);\n\n/**\n * @deprecated Use plugin extensions instead\n * */\nexport const Router = ({\n EntityPage = DefaultEntityPage,\n}: {\n EntityPage?: ComponentType;\n}) => (\n <Routes>\n <Route path=\"/\" element={<CatalogPage />} />\n <Route\n path=\"/:namespace/:kind/:name\"\n element={\n <EntityLoader>\n <EntityPageSwitch EntityPage={EntityPage} />\n </EntityLoader>\n }\n />\n <Route\n path=\"Component/:optionalNamespaceAndName/*\"\n element={<OldEntityRouteRedirect />}\n />\n </Routes>\n);\n","/*\n * Copyright 2020 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 { CatalogClient } from '@backstage/catalog-client';\nimport {\n catalogApiRef,\n catalogRouteRef,\n DefaultStarredEntitiesApi,\n entityRouteRef,\n starredEntitiesApiRef,\n} from '@backstage/plugin-catalog-react';\nimport { createComponentRouteRef, viewTechDocRouteRef } from './routes';\nimport {\n createApiFactory,\n createComponentExtension,\n createPlugin,\n createRoutableExtension,\n discoveryApiRef,\n fetchApiRef,\n storageApiRef,\n} from '@backstage/core-plugin-api';\n\nexport const catalogPlugin = createPlugin({\n id: 'catalog',\n apis: [\n createApiFactory({\n api: catalogApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n fetchApi: fetchApiRef,\n },\n factory: ({ discoveryApi, fetchApi }) =>\n new CatalogClient({ discoveryApi, fetchApi }),\n }),\n createApiFactory({\n api: starredEntitiesApiRef,\n deps: { storageApi: storageApiRef },\n factory: ({ storageApi }) =>\n new DefaultStarredEntitiesApi({ storageApi }),\n }),\n ],\n routes: {\n catalogIndex: catalogRouteRef,\n catalogEntity: entityRouteRef,\n },\n externalRoutes: {\n createComponent: createComponentRouteRef,\n viewTechDoc: viewTechDocRouteRef,\n },\n});\n\nexport const CatalogIndexPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogIndexPage',\n component: () =>\n import('./components/CatalogPage').then(m => m.CatalogPage),\n mountPoint: catalogRouteRef,\n }),\n);\n\nexport const CatalogEntityPage = catalogPlugin.provide(\n createRoutableExtension({\n name: 'CatalogEntityPage',\n component: () =>\n import('./components/CatalogEntityPage').then(m => m.CatalogEntityPage),\n mountPoint: entityRouteRef,\n }),\n);\n\nexport const EntityAboutCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityAboutCard',\n component: {\n lazy: () => import('./components/AboutCard').then(m => m.AboutCard),\n },\n }),\n);\n\nexport const EntityLinksCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityLinksCard',\n component: {\n lazy: () =>\n import('./components/EntityLinksCard').then(m => m.EntityLinksCard),\n },\n }),\n);\n\nexport const EntityHasSystemsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSystemsCard',\n component: {\n lazy: () =>\n import('./components/HasSystemsCard').then(m => m.HasSystemsCard),\n },\n }),\n);\n\nexport const EntityHasComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasComponentsCard',\n component: {\n lazy: () =>\n import('./components/HasComponentsCard').then(m => m.HasComponentsCard),\n },\n }),\n);\n\nexport const EntityHasSubcomponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasSubcomponentsCard',\n component: {\n lazy: () =>\n import('./components/HasSubcomponentsCard').then(\n m => m.HasSubcomponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityHasResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityHasResourcesCard',\n component: {\n lazy: () =>\n import('./components/HasResourcesCard').then(m => m.HasResourcesCard),\n },\n }),\n);\n\nexport const EntityDependsOnComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependsOnComponentsCard').then(\n m => m.DependsOnComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependencyOfComponentsCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependencyOfComponentsCard',\n component: {\n lazy: () =>\n import('./components/DependencyOfComponentsCard').then(\n m => m.DependencyOfComponentsCard,\n ),\n },\n }),\n);\n\nexport const EntityDependsOnResourcesCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntityDependsOnResourcesCard',\n component: {\n lazy: () =>\n import('./components/DependsOnResourcesCard').then(\n m => m.DependsOnResourcesCard,\n ),\n },\n }),\n);\n\nexport const EntitySystemDiagramCard = catalogPlugin.provide(\n createComponentExtension({\n name: 'EntitySystemDiagramCard',\n component: {\n lazy: () =>\n import('./components/SystemDiagramCard').then(m => m.SystemDiagramCard),\n },\n }),\n);\n"],"names":["useStyles","columnFactories.createNameColumn","columnFactories.createSystemColumn","columnFactories.createOwnerColumn","columnFactories.createSpecTypeColumn","columnFactories.createSpecLifecycleColumn","columnFactories.createMetadataDescriptionColumn","columnFactories.createTagsColumn","capitalize","Edit","makeStyles","headerProps","EntityLabels","Route"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-96cd0b79.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-c9b0afd8.esm.js","sources":["../../src/components/SystemDiagramCard/SystemDiagramCard.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 {\n Entity,\n RELATION_DEPENDS_ON,\n RELATION_PROVIDES_API,\n RELATION_PART_OF,\n stringifyEntityRef,\n ENTITY_DEFAULT_NAMESPACE,\n parseEntityRef,\n} from '@backstage/catalog-model';\nimport {\n catalogApiRef,\n entityRouteRef,\n getEntityRelations,\n useEntity,\n} from '@backstage/plugin-catalog-react';\nimport { Box, makeStyles, Typography, useTheme } from '@material-ui/core';\nimport ZoomOutMap from '@material-ui/icons/ZoomOutMap';\nimport React from 'react';\nimport { useAsync } from 'react-use';\nimport { BackstageTheme } from '@backstage/theme';\n\nimport {\n DependencyGraph,\n DependencyGraphTypes,\n InfoCard,\n Progress,\n ResponseErrorPanel,\n Link,\n} from '@backstage/core-components';\n\nimport { useApi, useRouteRef } from '@backstage/core-plugin-api';\n\n/** @public */\nexport type SystemDiagramCardClassKey =\n | 'domainNode'\n | 'systemNode'\n | 'componentNode'\n | 'apiNode'\n | 'resourceNode';\n\nconst useStyles = makeStyles(\n (theme: BackstageTheme) => ({\n domainNode: {\n fill: theme.palette.primary.main,\n stroke: theme.palette.border,\n },\n systemNode: {\n fill: 'coral',\n stroke: theme.palette.border,\n },\n componentNode: {\n fill: 'yellowgreen',\n stroke: theme.palette.border,\n },\n apiNode: {\n fill: theme.palette.gold,\n stroke: theme.palette.border,\n },\n resourceNode: {\n fill: 'grey',\n stroke: theme.palette.border,\n },\n }),\n { name: 'PluginCatalogSystemDiagramCard' },\n);\n\n// Simplifies the diagram output by hiding the default namespace and kind\nfunction readableEntityName(\n ref:\n | Entity\n | {\n kind: string;\n namespace?: string;\n name: string;\n },\n): string {\n return stringifyEntityRef(ref)\n .toLocaleLowerCase('en-US')\n .replace(`:${ENTITY_DEFAULT_NAMESPACE}/`, ':')\n .split(':')[1];\n}\n\nfunction RenderNode(props: DependencyGraphTypes.RenderNodeProps<any>) {\n const classes = useStyles();\n const catalogEntityRoute = useRouteRef(entityRouteRef);\n const kind = props.node.kind || 'Component';\n const ref = parseEntityRef(props.node.id);\n const MAX_NAME_LENGTH = 20;\n const truncatedNodeName =\n props.node.name.length < MAX_NAME_LENGTH\n ? props.node.name\n : `${props.node.name.slice(0, MAX_NAME_LENGTH)}...`;\n let nodeClass = classes.componentNode;\n\n switch (kind) {\n case 'Domain':\n nodeClass = classes.domainNode;\n break;\n case 'System':\n nodeClass = classes.systemNode;\n break;\n case 'Component':\n nodeClass = classes.componentNode;\n break;\n case 'API':\n nodeClass = classes.apiNode;\n break;\n case 'Resource':\n nodeClass = classes.resourceNode;\n break;\n default:\n nodeClass = classes.componentNode;\n }\n\n return (\n <g>\n <rect width={200} height={100} rx={20} className={nodeClass} />\n <Link\n to={catalogEntityRoute({\n kind: kind,\n namespace: ref.namespace,\n name: ref.name,\n })}\n >\n <text\n x={100}\n y={45}\n textAnchor=\"middle\"\n alignmentBaseline=\"baseline\"\n style={{ fontWeight: 'bold' }}\n >\n {truncatedNodeName}\n </text>\n </Link>\n\n <text x={100} y={65} textAnchor=\"middle\" alignmentBaseline=\"hanging\">\n {props.node.kind}\n </text>\n </g>\n );\n}\n\n/**\n * Dynamically generates a diagram of a system, its assigned entities,\n * and relationships of those entities.\n */\nexport function SystemDiagramCard() {\n const { entity } = useEntity();\n const theme = useTheme();\n const currentSystemName = entity.metadata.name;\n const currentSystemNode = stringifyEntityRef(entity);\n const systemNodes = new Array<{ id: string; kind: string; name: string }>();\n const systemEdges = new Array<{ from: string; to: string; label: string }>();\n\n const catalogApi = useApi(catalogApiRef);\n const {\n loading,\n error,\n value: catalogResponse,\n } = useAsync(() => {\n return catalogApi.getEntities({\n filter: {\n kind: ['Component', 'API', 'Resource', 'System', 'Domain'],\n 'spec.system': [\n currentSystemName,\n `${\n entity.metadata.namespace || ENTITY_DEFAULT_NAMESPACE\n }/${currentSystemName}`,\n ],\n },\n });\n }, [catalogApi, currentSystemName]);\n\n // pick out the system itself\n systemNodes.push({\n id: currentSystemNode,\n kind: 'System',\n name: readableEntityName(entity),\n });\n\n // check if the system has an assigned domain\n // even if the domain object doesn't exist in the catalog, display it in the map\n const catalogItemDomain = getEntityRelations(entity, RELATION_PART_OF, {\n kind: 'Domain',\n });\n catalogItemDomain.forEach(foundDomain =>\n systemNodes.push({\n id: stringifyEntityRef(foundDomain),\n kind: foundDomain.kind,\n name: readableEntityName(foundDomain),\n }),\n );\n catalogItemDomain.forEach(foundDomain =>\n systemEdges.push({\n from: currentSystemNode,\n to: stringifyEntityRef(foundDomain),\n label: 'part of',\n }),\n );\n\n if (catalogResponse && catalogResponse.items) {\n for (const catalogItem of catalogResponse.items) {\n systemNodes.push({\n id: stringifyEntityRef(catalogItem),\n kind: catalogItem.kind,\n name: readableEntityName(catalogItem),\n });\n\n // Check relations of the entity assigned to this system to see\n // if it relates to other entities.\n // Note those relations may, or may not, be explicitly\n // assigned to the system.\n const catalogItemRelations_partOf = getEntityRelations(\n catalogItem,\n RELATION_PART_OF,\n );\n catalogItemRelations_partOf.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'part of',\n }),\n );\n\n const catalogItemRelations_providesApi = getEntityRelations(\n catalogItem,\n RELATION_PROVIDES_API,\n );\n catalogItemRelations_providesApi.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'provides',\n }),\n );\n\n const catalogItemRelations_dependsOn = getEntityRelations(\n catalogItem,\n RELATION_DEPENDS_ON,\n );\n catalogItemRelations_dependsOn.forEach(foundRelation =>\n systemEdges.push({\n from: stringifyEntityRef(catalogItem),\n to: stringifyEntityRef(foundRelation),\n label: 'depends on',\n }),\n );\n }\n }\n\n if (loading) {\n return <Progress />;\n } else if (error) {\n return <ResponseErrorPanel error={error} />;\n }\n\n return (\n <InfoCard title=\"System Diagram\">\n <DependencyGraph\n nodes={systemNodes}\n edges={systemEdges}\n nodeMargin={10}\n direction={DependencyGraphTypes.Direction.BOTTOM_TOP}\n renderNode={RenderNode}\n paddingX={theme.spacing(4)}\n paddingY={theme.spacing(4)}\n />\n <Box m={1} />\n <Typography\n variant=\"caption\"\n style={{ display: 'block', textAlign: 'right' }}\n >\n <ZoomOutMap style={{ verticalAlign: 'bottom' }} /> Use pinch & zoom\n to move around the diagram.\n </Typography>\n </InfoCard>\n );\n}\n"],"names":[],"mappings":"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"}
|