@backstage/plugin-catalog 1.32.3-next.0 → 1.33.0-next.2
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 +54 -0
- package/dist/alpha/DefaultEntityContentLayout.esm.js +7 -0
- package/dist/alpha/DefaultEntityContentLayout.esm.js.map +1 -1
- package/dist/alpha/components/EntityLayout/EntityLayout.esm.js +16 -10
- package/dist/alpha/components/EntityLayout/EntityLayout.esm.js.map +1 -1
- package/dist/alpha/components/EntityTabs/EntityTabs.esm.js +28 -14
- package/dist/alpha/components/EntityTabs/EntityTabs.esm.js.map +1 -1
- package/dist/alpha/components/EntityTabs/EntityTabsGroup.esm.js +76 -52
- package/dist/alpha/components/EntityTabs/EntityTabsGroup.esm.js.map +1 -1
- package/dist/alpha/components/EntityTabs/EntityTabsList.esm.js +34 -44
- package/dist/alpha/components/EntityTabs/EntityTabsList.esm.js.map +1 -1
- package/dist/alpha/pages.esm.js +36 -51
- package/dist/alpha/pages.esm.js.map +1 -1
- package/dist/alpha/translation.esm.js +19 -4
- package/dist/alpha/translation.esm.js.map +1 -1
- package/dist/alpha.d.ts +91 -68
- package/dist/components/AboutCard/AboutCard.esm.js +2 -2
- package/dist/components/AboutCard/AboutCard.esm.js.map +1 -1
- package/dist/components/AboutCard/AboutContent.esm.js +1 -1
- package/dist/components/AboutCard/AboutContent.esm.js.map +1 -1
- package/dist/components/AboutCard/AboutField.esm.js +4 -1
- package/dist/components/AboutCard/AboutField.esm.js.map +1 -1
- package/dist/components/CatalogSearchResultListItem/CatalogSearchResultListItem.esm.js +15 -3
- package/dist/components/CatalogSearchResultListItem/CatalogSearchResultListItem.esm.js.map +1 -1
- package/dist/components/CatalogTable/CatalogTable.esm.js +3 -1
- package/dist/components/CatalogTable/CatalogTable.esm.js.map +1 -1
- package/dist/components/CatalogTable/columns.esm.js +1 -1
- package/dist/components/CatalogTable/columns.esm.js.map +1 -1
- package/dist/components/EntityContextMenu/EntityContextMenu.esm.js +1 -1
- package/dist/components/EntityContextMenu/EntityContextMenu.esm.js.map +1 -1
- package/dist/components/EntityLayout/EntityLayout.esm.js +3 -7
- package/dist/components/EntityLayout/EntityLayout.esm.js.map +1 -1
- package/dist/components/EntityOrphanWarning/DeleteEntityDialog.esm.js +6 -18
- package/dist/components/EntityOrphanWarning/DeleteEntityDialog.esm.js.map +1 -1
- package/dist/components/EntityOrphanWarning/EntityOrphanWarning.esm.js +19 -2
- package/dist/components/EntityOrphanWarning/EntityOrphanWarning.esm.js.map +1 -1
- package/dist/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.esm.js +4 -4
- package/dist/components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.esm.js.map +1 -1
- package/dist/components/EntityRelationWarning/EntityRelationWarning.esm.js +16 -9
- package/dist/components/EntityRelationWarning/EntityRelationWarning.esm.js.map +1 -1
- package/dist/package.json.esm.js +4 -3
- package/dist/package.json.esm.js.map +1 -1
- package/package.json +22 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# @backstage/plugin-catalog
|
|
2
2
|
|
|
3
|
+
## 1.33.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 491a06c: Add the ability to show icons for the tabs on the entity page (new frontend)
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 220d6c3: Add missing translation entries for catalog UI text.
|
|
12
|
+
|
|
13
|
+
This change adds translation keys and updates relevant UI components to use the correct localized labels and text in the catalog plugin. It ensures that catalog screens such as entity layout, tabs, search result items, table labels, and other UI elements correctly reference the i18n system for translation.
|
|
14
|
+
|
|
15
|
+
No functional behavior is changed aside from the improved internationalization support.
|
|
16
|
+
|
|
17
|
+
- 7feb83b: Adjusted to use the new `@backstage/filter-predicates` types for predicate expressions.
|
|
18
|
+
- a7e0d50: Prepare for React Router v7 migration by updating to v6.30.2 across all NFS packages and enabling v7 future flags. Convert routes from splat paths to parent/child structure with Outlet components.
|
|
19
|
+
- 75ac651: Migrated `EntityRelationWarning` and `EntityProcessingErrorsPanel` components from Material UI to Backstage UI.
|
|
20
|
+
- Updated dependencies
|
|
21
|
+
- @backstage/ui@0.12.0-next.2
|
|
22
|
+
- @backstage/plugin-catalog-react@2.0.0-next.2
|
|
23
|
+
- @backstage/catalog-client@1.12.2-next.0
|
|
24
|
+
- @backstage/frontend-plugin-api@0.14.0-next.2
|
|
25
|
+
- @backstage/integration-react@1.2.15-next.2
|
|
26
|
+
- @backstage/core-compat-api@0.5.8-next.2
|
|
27
|
+
- @backstage/core-components@0.18.7-next.2
|
|
28
|
+
- @backstage/core-plugin-api@1.12.3-next.1
|
|
29
|
+
- @backstage/plugin-permission-react@0.4.40-next.1
|
|
30
|
+
- @backstage/version-bridge@1.0.12-next.0
|
|
31
|
+
- @backstage/plugin-techdocs-react@1.3.8-next.1
|
|
32
|
+
- @backstage/plugin-search-react@1.10.3-next.2
|
|
33
|
+
|
|
34
|
+
## 1.33.0-next.1
|
|
35
|
+
|
|
36
|
+
### Minor Changes
|
|
37
|
+
|
|
38
|
+
- 05aac34: Migrated `DeleteEntityDialog` and `EntityOrphanWarning` components to Backstage UI.
|
|
39
|
+
|
|
40
|
+
The `deleteEntity.description` translation key no longer includes "Click here to delete" text. A new `deleteEntity.actionButtonTitle` key was added for the action button.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- 8d4c48b: Fixed vertical spacing between tags in the catalog table.
|
|
45
|
+
- e8258d0: The default entity content layout still supports rendering summary cards at runtime for backward compatibility, but logs a console warning when they are detected to help identify where migration is needed.
|
|
46
|
+
- Updated dependencies
|
|
47
|
+
- @backstage/plugin-catalog-react@1.22.0-next.1
|
|
48
|
+
- @backstage/ui@0.12.0-next.1
|
|
49
|
+
- @backstage/frontend-plugin-api@0.14.0-next.1
|
|
50
|
+
- @backstage/core-compat-api@0.5.8-next.1
|
|
51
|
+
- @backstage/plugin-search-react@1.10.3-next.1
|
|
52
|
+
- @backstage/core-components@0.18.7-next.1
|
|
53
|
+
- @backstage/plugin-techdocs-react@1.3.8-next.0
|
|
54
|
+
- @backstage/integration-react@1.2.15-next.1
|
|
55
|
+
- @backstage/plugin-scaffolder-common@1.7.6-next.1
|
|
56
|
+
|
|
3
57
|
## 1.32.3-next.0
|
|
4
58
|
|
|
5
59
|
### Patch Changes
|
|
@@ -7,6 +7,7 @@ import { hasRelationWarnings, EntityRelationWarning } from '../components/Entity
|
|
|
7
7
|
import { hasCatalogProcessingErrors, EntityProcessingErrorsPanel } from '../components/EntityProcessingErrorsPanel/EntityProcessingErrorsPanel.esm.js';
|
|
8
8
|
import { HorizontalScrollGrid } from '@backstage/core-components';
|
|
9
9
|
|
|
10
|
+
let hasLoggedSummaryWarning = false;
|
|
10
11
|
const useStyles = makeStyles((theme) => ({
|
|
11
12
|
root: {
|
|
12
13
|
display: "flex",
|
|
@@ -113,6 +114,12 @@ function DefaultEntityContentLayout(props) {
|
|
|
113
114
|
const contentCards = cards.filter(
|
|
114
115
|
(card) => !card.type || card.type === "content"
|
|
115
116
|
);
|
|
117
|
+
if (summaryCards.length > 0 && !hasLoggedSummaryWarning) {
|
|
118
|
+
hasLoggedSummaryWarning = true;
|
|
119
|
+
console.warn(
|
|
120
|
+
"The 'summary' entity card type has been removed. Please update your cards to use 'content' or 'info' types instead."
|
|
121
|
+
);
|
|
122
|
+
}
|
|
116
123
|
const classes = useStyles({
|
|
117
124
|
infoCards: !!infoCards.length,
|
|
118
125
|
summaryCards: !!summaryCards.length,
|
|
@@ -1 +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 { Fragment } from 'react';\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 warningArea: {\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n marginBottom: theme.spacing(3),\n '&:empty': {\n marginBottom: 0,\n display: 'none',\n },\n },\n mainContent: {\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 flexShrink: 0,\n flexGrow: 0,\n },\n },\n summaryArea: {\n minWidth: 0,\n margin: theme.spacing(1), // To counteract MUI negative grid margin\n },\n summaryCard: {\n flex: '0 0 auto',\n width: '100%',\n '& + &': {\n marginLeft: theme.spacing(3),\n },\n },\n contentArea: {\n display: 'flex',\n flexFlow: 'column',\n gap: theme.spacing(3),\n alignItems: 'stretch',\n minWidth: 0,\n },\n [theme.breakpoints.up('md')]: {\n root: {\n display: 'grid',\n gap: theme.spacing(3),\n gridTemplateAreas: ({ summaryCards }) => `\n \"${summaryCards ? 'summary' : 'content'} info\"\n \"content info\"\n `,\n gridTemplateColumns: ({ infoCards }) => (infoCards ? '2fr 1fr' : '1fr'),\n alignItems: 'start',\n },\n mainContent: {\n display: 'contents',\n },\n contentArea: {\n gridArea: 'content',\n },\n summaryArea: {\n gridArea: 'summary',\n margin: theme.spacing(1), // To counteract MUI negative grid margin\n },\n infoArea: {\n gridArea: 'info',\n position: 'sticky',\n top: theme.spacing(3),\n // this is a little unfortunate, but it's required to make the info cards scrollable\n // in a fixed container of the full height when it's stuck.\n // 100% doesn't work as that's the height of the entire layout, which is what powers the card scrolling.\n maxHeight: '100vh',\n overflowY: 'auto',\n alignSelf: 'start',\n alignItems: 'stretch',\n // Hide the scrollbar for the inner info cards\n // kind of an accessibility nightmare, but we see.\n scrollbarWidth: 'none',\n msOverflowStyle: 'none',\n '&::-webkit-scrollbar': {\n display: 'none',\n },\n },\n summaryCard: {\n width: 'auto',\n },\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 <div className={classes.warningArea}>\n <EntitySwitch>\n <EntitySwitch.Case if={isOrphan}>\n <EntityOrphanWarning />\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasRelationWarnings}>\n <EntityRelationWarning />\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasCatalogProcessingErrors}>\n <EntityProcessingErrorsPanel />\n </EntitySwitch.Case>\n </EntitySwitch>\n </div>\n <div className={classes.root}>\n {infoCards.length > 0 ? (\n <div className={classes.infoArea}>\n {infoCards.map((card, index) => (\n <Fragment key={card.element.key ?? index}>\n {card.element}\n </Fragment>\n ))}\n </div>\n ) : null}\n <div className={classes.mainContent}>\n {summaryCards.length > 0 ? (\n <div className={classes.summaryArea}>\n <HorizontalScrollGrid scrollStep={400} scrollSpeed={100}>\n {summaryCards.map((card, index) => (\n <div\n key={card.element.key ?? index}\n className={classes.summaryCard}\n >\n {card.element}\n </div>\n ))}\n </HorizontalScrollGrid>\n </div>\n ) : null}\n {contentCards.length > 0 ? (\n <div className={classes.contentArea}>\n {contentCards.map((card, index) => (\n <Fragment key={card.element.key ?? index}>\n {card.element}\n </Fragment>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n </>\n );\n}\n"],"names":["Fragment"],"mappings":"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"}
|
|
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 { Fragment } from 'react';\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\n// Module-level flag to ensure deprecation warning is only logged once\nlet hasLoggedSummaryWarning = false;\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 warningArea: {\n display: 'flex',\n flexDirection: 'column',\n gap: theme.spacing(2),\n marginBottom: theme.spacing(3),\n '&:empty': {\n marginBottom: 0,\n display: 'none',\n },\n },\n mainContent: {\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 flexShrink: 0,\n flexGrow: 0,\n },\n },\n summaryArea: {\n minWidth: 0,\n margin: theme.spacing(1), // To counteract MUI negative grid margin\n },\n summaryCard: {\n flex: '0 0 auto',\n width: '100%',\n '& + &': {\n marginLeft: theme.spacing(3),\n },\n },\n contentArea: {\n display: 'flex',\n flexFlow: 'column',\n gap: theme.spacing(3),\n alignItems: 'stretch',\n minWidth: 0,\n },\n [theme.breakpoints.up('md')]: {\n root: {\n display: 'grid',\n gap: theme.spacing(3),\n gridTemplateAreas: ({ summaryCards }) => `\n \"${summaryCards ? 'summary' : 'content'} info\"\n \"content info\"\n `,\n gridTemplateColumns: ({ infoCards }) => (infoCards ? '2fr 1fr' : '1fr'),\n alignItems: 'start',\n },\n mainContent: {\n display: 'contents',\n },\n contentArea: {\n gridArea: 'content',\n },\n summaryArea: {\n gridArea: 'summary',\n margin: theme.spacing(1), // To counteract MUI negative grid margin\n },\n infoArea: {\n gridArea: 'info',\n position: 'sticky',\n top: theme.spacing(3),\n // this is a little unfortunate, but it's required to make the info cards scrollable\n // in a fixed container of the full height when it's stuck.\n // 100% doesn't work as that's the height of the entire layout, which is what powers the card scrolling.\n maxHeight: '100vh',\n overflowY: 'auto',\n alignSelf: 'start',\n alignItems: 'stretch',\n // Hide the scrollbar for the inner info cards\n // kind of an accessibility nightmare, but we see.\n scrollbarWidth: 'none',\n msOverflowStyle: 'none',\n '&::-webkit-scrollbar': {\n display: 'none',\n },\n },\n summaryCard: {\n width: 'auto',\n },\n },\n}));\n\nexport function DefaultEntityContentLayout(props: EntityContentLayoutProps) {\n const { cards } = props;\n\n const infoCards = cards.filter(card => card.type === 'info');\n // Keep support for 'summary' type at runtime for backward compatibility\n // even though it's been removed from the type system\n const summaryCards = cards.filter(card => card.type === ('summary' as any));\n const contentCards = cards.filter(\n card => !card.type || card.type === 'content',\n );\n\n if (summaryCards.length > 0 && !hasLoggedSummaryWarning) {\n hasLoggedSummaryWarning = true;\n // eslint-disable-next-line no-console\n console.warn(\n \"The 'summary' entity card type has been removed. Please update your cards to use 'content' or 'info' types instead.\",\n );\n }\n\n const classes = useStyles({\n infoCards: !!infoCards.length,\n summaryCards: !!summaryCards.length,\n contentCards: !!contentCards.length,\n });\n\n return (\n <>\n <div className={classes.warningArea}>\n <EntitySwitch>\n <EntitySwitch.Case if={isOrphan}>\n <EntityOrphanWarning />\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasRelationWarnings}>\n <EntityRelationWarning />\n </EntitySwitch.Case>\n </EntitySwitch>\n\n <EntitySwitch>\n <EntitySwitch.Case if={hasCatalogProcessingErrors}>\n <EntityProcessingErrorsPanel />\n </EntitySwitch.Case>\n </EntitySwitch>\n </div>\n <div className={classes.root}>\n {infoCards.length > 0 ? (\n <div className={classes.infoArea}>\n {infoCards.map((card, index) => (\n <Fragment key={card.element.key ?? index}>\n {card.element}\n </Fragment>\n ))}\n </div>\n ) : null}\n <div className={classes.mainContent}>\n {summaryCards.length > 0 ? (\n <div className={classes.summaryArea}>\n <HorizontalScrollGrid scrollStep={400} scrollSpeed={100}>\n {summaryCards.map((card, index) => (\n <div\n key={card.element.key ?? index}\n className={classes.summaryCard}\n >\n {card.element}\n </div>\n ))}\n </HorizontalScrollGrid>\n </div>\n ) : null}\n {contentCards.length > 0 ? (\n <div className={classes.contentArea}>\n {contentCards.map((card, index) => (\n <Fragment key={card.element.key ?? index}>\n {card.element}\n </Fragment>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n </>\n );\n}\n"],"names":["Fragment"],"mappings":"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"}
|
|
@@ -20,7 +20,9 @@ const EntityLayout = (props) => {
|
|
|
20
20
|
children,
|
|
21
21
|
header,
|
|
22
22
|
NotFoundComponent,
|
|
23
|
-
parentEntityRelations
|
|
23
|
+
parentEntityRelations,
|
|
24
|
+
groupDefinitions,
|
|
25
|
+
showNavItemIcons
|
|
24
26
|
} = props;
|
|
25
27
|
const { kind } = useRouteRefParams(entityRouteRef);
|
|
26
28
|
const { entity, loading, error } = useAsyncEntity();
|
|
@@ -41,7 +43,8 @@ const EntityLayout = (props) => {
|
|
|
41
43
|
path: elementProps.path,
|
|
42
44
|
title: elementProps.title,
|
|
43
45
|
group: elementProps.group,
|
|
44
|
-
children: elementProps.children
|
|
46
|
+
children: elementProps.children,
|
|
47
|
+
icon: elementProps.icon
|
|
45
48
|
}
|
|
46
49
|
];
|
|
47
50
|
}),
|
|
@@ -59,16 +62,19 @@ const EntityLayout = (props) => {
|
|
|
59
62
|
}
|
|
60
63
|
),
|
|
61
64
|
loading && /* @__PURE__ */ jsx(Progress, {}),
|
|
62
|
-
entity && /* @__PURE__ */ jsx(
|
|
65
|
+
entity && /* @__PURE__ */ jsx(
|
|
66
|
+
EntityTabs,
|
|
67
|
+
{
|
|
68
|
+
routes,
|
|
69
|
+
groupDefinitions,
|
|
70
|
+
showIcons: showNavItemIcons
|
|
71
|
+
}
|
|
72
|
+
),
|
|
63
73
|
error && /* @__PURE__ */ jsx(Content, { children: /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.toString() }) }),
|
|
64
|
-
!loading && !error && !entity && /* @__PURE__ */ jsx(Content, { children: NotFoundComponent ? NotFoundComponent : /* @__PURE__ */
|
|
65
|
-
"There is no ",
|
|
74
|
+
!loading && !error && !entity && /* @__PURE__ */ jsx(Content, { children: NotFoundComponent ? NotFoundComponent : /* @__PURE__ */ jsx(WarningPanel, { title: t("entityLabels.warningPanelTitle"), children: t("entityPage.notFoundMessage", {
|
|
66
75
|
kind,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/* @__PURE__ */ jsx(Link, { to: "https://backstage.io/docs/features/software-catalog/references", children: "kind, namespace, and name" }),
|
|
70
|
-
"."
|
|
71
|
-
] }) })
|
|
76
|
+
link: /* @__PURE__ */ jsx(Link, { to: "https://backstage.io/docs/features/software-catalog/references", children: t("entityPage.notFoundLinkText") })
|
|
77
|
+
}) }) })
|
|
72
78
|
] });
|
|
73
79
|
};
|
|
74
80
|
EntityLayout.Route = Route;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityLayout.esm.js","sources":["../../../../src/alpha/components/EntityLayout/EntityLayout.tsx"],"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 { ComponentProps, ReactNode } from 'react';\n\nimport Alert from '@material-ui/lab/Alert';\n\nimport {\n attachComponentData,\n useElementFilter,\n useRouteRefParams,\n} from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport {\n Content,\n Link,\n Page,\n Progress,\n WarningPanel,\n} from '@backstage/core-components';\nimport { Entity } from '@backstage/catalog-model';\nimport {\n entityRouteRef,\n useAsyncEntity,\n} from '@backstage/plugin-catalog-react';\n\nimport { catalogTranslationRef } from '../../translation';\nimport { EntityHeader } from '../EntityHeader';\nimport { EntityTabs } from '../EntityTabs';\n\nexport type EntityLayoutRouteProps = {\n path: string;\n title: string;\n group
|
|
1
|
+
{"version":3,"file":"EntityLayout.esm.js","sources":["../../../../src/alpha/components/EntityLayout/EntityLayout.tsx"],"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 { ComponentProps, ReactNode, ReactElement } from 'react';\n\nimport Alert from '@material-ui/lab/Alert';\n\nimport {\n attachComponentData,\n useElementFilter,\n useRouteRefParams,\n} from '@backstage/core-plugin-api';\nimport { useTranslationRef } from '@backstage/core-plugin-api/alpha';\nimport {\n Content,\n Link,\n Page,\n Progress,\n WarningPanel,\n} from '@backstage/core-components';\nimport { Entity } from '@backstage/catalog-model';\nimport {\n entityRouteRef,\n useAsyncEntity,\n} from '@backstage/plugin-catalog-react';\n\nimport { catalogTranslationRef } from '../../translation';\nimport { EntityHeader } from '../EntityHeader';\nimport { EntityTabs } from '../EntityTabs';\nimport { EntityContentGroupDefinitions } from '@backstage/plugin-catalog-react/alpha';\n\nexport type EntityLayoutRouteProps = {\n path: string;\n title: string;\n group?: string;\n icon?: string | ReactElement;\n children: JSX.Element;\n if?: (entity: Entity) => boolean;\n};\n\nconst dataKey = 'plugin.catalog.entityLayoutRoute';\nconst Route: (props: EntityLayoutRouteProps) => null = () => null;\nattachComponentData(Route, dataKey, true);\nattachComponentData(Route, 'core.gatherMountPoints', true); // This causes all mount points that are discovered within this route to use the path of the route itself\n\n/** @public */\nexport interface EntityLayoutProps {\n UNSTABLE_contextMenuOptions?: ComponentProps<\n typeof EntityHeader\n >['UNSTABLE_contextMenuOptions'];\n UNSTABLE_extraContextMenuItems?: ComponentProps<\n typeof EntityHeader\n >['UNSTABLE_extraContextMenuItems'];\n contextMenuItems?: ComponentProps<typeof EntityHeader>['contextMenuItems'];\n children?: ReactNode;\n header?: JSX.Element;\n NotFoundComponent?: ReactNode;\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 groupDefinitions: EntityContentGroupDefinitions;\n showNavItemIcons?: boolean;\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 *\n * @public\n */\nexport const EntityLayout = (props: EntityLayoutProps) => {\n const {\n UNSTABLE_extraContextMenuItems,\n UNSTABLE_contextMenuOptions,\n contextMenuItems,\n children,\n header,\n NotFoundComponent,\n parentEntityRelations,\n groupDefinitions,\n showNavItemIcons,\n } = props;\n const { kind } = useRouteRefParams(entityRouteRef);\n const { entity, loading, error } = useAsyncEntity();\n\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<EntityLayoutRouteProps>() // all nodes, element data, maintain structure or not?\n .flatMap(({ props: elementProps }) => {\n if (!entity) {\n return [];\n }\n if (elementProps.if && !elementProps.if(entity)) {\n return [];\n }\n return [\n {\n path: elementProps.path,\n title: elementProps.title,\n group: elementProps.group,\n children: elementProps.children,\n icon: elementProps.icon,\n },\n ];\n }),\n [entity],\n );\n\n const { t } = useTranslationRef(catalogTranslationRef);\n\n return (\n <Page themeId={entity?.spec?.type?.toString() ?? 'home'}>\n {header ?? (\n <EntityHeader\n parentEntityRelations={parentEntityRelations}\n UNSTABLE_contextMenuOptions={UNSTABLE_contextMenuOptions}\n UNSTABLE_extraContextMenuItems={UNSTABLE_extraContextMenuItems}\n contextMenuItems={contextMenuItems}\n />\n )}\n\n {loading && <Progress />}\n\n {entity && (\n <EntityTabs\n routes={routes}\n groupDefinitions={groupDefinitions}\n showIcons={showNavItemIcons}\n />\n )}\n\n {error && (\n <Content>\n <Alert severity=\"error\">{error.toString()}</Alert>\n </Content>\n )}\n\n {!loading && !error && !entity && (\n <Content>\n {NotFoundComponent ? (\n NotFoundComponent\n ) : (\n <WarningPanel title={t('entityLabels.warningPanelTitle')}>\n {t('entityPage.notFoundMessage', {\n kind,\n link: (\n <Link to=\"https://backstage.io/docs/features/software-catalog/references\">\n {t('entityPage.notFoundLinkText')}\n </Link>\n ),\n })}\n </WarningPanel>\n )}\n </Content>\n )}\n </Page>\n );\n};\n\nEntityLayout.Route = Route;\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { Helmet } from 'react-helmet';
|
|
4
|
-
import { useParams, useRoutes, matchRoutes } from 'react-router-dom';
|
|
4
|
+
import { useParams, Outlet, useRoutes, matchRoutes } from 'react-router-dom';
|
|
5
5
|
import { EntityTabsPanel } from './EntityTabsPanel.esm.js';
|
|
6
6
|
import { EntityTabsList } from './EntityTabsList.esm.js';
|
|
7
7
|
|
|
@@ -9,22 +9,27 @@ function useSelectedSubRoute(subRoutes) {
|
|
|
9
9
|
const params = useParams();
|
|
10
10
|
const routes = subRoutes.map(({ path, children }) => ({
|
|
11
11
|
caseSensitive: false,
|
|
12
|
-
path
|
|
13
|
-
element:
|
|
12
|
+
path,
|
|
13
|
+
element: /* @__PURE__ */ jsx(Outlet, {}),
|
|
14
|
+
children: [
|
|
15
|
+
{
|
|
16
|
+
index: true,
|
|
17
|
+
element: children
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
path: "*",
|
|
21
|
+
element: children
|
|
22
|
+
}
|
|
23
|
+
]
|
|
14
24
|
}));
|
|
15
|
-
const sortedRoutes = routes.sort(
|
|
16
|
-
(a, b) => (
|
|
17
|
-
// remove "/*" symbols from path end before comparing
|
|
18
|
-
b.path.replace(/\/\*$/, "").localeCompare(a.path.replace(/\/\*$/, ""))
|
|
19
|
-
)
|
|
20
|
-
);
|
|
25
|
+
const sortedRoutes = routes.sort((a, b) => b.path.localeCompare(a.path));
|
|
21
26
|
const element = useRoutes(sortedRoutes) ?? subRoutes[0]?.children;
|
|
22
27
|
let currentRoute = params["*"] ?? "";
|
|
23
28
|
if (!currentRoute.startsWith("/")) {
|
|
24
29
|
currentRoute = `/${currentRoute}`;
|
|
25
30
|
}
|
|
26
31
|
const [matchedRoute] = matchRoutes(sortedRoutes, currentRoute) ?? [];
|
|
27
|
-
const foundIndex = matchedRoute ? subRoutes.findIndex((t) =>
|
|
32
|
+
const foundIndex = matchedRoute ? subRoutes.findIndex((t) => t.path === matchedRoute.route.path) : 0;
|
|
28
33
|
return {
|
|
29
34
|
index: foundIndex === -1 ? 0 : foundIndex,
|
|
30
35
|
element,
|
|
@@ -32,11 +37,11 @@ function useSelectedSubRoute(subRoutes) {
|
|
|
32
37
|
};
|
|
33
38
|
}
|
|
34
39
|
function EntityTabs(props) {
|
|
35
|
-
const { routes } = props;
|
|
40
|
+
const { routes, groupDefinitions, showIcons } = props;
|
|
36
41
|
const { index, route, element } = useSelectedSubRoute(routes);
|
|
37
42
|
const tabs = useMemo(
|
|
38
43
|
() => routes.map((t) => {
|
|
39
|
-
const { path, title, group } = t;
|
|
44
|
+
const { path, title, group, icon } = t;
|
|
40
45
|
let to = path;
|
|
41
46
|
to = to.replace(/\/\*$/, "");
|
|
42
47
|
to = to.replace(/^\//, "");
|
|
@@ -44,13 +49,22 @@ function EntityTabs(props) {
|
|
|
44
49
|
group,
|
|
45
50
|
id: path,
|
|
46
51
|
path: to,
|
|
47
|
-
label: title
|
|
52
|
+
label: title,
|
|
53
|
+
icon
|
|
48
54
|
};
|
|
49
55
|
}),
|
|
50
56
|
[routes]
|
|
51
57
|
);
|
|
52
58
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
53
|
-
/* @__PURE__ */ jsx(
|
|
59
|
+
/* @__PURE__ */ jsx(
|
|
60
|
+
EntityTabsList,
|
|
61
|
+
{
|
|
62
|
+
tabs,
|
|
63
|
+
selectedIndex: index,
|
|
64
|
+
showIcons,
|
|
65
|
+
groupDefinitions
|
|
66
|
+
}
|
|
67
|
+
),
|
|
54
68
|
/* @__PURE__ */ jsxs(EntityTabsPanel, { children: [
|
|
55
69
|
/* @__PURE__ */ jsx(Helmet, { title: route?.title }),
|
|
56
70
|
element
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntityTabs.esm.js","sources":["../../../../src/alpha/components/EntityTabs/EntityTabs.tsx"],"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 */\nimport { useMemo } from 'react';\nimport { Helmet } from 'react-helmet';\nimport { matchRoutes, useParams, useRoutes } from 'react-router-dom';\nimport { EntityTabsPanel } from './EntityTabsPanel';\nimport { EntityTabsList } from './EntityTabsList';\n\ntype SubRoute = {\n group
|
|
1
|
+
{"version":3,"file":"EntityTabs.esm.js","sources":["../../../../src/alpha/components/EntityTabs/EntityTabs.tsx"],"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 */\nimport { ReactElement, useMemo } from 'react';\nimport { Helmet } from 'react-helmet';\nimport { matchRoutes, useParams, useRoutes, Outlet } from 'react-router-dom';\nimport { EntityTabsPanel } from './EntityTabsPanel';\nimport { EntityTabsList } from './EntityTabsList';\nimport { EntityContentGroupDefinitions } from '@backstage/plugin-catalog-react/alpha';\n\ntype SubRoute = {\n group?: string;\n path: string;\n title: string;\n icon?: string | ReactElement;\n children: JSX.Element;\n};\n\nexport function useSelectedSubRoute(subRoutes: SubRoute[]): {\n index: number;\n route?: SubRoute;\n element?: JSX.Element;\n} {\n const params = useParams();\n\n // For v7_relativeSplatPath: convert splat paths to parent/child structure\n const routes = subRoutes.map(({ path, children }) => ({\n caseSensitive: false,\n path: path,\n element: <Outlet />,\n children: [\n {\n index: true,\n element: children,\n },\n {\n path: '*',\n element: children,\n },\n ],\n }));\n\n // Sort routes by path length (longest first) for proper matching\n const sortedRoutes = routes.sort((a, b) => b.path.localeCompare(a.path));\n\n const element = useRoutes(sortedRoutes) ?? subRoutes[0]?.children;\n\n // TODO(Rugvip): Once we only support v6 stable we can always prefix\n // This avoids having a double / prefix for react-router v6 beta, which in turn breaks\n // the tab highlighting when using relative paths for the tabs.\n let currentRoute = params['*'] ?? '';\n if (!currentRoute.startsWith('/')) {\n currentRoute = `/${currentRoute}`;\n }\n\n const [matchedRoute] = matchRoutes(sortedRoutes, currentRoute) ?? [];\n const foundIndex = matchedRoute\n ? subRoutes.findIndex(t => t.path === matchedRoute.route.path)\n : 0;\n\n return {\n index: foundIndex === -1 ? 0 : foundIndex,\n element,\n route: subRoutes[foundIndex] ?? subRoutes[0],\n };\n}\n\ntype EntityTabsProps = {\n routes: SubRoute[];\n groupDefinitions: EntityContentGroupDefinitions;\n showIcons?: boolean;\n};\n\nexport function EntityTabs(props: EntityTabsProps) {\n const { routes, groupDefinitions, showIcons } = props;\n\n const { index, route, element } = useSelectedSubRoute(routes);\n\n const tabs = useMemo(\n () =>\n routes.map(t => {\n const { path, title, group, icon } = t;\n let to = path;\n // Remove trailing /*\n to = to.replace(/\\/\\*$/, '');\n // And remove leading / for relative navigation\n to = to.replace(/^\\//, '');\n return {\n group,\n id: path,\n path: to,\n label: title,\n icon,\n };\n }),\n [routes],\n );\n\n return (\n <>\n <EntityTabsList\n tabs={tabs}\n selectedIndex={index}\n showIcons={showIcons}\n groupDefinitions={groupDefinitions}\n />\n <EntityTabsPanel>\n <Helmet title={route?.title} />\n {element}\n </EntityTabsPanel>\n </>\n );\n}\n"],"names":[],"mappings":";;;;;;;AA8BO,SAAS,oBAAoB,SAAA,EAIlC;AACA,EAAA,MAAM,SAAS,SAAA,EAAU;AAGzB,EAAA,MAAM,SAAS,SAAA,CAAU,GAAA,CAAI,CAAC,EAAE,IAAA,EAAM,UAAS,MAAO;AAAA,IACpD,aAAA,EAAe,KAAA;AAAA,IACf,IAAA;AAAA,IACA,OAAA,sBAAU,MAAA,EAAA,EAAO,CAAA;AAAA,IACjB,QAAA,EAAU;AAAA,MACR;AAAA,QACE,KAAA,EAAO,IAAA;AAAA,QACP,OAAA,EAAS;AAAA,OACX;AAAA,MACA;AAAA,QACE,IAAA,EAAM,GAAA;AAAA,QACN,OAAA,EAAS;AAAA;AACX;AACF,GACF,CAAE,CAAA;AAGF,EAAA,MAAM,YAAA,GAAe,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,IAAA,CAAK,aAAA,CAAc,CAAA,CAAE,IAAI,CAAC,CAAA;AAEvE,EAAA,MAAM,UAAU,SAAA,CAAU,YAAY,CAAA,IAAK,SAAA,CAAU,CAAC,CAAA,EAAG,QAAA;AAKzD,EAAA,IAAI,YAAA,GAAe,MAAA,CAAO,GAAG,CAAA,IAAK,EAAA;AAClC,EAAA,IAAI,CAAC,YAAA,CAAa,UAAA,CAAW,GAAG,CAAA,EAAG;AACjC,IAAA,YAAA,GAAe,IAAI,YAAY,CAAA,CAAA;AAAA,EACjC;AAEA,EAAA,MAAM,CAAC,YAAY,CAAA,GAAI,YAAY,YAAA,EAAc,YAAY,KAAK,EAAC;AACnE,EAAA,MAAM,UAAA,GAAa,YAAA,GACf,SAAA,CAAU,SAAA,CAAU,CAAA,CAAA,KAAK,EAAE,IAAA,KAAS,YAAA,CAAa,KAAA,CAAM,IAAI,CAAA,GAC3D,CAAA;AAEJ,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,UAAA,KAAe,EAAA,GAAK,CAAA,GAAI,UAAA;AAAA,IAC/B,OAAA;AAAA,IACA,KAAA,EAAO,SAAA,CAAU,UAAU,CAAA,IAAK,UAAU,CAAC;AAAA,GAC7C;AACF;AAQO,SAAS,WAAW,KAAA,EAAwB;AACjD,EAAA,MAAM,EAAE,MAAA,EAAQ,gBAAA,EAAkB,SAAA,EAAU,GAAI,KAAA;AAEhD,EAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,OAAA,EAAQ,GAAI,oBAAoB,MAAM,CAAA;AAE5D,EAAA,MAAM,IAAA,GAAO,OAAA;AAAA,IACX,MACE,MAAA,CAAO,GAAA,CAAI,CAAA,CAAA,KAAK;AACd,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,KAAA,EAAO,MAAK,GAAI,CAAA;AACrC,MAAA,IAAI,EAAA,GAAK,IAAA;AAET,MAAA,EAAA,GAAK,EAAA,CAAG,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAA;AAE3B,MAAA,EAAA,GAAK,EAAA,CAAG,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACzB,MAAA,OAAO;AAAA,QACL,KAAA;AAAA,QACA,EAAA,EAAI,IAAA;AAAA,QACJ,IAAA,EAAM,EAAA;AAAA,QACN,KAAA,EAAO,KAAA;AAAA,QACP;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,IACH,CAAC,MAAM;AAAA,GACT;AAEA,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,IAAA;AAAA,QACA,aAAA,EAAe,KAAA;AAAA,QACf,SAAA;AAAA,QACA;AAAA;AAAA,KACF;AAAA,yBACC,eAAA,EAAA,EACC,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,CAAA;AAAA,MAC5B;AAAA,KAAA,EACH;AAAA,GAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { jsxs,
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { forwardRef, useState } from 'react';
|
|
3
3
|
import { Link } from 'react-router-dom';
|
|
4
4
|
import classnames from 'classnames';
|
|
5
5
|
import Typography from '@material-ui/core/Typography';
|
|
6
|
-
import ButtonBase from '@material-ui/core/ButtonBase';
|
|
7
6
|
import Popover from '@material-ui/core/Popover';
|
|
8
7
|
import { capitalize } from '@material-ui/core/utils';
|
|
9
8
|
import { withStyles, createStyles } from '@material-ui/core/styles';
|
|
10
9
|
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
|
10
|
+
import Button from '@material-ui/core/Button';
|
|
11
|
+
import ListItem from '@material-ui/core/ListItem';
|
|
12
|
+
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|
13
|
+
import ListItemText from '@material-ui/core/ListItemText';
|
|
14
|
+
import List from '@material-ui/core/List';
|
|
15
|
+
import { useApi } from '@backstage/core-plugin-api';
|
|
16
|
+
import { iconsApiRef } from '@backstage/frontend-plugin-api';
|
|
11
17
|
|
|
12
18
|
const styles = (theme) => createStyles({
|
|
13
19
|
/* Styles applied to the root element. */
|
|
@@ -30,9 +36,6 @@ const styles = (theme) => createStyles({
|
|
|
30
36
|
minWidth: 160
|
|
31
37
|
}
|
|
32
38
|
},
|
|
33
|
-
popInButton: {
|
|
34
|
-
width: "100%"
|
|
35
|
-
},
|
|
36
39
|
defaultTab: {
|
|
37
40
|
...theme.typography.caption,
|
|
38
41
|
padding: theme.spacing(3, 3),
|
|
@@ -112,8 +115,22 @@ const styles = (theme) => createStyles({
|
|
|
112
115
|
flexDirection: "row"
|
|
113
116
|
}
|
|
114
117
|
});
|
|
118
|
+
function resolveIcon(icon, iconsApi, showIcons) {
|
|
119
|
+
if (!showIcons) {
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
if (typeof icon === "string") {
|
|
123
|
+
const Icon = iconsApi.getIcon(icon);
|
|
124
|
+
if (Icon) {
|
|
125
|
+
return /* @__PURE__ */ jsx(Icon, {});
|
|
126
|
+
}
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
return icon;
|
|
130
|
+
}
|
|
115
131
|
const Tab = forwardRef(function Tab2(props, ref) {
|
|
116
132
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
133
|
+
const iconsApi = useApi(iconsApiRef);
|
|
117
134
|
const open = Boolean(anchorEl);
|
|
118
135
|
const submenuId = open ? "tabbed-submenu" : void 0;
|
|
119
136
|
const {
|
|
@@ -123,15 +140,16 @@ const Tab = forwardRef(function Tab2(props, ref) {
|
|
|
123
140
|
disableFocusRipple = false,
|
|
124
141
|
items,
|
|
125
142
|
fullWidth,
|
|
126
|
-
icon,
|
|
127
143
|
indicator,
|
|
128
144
|
label,
|
|
129
145
|
onSelectTab,
|
|
130
146
|
selected,
|
|
131
147
|
textColor = "inherit",
|
|
132
148
|
wrapped = false,
|
|
133
|
-
highlightedButton
|
|
149
|
+
highlightedButton,
|
|
150
|
+
showIcons = false
|
|
134
151
|
} = props;
|
|
152
|
+
const groupIcon = resolveIcon(props.icon, iconsApi, showIcons);
|
|
135
153
|
const testId = "data-testid" in props && props["data-testid"];
|
|
136
154
|
const handleMenuClose = () => {
|
|
137
155
|
setAnchorEl(null);
|
|
@@ -145,30 +163,24 @@ const Tab = forwardRef(function Tab2(props, ref) {
|
|
|
145
163
|
classes && {
|
|
146
164
|
[classes.disabled]: disabled,
|
|
147
165
|
[classes.selected]: selected,
|
|
148
|
-
[classes.labelIcon]: label &&
|
|
166
|
+
[classes.labelIcon]: label && groupIcon,
|
|
149
167
|
[classes.fullWidth]: fullWidth,
|
|
150
168
|
[classes.wrapped]: wrapped
|
|
151
169
|
},
|
|
152
170
|
className
|
|
153
171
|
];
|
|
154
|
-
const innerButtonClasses = [
|
|
155
|
-
classes?.root,
|
|
156
|
-
classes?.[`textColor${capitalize(textColor)}`],
|
|
157
|
-
classes?.defaultTab,
|
|
158
|
-
classes && {
|
|
159
|
-
[classes.disabled]: disabled,
|
|
160
|
-
[classes.labelIcon]: label && icon,
|
|
161
|
-
[classes.fullWidth]: fullWidth,
|
|
162
|
-
[classes.wrapped]: wrapped
|
|
163
|
-
}
|
|
164
|
-
];
|
|
165
172
|
if (items.length === 1) {
|
|
166
173
|
return /* @__PURE__ */ jsxs(
|
|
167
|
-
|
|
174
|
+
Button,
|
|
168
175
|
{
|
|
169
176
|
focusRipple: !disableFocusRipple,
|
|
170
177
|
"data-testid": testId,
|
|
171
|
-
className: classnames(
|
|
178
|
+
className: classnames(
|
|
179
|
+
classArray,
|
|
180
|
+
classes && {
|
|
181
|
+
[classes.labelIcon]: label && (items[0].icon ?? groupIcon)
|
|
182
|
+
}
|
|
183
|
+
),
|
|
172
184
|
ref,
|
|
173
185
|
role: "tab",
|
|
174
186
|
"aria-selected": selected,
|
|
@@ -176,19 +188,18 @@ const Tab = forwardRef(function Tab2(props, ref) {
|
|
|
176
188
|
component: Link,
|
|
177
189
|
onClick: onSelectTab,
|
|
178
190
|
to: items[0]?.path,
|
|
191
|
+
startIcon: resolveIcon(items[0].icon, iconsApi, showIcons),
|
|
179
192
|
children: [
|
|
180
|
-
/* @__PURE__ */
|
|
181
|
-
icon,
|
|
182
|
-
items[0].label
|
|
183
|
-
] }),
|
|
193
|
+
/* @__PURE__ */ jsx(Typography, { className: classes?.wrapper, variant: "button", children: items[0].label }),
|
|
184
194
|
indicator
|
|
185
195
|
]
|
|
186
196
|
}
|
|
187
197
|
);
|
|
188
198
|
}
|
|
199
|
+
const hasIcons = showIcons && items.some((i) => i.icon);
|
|
189
200
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
190
201
|
/* @__PURE__ */ jsxs(
|
|
191
|
-
|
|
202
|
+
Button,
|
|
192
203
|
{
|
|
193
204
|
"data-testid": testId,
|
|
194
205
|
focusRipple: !disableFocusRipple,
|
|
@@ -198,6 +209,7 @@ const Tab = forwardRef(function Tab2(props, ref) {
|
|
|
198
209
|
"aria-selected": selected,
|
|
199
210
|
disabled,
|
|
200
211
|
onClick: handleMenuClick,
|
|
212
|
+
startIcon: groupIcon,
|
|
201
213
|
children: [
|
|
202
214
|
/* @__PURE__ */ jsx(Typography, { className: classes?.wrapper, variant: "button", children: label }),
|
|
203
215
|
/* @__PURE__ */ jsx(ExpandMoreIcon, {})
|
|
@@ -219,33 +231,45 @@ const Tab = forwardRef(function Tab2(props, ref) {
|
|
|
219
231
|
vertical: "top",
|
|
220
232
|
horizontal: "center"
|
|
221
233
|
},
|
|
222
|
-
children:
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
children: /* @__PURE__ */ jsx(List, { component: "nav", children: items.map((i) => {
|
|
235
|
+
const itemIcon = resolveIcon(i.icon, iconsApi, showIcons);
|
|
236
|
+
return /* @__PURE__ */ jsxs(
|
|
237
|
+
ListItem,
|
|
238
|
+
{
|
|
239
|
+
button: true,
|
|
240
|
+
focusRipple: !disableFocusRipple,
|
|
241
|
+
classes: {
|
|
242
|
+
selected: classnames(classes?.selectedButton),
|
|
243
|
+
default: classnames(classes?.unselectedButton),
|
|
244
|
+
disabled: classnames(classes?.disabled)
|
|
245
|
+
},
|
|
246
|
+
ref,
|
|
247
|
+
"aria-selected": selected,
|
|
248
|
+
disabled,
|
|
249
|
+
selected: highlightedButton === i.id,
|
|
250
|
+
component: Link,
|
|
251
|
+
onClick: (e) => {
|
|
252
|
+
handleMenuClose();
|
|
253
|
+
onSelectTab?.(e);
|
|
254
|
+
},
|
|
255
|
+
to: i.path,
|
|
256
|
+
children: [
|
|
257
|
+
itemIcon && /* @__PURE__ */ jsx(ListItemIcon, { children: itemIcon }),
|
|
258
|
+
/* @__PURE__ */ jsx(
|
|
259
|
+
ListItemText,
|
|
260
|
+
{
|
|
261
|
+
inset: !itemIcon && hasIcons,
|
|
262
|
+
primary: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
263
|
+
/* @__PURE__ */ jsx(Typography, { variant: "button", children: i.label }),
|
|
264
|
+
indicator
|
|
265
|
+
] })
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
]
|
|
238
269
|
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
icon,
|
|
243
|
-
i.label
|
|
244
|
-
] }),
|
|
245
|
-
indicator
|
|
246
|
-
]
|
|
247
|
-
}
|
|
248
|
-
) }, `popover_item_${idx}`))
|
|
270
|
+
`popover_item_${i.id}`
|
|
271
|
+
);
|
|
272
|
+
}) })
|
|
249
273
|
}
|
|
250
274
|
)
|
|
251
275
|
] });
|