@backstage/plugin-catalog 1.28.0-next.1 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,193 @@
1
1
  # @backstage/plugin-catalog
2
2
 
3
+ ## 1.28.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 247a40b: Now a custom entity page header can be passed as input to the default entity page.
8
+ - a3d93ca: The default layout of the entity page can now optionally be customized with 3 card types: info, peek and full.
9
+
10
+ - Cards of type `info` are rendered in a fixed area on the right;
11
+ - Cards of type `peek` are rendered on top of the main content area;
12
+ - Cards of type `full` and cards with undefined type are rendered as they were before, in the main content area, below the peek cards.
13
+
14
+ If you want to keep the layout as it was before, you don't need to do anything. But if you want to experiment with the card types and see how they render, here is an example setting the about card to be rendered as an `info` card:
15
+
16
+ ```diff
17
+ app:
18
+ extensions:
19
+ # Entity page cards
20
+ + - entity-card:catalog/about:
21
+ + config:
22
+ + type: info # or peek or full
23
+ ```
24
+
25
+ - 93533bd: The order in which group tabs appear on the entity page has been changed.
26
+
27
+ ### Before
28
+
29
+ Previously, entity contents determined the order in which groups were rendered, so a group was rendered as soon as its first entity content was detected.
30
+
31
+ ### After
32
+
33
+ Groups are now rendered first by default based on their order in the `app-config.yaml` file:
34
+
35
+ ```diff
36
+ app:
37
+ extensions:
38
+ - page:catalog/entity:
39
+ + config:
40
+ + groups:
41
+ + # this will be the first tab of the default entity page
42
+ + - deployment:
43
+ + title: Deployment
44
+ + # this will be the second tab of the default entiy page
45
+ + - documentation:
46
+ + title: Documentation
47
+ ```
48
+
49
+ If you wish to place a normal tab before a group, you must add the tab to a group and place the group in the order you wish it to appear on the entity page (groups that contains only one tab are rendered as normal tabs).
50
+
51
+ ```diff
52
+ app:
53
+ extensions:
54
+ - page:catalog/entity:
55
+ config:
56
+ groups:
57
+ + # Example placing the overview tab first
58
+ + - overview:
59
+ + title: Overview
60
+ - deployment:
61
+ title: Deployment
62
+ # this will be the second tab of the default entiy page
63
+ - documentation:
64
+ title: Documentation
65
+ - entity-content:catalog/overview:
66
+ + config:
67
+ + group: 'overview'
68
+ ```
69
+
70
+ - 06d1226: Allow providing `kind` parameters to replace the default `Component` kind for `SubComponents` card
71
+
72
+ ### Patch Changes
73
+
74
+ - 31731b0: Internal refactor to avoid `expiry-map` dependency.
75
+ - ba9649a: Update the default entity page extension component to support grouping multiple entity content items in the same tab.
76
+
77
+ Disable all default groups:
78
+
79
+ ```diff
80
+ # app-config.yaml
81
+ app:
82
+ extensions:
83
+ # Pages
84
+ + - page:catalog/entity:
85
+ + config:
86
+ + groups: []
87
+ ```
88
+
89
+ Create a custom list of :
90
+
91
+ ```diff
92
+ # app-config.yaml
93
+ app:
94
+ extensions:
95
+ # Pages
96
+ + - page:catalog/entity:
97
+ + config:
98
+ + groups:
99
+ + # This array of groups completely replaces the default groups
100
+ + - custom:
101
+ + title: 'Custom'
102
+ ```
103
+
104
+ - Updated dependencies
105
+ - @backstage/core-components@0.17.0
106
+ - @backstage/core-plugin-api@1.10.5
107
+ - @backstage/plugin-search-react@1.8.7
108
+ - @backstage/frontend-plugin-api@0.10.0
109
+ - @backstage/plugin-catalog-react@1.16.0
110
+ - @backstage/core-compat-api@0.4.0
111
+ - @backstage/plugin-scaffolder-common@1.5.10
112
+ - @backstage/integration-react@1.2.5
113
+ - @backstage/plugin-permission-react@0.4.32
114
+ - @backstage/catalog-client@1.9.1
115
+ - @backstage/catalog-model@1.7.3
116
+ - @backstage/errors@1.2.7
117
+ - @backstage/types@1.2.1
118
+ - @backstage/plugin-catalog-common@1.1.3
119
+ - @backstage/plugin-search-common@1.2.17
120
+
121
+ ## 1.28.0-next.2
122
+
123
+ ### Minor Changes
124
+
125
+ - 247a40b: Now a custom entity page header can be passed as input to the default entity page.
126
+ - 93533bd: The order in which group tabs appear on the entity page has been changed.
127
+
128
+ ### Before
129
+
130
+ Previously, entity contents determined the order in which groups were rendered, so a group was rendered as soon as its first entity content was detected.
131
+
132
+ ### After
133
+
134
+ Groups are now rendered first by default based on their order in the `app-config.yaml` file:
135
+
136
+ ```diff
137
+ app:
138
+ extensions:
139
+ - page:catalog/entity:
140
+ + config:
141
+ + groups:
142
+ + # this will be the first tab of the default entity page
143
+ + - deployment:
144
+ + title: Deployment
145
+ + # this will be the second tab of the default entiy page
146
+ + - documentation:
147
+ + title: Documentation
148
+ ```
149
+
150
+ If you wish to place a normal tab before a group, you must add the tab to a group and place the group in the order you wish it to appear on the entity page (groups that contains only one tab are rendered as normal tabs).
151
+
152
+ ```diff
153
+ app:
154
+ extensions:
155
+ - page:catalog/entity:
156
+ config:
157
+ groups:
158
+ + # Example placing the overview tab first
159
+ + - overview:
160
+ + title: Overview
161
+ - deployment:
162
+ title: Deployment
163
+ # this will be the second tab of the default entiy page
164
+ - documentation:
165
+ title: Documentation
166
+ - entity-content:catalog/overview:
167
+ + config:
168
+ + group: 'overview'
169
+ ```
170
+
171
+ ### Patch Changes
172
+
173
+ - 31731b0: Internal refactor to avoid `expiry-map` dependency.
174
+ - Updated dependencies
175
+ - @backstage/frontend-plugin-api@0.10.0-next.2
176
+ - @backstage/plugin-catalog-react@1.16.0-next.2
177
+ - @backstage/core-compat-api@0.4.0-next.2
178
+ - @backstage/core-components@0.16.5-next.1
179
+ - @backstage/plugin-search-react@1.8.7-next.2
180
+ - @backstage/catalog-client@1.9.1
181
+ - @backstage/catalog-model@1.7.3
182
+ - @backstage/core-plugin-api@1.10.4
183
+ - @backstage/errors@1.2.7
184
+ - @backstage/integration-react@1.2.5-next.0
185
+ - @backstage/types@1.2.1
186
+ - @backstage/plugin-catalog-common@1.1.3
187
+ - @backstage/plugin-permission-react@0.4.31
188
+ - @backstage/plugin-scaffolder-common@1.5.10-next.0
189
+ - @backstage/plugin-search-common@1.2.17
190
+
3
191
  ## 1.28.0-next.1
4
192
 
5
193
  ### Minor Changes
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import Grid from '@material-ui/core/Grid';
3
+ import { makeStyles } from '@material-ui/core/styles';
4
+ import { EntitySwitch } from '../components/EntitySwitch/EntitySwitch.esm.js';
5
+ import { isOrphan, EntityOrphanWarning } from '../components/EntityOrphanWarning/EntityOrphanWarning.esm.js';
6
+ import { hasRelationWarnings, EntityRelationWarning } from '../components/EntityRelationWarning/EntityRelationWarning.esm.js';
7
+ import { hasCatalogProcessingErrors, EntityProcessingErrorsPanel } from '../components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.esm.js';
8
+ import { HorizontalScrollGrid } from '@backstage/core-components';
9
+
10
+ const useStyles = makeStyles((theme) => ({
11
+ root: {
12
+ display: "flex",
13
+ flexFlow: "column nowrap",
14
+ gap: theme.spacing(3)
15
+ },
16
+ contentArea: {
17
+ display: "flex",
18
+ flexFlow: "column",
19
+ gap: theme.spacing(3),
20
+ alignItems: "stretch",
21
+ minWidth: 0
22
+ },
23
+ infoArea: {
24
+ display: "flex",
25
+ flexFlow: "column nowrap",
26
+ alignItems: "stretch",
27
+ gap: theme.spacing(3),
28
+ minWidth: 0
29
+ },
30
+ summaryArea: {
31
+ margin: theme.spacing(1.5)
32
+ // To counteract MUI negative grid margin
33
+ },
34
+ summaryCard: {
35
+ flex: "0 0 auto",
36
+ "& + &": {
37
+ marginLeft: theme.spacing(3)
38
+ }
39
+ },
40
+ [theme.breakpoints.up("md")]: {
41
+ root: {
42
+ display: "grid",
43
+ gap: 0,
44
+ gridTemplateAreas: ({ summaryCards }) => `
45
+ "${summaryCards ? "summary" : "content"} info"
46
+ "content info"
47
+ `,
48
+ gridTemplateColumns: ({ infoCards }) => infoCards ? "2fr 1fr" : "1fr",
49
+ alignItems: "start"
50
+ },
51
+ infoArea: {
52
+ gridArea: "info",
53
+ position: "sticky",
54
+ top: theme.spacing(3),
55
+ marginLeft: theme.spacing(3)
56
+ },
57
+ contentArea: {
58
+ gridArea: "content"
59
+ },
60
+ summaryArea: {
61
+ gridArea: "summary",
62
+ marginBottom: theme.spacing(3)
63
+ }
64
+ }
65
+ }));
66
+ const entityWarningContent = /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(EntitySwitch, null, /* @__PURE__ */ React.createElement(EntitySwitch.Case, { if: isOrphan }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(EntityOrphanWarning, null)))), /* @__PURE__ */ React.createElement(EntitySwitch, null, /* @__PURE__ */ React.createElement(EntitySwitch.Case, { if: hasRelationWarnings }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(EntityRelationWarning, null)))), /* @__PURE__ */ React.createElement(EntitySwitch, null, /* @__PURE__ */ React.createElement(EntitySwitch.Case, { if: hasCatalogProcessingErrors }, /* @__PURE__ */ React.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React.createElement(EntityProcessingErrorsPanel, null)))));
67
+ function DefaultEntityContentLayout(props) {
68
+ const { cards } = props;
69
+ const infoCards = cards.filter((card) => card.type === "info");
70
+ const summaryCards = cards.filter((card) => card.type === "summary");
71
+ const contentCards = cards.filter(
72
+ (card) => !card.type || card.type === "content"
73
+ );
74
+ const classes = useStyles({
75
+ infoCards: !!infoCards.length,
76
+ summaryCards: !!summaryCards.length,
77
+ contentCards: !!contentCards.length
78
+ });
79
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, entityWarningContent, /* @__PURE__ */ React.createElement("div", { className: classes.root }, infoCards.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: classes.infoArea }, infoCards.map((card) => card.element)) : null, summaryCards.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: classes.summaryArea }, /* @__PURE__ */ React.createElement(HorizontalScrollGrid, null, summaryCards.map((card) => /* @__PURE__ */ React.createElement("div", { className: classes.summaryCard }, card.element)))) : null, contentCards.length > 0 ? /* @__PURE__ */ React.createElement("div", { className: classes.contentArea }, contentCards.map((card) => card.element)) : null));
80
+ }
81
+
82
+ export { DefaultEntityContentLayout };
83
+ //# sourceMappingURL=DefaultEntityContentLayout.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultEntityContentLayout.esm.js","sources":["../../src/alpha/DefaultEntityContentLayout.tsx"],"sourcesContent":["/*\n * Copyright 2023 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 from '@material-ui/core/Grid';\nimport { makeStyles, Theme } from '@material-ui/core/styles';\nimport { EntityContentLayoutProps } from '@backstage/plugin-catalog-react/alpha';\nimport { EntitySwitch } from '../components/EntitySwitch';\nimport {\n EntityOrphanWarning,\n isOrphan,\n} from '../components/EntityOrphanWarning';\nimport {\n EntityRelationWarning,\n hasRelationWarnings,\n} from '../components/EntityRelationWarning';\nimport {\n EntityProcessingErrorsPanel,\n hasCatalogProcessingErrors,\n} from '../components/EntityProcessingErrorsPanel';\nimport { HorizontalScrollGrid } from '@backstage/core-components';\n\nconst useStyles = makeStyles<\n Theme,\n { infoCards: boolean; summaryCards: boolean; contentCards: boolean }\n>(theme => ({\n root: {\n display: 'flex',\n flexFlow: 'column nowrap',\n gap: theme.spacing(3),\n },\n contentArea: {\n display: 'flex',\n flexFlow: 'column',\n gap: theme.spacing(3),\n alignItems: 'stretch',\n minWidth: 0,\n },\n infoArea: {\n display: 'flex',\n flexFlow: 'column nowrap',\n alignItems: 'stretch',\n gap: theme.spacing(3),\n minWidth: 0,\n },\n summaryArea: {\n margin: theme.spacing(1.5), // To counteract MUI negative grid margin\n },\n summaryCard: {\n flex: '0 0 auto',\n '& + &': {\n marginLeft: theme.spacing(3),\n },\n },\n [theme.breakpoints.up('md')]: {\n root: {\n display: 'grid',\n gap: 0,\n gridTemplateAreas: ({ summaryCards }) => `\n \"${summaryCards ? 'summary' : 'content'} info\"\n \"content info\"\n `,\n gridTemplateColumns: ({ infoCards }) => (infoCards ? '2fr 1fr' : '1fr'),\n alignItems: 'start',\n },\n infoArea: {\n gridArea: 'info',\n position: 'sticky',\n top: theme.spacing(3),\n marginLeft: theme.spacing(3),\n },\n contentArea: {\n gridArea: 'content',\n },\n summaryArea: {\n gridArea: 'summary',\n marginBottom: theme.spacing(3),\n },\n },\n}));\n\nconst entityWarningContent = (\n <>\n <EntitySwitch>\n <EntitySwitch.Case if={isOrphan}>\n <Grid item xs={12}>\n <EntityOrphanWarning />\n </Grid>\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasRelationWarnings}>\n <Grid item xs={12}>\n <EntityRelationWarning />\n </Grid>\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasCatalogProcessingErrors}>\n <Grid item xs={12}>\n <EntityProcessingErrorsPanel />\n </Grid>\n </EntitySwitch.Case>\n </EntitySwitch>\n </>\n);\n\nexport function DefaultEntityContentLayout(props: EntityContentLayoutProps) {\n const { cards } = props;\n\n const infoCards = cards.filter(card => card.type === 'info');\n const summaryCards = cards.filter(card => card.type === 'summary');\n const contentCards = cards.filter(\n card => !card.type || card.type === 'content',\n );\n\n const classes = useStyles({\n infoCards: !!infoCards.length,\n summaryCards: !!summaryCards.length,\n contentCards: !!contentCards.length,\n });\n\n return (\n <>\n {entityWarningContent}\n <div className={classes.root}>\n {infoCards.length > 0 ? (\n <div className={classes.infoArea}>\n {infoCards.map(card => card.element)}\n </div>\n ) : null}\n {summaryCards.length > 0 ? (\n <div className={classes.summaryArea}>\n <HorizontalScrollGrid>\n {summaryCards.map(card => (\n <div className={classes.summaryCard}>{card.element}</div>\n ))}\n </HorizontalScrollGrid>\n </div>\n ) : null}\n {contentCards.length > 0 ? (\n <div className={classes.contentArea}>\n {contentCards.map(card => card.element)}\n </div>\n ) : null}\n </div>\n </>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,187 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
3
+ import useAsync from 'react-use/esm/useAsync';
4
+ import { makeStyles } from '@material-ui/core/styles';
5
+ import Box from '@material-ui/core/Box';
6
+ import { Header, Breadcrumbs } from '@backstage/core-components';
7
+ import { useRouteRefParams, useRouteRef, useApi } from '@backstage/core-plugin-api';
8
+ import { DEFAULT_NAMESPACE } from '@backstage/catalog-model';
9
+ import { useAsyncEntity, entityRouteRef, InspectEntityDialog, UnregisterEntityDialog, EntityDisplayName, FavoriteEntity, catalogApiRef, EntityRefLink } from '@backstage/plugin-catalog-react';
10
+ import { EntityLabels } from '../EntityLabels/EntityLabels.esm.js';
11
+ import { EntityContextMenu } from '../../../components/EntityContextMenu/EntityContextMenu.esm.js';
12
+ import { rootRouteRef, unregisterRedirectRouteRef } from '../../../routes.esm.js';
13
+
14
+ function headerProps(paramKind, paramNamespace, paramName, entity) {
15
+ const kind = paramKind ?? entity?.kind ?? "";
16
+ const namespace = paramNamespace ?? entity?.metadata.namespace ?? "";
17
+ const name = entity?.metadata.title ?? paramName ?? entity?.metadata.name ?? "";
18
+ return {
19
+ headerTitle: `${name}${namespace && namespace !== DEFAULT_NAMESPACE ? ` in ${namespace}` : ""}`,
20
+ headerType: (() => {
21
+ let t = kind.toLocaleLowerCase("en-US");
22
+ if (entity && entity.spec && "type" in entity.spec) {
23
+ t += " \u2014 ";
24
+ t += entity.spec.type.toLocaleLowerCase("en-US");
25
+ }
26
+ return t;
27
+ })()
28
+ };
29
+ }
30
+ function findParentRelation(entityRelations = [], relationTypes = []) {
31
+ for (const type of relationTypes) {
32
+ const foundRelation = entityRelations.find(
33
+ (relation) => relation.type === type
34
+ );
35
+ if (foundRelation) {
36
+ return foundRelation;
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ const useStyles = makeStyles((theme) => ({
42
+ breadcrumbs: {
43
+ color: theme.page.fontColor,
44
+ fontSize: theme.typography.caption.fontSize,
45
+ textTransform: "uppercase",
46
+ marginTop: theme.spacing(1),
47
+ opacity: 0.8,
48
+ "& span ": {
49
+ color: theme.page.fontColor,
50
+ textDecoration: "underline",
51
+ textUnderlineOffset: "3px"
52
+ }
53
+ }
54
+ }));
55
+ function EntityHeaderTitle() {
56
+ const { entity } = useAsyncEntity();
57
+ const { kind, namespace, name } = useRouteRefParams(entityRouteRef);
58
+ const { headerTitle: title } = headerProps(kind, namespace, name, entity);
59
+ return /* @__PURE__ */ React.createElement(Box, { display: "inline-flex", alignItems: "center", height: "1em", maxWidth: "100%" }, /* @__PURE__ */ React.createElement(
60
+ Box,
61
+ {
62
+ component: "span",
63
+ textOverflow: "ellipsis",
64
+ whiteSpace: "nowrap",
65
+ overflow: "hidden"
66
+ },
67
+ entity ? /* @__PURE__ */ React.createElement(EntityDisplayName, { entityRef: entity, hideIcon: true }) : title
68
+ ), entity && /* @__PURE__ */ React.createElement(FavoriteEntity, { entity }));
69
+ }
70
+ function EntityHeaderSubtitle(props) {
71
+ const { parentEntityRelations } = props;
72
+ const classes = useStyles();
73
+ const { entity } = useAsyncEntity();
74
+ const { name } = useRouteRefParams(entityRouteRef);
75
+ const parentEntity = findParentRelation(
76
+ entity?.relations ?? [],
77
+ parentEntityRelations ?? []
78
+ );
79
+ const catalogApi = useApi(catalogApiRef);
80
+ const { value: ancestorEntity } = useAsync(async () => {
81
+ if (parentEntity) {
82
+ return findParentRelation(
83
+ (await catalogApi.getEntityByRef(parentEntity?.targetRef))?.relations,
84
+ parentEntityRelations
85
+ );
86
+ }
87
+ return null;
88
+ }, [parentEntity, catalogApi]);
89
+ return parentEntity ? /* @__PURE__ */ React.createElement(Breadcrumbs, { separator: ">", className: classes.breadcrumbs }, ancestorEntity && /* @__PURE__ */ React.createElement(EntityRefLink, { entityRef: ancestorEntity.targetRef, disableTooltip: true }), /* @__PURE__ */ React.createElement(EntityRefLink, { entityRef: parentEntity.targetRef, disableTooltip: true }), name) : null;
90
+ }
91
+ function EntityHeader(props) {
92
+ const {
93
+ UNSTABLE_extraContextMenuItems,
94
+ UNSTABLE_contextMenuOptions,
95
+ parentEntityRelations,
96
+ title,
97
+ subtitle
98
+ } = props;
99
+ const { entity } = useAsyncEntity();
100
+ const { kind, namespace, name } = useRouteRefParams(entityRouteRef);
101
+ const { headerTitle: entityFallbackText, headerType: type } = headerProps(
102
+ kind,
103
+ namespace,
104
+ name,
105
+ entity
106
+ );
107
+ const location = useLocation();
108
+ const navigate = useNavigate();
109
+ const catalogRoute = useRouteRef(rootRouteRef);
110
+ const unregisterRedirectRoute = useRouteRef(unregisterRedirectRouteRef);
111
+ const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
112
+ const openUnregisterEntityDialog = useCallback(
113
+ () => setConfirmationDialogOpen(true),
114
+ [setConfirmationDialogOpen]
115
+ );
116
+ const closeUnregisterEntityDialog = useCallback(
117
+ () => setConfirmationDialogOpen(false),
118
+ [setConfirmationDialogOpen]
119
+ );
120
+ const cleanUpAfterUnregisterConfirmation = useCallback(async () => {
121
+ setConfirmationDialogOpen(false);
122
+ navigate(
123
+ unregisterRedirectRoute ? unregisterRedirectRoute() : catalogRoute()
124
+ );
125
+ }, [
126
+ navigate,
127
+ catalogRoute,
128
+ unregisterRedirectRoute,
129
+ setConfirmationDialogOpen
130
+ ]);
131
+ useEffect(() => {
132
+ setConfirmationDialogOpen(false);
133
+ }, [location.pathname]);
134
+ const [searchParams, setSearchParams] = useSearchParams();
135
+ const selectedInspectEntityDialogTab = searchParams.get("inspect");
136
+ const setInspectEntityDialogTab = useCallback(
137
+ (newTab) => setSearchParams(`inspect=${newTab}`),
138
+ [setSearchParams]
139
+ );
140
+ const openInspectEntityDialog = useCallback(
141
+ () => setSearchParams("inspect"),
142
+ [setSearchParams]
143
+ );
144
+ const closeInspectEntityDialog = useCallback(
145
+ () => setSearchParams(),
146
+ [setSearchParams]
147
+ );
148
+ const inspectDialogOpen = typeof selectedInspectEntityDialogTab === "string";
149
+ return /* @__PURE__ */ React.createElement(
150
+ Header,
151
+ {
152
+ pageTitleOverride: entityFallbackText,
153
+ type,
154
+ title: title ?? /* @__PURE__ */ React.createElement(EntityHeaderTitle, null),
155
+ subtitle: subtitle ?? /* @__PURE__ */ React.createElement(EntityHeaderSubtitle, { parentEntityRelations })
156
+ },
157
+ entity && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(EntityLabels, { entity }), /* @__PURE__ */ React.createElement(
158
+ EntityContextMenu,
159
+ {
160
+ UNSTABLE_extraContextMenuItems,
161
+ UNSTABLE_contextMenuOptions,
162
+ onInspectEntity: openInspectEntityDialog,
163
+ onUnregisterEntity: openUnregisterEntityDialog
164
+ }
165
+ ), /* @__PURE__ */ React.createElement(
166
+ InspectEntityDialog,
167
+ {
168
+ entity,
169
+ initialTab: selectedInspectEntityDialogTab || void 0,
170
+ open: inspectDialogOpen,
171
+ onClose: closeInspectEntityDialog,
172
+ onSelect: setInspectEntityDialogTab
173
+ }
174
+ ), /* @__PURE__ */ React.createElement(
175
+ UnregisterEntityDialog,
176
+ {
177
+ entity,
178
+ open: confirmationDialogOpen,
179
+ onClose: closeUnregisterEntityDialog,
180
+ onConfirm: cleanUpAfterUnregisterConfirmation
181
+ }
182
+ ))
183
+ );
184
+ }
185
+
186
+ export { EntityHeader };
187
+ //# sourceMappingURL=EntityHeader.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityHeader.esm.js","sources":["../../../../src/alpha/components/EntityHeader/EntityHeader.tsx"],"sourcesContent":["/*\n * Copyright 2025 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, {\n useState,\n useCallback,\n useEffect,\n ComponentProps,\n ReactNode,\n} from 'react';\nimport { useNavigate, useLocation, useSearchParams } from 'react-router-dom';\nimport useAsync from 'react-use/esm/useAsync';\n\nimport { makeStyles } from '@material-ui/core/styles';\nimport Box from '@material-ui/core/Box';\n\nimport { Header, Breadcrumbs } from '@backstage/core-components';\nimport {\n useApi,\n useRouteRef,\n useRouteRefParams,\n} from '@backstage/core-plugin-api';\nimport { IconComponent } from '@backstage/frontend-plugin-api';\n\nimport {\n Entity,\n EntityRelation,\n DEFAULT_NAMESPACE,\n} from '@backstage/catalog-model';\n\nimport {\n useAsyncEntity,\n entityRouteRef,\n catalogApiRef,\n EntityRefLink,\n InspectEntityDialog,\n UnregisterEntityDialog,\n EntityDisplayName,\n FavoriteEntity,\n} from '@backstage/plugin-catalog-react';\n\nimport { EntityLabels } from '../EntityLabels';\nimport { EntityContextMenu } from '../../../components/EntityContextMenu';\nimport { rootRouteRef, unregisterRedirectRouteRef } from '../../../routes';\n\nfunction 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\n return {\n headerTitle: `${name}${\n namespace && namespace !== DEFAULT_NAMESPACE ? ` in ${namespace}` : ''\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\nfunction findParentRelation(\n entityRelations: EntityRelation[] = [],\n relationTypes: string[] = [],\n) {\n for (const type of relationTypes) {\n const foundRelation = entityRelations.find(\n relation => relation.type === type,\n );\n if (foundRelation) {\n return foundRelation; // Return the first found relation and stop\n }\n }\n return null;\n}\n\nconst useStyles = makeStyles(theme => ({\n breadcrumbs: {\n color: theme.page.fontColor,\n fontSize: theme.typography.caption.fontSize,\n textTransform: 'uppercase',\n marginTop: theme.spacing(1),\n opacity: 0.8,\n '& span ': {\n color: theme.page.fontColor,\n textDecoration: 'underline',\n textUnderlineOffset: '3px',\n },\n },\n}));\n\nfunction EntityHeaderTitle() {\n const { entity } = useAsyncEntity();\n const { kind, namespace, name } = useRouteRefParams(entityRouteRef);\n const { headerTitle: title } = headerProps(kind, namespace, name, entity);\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 {entity ? <EntityDisplayName entityRef={entity} hideIcon /> : title}\n </Box>\n {entity && <FavoriteEntity entity={entity} />}\n </Box>\n );\n}\n\nfunction EntityHeaderSubtitle(props: { parentEntityRelations?: string[] }) {\n const { parentEntityRelations } = props;\n const classes = useStyles();\n const { entity } = useAsyncEntity();\n const { name } = useRouteRefParams(entityRouteRef);\n const parentEntity = findParentRelation(\n entity?.relations ?? [],\n parentEntityRelations ?? [],\n );\n\n const catalogApi = useApi(catalogApiRef);\n\n const { value: ancestorEntity } = useAsync(async () => {\n if (parentEntity) {\n return findParentRelation(\n (await catalogApi.getEntityByRef(parentEntity?.targetRef))?.relations,\n parentEntityRelations,\n );\n }\n return null;\n }, [parentEntity, catalogApi]);\n\n return parentEntity ? (\n <Breadcrumbs separator=\">\" className={classes.breadcrumbs}>\n {ancestorEntity && (\n <EntityRefLink entityRef={ancestorEntity.targetRef} disableTooltip />\n )}\n <EntityRefLink entityRef={parentEntity.targetRef} disableTooltip />\n {name}\n </Breadcrumbs>\n ) : null;\n}\n\n/** @alpha */\nexport function EntityHeader(props: {\n // NOTE(freben): Intentionally not exported at this point, since it's part of\n // the unstable extra context menu items concept below\n UNSTABLE_extraContextMenuItems?: {\n title: string;\n Icon: IconComponent;\n onClick: () => void;\n }[];\n // NOTE(blam): Intentionally not exported at this point, since it's part of\n // unstable context menu option, eg: disable the unregister entity menu\n UNSTABLE_contextMenuOptions?: {\n disableUnregister: boolean | 'visible' | 'hidden' | 'disable';\n };\n /**\n * An array of relation types used to determine the parent entities in the hierarchy.\n * These relations are prioritized in the order provided, allowing for flexible\n * navigation through entity relationships.\n *\n * For example, use relation types like `[\"partOf\", \"memberOf\", \"ownedBy\"]` to define how the entity is related to\n * its parents in the Entity Catalog.\n *\n * It adds breadcrumbs in the Entity page to enhance user navigation and context awareness.\n */\n parentEntityRelations?: string[];\n title?: ReactNode;\n subtitle?: ReactNode;\n}) {\n const {\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n parentEntityRelations,\n title,\n subtitle,\n } = props;\n const { entity } = useAsyncEntity();\n const { kind, namespace, name } = useRouteRefParams(entityRouteRef);\n const { headerTitle: entityFallbackText, headerType: type } = headerProps(\n kind,\n namespace,\n name,\n entity,\n );\n\n const location = useLocation();\n const navigate = useNavigate();\n const catalogRoute = useRouteRef(rootRouteRef);\n const unregisterRedirectRoute = useRouteRef(unregisterRedirectRouteRef);\n\n const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);\n\n const openUnregisterEntityDialog = useCallback(\n () => setConfirmationDialogOpen(true),\n [setConfirmationDialogOpen],\n );\n\n const closeUnregisterEntityDialog = useCallback(\n () => setConfirmationDialogOpen(false),\n [setConfirmationDialogOpen],\n );\n\n const cleanUpAfterUnregisterConfirmation = useCallback(async () => {\n setConfirmationDialogOpen(false);\n navigate(\n unregisterRedirectRoute ? unregisterRedirectRoute() : catalogRoute(),\n );\n }, [\n navigate,\n catalogRoute,\n unregisterRedirectRoute,\n setConfirmationDialogOpen,\n ]);\n\n // Make sure to close the dialog if the user clicks links in it that navigate\n // to another entity.\n useEffect(() => {\n setConfirmationDialogOpen(false);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [location.pathname]);\n\n const [searchParams, setSearchParams] = useSearchParams();\n const selectedInspectEntityDialogTab = searchParams.get('inspect');\n\n const setInspectEntityDialogTab = useCallback(\n (newTab: string) => setSearchParams(`inspect=${newTab}`),\n [setSearchParams],\n );\n\n const openInspectEntityDialog = useCallback(\n () => setSearchParams('inspect'),\n [setSearchParams],\n );\n\n const closeInspectEntityDialog = useCallback(\n () => setSearchParams(),\n [setSearchParams],\n );\n\n const inspectDialogOpen = typeof selectedInspectEntityDialogTab === 'string';\n\n return (\n <Header\n pageTitleOverride={entityFallbackText}\n type={type}\n title={title ?? <EntityHeaderTitle />}\n subtitle={\n subtitle ?? (\n <EntityHeaderSubtitle parentEntityRelations={parentEntityRelations} />\n )\n }\n >\n {entity && (\n <>\n <EntityLabels entity={entity} />\n <EntityContextMenu\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n onInspectEntity={openInspectEntityDialog}\n onUnregisterEntity={openUnregisterEntityDialog}\n />\n <InspectEntityDialog\n entity={entity!}\n initialTab={\n (selectedInspectEntityDialogTab as ComponentProps<\n typeof InspectEntityDialog\n >['initialTab']) || undefined\n }\n open={inspectDialogOpen}\n onClose={closeInspectEntityDialog}\n onSelect={setInspectEntityDialogTab}\n />\n <UnregisterEntityDialog\n entity={entity!}\n open={confirmationDialogOpen}\n onClose={closeUnregisterEntityDialog}\n onConfirm={cleanUpAfterUnregisterConfirmation}\n />\n </>\n )}\n </Header>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AA0DA,SAAS,WACP,CAAA,SAAA,EACA,cACA,EAAA,SAAA,EACA,MAC6C,EAAA;AAC7C,EAAM,MAAA,IAAA,GAAO,SAAa,IAAA,MAAA,EAAQ,IAAQ,IAAA,EAAA;AAC1C,EAAA,MAAM,SAAY,GAAA,cAAA,IAAkB,MAAQ,EAAA,QAAA,CAAS,SAAa,IAAA,EAAA;AAClE,EAAA,MAAM,OACJ,MAAQ,EAAA,QAAA,CAAS,SAAS,SAAa,IAAA,MAAA,EAAQ,SAAS,IAAQ,IAAA,EAAA;AAElE,EAAO,OAAA;AAAA,IACL,WAAA,EAAa,CAAG,EAAA,IAAI,CAClB,EAAA,SAAA,IAAa,cAAc,iBAAoB,GAAA,CAAA,IAAA,EAAO,SAAS,CAAA,CAAA,GAAK,EACtE,CAAA,CAAA;AAAA,IACA,aAAa,MAAM;AACjB,MAAI,IAAA,CAAA,GAAI,IAAK,CAAA,iBAAA,CAAkB,OAAO,CAAA;AACtC,MAAA,IAAI,MAAU,IAAA,MAAA,CAAO,IAAQ,IAAA,MAAA,IAAU,OAAO,IAAM,EAAA;AAClD,QAAK,CAAA,IAAA,UAAA;AACL,QAAA,CAAA,IAAM,MAAO,CAAA,IAAA,CAA0B,IAAK,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA;AAEvE,MAAO,OAAA,CAAA;AAAA,KACN;AAAA,GACL;AACF;AAEA,SAAS,mBACP,eAAoC,GAAA,EACpC,EAAA,aAAA,GAA0B,EAC1B,EAAA;AACA,EAAA,KAAA,MAAW,QAAQ,aAAe,EAAA;AAChC,IAAA,MAAM,gBAAgB,eAAgB,CAAA,IAAA;AAAA,MACpC,CAAA,QAAA,KAAY,SAAS,IAAS,KAAA;AAAA,KAChC;AACA,IAAA,IAAI,aAAe,EAAA;AACjB,MAAO,OAAA,aAAA;AAAA;AACT;AAEF,EAAO,OAAA,IAAA;AACT;AAEA,MAAM,SAAA,GAAY,WAAW,CAAU,KAAA,MAAA;AAAA,EACrC,WAAa,EAAA;AAAA,IACX,KAAA,EAAO,MAAM,IAAK,CAAA,SAAA;AAAA,IAClB,QAAA,EAAU,KAAM,CAAA,UAAA,CAAW,OAAQ,CAAA,QAAA;AAAA,IACnC,aAAe,EAAA,WAAA;AAAA,IACf,SAAA,EAAW,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAAA,IAC1B,OAAS,EAAA,GAAA;AAAA,IACT,SAAW,EAAA;AAAA,MACT,KAAA,EAAO,MAAM,IAAK,CAAA,SAAA;AAAA,MAClB,cAAgB,EAAA,WAAA;AAAA,MAChB,mBAAqB,EAAA;AAAA;AACvB;AAEJ,CAAE,CAAA,CAAA;AAEF,SAAS,iBAAoB,GAAA;AAC3B,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,cAAe,EAAA;AAClC,EAAA,MAAM,EAAE,IAAM,EAAA,SAAA,EAAW,IAAK,EAAA,GAAI,kBAAkB,cAAc,CAAA;AAClE,EAAM,MAAA,EAAE,aAAa,KAAM,EAAA,GAAI,YAAY,IAAM,EAAA,SAAA,EAAW,MAAM,MAAM,CAAA;AACxE,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,OAAI,OAAQ,EAAA,aAAA,EAAc,YAAW,QAAS,EAAA,MAAA,EAAO,KAAM,EAAA,QAAA,EAAS,MACnE,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,SAAU,EAAA,MAAA;AAAA,MACV,YAAa,EAAA,UAAA;AAAA,MACb,UAAW,EAAA,QAAA;AAAA,MACX,QAAS,EAAA;AAAA,KAAA;AAAA,IAER,yBAAU,KAAA,CAAA,aAAA,CAAA,iBAAA,EAAA,EAAkB,WAAW,MAAQ,EAAA,QAAA,EAAQ,MAAC,CAAK,GAAA;AAAA,GAE/D,EAAA,MAAA,oBAAW,KAAA,CAAA,aAAA,CAAA,cAAA,EAAA,EAAe,QAAgB,CAC7C,CAAA;AAEJ;AAEA,SAAS,qBAAqB,KAA6C,EAAA;AACzE,EAAM,MAAA,EAAE,uBAA0B,GAAA,KAAA;AAClC,EAAA,MAAM,UAAU,SAAU,EAAA;AAC1B,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,cAAe,EAAA;AAClC,EAAA,MAAM,EAAE,IAAA,EAAS,GAAA,iBAAA,CAAkB,cAAc,CAAA;AACjD,EAAA,MAAM,YAAe,GAAA,kBAAA;AAAA,IACnB,MAAA,EAAQ,aAAa,EAAC;AAAA,IACtB,yBAAyB;AAAC,GAC5B;AAEA,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM,EAAE,KAAA,EAAO,cAAe,EAAA,GAAI,SAAS,YAAY;AACrD,IAAA,IAAI,YAAc,EAAA;AAChB,MAAO,OAAA,kBAAA;AAAA,QAAA,CACJ,MAAM,UAAA,CAAW,cAAe,CAAA,YAAA,EAAc,SAAS,CAAI,GAAA,SAAA;AAAA,QAC5D;AAAA,OACF;AAAA;AAEF,IAAO,OAAA,IAAA;AAAA,GACN,EAAA,CAAC,YAAc,EAAA,UAAU,CAAC,CAAA;AAE7B,EAAO,OAAA,YAAA,mBACJ,KAAA,CAAA,aAAA,CAAA,WAAA,EAAA,EAAY,SAAU,EAAA,GAAA,EAAI,SAAW,EAAA,OAAA,CAAQ,WAC3C,EAAA,EAAA,cAAA,oBACE,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA,EAAc,SAAW,EAAA,cAAA,CAAe,WAAW,cAAc,EAAA,IAAA,EAAC,CAErE,kBAAA,KAAA,CAAA,aAAA,CAAC,aAAc,EAAA,EAAA,SAAA,EAAW,YAAa,CAAA,SAAA,EAAW,cAAc,EAAA,IAAA,EAAC,CAChE,EAAA,IACH,CACE,GAAA,IAAA;AACN;AAGO,SAAS,aAAa,KA0B1B,EAAA;AACD,EAAM,MAAA;AAAA,IACJ,8BAAA;AAAA,IACA,2BAAA;AAAA,IACA,qBAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACE,GAAA,KAAA;AACJ,EAAM,MAAA,EAAE,MAAO,EAAA,GAAI,cAAe,EAAA;AAClC,EAAA,MAAM,EAAE,IAAM,EAAA,SAAA,EAAW,IAAK,EAAA,GAAI,kBAAkB,cAAc,CAAA;AAClE,EAAA,MAAM,EAAE,WAAA,EAAa,kBAAoB,EAAA,UAAA,EAAY,MAAS,GAAA,WAAA;AAAA,IAC5D,IAAA;AAAA,IACA,SAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,WAAW,WAAY,EAAA;AAC7B,EAAA,MAAM,WAAW,WAAY,EAAA;AAC7B,EAAM,MAAA,YAAA,GAAe,YAAY,YAAY,CAAA;AAC7C,EAAM,MAAA,uBAAA,GAA0B,YAAY,0BAA0B,CAAA;AAEtE,EAAA,MAAM,CAAC,sBAAA,EAAwB,yBAAyB,CAAA,GAAI,SAAS,KAAK,CAAA;AAE1E,EAAA,MAAM,0BAA6B,GAAA,WAAA;AAAA,IACjC,MAAM,0BAA0B,IAAI,CAAA;AAAA,IACpC,CAAC,yBAAyB;AAAA,GAC5B;AAEA,EAAA,MAAM,2BAA8B,GAAA,WAAA;AAAA,IAClC,MAAM,0BAA0B,KAAK,CAAA;AAAA,IACrC,CAAC,yBAAyB;AAAA,GAC5B;AAEA,EAAM,MAAA,kCAAA,GAAqC,YAAY,YAAY;AACjE,IAAA,yBAAA,CAA0B,KAAK,CAAA;AAC/B,IAAA,QAAA;AAAA,MACE,uBAAA,GAA0B,uBAAwB,EAAA,GAAI,YAAa;AAAA,KACrE;AAAA,GACC,EAAA;AAAA,IACD,QAAA;AAAA,IACA,YAAA;AAAA,IACA,uBAAA;AAAA,IACA;AAAA,GACD,CAAA;AAID,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,yBAAA,CAA0B,KAAK,CAAA;AAAA,GAE9B,EAAA,CAAC,QAAS,CAAA,QAAQ,CAAC,CAAA;AAEtB,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,eAAgB,EAAA;AACxD,EAAM,MAAA,8BAAA,GAAiC,YAAa,CAAA,GAAA,CAAI,SAAS,CAAA;AAEjE,EAAA,MAAM,yBAA4B,GAAA,WAAA;AAAA,IAChC,CAAC,MAAA,KAAmB,eAAgB,CAAA,CAAA,QAAA,EAAW,MAAM,CAAE,CAAA,CAAA;AAAA,IACvD,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,uBAA0B,GAAA,WAAA;AAAA,IAC9B,MAAM,gBAAgB,SAAS,CAAA;AAAA,IAC/B,CAAC,eAAe;AAAA,GAClB;AAEA,EAAA,MAAM,wBAA2B,GAAA,WAAA;AAAA,IAC/B,MAAM,eAAgB,EAAA;AAAA,IACtB,CAAC,eAAe;AAAA,GAClB;AAEA,EAAM,MAAA,iBAAA,GAAoB,OAAO,8BAAmC,KAAA,QAAA;AAEpE,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,iBAAmB,EAAA,kBAAA;AAAA,MACnB,IAAA;AAAA,MACA,KAAA,EAAO,KAAS,oBAAA,KAAA,CAAA,aAAA,CAAC,iBAAkB,EAAA,IAAA,CAAA;AAAA,MACnC,QACE,EAAA,QAAA,oBACG,KAAA,CAAA,aAAA,CAAA,oBAAA,EAAA,EAAqB,qBAA8C,EAAA;AAAA,KAAA;AAAA,IAIvE,MACC,oBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBACG,KAAA,CAAA,aAAA,CAAA,YAAA,EAAA,EAAa,QAAgB,CAC9B,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,iBAAA;AAAA,MAAA;AAAA,QACC,8BAAA;AAAA,QACA,2BAAA;AAAA,QACA,eAAiB,EAAA,uBAAA;AAAA,QACjB,kBAAoB,EAAA;AAAA;AAAA,KAEtB,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QACC,MAAA;AAAA,QACA,YACG,8BAEmB,IAAA,KAAA,CAAA;AAAA,QAEtB,IAAM,EAAA,iBAAA;AAAA,QACN,OAAS,EAAA,wBAAA;AAAA,QACT,QAAU,EAAA;AAAA;AAAA,KAEZ,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,sBAAA;AAAA,MAAA;AAAA,QACC,MAAA;AAAA,QACA,IAAM,EAAA,sBAAA;AAAA,QACN,OAAS,EAAA,2BAAA;AAAA,QACT,SAAW,EAAA;AAAA;AAAA,KAEf;AAAA,GAEJ;AAEJ;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"EntityLabels.esm.js","sources":["../../../../src/alpha/components/EntityLabels/EntityLabels.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { HeaderLabel } from '@backstage/core-components';\nimport { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { catalogTranslationRef } from '../../../alpha/translation';\n\ntype EntityLabelsProps = {\n entity: Entity;\n};\n\nexport function EntityLabels(props: EntityLabelsProps) {\n const { entity } = props;\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n const { t } = useTranslationRef(catalogTranslationRef);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label={t('entityLabels.ownerLabel')}\n contentTypograpyRootComponent=\"p\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel\n label={t('entityLabels.lifecycleLabel')}\n value={entity.spec.lifecycle?.toString()}\n />\n )}\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA8BO,SAAS,aAAa,KAA0B,EAAA;AACrD,EAAM,MAAA,EAAE,QAAW,GAAA,KAAA;AACnB,EAAM,MAAA,gBAAA,GAAmB,kBAAmB,CAAA,MAAA,EAAQ,iBAAiB,CAAA;AACrE,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,qBAAqB,CAAA;AACrD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EACG,gBAAiB,CAAA,MAAA,GAAS,CACzB,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,MAClC,6BAA8B,EAAA,GAAA;AAAA,MAC9B,KACE,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UACC,UAAY,EAAA,gBAAA;AAAA,UACZ,WAAY,EAAA,OAAA;AAAA,UACZ,KAAM,EAAA;AAAA;AAAA;AACR;AAAA,GAEJ,EAED,MAAO,CAAA,IAAA,EAAM,SACZ,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,6BAA6B,CAAA;AAAA,MACtC,KAAO,EAAA,MAAA,CAAO,IAAK,CAAA,SAAA,EAAW,QAAS;AAAA;AAAA,GAG7C,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EntityLabels.esm.js","sources":["../../../../src/alpha/components/EntityLabels/EntityLabels.tsx"],"sourcesContent":["/*\n * Copyright 2025 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 { HeaderLabel } from '@backstage/core-components';\nimport { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';\nimport {\n EntityRefLinks,\n getEntityRelations,\n} from '@backstage/plugin-catalog-react';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport { catalogTranslationRef } from '../../translation';\n\ntype EntityLabelsProps = {\n entity: Entity;\n};\n\nexport function EntityLabels(props: EntityLabelsProps) {\n const { entity } = props;\n const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);\n const { t } = useTranslationRef(catalogTranslationRef);\n return (\n <>\n {ownedByRelations.length > 0 && (\n <HeaderLabel\n label={t('entityLabels.ownerLabel')}\n contentTypograpyRootComponent=\"p\"\n value={\n <EntityRefLinks\n entityRefs={ownedByRelations}\n defaultKind=\"Group\"\n color=\"inherit\"\n />\n }\n />\n )}\n {entity.spec?.lifecycle && (\n <HeaderLabel\n label={t('entityLabels.lifecycleLabel')}\n value={entity.spec.lifecycle?.toString()}\n />\n )}\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA8BO,SAAS,aAAa,KAA0B,EAAA;AACrD,EAAM,MAAA,EAAE,QAAW,GAAA,KAAA;AACnB,EAAM,MAAA,gBAAA,GAAmB,kBAAmB,CAAA,MAAA,EAAQ,iBAAiB,CAAA;AACrE,EAAA,MAAM,EAAE,CAAA,EAAM,GAAA,iBAAA,CAAkB,qBAAqB,CAAA;AACrD,EACE,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EACG,gBAAiB,CAAA,MAAA,GAAS,CACzB,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,yBAAyB,CAAA;AAAA,MAClC,6BAA8B,EAAA,GAAA;AAAA,MAC9B,KACE,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UACC,UAAY,EAAA,gBAAA;AAAA,UACZ,WAAY,EAAA,OAAA;AAAA,UACZ,KAAM,EAAA;AAAA;AAAA;AACR;AAAA,GAEJ,EAED,MAAO,CAAA,IAAA,EAAM,SACZ,oBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAE,6BAA6B,CAAA;AAAA,MACtC,KAAO,EAAA,MAAA,CAAO,IAAK,CAAA,SAAA,EAAW,QAAS;AAAA;AAAA,GAG7C,CAAA;AAEJ;;;;"}