@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 +188 -0
- package/dist/alpha/DefaultEntityContentLayout.esm.js +83 -0
- package/dist/alpha/DefaultEntityContentLayout.esm.js.map +1 -0
- package/dist/alpha/components/EntityHeader/EntityHeader.esm.js +187 -0
- package/dist/alpha/components/EntityHeader/EntityHeader.esm.js.map +1 -0
- package/dist/alpha/components/EntityLabels/EntityLabels.esm.js.map +1 -1
- package/dist/alpha/components/EntityLayout/EntityLayout.esm.js +13 -137
- package/dist/alpha/components/EntityLayout/EntityLayout.esm.js.map +1 -1
- package/dist/alpha/entityContents.esm.js +2 -2
- package/dist/alpha/entityContents.esm.js.map +1 -1
- package/dist/alpha/filter/FilterWrapper.esm.js +3 -11
- package/dist/alpha/filter/FilterWrapper.esm.js.map +1 -1
- package/dist/alpha/pages.esm.js +39 -28
- package/dist/alpha/pages.esm.js.map +1 -1
- package/dist/alpha.d.ts +240 -235
- package/dist/apis/EntityPresentationApi/DefaultEntityPresentationApi.esm.js +33 -2
- package/dist/apis/EntityPresentationApi/DefaultEntityPresentationApi.esm.js.map +1 -1
- package/dist/index.d.ts +12 -13
- package/package.json +23 -24
- package/dist/alpha/EntityOverviewPage.esm.js +0 -17
- package/dist/alpha/EntityOverviewPage.esm.js.map +0 -1
- package/dist/alpha/components/EntityLayout/EntityLayoutTitle.esm.js +0 -20
- package/dist/alpha/components/EntityLayout/EntityLayoutTitle.esm.js.map +0 -1
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":"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"}
|
|
@@ -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 '
|
|
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;;;;"}
|