@backstage/plugin-catalog 0.7.6 → 0.7.7
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 +12 -0
- package/dist/esm/{index-96cd0b79.esm.js → index-36778da3.esm.js} +3 -3
- package/dist/esm/index-36778da3.esm.js.map +1 -0
- package/dist/esm/{index-66d685f8.esm.js → index-766926dc.esm.js} +19 -11
- package/dist/esm/index-766926dc.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/esm/{index-00a86fa7.esm.js → index-d9ca5a48.esm.js} +3 -3
- package/dist/esm/index-d9ca5a48.esm.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.esm.js +2 -2
- package/package.json +8 -8
- 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,17 @@
|
|
|
1
1
|
# @backstage/plugin-catalog
|
|
2
2
|
|
|
3
|
+
## 0.7.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 4ce51ab0f1: Internal refactor of the `react-use` imports to use `react-use/lib/*` instead.
|
|
8
|
+
- 11b81683a9: Support customizing index page layouts via outlets
|
|
9
|
+
- e195390974: Allow entities from `file` locations to be manually refreshed through the UI
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
- @backstage/core-plugin-api@0.4.1
|
|
12
|
+
- @backstage/plugin-catalog-react@0.6.10
|
|
13
|
+
- @backstage/core-components@0.8.3
|
|
14
|
+
|
|
3
15
|
## 0.7.6
|
|
4
16
|
|
|
5
17
|
### 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-766926dc.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-36778da3.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-36778da3.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';
|
|
@@ -233,7 +233,7 @@ const useStyles$5 = makeStyles({
|
|
|
233
233
|
}
|
|
234
234
|
});
|
|
235
235
|
function AboutCard({ variant }) {
|
|
236
|
-
var _a, _b
|
|
236
|
+
var _a, _b;
|
|
237
237
|
const classes = useStyles$5();
|
|
238
238
|
const { entity } = useEntity();
|
|
239
239
|
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
|
|
@@ -272,7 +272,8 @@ function AboutCard({ variant }) {
|
|
|
272
272
|
} else if (variant === "fullHeight") {
|
|
273
273
|
cardContentClass = classes.fullHeightCardContent;
|
|
274
274
|
}
|
|
275
|
-
const
|
|
275
|
+
const entityLocation = (_b = entity.metadata.annotations) == null ? void 0 : _b[LOCATION_ANNOTATION];
|
|
276
|
+
const allowRefresh = (entityLocation == null ? void 0 : entityLocation.startsWith("url:")) || (entityLocation == null ? void 0 : entityLocation.startsWith("file:"));
|
|
276
277
|
const refreshEntity = useCallback(async () => {
|
|
277
278
|
await catalogApi.refreshEntity(stringifyEntityRef(entity));
|
|
278
279
|
alertApi.post({ message: "Refresh scheduled", severity: "info" });
|
|
@@ -281,7 +282,7 @@ function AboutCard({ variant }) {
|
|
|
281
282
|
className: cardClass
|
|
282
283
|
}, /* @__PURE__ */ React.createElement(CardHeader, {
|
|
283
284
|
title: "About",
|
|
284
|
-
action: /* @__PURE__ */ React.createElement(React.Fragment, null,
|
|
285
|
+
action: /* @__PURE__ */ React.createElement(React.Fragment, null, allowRefresh && /* @__PURE__ */ React.createElement(IconButton, {
|
|
285
286
|
"aria-label": "Refresh",
|
|
286
287
|
title: "Schedule entity refresh",
|
|
287
288
|
onClick: refreshEntity
|
|
@@ -1119,7 +1120,7 @@ const EntityListContainer = ({ children }) => /* @__PURE__ */ React.createElemen
|
|
|
1119
1120
|
lg: 10
|
|
1120
1121
|
}, children);
|
|
1121
1122
|
|
|
1122
|
-
const
|
|
1123
|
+
const DefaultCatalogPage = ({
|
|
1123
1124
|
columns,
|
|
1124
1125
|
actions,
|
|
1125
1126
|
initiallySelectedFilter = "owned"
|
|
@@ -1143,6 +1144,13 @@ const CatalogPage = ({
|
|
|
1143
1144
|
}))))));
|
|
1144
1145
|
};
|
|
1145
1146
|
|
|
1147
|
+
const CatalogPage = (props) => {
|
|
1148
|
+
const outlet = useOutlet();
|
|
1149
|
+
return outlet || /* @__PURE__ */ React.createElement(DefaultCatalogPage, {
|
|
1150
|
+
...props
|
|
1151
|
+
});
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1146
1154
|
const useStyles$1 = makeStyles((theme) => ({
|
|
1147
1155
|
illo: {
|
|
1148
1156
|
maxWidth: "60%",
|
|
@@ -1287,7 +1295,7 @@ const catalogPlugin = createPlugin({
|
|
|
1287
1295
|
});
|
|
1288
1296
|
const CatalogIndexPage = catalogPlugin.provide(createRoutableExtension({
|
|
1289
1297
|
name: "CatalogIndexPage",
|
|
1290
|
-
component: () => import('./index-
|
|
1298
|
+
component: () => import('./index-d9ca5a48.esm.js').then((m) => m.CatalogPage),
|
|
1291
1299
|
mountPoint: catalogRouteRef
|
|
1292
1300
|
}));
|
|
1293
1301
|
const CatalogEntityPage = catalogPlugin.provide(createRoutableExtension({
|
|
@@ -1298,7 +1306,7 @@ const CatalogEntityPage = catalogPlugin.provide(createRoutableExtension({
|
|
|
1298
1306
|
const EntityAboutCard = catalogPlugin.provide(createComponentExtension({
|
|
1299
1307
|
name: "EntityAboutCard",
|
|
1300
1308
|
component: {
|
|
1301
|
-
lazy: () => import('./index-
|
|
1309
|
+
lazy: () => import('./index-36778da3.esm.js').then((m) => m.AboutCard)
|
|
1302
1310
|
}
|
|
1303
1311
|
}));
|
|
1304
1312
|
const EntityLinksCard = catalogPlugin.provide(createComponentExtension({
|
|
@@ -1352,9 +1360,9 @@ const EntityDependsOnResourcesCard = catalogPlugin.provide(createComponentExtens
|
|
|
1352
1360
|
const EntitySystemDiagramCard = catalogPlugin.provide(createComponentExtension({
|
|
1353
1361
|
name: "EntitySystemDiagramCard",
|
|
1354
1362
|
component: {
|
|
1355
|
-
lazy: () => import('./index-
|
|
1363
|
+
lazy: () => import('./index-d363820f.esm.js').then((m) => m.SystemDiagramCard)
|
|
1356
1364
|
}
|
|
1357
1365
|
}));
|
|
1358
1366
|
|
|
1359
|
-
export { AboutCard as A, EntityOrphanWarning as B, CatalogPage as C,
|
|
1360
|
-
//# sourceMappingURL=index-
|
|
1367
|
+
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 };
|
|
1368
|
+
//# sourceMappingURL=index-766926dc.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-766926dc.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(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 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 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/lib/useAsync';\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/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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"}
|
|
@@ -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":";;;;;;;;;AAwDA,MAAM,YAAY,WAChB,CAAC;AAA2B,EAC1B,YAAY;AAAA,IACV,MAAM,MAAM,QAAQ,QAAQ;AAAA,IAC5B,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAExB,YAAY;AAAA,IACV,MAAM;AAAA,IACN,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAExB,eAAe;AAAA,IACb,MAAM;AAAA,IACN,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAExB,SAAS;AAAA,IACP,MAAM,MAAM,QAAQ;AAAA,IACpB,QAAQ,MAAM,QAAQ;AAAA;AAAA,EAExB,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,QAAQ,MAAM,QAAQ;AAAA;AAAA,IAG1B,EAAE,MAAM;AAIV,4BACE,KAOQ;AACR,SAAO,mBAAmB,KACvB,kBAAkB,SAClB,QAAQ,IAAI,6BAA6B,KACzC,MAAM,KAAK;AAAA;AAGhB,oBAAoB,OAAkD;AACpE,QAAM,UAAU;AAChB,QAAM,qBAAqB,YAAY;AACvC,QAAM,OAAO,MAAM,KAAK,QAAQ;AAChC,QAAM,MAAM,eAAe,MAAM,KAAK;AACtC,QAAM,kBAAkB;AACxB,QAAM,oBACJ,MAAM,KAAK,KAAK,SAAS,kBACrB,MAAM,KAAK,OACX,GAAG,MAAM,KAAK,KAAK,MAAM,GAAG;AAClC,MAAI,YAAY,QAAQ;AAExB,UAAQ;AAAA,SACD;AACH,kBAAY,QAAQ;AACpB;AAAA,SACG;AACH,kBAAY,QAAQ;AACpB;AAAA,SACG;AACH,kBAAY,QAAQ;AACpB;AAAA,SACG;AACH,kBAAY,QAAQ;AACpB;AAAA,SACG;AACH,kBAAY,QAAQ;AACpB;AAAA;AAEA,kBAAY,QAAQ;AAAA;AAGxB,6CACG,KAAD,0CACG,QAAD;AAAA,IAAM,OAAO;AAAA,IAAK,QAAQ;AAAA,IAAK,IAAI;AAAA,IAAI,WAAW;AAAA,0CACjD,MAAD;AAAA,IACE,IAAI,mBAAmB;AAAA,MACrB;AAAA,MACA,WAAW,IAAI;AAAA,MACf,MAAM,IAAI;AAAA;AAAA,yCAGX,QAAD;AAAA,IACE,GAAG;AAAA,IACH,GAAG;AAAA,IACH,YAAW;AAAA,IACX,mBAAkB;AAAA,IAClB,OAAO,EAAE,YAAY;AAAA,KAEpB,yDAIJ,QAAD;AAAA,IAAM,GAAG;AAAA,IAAK,GAAG;AAAA,IAAI,YAAW;AAAA,IAAS,mBAAkB;AAAA,KACxD,MAAM,KAAK;AAAA;6BAUgB;AAClC,QAAM,EAAE,WAAW;AACnB,QAAM,QAAQ;AACd,QAAM,oBAAoB,OAAO,SAAS;AAC1C,QAAM,oBAAoB,mBAAmB;AAC7C,QAAM,cAAc,IAAI;AACxB,QAAM,cAAc,IAAI;AAExB,QAAM,aAAa,OAAO;AAC1B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,SAAS,MAAM;AACjB,WAAO,WAAW,YAAY;AAAA,MAC5B,QAAQ;AAAA,QACN,MAAM,CAAC,aAAa,OAAO,YAAY,UAAU;AAAA,QACjD,eAAe;AAAA,UACb;AAAA,UACA,GACE,OAAO,SAAS,aAAa,4BAC3B;AAAA;AAAA;AAAA;AAAA,KAIT,CAAC,YAAY;AAGhB,cAAY,KAAK;AAAA,IACf,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM,mBAAmB;AAAA;AAK3B,QAAM,oBAAoB,mBAAmB,QAAQ,kBAAkB;AAAA,IACrE,MAAM;AAAA;AAER,oBAAkB,QAAQ,iBACxB,YAAY,KAAK;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,MAAM,YAAY;AAAA,IAClB,MAAM,mBAAmB;AAAA;AAG7B,oBAAkB,QAAQ,iBACxB,YAAY,KAAK;AAAA,IACf,MAAM;AAAA,IACN,IAAI,mBAAmB;AAAA,IACvB,OAAO;AAAA;AAIX,MAAI,mBAAmB,gBAAgB,OAAO;AAC5C,eAAW,eAAe,gBAAgB,OAAO;AAC/C,kBAAY,KAAK;AAAA,QACf,IAAI,mBAAmB;AAAA,QACvB,MAAM,YAAY;AAAA,QAClB,MAAM,mBAAmB;AAAA;AAO3B,YAAM,8BAA8B,mBAClC,aACA;AAEF,kCAA4B,QAAQ,mBAClC,YAAY,KAAK;AAAA,QACf,MAAM,mBAAmB;AAAA,QACzB,IAAI,mBAAmB;AAAA,QACvB,OAAO;AAAA;AAIX,YAAM,mCAAmC,mBACvC,aACA;AAEF,uCAAiC,QAAQ,mBACvC,YAAY,KAAK;AAAA,QACf,MAAM,mBAAmB;AAAA,QACzB,IAAI,mBAAmB;AAAA,QACvB,OAAO;AAAA;AAIX,YAAM,iCAAiC,mBACrC,aACA;AAEF,qCAA+B,QAAQ,mBACrC,YAAY,KAAK;AAAA,QACf,MAAM,mBAAmB;AAAA,QACzB,IAAI,mBAAmB;AAAA,QACvB,OAAO;AAAA;AAAA;AAAA;AAMf,MAAI,SAAS;AACX,+CAAQ,UAAD;AAAA,aACE,OAAO;AAChB,+CAAQ,oBAAD;AAAA,MAAoB;AAAA;AAAA;AAG7B,6CACG,UAAD;AAAA,IAAU,OAAM;AAAA,yCACb,iBAAD;AAAA,IACE,OAAO;AAAA,IACP,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,WAAW,qBAAqB,UAAU;AAAA,IAC1C,YAAY;AAAA,IACZ,UAAU,MAAM,QAAQ;AAAA,IACxB,UAAU,MAAM,QAAQ;AAAA,0CAEzB,KAAD;AAAA,IAAK,GAAG;AAAA,0CACP,YAAD;AAAA,IACE,SAAQ;AAAA,IACR,OAAO,EAAE,SAAS,SAAS,WAAW;AAAA,yCAErC,YAAD;AAAA,IAAY,OAAO,EAAE,eAAe;AAAA,MAAc;AAAA;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CatalogPage } from './index-
|
|
1
|
+
export { C as CatalogPage, D as DefaultCatalogPage } from './index-766926dc.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-d9ca5a48.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-d9ca5a48.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -246,7 +246,11 @@ declare const Router: ({ EntityPage, }: {
|
|
|
246
246
|
EntityPage?: React.ComponentType<{}> | undefined;
|
|
247
247
|
}) => JSX.Element;
|
|
248
248
|
|
|
249
|
-
|
|
249
|
+
/**
|
|
250
|
+
* DefaultCatalogPageProps
|
|
251
|
+
* @public
|
|
252
|
+
*/
|
|
253
|
+
declare type DefaultCatalogPageProps = {
|
|
250
254
|
initiallySelectedFilter?: UserListFilterKind;
|
|
251
255
|
columns?: TableColumn<EntityRow>[];
|
|
252
256
|
actions?: TableProps<EntityRow>['actions'];
|
|
@@ -267,7 +271,7 @@ declare const catalogPlugin: _backstage_core_plugin_api.BackstagePlugin<{
|
|
|
267
271
|
namespace: string;
|
|
268
272
|
}, true>;
|
|
269
273
|
}>;
|
|
270
|
-
declare const CatalogIndexPage: (
|
|
274
|
+
declare const CatalogIndexPage: (props: DefaultCatalogPageProps) => JSX.Element;
|
|
271
275
|
declare const CatalogEntityPage: () => JSX.Element;
|
|
272
276
|
declare const EntityAboutCard: typeof AboutCard;
|
|
273
277
|
declare const EntityLinksCard: ({ cols, variant }: {
|
|
@@ -300,4 +304,4 @@ declare const EntityDependsOnResourcesCard: ({ variant }: {
|
|
|
300
304
|
}) => JSX.Element;
|
|
301
305
|
declare const EntitySystemDiagramCard: typeof SystemDiagramCard;
|
|
302
306
|
|
|
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 };
|
|
307
|
+
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-766926dc.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.7",
|
|
5
5
|
"main": "dist/index.esm.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "Apache-2.0",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@backstage/catalog-client": "^0.5.3",
|
|
35
35
|
"@backstage/catalog-model": "^0.9.7",
|
|
36
|
-
"@backstage/core-components": "^0.8.
|
|
37
|
-
"@backstage/core-plugin-api": "^0.4.
|
|
36
|
+
"@backstage/core-components": "^0.8.3",
|
|
37
|
+
"@backstage/core-plugin-api": "^0.4.1",
|
|
38
38
|
"@backstage/errors": "^0.1.3",
|
|
39
39
|
"@backstage/integration-react": "^0.1.17",
|
|
40
|
-
"@backstage/plugin-catalog-react": "^0.6.
|
|
40
|
+
"@backstage/plugin-catalog-react": "^0.6.10",
|
|
41
41
|
"@backstage/theme": "^0.2.14",
|
|
42
42
|
"@material-ui/core": "^4.12.2",
|
|
43
43
|
"@material-ui/icons": "^4.9.1",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"react": "^16.13.1 || ^17.0.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@backstage/cli": "^0.10.
|
|
57
|
-
"@backstage/core-app-api": "^0.3.
|
|
58
|
-
"@backstage/dev-utils": "^0.2.
|
|
56
|
+
"@backstage/cli": "^0.10.5",
|
|
57
|
+
"@backstage/core-app-api": "^0.3.1",
|
|
58
|
+
"@backstage/dev-utils": "^0.2.16",
|
|
59
59
|
"@backstage/test-utils": "^0.2.1",
|
|
60
60
|
"@testing-library/jest-dom": "^5.10.1",
|
|
61
61
|
"@testing-library/react": "^11.2.5",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"files": [
|
|
67
67
|
"dist"
|
|
68
68
|
],
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "ffdb98aa2973366d48ff1774a7f892bc0c926e7e"
|
|
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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"}
|