@red-hat-developer-hub/backstage-plugin-dynamic-home-page 1.7.0 → 1.9.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 +16 -0
- package/app-config.dynamic.yaml +12 -12
- package/dist/components/CustomizableGrid.esm.js +48 -6
- package/dist/components/CustomizableGrid.esm.js.map +1 -1
- package/dist/components/CustomizableHomePage.esm.js +3 -7
- package/dist/components/CustomizableHomePage.esm.js.map +1 -1
- package/dist/components/EntitySection/EntitySection.esm.js +18 -13
- package/dist/components/EntitySection/EntitySection.esm.js.map +1 -1
- package/dist/components/FeaturedDocsCard.esm.js +9 -1
- package/dist/components/FeaturedDocsCard.esm.js.map +1 -1
- package/dist/components/Header.esm.js +24 -12
- package/dist/components/Header.esm.js.map +1 -1
- package/dist/components/HomePage.esm.js +4 -8
- package/dist/components/HomePage.esm.js.map +1 -1
- package/dist/components/OnboardingSection/OnboardingSection.esm.js +5 -3
- package/dist/components/OnboardingSection/OnboardingSection.esm.js.map +1 -1
- package/dist/components/QuickAccessCard.esm.js +5 -3
- package/dist/components/QuickAccessCard.esm.js.map +1 -1
- package/dist/components/SearchBar.esm.js +3 -1
- package/dist/components/SearchBar.esm.js.map +1 -1
- package/dist/components/TemplateSection/TemplateSection.esm.js +16 -12
- package/dist/components/TemplateSection/TemplateSection.esm.js.map +1 -1
- package/dist/components/Trans.esm.js +9 -0
- package/dist/components/Trans.esm.js.map +1 -0
- package/dist/defaults.esm.js +29 -0
- package/dist/defaults.esm.js.map +1 -0
- package/dist/hooks/useGreeting.esm.js +12 -8
- package/dist/hooks/useGreeting.esm.js.map +1 -1
- package/dist/hooks/useLanguage.esm.js +7 -0
- package/dist/hooks/useLanguage.esm.js.map +1 -0
- package/dist/hooks/useTranslation.esm.js +8 -0
- package/dist/hooks/useTranslation.esm.js.map +1 -0
- package/dist/index.d.ts +142 -1
- package/dist/index.esm.js +3 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/translations/de.esm.js +52 -0
- package/dist/translations/de.esm.js.map +1 -0
- package/dist/translations/es.esm.js +52 -0
- package/dist/translations/es.esm.js.map +1 -0
- package/dist/translations/fr.esm.js +52 -0
- package/dist/translations/fr.esm.js.map +1 -0
- package/dist/translations/index.esm.js +15 -0
- package/dist/translations/index.esm.js.map +1 -0
- package/dist/translations/it.esm.js +52 -0
- package/dist/translations/it.esm.js.map +1 -0
- package/dist/translations/ref.esm.js +76 -0
- package/dist/translations/ref.esm.js.map +1 -0
- package/dist/utils/constants.esm.js +14 -14
- package/dist/utils/constants.esm.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-dynamic-home-page
|
|
2
2
|
|
|
3
|
+
## 1.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1e6b861: Add customizable homepage functionality with drag, drop, resize, and widget management capabilities
|
|
8
|
+
|
|
9
|
+
## 1.8.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 8b64e16: Add internationalization (i18n) support with German, French, Italian, and Spanish translations.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- a994094: Updated dependency `@red-hat-developer-hub/backstage-plugin-theme` to `^0.10.0`.
|
|
18
|
+
|
|
3
19
|
## 1.7.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/app-config.dynamic.yaml
CHANGED
|
@@ -10,22 +10,22 @@ dynamicPlugins:
|
|
|
10
10
|
importName: OnboardingSection
|
|
11
11
|
config:
|
|
12
12
|
layouts:
|
|
13
|
-
xl: { w: 12, h:
|
|
14
|
-
lg: { w: 12, h:
|
|
15
|
-
md: { w: 12, h:
|
|
16
|
-
sm: { w: 12, h:
|
|
17
|
-
xs: { w: 12, h:
|
|
18
|
-
xxs: { w: 12, h:
|
|
13
|
+
xl: { w: 12, h: 6 }
|
|
14
|
+
lg: { w: 12, h: 6 }
|
|
15
|
+
md: { w: 12, h: 7 }
|
|
16
|
+
sm: { w: 12, h: 8 }
|
|
17
|
+
xs: { w: 12, h: 9 }
|
|
18
|
+
xxs: { w: 12, h: 14 }
|
|
19
19
|
- mountPoint: home.page/cards
|
|
20
20
|
importName: EntitySection
|
|
21
21
|
config:
|
|
22
22
|
layouts:
|
|
23
|
-
xl: { w: 12, h:
|
|
24
|
-
lg: { w: 12, h:
|
|
25
|
-
md: { w: 12, h:
|
|
26
|
-
sm: { w: 12, h:
|
|
27
|
-
xs: { w: 12, h:
|
|
28
|
-
xxs: { w: 12, h:
|
|
23
|
+
xl: { w: 12, h: 7 }
|
|
24
|
+
lg: { w: 12, h: 7 }
|
|
25
|
+
md: { w: 12, h: 8 }
|
|
26
|
+
sm: { w: 12, h: 9 }
|
|
27
|
+
xs: { w: 12, h: 11 }
|
|
28
|
+
xxs: { w: 12, h: 15 }
|
|
29
29
|
- mountPoint: home.page/cards
|
|
30
30
|
importName: TemplateSection
|
|
31
31
|
config:
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
|
+
import GlobalStyles from '@mui/material/GlobalStyles';
|
|
4
|
+
import { useTheme } from '@mui/material/styles';
|
|
3
5
|
import { ErrorBoundary } from '@backstage/core-components';
|
|
4
6
|
import { CustomHomepageGrid } from '@backstage/plugin-home';
|
|
5
7
|
import { makeStyles } from 'tss-react/mui';
|
|
@@ -19,6 +21,7 @@ const useStyles = makeStyles()({
|
|
|
19
21
|
});
|
|
20
22
|
const CustomizableGrid = (props) => {
|
|
21
23
|
const { classes } = useStyles();
|
|
24
|
+
const theme = useTheme();
|
|
22
25
|
const cards = useMemo(() => {
|
|
23
26
|
return props.mountPoints.map((mountPoint, index) => {
|
|
24
27
|
const id = (index + 1).toString();
|
|
@@ -33,8 +36,8 @@ const CustomizableGrid = (props) => {
|
|
|
33
36
|
y: layout.y ?? 0,
|
|
34
37
|
w: layout.w ?? 12,
|
|
35
38
|
h: layout.h ?? 4,
|
|
36
|
-
isDraggable:
|
|
37
|
-
isResizable:
|
|
39
|
+
isDraggable: true,
|
|
40
|
+
isResizable: true
|
|
38
41
|
};
|
|
39
42
|
}
|
|
40
43
|
} else {
|
|
@@ -45,8 +48,8 @@ const CustomizableGrid = (props) => {
|
|
|
45
48
|
y: 0,
|
|
46
49
|
w: 12,
|
|
47
50
|
h: 4,
|
|
48
|
-
isDraggable:
|
|
49
|
-
isResizable:
|
|
51
|
+
isDraggable: true,
|
|
52
|
+
isResizable: true
|
|
50
53
|
};
|
|
51
54
|
});
|
|
52
55
|
}
|
|
@@ -71,7 +74,46 @@ const CustomizableGrid = (props) => {
|
|
|
71
74
|
card.id
|
|
72
75
|
));
|
|
73
76
|
}, [cards, classes.cardWrapper]);
|
|
74
|
-
|
|
77
|
+
const defaultConfig = useMemo(() => {
|
|
78
|
+
if (!props.mountPoints || props.mountPoints.length === 0) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return props.mountPoints.map((mountPoint, index) => {
|
|
82
|
+
const layout = mountPoint.config?.layouts?.xl || {};
|
|
83
|
+
return {
|
|
84
|
+
component: /* @__PURE__ */ jsx(mountPoint.Component, { ...mountPoint.config?.props || {} }),
|
|
85
|
+
x: layout.x ?? 0,
|
|
86
|
+
y: layout.y ?? index * 5,
|
|
87
|
+
width: layout.w ?? 12,
|
|
88
|
+
height: layout.h ?? 4,
|
|
89
|
+
movable: true,
|
|
90
|
+
resizable: true,
|
|
91
|
+
draggable: true,
|
|
92
|
+
deletable: true
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}, [props.mountPoints]);
|
|
96
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
97
|
+
/* @__PURE__ */ jsx(
|
|
98
|
+
GlobalStyles,
|
|
99
|
+
{
|
|
100
|
+
styles: {
|
|
101
|
+
'[class*="makeStyles-settingsOverlay"]': {
|
|
102
|
+
backgroundColor: theme.palette.mode === "dark" ? "rgba(20, 20, 20, 0.95) !important" : "rgba(40, 40, 40, 0.93) !important"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
CustomHomepageGrid,
|
|
109
|
+
{
|
|
110
|
+
config: defaultConfig,
|
|
111
|
+
preventCollision: false,
|
|
112
|
+
compactType: "vertical",
|
|
113
|
+
children
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] });
|
|
75
117
|
};
|
|
76
118
|
|
|
77
119
|
export { CustomizableGrid };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomizableGrid.esm.js","sources":["../../src/components/CustomizableGrid.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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\n// This complete read-only home page grid picks up the idea and styles from\n// https://github.com/backstage/backstage/blob/master/plugins/home\n// Esp. from the CustomHomepageGrid component:\n// https://github.com/backstage/backstage/blob/master/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx\n// but without the drag and drop functionality.\n\nimport type { ComponentType } from 'react';\n\nimport { useMemo } from 'react';\nimport { Layout } from 'react-grid-layout';\n\nimport { ErrorBoundary } from '@backstage/core-components';\nimport { CustomHomepageGrid } from '@backstage/plugin-home';\n\nimport { makeStyles } from 'tss-react/mui';\n\n// Removes the doubled scrollbar\nimport 'react-grid-layout/css/styles.css';\n\nimport { HomePageCardMountPoint } from '../types';\n\ninterface Card {\n id: string;\n Component: ComponentType<any>;\n props?: Record<string, any>;\n layouts: Record<string, Layout>;\n}\n\nconst useStyles = makeStyles()({\n // Make card content scrollable (so that cards don't overlap)\n cardWrapper: {\n '& > div[class*=\"MuiCard-root\"]': {\n width: '100%',\n height: '100%',\n },\n '& div[class*=\"MuiCardContent-root\"]': {\n overflow: 'auto',\n },\n },\n});\n\n/**\n * @public\n */\nexport interface CustomizableGridProps {\n mountPoints: HomePageCardMountPoint[];\n breakpoints?: Record<string, number>;\n cols?: Record<string, number>;\n}\n\n/**\n * @public\n */\nexport const CustomizableGrid = (props: CustomizableGridProps) => {\n const { classes } = useStyles();\n\n const cards = useMemo<Card[]>(() => {\n return props.mountPoints.map<Card>((mountPoint, index) => {\n const id = (index + 1).toString();\n const layouts: Record<string, Layout> = {};\n\n if (mountPoint.config?.layouts) {\n for (const [breakpoint, layout] of Object.entries(\n mountPoint.config.layouts,\n )) {\n layouts[breakpoint] = {\n i: id,\n x: layout.x ?? 0,\n y: layout.y ?? 0,\n w: layout.w ?? 12,\n h: layout.h ?? 4,\n isDraggable:
|
|
1
|
+
{"version":3,"file":"CustomizableGrid.esm.js","sources":["../../src/components/CustomizableGrid.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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\n// This complete read-only home page grid picks up the idea and styles from\n// https://github.com/backstage/backstage/blob/master/plugins/home\n// Esp. from the CustomHomepageGrid component:\n// https://github.com/backstage/backstage/blob/master/plugins/home/src/components/CustomHomepage/CustomHomepageGrid.tsx\n// but without the drag and drop functionality.\n\nimport type { ComponentType } from 'react';\n\nimport { useMemo } from 'react';\nimport { Layout } from 'react-grid-layout';\nimport GlobalStyles from '@mui/material/GlobalStyles';\nimport { useTheme } from '@mui/material/styles';\n\nimport { ErrorBoundary } from '@backstage/core-components';\nimport { CustomHomepageGrid } from '@backstage/plugin-home';\n\nimport { makeStyles } from 'tss-react/mui';\n\n// Removes the doubled scrollbar\nimport 'react-grid-layout/css/styles.css';\n\nimport { HomePageCardMountPoint } from '../types';\n\ninterface Card {\n id: string;\n Component: ComponentType<any>;\n props?: Record<string, any>;\n layouts: Record<string, Layout>;\n}\n\nconst useStyles = makeStyles()({\n // Make card content scrollable (so that cards don't overlap)\n cardWrapper: {\n '& > div[class*=\"MuiCard-root\"]': {\n width: '100%',\n height: '100%',\n },\n '& div[class*=\"MuiCardContent-root\"]': {\n overflow: 'auto',\n },\n },\n});\n\n/**\n * @public\n */\nexport interface CustomizableGridProps {\n mountPoints: HomePageCardMountPoint[];\n breakpoints?: Record<string, number>;\n cols?: Record<string, number>;\n}\n\n/**\n * @public\n */\nexport const CustomizableGrid = (props: CustomizableGridProps) => {\n const { classes } = useStyles();\n const theme = useTheme();\n\n const cards = useMemo<Card[]>(() => {\n return props.mountPoints.map<Card>((mountPoint, index) => {\n const id = (index + 1).toString();\n const layouts: Record<string, Layout> = {};\n\n if (mountPoint.config?.layouts) {\n for (const [breakpoint, layout] of Object.entries(\n mountPoint.config.layouts,\n )) {\n layouts[breakpoint] = {\n i: id,\n x: layout.x ?? 0,\n y: layout.y ?? 0,\n w: layout.w ?? 12,\n h: layout.h ?? 4,\n isDraggable: true,\n isResizable: true,\n };\n }\n } else {\n // Default layout for cards without a layout configuration\n ['xl', 'lg', 'md', 'sm', 'xs', 'xxs'].forEach(breakpoint => {\n layouts[breakpoint] = {\n i: id,\n x: 0,\n y: 0,\n w: 12,\n h: 4,\n isDraggable: true,\n isResizable: true,\n };\n });\n }\n\n return {\n id,\n Component: mountPoint.Component,\n props: mountPoint.config?.props,\n layouts,\n };\n });\n }, [props.mountPoints]);\n\n const children = useMemo(() => {\n return cards.map(card => (\n <div\n key={card.id}\n data-cardid={card.id}\n data-testid={`home-page card ${card.id}`}\n data-layout={JSON.stringify(card.layouts)}\n className={classes.cardWrapper}\n >\n <ErrorBoundary>\n <card.Component {...card.props} />\n </ErrorBoundary>\n </div>\n ));\n }, [cards, classes.cardWrapper]);\n\n // Create default layout configuration for initial display AND restore defaults functionality\n const defaultConfig = useMemo(() => {\n if (!props.mountPoints || props.mountPoints.length === 0) {\n return [];\n }\n\n return props.mountPoints.map((mountPoint, index) => {\n const layout = mountPoint.config?.layouts?.xl || {};\n\n return {\n component: (\n <mountPoint.Component {...(mountPoint.config?.props || {})} />\n ),\n x: layout.x ?? 0,\n y: layout.y ?? index * 5,\n width: layout.w ?? 12,\n height: layout.h ?? 4,\n movable: true,\n resizable: true,\n draggable: true,\n deletable: true,\n };\n });\n }, [props.mountPoints]);\n\n return (\n <>\n <GlobalStyles\n styles={{\n '[class*=\"makeStyles-settingsOverlay\"]': {\n backgroundColor:\n theme.palette.mode === 'dark'\n ? 'rgba(20, 20, 20, 0.95) !important'\n : 'rgba(40, 40, 40, 0.93) !important',\n },\n }}\n />\n <CustomHomepageGrid\n config={defaultConfig}\n preventCollision={false}\n compactType=\"vertical\"\n >\n {children}\n </CustomHomepageGrid>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { Page, Content, EmptyState } from '@backstage/core-components';
|
|
4
|
+
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
4
5
|
import { Header } from './Header.esm.js';
|
|
5
6
|
import { CustomizableGrid } from './CustomizableGrid.esm.js';
|
|
6
7
|
|
|
7
8
|
const CustomizableHomePage = (props) => {
|
|
9
|
+
const { t } = useTranslation();
|
|
8
10
|
const filteredAndSortedHomePageCards = useMemo(() => {
|
|
9
11
|
if (!props.cards) {
|
|
10
12
|
return [];
|
|
@@ -19,13 +21,7 @@ const CustomizableHomePage = (props) => {
|
|
|
19
21
|
}, [props.cards]);
|
|
20
22
|
return /* @__PURE__ */ jsxs(Page, { themeId: "home", children: [
|
|
21
23
|
/* @__PURE__ */ jsx(Header, { ...props }),
|
|
22
|
-
/* @__PURE__ */ jsx(Content, { children: filteredAndSortedHomePageCards.length === 0 ? /* @__PURE__ */ jsx(
|
|
23
|
-
EmptyState,
|
|
24
|
-
{
|
|
25
|
-
title: "No home page cards (mount points) configured or found.",
|
|
26
|
-
missing: "content"
|
|
27
|
-
}
|
|
28
|
-
) : /* @__PURE__ */ jsx(CustomizableGrid, { mountPoints: filteredAndSortedHomePageCards }) })
|
|
24
|
+
/* @__PURE__ */ jsx(Content, { children: filteredAndSortedHomePageCards.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { title: t("homePage.empty"), missing: "content" }) : /* @__PURE__ */ jsx(CustomizableGrid, { mountPoints: filteredAndSortedHomePageCards }) })
|
|
29
25
|
] });
|
|
30
26
|
};
|
|
31
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomizableHomePage.esm.js","sources":["../../src/components/CustomizableHomePage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { Content, EmptyState, Page } from '@backstage/core-components';\n\nimport { HomePageCardMountPoint } from '../types';\n\nimport { Header, HeaderProps } from './Header';\nimport { CustomizableGrid } from './CustomizableGrid';\n\nexport interface HomePageProps extends HeaderProps {\n cards?: HomePageCardMountPoint[];\n}\n\nexport const CustomizableHomePage = (props: HomePageProps) => {\n const filteredAndSortedHomePageCards = useMemo(() => {\n if (!props.cards) {\n return [];\n }\n\n const filteredAndSorted = props.cards.filter(\n card =>\n card.enabled !== false &&\n (!card.config?.priority || card.config.priority >= 0),\n );\n\n filteredAndSorted.sort(\n (a, b) => (b.config?.priority ?? 0) - (a.config?.priority ?? 0),\n );\n\n return filteredAndSorted;\n }, [props.cards]);\n\n return (\n <Page themeId=\"home\">\n <Header {...props} />\n <Content>\n {filteredAndSortedHomePageCards.length === 0 ? (\n <EmptyState
|
|
1
|
+
{"version":3,"file":"CustomizableHomePage.esm.js","sources":["../../src/components/CustomizableHomePage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { Content, EmptyState, Page } from '@backstage/core-components';\n\nimport { HomePageCardMountPoint } from '../types';\nimport { useTranslation } from '../hooks/useTranslation';\n\nimport { Header, HeaderProps } from './Header';\nimport { CustomizableGrid } from './CustomizableGrid';\n\nexport interface HomePageProps extends HeaderProps {\n cards?: HomePageCardMountPoint[];\n}\n\nexport const CustomizableHomePage = (props: HomePageProps) => {\n const { t } = useTranslation();\n const filteredAndSortedHomePageCards = useMemo(() => {\n if (!props.cards) {\n return [];\n }\n\n const filteredAndSorted = props.cards.filter(\n card =>\n card.enabled !== false &&\n (!card.config?.priority || card.config.priority >= 0),\n );\n\n filteredAndSorted.sort(\n (a, b) => (b.config?.priority ?? 0) - (a.config?.priority ?? 0),\n );\n\n return filteredAndSorted;\n }, [props.cards]);\n\n return (\n <Page themeId=\"home\">\n <Header {...props} />\n <Content>\n {filteredAndSortedHomePageCards.length === 0 ? (\n <EmptyState title={t('homePage.empty')} missing=\"content\" />\n ) : (\n <CustomizableGrid mountPoints={filteredAndSortedHomePageCards} />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA8Ba,MAAA,oBAAA,GAAuB,CAAC,KAAyB,KAAA;AAC5D,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAC7B,EAAM,MAAA,8BAAA,GAAiC,QAAQ,MAAM;AACnD,IAAI,IAAA,CAAC,MAAM,KAAO,EAAA;AAChB,MAAA,OAAO,EAAC;AAAA;AAGV,IAAM,MAAA,iBAAA,GAAoB,MAAM,KAAM,CAAA,MAAA;AAAA,MACpC,CAAA,IAAA,KACE,IAAK,CAAA,OAAA,KAAY,KAChB,KAAA,CAAC,KAAK,MAAQ,EAAA,QAAA,IAAY,IAAK,CAAA,MAAA,CAAO,QAAY,IAAA,CAAA;AAAA,KACvD;AAEA,IAAkB,iBAAA,CAAA,IAAA;AAAA,MAChB,CAAC,GAAG,CAAO,KAAA,CAAA,CAAA,CAAE,QAAQ,QAAY,IAAA,CAAA,KAAM,CAAE,CAAA,MAAA,EAAQ,QAAY,IAAA,CAAA;AAAA,KAC/D;AAEA,IAAO,OAAA,iBAAA;AAAA,GACN,EAAA,CAAC,KAAM,CAAA,KAAK,CAAC,CAAA;AAEhB,EACE,uBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,MAAA,EAAA,EAAQ,GAAG,KAAO,EAAA,CAAA;AAAA,wBAClB,OACE,EAAA,EAAA,QAAA,EAAA,8BAAA,CAA+B,WAAW,CACzC,mBAAA,GAAA,CAAC,cAAW,KAAO,EAAA,CAAA,CAAE,gBAAgB,CAAA,EAAG,SAAQ,SAAU,EAAA,CAAA,uBAEzD,gBAAiB,EAAA,EAAA,WAAA,EAAa,gCAAgC,CAEnE,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -18,6 +18,8 @@ import { ViewMoreLink } from './ViewMoreLink.esm.js';
|
|
|
18
18
|
import HomePageEntityIllustration from '../../images/homepage-entities-1.svg';
|
|
19
19
|
import { useEntities } from '../../hooks/useEntities.esm.js';
|
|
20
20
|
import { hasEntityIllustrationUserDismissed, addDismissedEntityIllustrationUsers } from '../../utils/utils.esm.js';
|
|
21
|
+
import { useTranslation } from '../../hooks/useTranslation.esm.js';
|
|
22
|
+
import { Trans } from '../Trans.esm.js';
|
|
21
23
|
|
|
22
24
|
const StyledLink = styled(Link)(({ theme }) => ({
|
|
23
25
|
textDecoration: "none",
|
|
@@ -29,6 +31,7 @@ const StyledLink = styled(Link)(({ theme }) => ({
|
|
|
29
31
|
}));
|
|
30
32
|
const EntitySection = () => {
|
|
31
33
|
const theme = useTheme();
|
|
34
|
+
const { t } = useTranslation();
|
|
32
35
|
const { displayName, loading: profileLoading } = useUserProfile();
|
|
33
36
|
const [isRemoveFirstCard, setIsRemoveFirstCard] = useState(false);
|
|
34
37
|
const [showDiscoveryCard, setShowDiscoveryCard] = useState(true);
|
|
@@ -72,11 +75,11 @@ const EntitySection = () => {
|
|
|
72
75
|
}
|
|
73
76
|
);
|
|
74
77
|
} else if (!data) {
|
|
75
|
-
content = /* @__PURE__ */ jsx(WarningPanel, { severity: "error", title: "
|
|
78
|
+
content = /* @__PURE__ */ jsx(WarningPanel, { severity: "error", title: t("entities.fetchError"), children: /* @__PURE__ */ jsx(
|
|
76
79
|
CodeSnippet,
|
|
77
80
|
{
|
|
78
81
|
language: "text",
|
|
79
|
-
text: error?.toString() ?? "
|
|
82
|
+
text: error?.toString() ?? t("entities.error")
|
|
80
83
|
}
|
|
81
84
|
) });
|
|
82
85
|
} else {
|
|
@@ -123,12 +126,12 @@ const EntitySection = () => {
|
|
|
123
126
|
}
|
|
124
127
|
),
|
|
125
128
|
/* @__PURE__ */ jsxs(Box, { sx: { p: 2 }, children: [
|
|
126
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Typography, { variant: "body2", paragraph: true, children: "
|
|
129
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Typography, { variant: "body2", paragraph: true, children: t("entities.description") }) }),
|
|
127
130
|
entities?.length > 0 && /* @__PURE__ */ jsx(
|
|
128
131
|
IconButton,
|
|
129
132
|
{
|
|
130
133
|
onClick: handleClose,
|
|
131
|
-
"aria-label": "close",
|
|
134
|
+
"aria-label": t("entities.close"),
|
|
132
135
|
style: {
|
|
133
136
|
position: "absolute",
|
|
134
137
|
top: "8px",
|
|
@@ -175,7 +178,7 @@ const EntitySection = () => {
|
|
|
175
178
|
overflow: "hidden"
|
|
176
179
|
},
|
|
177
180
|
children: /* @__PURE__ */ jsxs(CardContent, { children: [
|
|
178
|
-
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: "1.125rem", fontWeight: 500 }, children: "
|
|
181
|
+
/* @__PURE__ */ jsx(Typography, { sx: { fontSize: "1.125rem", fontWeight: 500 }, children: t("entities.empty") }),
|
|
179
182
|
/* @__PURE__ */ jsx(
|
|
180
183
|
Typography,
|
|
181
184
|
{
|
|
@@ -185,10 +188,10 @@ const EntitySection = () => {
|
|
|
185
188
|
mt: "20px",
|
|
186
189
|
mb: "16px"
|
|
187
190
|
},
|
|
188
|
-
children: "
|
|
191
|
+
children: t("entities.emptyDescription")
|
|
189
192
|
}
|
|
190
193
|
),
|
|
191
|
-
/* @__PURE__ */ jsx(StyledLink, { to: "/catalog-import", underline: "none", children: "
|
|
194
|
+
/* @__PURE__ */ jsx(StyledLink, { to: "/catalog-import", underline: "none", children: t("entities.register") })
|
|
192
195
|
] })
|
|
193
196
|
}
|
|
194
197
|
) })
|
|
@@ -214,15 +217,17 @@ const EntitySection = () => {
|
|
|
214
217
|
fontWeight: "500",
|
|
215
218
|
fontSize: "1.5rem"
|
|
216
219
|
},
|
|
217
|
-
children: "
|
|
220
|
+
children: t("entities.title")
|
|
218
221
|
}
|
|
219
222
|
),
|
|
220
223
|
content,
|
|
221
|
-
entities?.length > 0 && /* @__PURE__ */ jsx(Box, { sx: { pt: 2 }, children: /* @__PURE__ */
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
entities?.length > 0 && /* @__PURE__ */ jsx(Box, { sx: { pt: 2 }, children: /* @__PURE__ */ jsx(ViewMoreLink, { to: "/catalog", children: /* @__PURE__ */ jsx(
|
|
225
|
+
Trans,
|
|
226
|
+
{
|
|
227
|
+
message: "entities.viewAll",
|
|
228
|
+
params: { count: data?.totalItems?.toString() || "" }
|
|
229
|
+
}
|
|
230
|
+
) }) })
|
|
226
231
|
]
|
|
227
232
|
}
|
|
228
233
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EntitySection.esm.js","sources":["../../../src/components/EntitySection/EntitySection.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 type { ReactNode } from 'react';\n\nimport { useState, useEffect, Fragment } from 'react';\n\nimport {\n CodeSnippet,\n WarningPanel,\n Link as BackstageLink,\n} from '@backstage/core-components';\nimport { useUserProfile } from '@backstage/plugin-user-settings';\n\nimport Grid from '@mui/material/Grid';\nimport Box from '@mui/material/Box';\nimport Card from '@mui/material/Card';\nimport IconButton from '@mui/material/IconButton';\nimport Skeleton from '@mui/material/Skeleton';\nimport Typography from '@mui/material/Typography';\nimport CloseIcon from '@mui/icons-material/Close';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport CardContent from '@mui/material/CardContent';\nimport { useTheme, styled } from '@mui/material/styles';\nimport useMediaQuery from '@mui/material/useMediaQuery';\n\nimport EntityCard from './EntityCard';\nimport { ViewMoreLink } from './ViewMoreLink';\nimport HomePageEntityIllustration from '../../images/homepage-entities-1.svg';\nimport { useEntities } from '../../hooks/useEntities';\nimport {\n addDismissedEntityIllustrationUsers,\n hasEntityIllustrationUserDismissed,\n} from '../../utils/utils';\n\nconst StyledLink = styled(BackstageLink)(({ theme }) => ({\n textDecoration: 'none',\n padding: theme.spacing(1, 1.5),\n fontSize: '16px',\n display: 'inline-flex',\n border: `1px solid ${theme.palette.primary.main}`,\n borderRadius: 4,\n}));\n\nexport const EntitySection = () => {\n const theme = useTheme();\n const { displayName, loading: profileLoading } = useUserProfile();\n const [isRemoveFirstCard, setIsRemoveFirstCard] = useState(false);\n const [showDiscoveryCard, setShowDiscoveryCard] = useState(true);\n const [imgLoaded, setImgLoaded] = useState(false);\n const [isMediumBreakpoint, setIsMediumBreakpoint] = useState(false);\n\n const isMd = useMediaQuery(theme.breakpoints.only('md'));\n\n useEffect(() => {\n if (isMd) {\n setIsMediumBreakpoint(true);\n } else {\n setIsMediumBreakpoint(false);\n }\n }, [isMd]);\n\n useEffect(() => {\n const isUserDismissedEntityIllustration =\n hasEntityIllustrationUserDismissed(displayName);\n setIsRemoveFirstCard(isUserDismissedEntityIllustration);\n }, [displayName]);\n\n const handleClose = () => {\n setShowDiscoveryCard(false);\n setTimeout(() => {\n addDismissedEntityIllustrationUsers(displayName);\n setIsRemoveFirstCard(true);\n }, 500);\n };\n\n const { data, error, isLoading } = useEntities({\n kind: ['Component', 'API', 'Resource', 'System'],\n });\n\n const entities = data?.items ?? [];\n\n let content: ReactNode;\n\n if (isLoading) {\n content = (\n <Box\n sx={{\n height: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <CircularProgress />\n </Box>\n );\n } else if (!data) {\n content = (\n <WarningPanel severity=\"error\" title=\"Could not fetch data.\">\n <CodeSnippet\n language=\"text\"\n text={error?.toString() ?? 'Unknown error'}\n />\n </WarningPanel>\n );\n } else {\n let entityCardCount = 2;\n if (isMediumBreakpoint) entityCardCount = 3;\n\n content = (\n <Box sx={{ padding: '8px 8px 8px 0' }}>\n <Fragment>\n <Grid container spacing={1} alignItems=\"stretch\">\n {!isRemoveFirstCard && !profileLoading && (\n <Grid item xs={12} md={6} lg={5} key=\"entities illustration\">\n <Card\n elevation={0}\n sx={{\n border: `1px solid ${theme.palette.grey[400]}`,\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n position: 'relative',\n transition:\n 'opacity 0.5s ease-out, transform 0.5s ease-in-out',\n opacity: showDiscoveryCard ? 1 : 0,\n transform: showDiscoveryCard\n ? 'translateX(0)'\n : 'translateX(-50px)',\n }}\n >\n {!imgLoaded && (\n <Skeleton\n variant=\"rectangular\"\n height={300}\n sx={{\n borderRadius: 3,\n width: 'clamp(140px, 14vw, 266px)',\n }}\n />\n )}\n <Box\n component=\"img\"\n src={HomePageEntityIllustration}\n onLoad={() => setImgLoaded(true)}\n alt=\"\"\n height={300}\n sx={{\n width: 'clamp(140px, 14vw, 266px)',\n }}\n />\n <Box sx={{ p: 2 }}>\n <Box>\n <Typography variant=\"body2\" paragraph>\n Browse the Systems, Components, Resources, and APIs that\n are available in your organization.\n </Typography>\n </Box>\n {entities?.length > 0 && (\n <IconButton\n onClick={handleClose}\n aria-label=\"close\"\n style={{\n position: 'absolute',\n top: '8px',\n right: '8px',\n }}\n >\n <CloseIcon style={{ width: '16px', height: '16px' }} />\n </IconButton>\n )}\n </Box>\n </Card>\n </Grid>\n )}\n {entities\n ?.slice(0, isRemoveFirstCard ? 4 : entityCardCount)\n .map((item: any) => (\n <Grid\n item\n xs={12}\n md={6}\n lg={isRemoveFirstCard ? 3 : 3.5}\n key={item.metadata.name}\n >\n <EntityCard\n entity={item}\n title={\n item.spec?.profile?.displayName ?? item.metadata.name\n }\n version=\"latest\"\n description={item.metadata.description ?? ''}\n tags={item.metadata?.tags ?? []}\n kind={item.kind}\n />\n </Grid>\n ))}\n {entities?.length === 0 && (\n <Grid item md={isRemoveFirstCard ? 12 : 7}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 300,\n border: muiTheme =>\n `1px solid ${muiTheme.palette.grey[400]}`,\n borderRadius: 3,\n overflow: 'hidden',\n }}\n >\n <CardContent>\n <Typography sx={{ fontSize: '1.125rem', fontWeight: 500 }}>\n No software catalog added yet\n </Typography>\n <Typography\n sx={{\n fontSize: '0.875rem',\n fontWeight: 400,\n mt: '20px',\n mb: '16px',\n }}\n >\n Once software catalogs are added, this space will showcase\n relevant content tailored to your experience.\n </Typography>\n <StyledLink to=\"/catalog-import\" underline=\"none\">\n Register a component\n </StyledLink>\n </CardContent>\n </Box>\n </Grid>\n )}\n </Grid>\n </Fragment>\n </Box>\n );\n }\n\n return (\n <Card\n elevation={0}\n sx={{\n padding: '24px',\n border: muitheme => `1px solid ${muitheme.palette.grey[300]}`,\n overflow: 'auto',\n }}\n >\n <Typography\n variant=\"h3\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n fontWeight: '500',\n fontSize: '1.5rem',\n }}\n >\n Explore Your Software Catalog\n </Typography>\n {content}\n {entities?.length > 0 && (\n <Box sx={{ pt: 2 }}>\n <ViewMoreLink to=\"/catalog\">\n View all {data?.totalItems ? data?.totalItems : ''} catalog entities\n </ViewMoreLink>\n </Box>\n )}\n </Card>\n );\n};\n"],"names":["BackstageLink"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EntitySection.esm.js","sources":["../../../src/components/EntitySection/EntitySection.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 type { ReactNode } from 'react';\n\nimport { useState, useEffect, Fragment } from 'react';\n\nimport {\n CodeSnippet,\n WarningPanel,\n Link as BackstageLink,\n} from '@backstage/core-components';\nimport { useUserProfile } from '@backstage/plugin-user-settings';\n\nimport Grid from '@mui/material/Grid';\nimport Box from '@mui/material/Box';\nimport Card from '@mui/material/Card';\nimport IconButton from '@mui/material/IconButton';\nimport Skeleton from '@mui/material/Skeleton';\nimport Typography from '@mui/material/Typography';\nimport CloseIcon from '@mui/icons-material/Close';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport CardContent from '@mui/material/CardContent';\nimport { useTheme, styled } from '@mui/material/styles';\nimport useMediaQuery from '@mui/material/useMediaQuery';\n\nimport EntityCard from './EntityCard';\nimport { ViewMoreLink } from './ViewMoreLink';\nimport HomePageEntityIllustration from '../../images/homepage-entities-1.svg';\nimport { useEntities } from '../../hooks/useEntities';\nimport {\n addDismissedEntityIllustrationUsers,\n hasEntityIllustrationUserDismissed,\n} from '../../utils/utils';\nimport { useTranslation } from '../../hooks/useTranslation';\nimport { Trans } from '../Trans';\n\nconst StyledLink = styled(BackstageLink)(({ theme }) => ({\n textDecoration: 'none',\n padding: theme.spacing(1, 1.5),\n fontSize: '16px',\n display: 'inline-flex',\n border: `1px solid ${theme.palette.primary.main}`,\n borderRadius: 4,\n}));\n\nexport const EntitySection = () => {\n const theme = useTheme();\n const { t } = useTranslation();\n const { displayName, loading: profileLoading } = useUserProfile();\n const [isRemoveFirstCard, setIsRemoveFirstCard] = useState(false);\n const [showDiscoveryCard, setShowDiscoveryCard] = useState(true);\n const [imgLoaded, setImgLoaded] = useState(false);\n const [isMediumBreakpoint, setIsMediumBreakpoint] = useState(false);\n\n const isMd = useMediaQuery(theme.breakpoints.only('md'));\n\n useEffect(() => {\n if (isMd) {\n setIsMediumBreakpoint(true);\n } else {\n setIsMediumBreakpoint(false);\n }\n }, [isMd]);\n\n useEffect(() => {\n const isUserDismissedEntityIllustration =\n hasEntityIllustrationUserDismissed(displayName);\n setIsRemoveFirstCard(isUserDismissedEntityIllustration);\n }, [displayName]);\n\n const handleClose = () => {\n setShowDiscoveryCard(false);\n setTimeout(() => {\n addDismissedEntityIllustrationUsers(displayName);\n setIsRemoveFirstCard(true);\n }, 500);\n };\n\n const { data, error, isLoading } = useEntities({\n kind: ['Component', 'API', 'Resource', 'System'],\n });\n\n const entities = data?.items ?? [];\n\n let content: ReactNode;\n\n if (isLoading) {\n content = (\n <Box\n sx={{\n height: '100%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <CircularProgress />\n </Box>\n );\n } else if (!data) {\n content = (\n <WarningPanel severity=\"error\" title={t('entities.fetchError')}>\n <CodeSnippet\n language=\"text\"\n text={error?.toString() ?? t('entities.error')}\n />\n </WarningPanel>\n );\n } else {\n let entityCardCount = 2;\n if (isMediumBreakpoint) entityCardCount = 3;\n\n content = (\n <Box sx={{ padding: '8px 8px 8px 0' }}>\n <Fragment>\n <Grid container spacing={1} alignItems=\"stretch\">\n {!isRemoveFirstCard && !profileLoading && (\n <Grid item xs={12} md={6} lg={5} key=\"entities illustration\">\n <Card\n elevation={0}\n sx={{\n border: `1px solid ${theme.palette.grey[400]}`,\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n position: 'relative',\n transition:\n 'opacity 0.5s ease-out, transform 0.5s ease-in-out',\n opacity: showDiscoveryCard ? 1 : 0,\n transform: showDiscoveryCard\n ? 'translateX(0)'\n : 'translateX(-50px)',\n }}\n >\n {!imgLoaded && (\n <Skeleton\n variant=\"rectangular\"\n height={300}\n sx={{\n borderRadius: 3,\n width: 'clamp(140px, 14vw, 266px)',\n }}\n />\n )}\n <Box\n component=\"img\"\n src={HomePageEntityIllustration}\n onLoad={() => setImgLoaded(true)}\n alt=\"\"\n height={300}\n sx={{\n width: 'clamp(140px, 14vw, 266px)',\n }}\n />\n <Box sx={{ p: 2 }}>\n <Box>\n <Typography variant=\"body2\" paragraph>\n {t('entities.description')}\n </Typography>\n </Box>\n {entities?.length > 0 && (\n <IconButton\n onClick={handleClose}\n aria-label={t('entities.close')}\n style={{\n position: 'absolute',\n top: '8px',\n right: '8px',\n }}\n >\n <CloseIcon style={{ width: '16px', height: '16px' }} />\n </IconButton>\n )}\n </Box>\n </Card>\n </Grid>\n )}\n {entities\n ?.slice(0, isRemoveFirstCard ? 4 : entityCardCount)\n .map((item: any) => (\n <Grid\n item\n xs={12}\n md={6}\n lg={isRemoveFirstCard ? 3 : 3.5}\n key={item.metadata.name}\n >\n <EntityCard\n entity={item}\n title={\n item.spec?.profile?.displayName ?? item.metadata.name\n }\n version=\"latest\"\n description={item.metadata.description ?? ''}\n tags={item.metadata?.tags ?? []}\n kind={item.kind}\n />\n </Grid>\n ))}\n {entities?.length === 0 && (\n <Grid item md={isRemoveFirstCard ? 12 : 7}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 300,\n border: muiTheme =>\n `1px solid ${muiTheme.palette.grey[400]}`,\n borderRadius: 3,\n overflow: 'hidden',\n }}\n >\n <CardContent>\n <Typography sx={{ fontSize: '1.125rem', fontWeight: 500 }}>\n {t('entities.empty')}\n </Typography>\n <Typography\n sx={{\n fontSize: '0.875rem',\n fontWeight: 400,\n mt: '20px',\n mb: '16px',\n }}\n >\n {t('entities.emptyDescription')}\n </Typography>\n <StyledLink to=\"/catalog-import\" underline=\"none\">\n {t('entities.register')}\n </StyledLink>\n </CardContent>\n </Box>\n </Grid>\n )}\n </Grid>\n </Fragment>\n </Box>\n );\n }\n\n return (\n <Card\n elevation={0}\n sx={{\n padding: '24px',\n border: muitheme => `1px solid ${muitheme.palette.grey[300]}`,\n overflow: 'auto',\n }}\n >\n <Typography\n variant=\"h3\"\n sx={{\n display: 'flex',\n alignItems: 'center',\n fontWeight: '500',\n fontSize: '1.5rem',\n }}\n >\n {t('entities.title')}\n </Typography>\n {content}\n {entities?.length > 0 && (\n <Box sx={{ pt: 2 }}>\n <ViewMoreLink to=\"/catalog\">\n <Trans\n message=\"entities.viewAll\"\n params={{ count: data?.totalItems?.toString() || '' }}\n />\n </ViewMoreLink>\n </Box>\n )}\n </Card>\n );\n};\n"],"names":["BackstageLink"],"mappings":"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"}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { FeaturedDocsCard as FeaturedDocsCard$1 } from '@backstage/plugin-home';
|
|
3
|
+
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
3
4
|
|
|
4
5
|
const FeaturedDocsCard = (props) => {
|
|
5
|
-
|
|
6
|
+
const { t } = useTranslation();
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
FeaturedDocsCard$1,
|
|
9
|
+
{
|
|
10
|
+
subLinkText: ` ${t("featuredDocs.learnMore")}`,
|
|
11
|
+
...props
|
|
12
|
+
}
|
|
13
|
+
);
|
|
6
14
|
};
|
|
7
15
|
|
|
8
16
|
export { FeaturedDocsCard };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FeaturedDocsCard.esm.js","sources":["../../src/components/FeaturedDocsCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FeaturedDocsCard as PluginHomeFeaturedDocsCard,\n FeaturedDocsCardProps,\n} from '@backstage/plugin-home';\n\n/**\n * Overrides `FeaturedDocsCard` from the home plugin, but overrides the\n * `subLinkText` prop to be \" Learn more\" instead of \"LEARN MORE\".\n *\n * 1. To fix the all uppercase that is used in home plugin\n * 2. To add a small missing gap between the title and the button\n */\nexport const FeaturedDocsCard = (props: FeaturedDocsCardProps) => {\n return <PluginHomeFeaturedDocsCard
|
|
1
|
+
{"version":3,"file":"FeaturedDocsCard.esm.js","sources":["../../src/components/FeaturedDocsCard.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n FeaturedDocsCard as PluginHomeFeaturedDocsCard,\n FeaturedDocsCardProps,\n} from '@backstage/plugin-home';\n\nimport { useTranslation } from '../hooks/useTranslation';\n\n/**\n * Overrides `FeaturedDocsCard` from the home plugin, but overrides the\n * `subLinkText` prop to be \" Learn more\" instead of \"LEARN MORE\".\n *\n * 1. To fix the all uppercase that is used in home plugin\n * 2. To add a small missing gap between the title and the button\n */\nexport const FeaturedDocsCard = (props: FeaturedDocsCardProps) => {\n const { t } = useTranslation();\n return (\n <PluginHomeFeaturedDocsCard\n subLinkText={` ${t('featuredDocs.learnMore')}`}\n {...props}\n />\n );\n};\n"],"names":["PluginHomeFeaturedDocsCard"],"mappings":";;;;AA8Ba,MAAA,gBAAA,GAAmB,CAAC,KAAiC,KAAA;AAChE,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAC7B,EACE,uBAAA,GAAA;AAAA,IAACA,kBAAA;AAAA,IAAA;AAAA,MACC,WAAa,EAAA,CAAA,CAAA,EAAI,CAAE,CAAA,wBAAwB,CAAC,CAAA,CAAA;AAAA,MAC3C,GAAG;AAAA;AAAA,GACN;AAEJ;;;;"}
|
|
@@ -5,25 +5,37 @@ import { Header as Header$1 } from '@backstage/core-components';
|
|
|
5
5
|
import { HeaderWorldClock } from '@backstage/plugin-home';
|
|
6
6
|
import useAsync from 'react-use/esm/useAsync';
|
|
7
7
|
import { LocalClock } from './LocalClock.esm.js';
|
|
8
|
+
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const interpolateUserTitle = (title, displayName) => {
|
|
11
|
+
if (!displayName) {
|
|
12
|
+
return title.replace(/\{\{(firstName|displayName)\}\}/g, "");
|
|
13
|
+
}
|
|
14
|
+
const firstName = displayName.split(" ")[0];
|
|
15
|
+
return title.replace(/\{\{firstName\}\}/g, firstName).replace(/\{\{displayName\}\}/g, displayName);
|
|
13
16
|
};
|
|
14
17
|
const Header = (props) => {
|
|
15
18
|
const identityApi = useApi(identityApiRef);
|
|
16
19
|
const { value: profile } = useAsync(() => identityApi.getProfileInfo());
|
|
20
|
+
const { t } = useTranslation();
|
|
17
21
|
const title = useMemo(() => {
|
|
22
|
+
const firstName = profile?.displayName?.split(" ")[0];
|
|
18
23
|
if (profile?.displayName && props.personalizedTitle) {
|
|
19
|
-
return
|
|
20
|
-
} else if (props.title) {
|
|
21
|
-
return getPersonalizedTitle(props.title, profile?.displayName);
|
|
24
|
+
return interpolateUserTitle(props.personalizedTitle, profile.displayName);
|
|
22
25
|
}
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
if (props.title) {
|
|
27
|
+
return interpolateUserTitle(props.title, profile?.displayName);
|
|
28
|
+
}
|
|
29
|
+
if (profile?.displayName && firstName) {
|
|
30
|
+
return t("header.welcomePersonalized", { name: firstName });
|
|
31
|
+
}
|
|
32
|
+
return t("header.welcome");
|
|
33
|
+
}, [profile?.displayName, props.personalizedTitle, props.title, t]);
|
|
25
34
|
const subtitle = useMemo(() => {
|
|
26
|
-
|
|
35
|
+
if (props.subtitle) {
|
|
36
|
+
return interpolateUserTitle(props.subtitle, profile?.displayName);
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
27
39
|
}, [props.subtitle, profile?.displayName]);
|
|
28
40
|
return /* @__PURE__ */ jsxs(
|
|
29
41
|
Header$1,
|
|
@@ -35,7 +47,7 @@ const Header = (props) => {
|
|
|
35
47
|
props.localClock?.format && props.localClock?.format !== "none" ? /* @__PURE__ */ jsx(
|
|
36
48
|
LocalClock,
|
|
37
49
|
{
|
|
38
|
-
label: props.localClock?.label ?? (props.worldClocks && props.worldClocks.length > 0 ? "
|
|
50
|
+
label: props.localClock?.label ?? (props.worldClocks && props.worldClocks.length > 0 ? t("header.local") : undefined),
|
|
39
51
|
format: props.localClock?.format ?? (props.worldClocks && props.worldClocks.length > 0 ? "time" : undefined),
|
|
40
52
|
lang: props.localClock?.lang
|
|
41
53
|
}
|
|
@@ -46,5 +58,5 @@ const Header = (props) => {
|
|
|
46
58
|
);
|
|
47
59
|
};
|
|
48
60
|
|
|
49
|
-
export { Header
|
|
61
|
+
export { Header };
|
|
50
62
|
//# sourceMappingURL=Header.esm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.esm.js","sources":["../../src/components/Header.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Header as BackstageHeader } from '@backstage/core-components';\nimport { ClockConfig, HeaderWorldClock } from '@backstage/plugin-home';\n\nimport useAsync from 'react-use/esm/useAsync';\n\nimport { LocalClock, LocalClockProps } from './LocalClock';\n\nexport interface HeaderProps {\n title?: string;\n personalizedTitle?: string;\n pageTitle?: string;\n subtitle?: string;\n localClock?: LocalClockProps;\n worldClocks?: ClockConfig[];\n}\n\n// I kept this because I hope that we will add this soon or at least in Dynamic Home Page plugin 1.2 ~ RHDH 1.6.\n// const getTimeBasedTitle = (): string => {\n// const currentHour = new Date(Date.now()).getHours();\n// if (currentHour < 12) {\n// return 'Good morning {{firstName}}';\n// } else if (currentHour < 17) {\n// return 'Good afternoon {{firstName}}';\n// }\n// return 'Good evening {{firstName}}';\n// };\n\
|
|
1
|
+
{"version":3,"file":"Header.esm.js","sources":["../../src/components/Header.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { identityApiRef, useApi } from '@backstage/core-plugin-api';\nimport { Header as BackstageHeader } from '@backstage/core-components';\nimport { ClockConfig, HeaderWorldClock } from '@backstage/plugin-home';\n\nimport useAsync from 'react-use/esm/useAsync';\n\nimport { LocalClock, LocalClockProps } from './LocalClock';\nimport { useTranslation } from '../hooks/useTranslation';\n\nexport interface HeaderProps {\n title?: string;\n personalizedTitle?: string;\n pageTitle?: string;\n subtitle?: string;\n localClock?: LocalClockProps;\n worldClocks?: ClockConfig[];\n}\n\n// I kept this because I hope that we will add this soon or at least in Dynamic Home Page plugin 1.2 ~ RHDH 1.6.\n// const getTimeBasedTitle = (): string => {\n// const currentHour = new Date(Date.now()).getHours();\n// if (currentHour < 12) {\n// return 'Good morning {{firstName}}';\n// } else if (currentHour < 17) {\n// return 'Good afternoon {{firstName}}';\n// }\n// return 'Good evening {{firstName}}';\n// };\n\n/**\n * Handles user-provided title customization with variable interpolation.\n *\n * When users provide custom titles in their configuration, they take responsibility\n * for internationalization at the configuration level. This function simply handles\n * the variable interpolation for their custom strings.\n *\n * Supports variables:\n * - {{firstName}} - First part of displayName (split by space)\n * - {{displayName}} - Full displayName from user profile\n *\n * @param title - User-provided title string with optional {{variables}}\n * @param displayName - User's displayName from profile, if available\n */\nconst interpolateUserTitle = (\n title: string,\n displayName: string | undefined,\n) => {\n if (!displayName) {\n // Remove variable placeholders when no displayName is available\n return title.replace(/\\{\\{(firstName|displayName)\\}\\}/g, '');\n }\n\n const firstName = displayName.split(' ')[0];\n return title\n .replace(/\\{\\{firstName\\}\\}/g, firstName)\n .replace(/\\{\\{displayName\\}\\}/g, displayName);\n};\n\nexport const Header = (props: HeaderProps) => {\n const identityApi = useApi(identityApiRef);\n const { value: profile } = useAsync(() => identityApi.getProfileInfo());\n const { t } = useTranslation();\n\n const title = useMemo<string>(() => {\n const firstName = profile?.displayName?.split(' ')[0];\n\n // Priority 1: User-provided personalized title (user handles i18n)\n if (profile?.displayName && props.personalizedTitle) {\n return interpolateUserTitle(props.personalizedTitle, profile.displayName);\n }\n\n // Priority 2: User-provided general title (user handles i18n)\n if (props.title) {\n return interpolateUserTitle(props.title, profile?.displayName);\n }\n\n // Default: Use plugin's translation system\n if (profile?.displayName && firstName) {\n return t('header.welcomePersonalized' as any, { name: firstName });\n }\n\n return t('header.welcome');\n }, [profile?.displayName, props.personalizedTitle, props.title, t]);\n\n const subtitle = useMemo<string | undefined>(() => {\n // User-provided subtitle (user handles i18n)\n if (props.subtitle) {\n return interpolateUserTitle(props.subtitle, profile?.displayName);\n }\n\n return undefined;\n }, [props.subtitle, profile?.displayName]);\n\n return (\n <BackstageHeader\n title={title}\n subtitle={subtitle}\n pageTitleOverride={props.pageTitle}\n >\n {props.localClock?.format && props.localClock?.format !== 'none' ? (\n <LocalClock\n label={\n props.localClock?.label ??\n (props.worldClocks && props.worldClocks.length > 0\n ? t('header.local')\n : undefined)\n }\n format={\n props.localClock?.format ??\n (props.worldClocks && props.worldClocks.length > 0\n ? 'time'\n : undefined)\n }\n lang={props.localClock?.lang}\n />\n ) : null}\n\n {props.worldClocks && props.worldClocks.length > 0 ? (\n <HeaderWorldClock clockConfigs={props.worldClocks} />\n ) : null}\n </BackstageHeader>\n );\n};\n"],"names":["BackstageHeader"],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
import { Page, Content, EmptyState } from '@backstage/core-components';
|
|
4
|
+
import { useTranslation } from '../hooks/useTranslation.esm.js';
|
|
4
5
|
import { Header } from './Header.esm.js';
|
|
5
6
|
import { ReadOnlyGrid } from './ReadOnlyGrid.esm.js';
|
|
6
7
|
|
|
7
8
|
const HomePage = (props) => {
|
|
9
|
+
const { t } = useTranslation();
|
|
8
10
|
const filteredAndSortedHomePageCards = useMemo(() => {
|
|
9
11
|
if (!props.cards) {
|
|
10
12
|
return [];
|
|
@@ -18,14 +20,8 @@ const HomePage = (props) => {
|
|
|
18
20
|
return filteredAndSorted;
|
|
19
21
|
}, [props.cards]);
|
|
20
22
|
return /* @__PURE__ */ jsxs(Page, { themeId: "home", children: [
|
|
21
|
-
/* @__PURE__ */ jsx(Header, { title: "
|
|
22
|
-
/* @__PURE__ */ jsx(Content, { children: filteredAndSortedHomePageCards.length === 0 ? /* @__PURE__ */ jsx(
|
|
23
|
-
EmptyState,
|
|
24
|
-
{
|
|
25
|
-
title: "No home page cards (mount points) configured or found.",
|
|
26
|
-
missing: "content"
|
|
27
|
-
}
|
|
28
|
-
) : /* @__PURE__ */ jsx(ReadOnlyGrid, { mountPoints: filteredAndSortedHomePageCards }) })
|
|
23
|
+
/* @__PURE__ */ jsx(Header, { title: t("header.welcome"), ...props }),
|
|
24
|
+
/* @__PURE__ */ jsx(Content, { children: filteredAndSortedHomePageCards.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { title: t("homePage.empty"), missing: "content" }) : /* @__PURE__ */ jsx(ReadOnlyGrid, { mountPoints: filteredAndSortedHomePageCards }) })
|
|
29
25
|
] });
|
|
30
26
|
};
|
|
31
27
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.esm.js","sources":["../../src/components/HomePage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { Content, EmptyState, Page } from '@backstage/core-components';\n\nimport { HomePageCardMountPoint } from '../types';\n\nimport { Header, HeaderProps } from './Header';\nimport { ReadOnlyGrid } from './ReadOnlyGrid';\n\nexport interface HomePageProps extends HeaderProps {\n cards?: HomePageCardMountPoint[];\n}\n\nexport const HomePage = (props: HomePageProps) => {\n const filteredAndSortedHomePageCards = useMemo(() => {\n if (!props.cards) {\n return [];\n }\n\n const filteredAndSorted = props.cards.filter(\n card =>\n card.enabled !== false &&\n (!card.config?.priority || card.config.priority >= 0),\n );\n\n filteredAndSorted.sort(\n (a, b) => (b.config?.priority ?? 0) - (a.config?.priority ?? 0),\n );\n\n return filteredAndSorted;\n }, [props.cards]);\n\n return (\n <Page themeId=\"home\">\n <Header title
|
|
1
|
+
{"version":3,"file":"HomePage.esm.js","sources":["../../src/components/HomePage.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\n\nimport { Content, EmptyState, Page } from '@backstage/core-components';\n\nimport { HomePageCardMountPoint } from '../types';\nimport { useTranslation } from '../hooks/useTranslation';\n\nimport { Header, HeaderProps } from './Header';\nimport { ReadOnlyGrid } from './ReadOnlyGrid';\n\nexport interface HomePageProps extends HeaderProps {\n cards?: HomePageCardMountPoint[];\n}\n\nexport const HomePage = (props: HomePageProps) => {\n const { t } = useTranslation();\n const filteredAndSortedHomePageCards = useMemo(() => {\n if (!props.cards) {\n return [];\n }\n\n const filteredAndSorted = props.cards.filter(\n card =>\n card.enabled !== false &&\n (!card.config?.priority || card.config.priority >= 0),\n );\n\n filteredAndSorted.sort(\n (a, b) => (b.config?.priority ?? 0) - (a.config?.priority ?? 0),\n );\n\n return filteredAndSorted;\n }, [props.cards]);\n\n return (\n <Page themeId=\"home\">\n <Header title={t('header.welcome')} {...props} />\n <Content>\n {filteredAndSortedHomePageCards.length === 0 ? (\n <EmptyState title={t('homePage.empty')} missing=\"content\" />\n ) : (\n <ReadOnlyGrid mountPoints={filteredAndSortedHomePageCards} />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;;AA8Ba,MAAA,QAAA,GAAW,CAAC,KAAyB,KAAA;AAChD,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAC7B,EAAM,MAAA,8BAAA,GAAiC,QAAQ,MAAM;AACnD,IAAI,IAAA,CAAC,MAAM,KAAO,EAAA;AAChB,MAAA,OAAO,EAAC;AAAA;AAGV,IAAM,MAAA,iBAAA,GAAoB,MAAM,KAAM,CAAA,MAAA;AAAA,MACpC,CAAA,IAAA,KACE,IAAK,CAAA,OAAA,KAAY,KAChB,KAAA,CAAC,KAAK,MAAQ,EAAA,QAAA,IAAY,IAAK,CAAA,MAAA,CAAO,QAAY,IAAA,CAAA;AAAA,KACvD;AAEA,IAAkB,iBAAA,CAAA,IAAA;AAAA,MAChB,CAAC,GAAG,CAAO,KAAA,CAAA,CAAA,CAAE,QAAQ,QAAY,IAAA,CAAA,KAAM,CAAE,CAAA,MAAA,EAAQ,QAAY,IAAA,CAAA;AAAA,KAC/D;AAEA,IAAO,OAAA,iBAAA;AAAA,GACN,EAAA,CAAC,KAAM,CAAA,KAAK,CAAC,CAAA;AAEhB,EACE,uBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAO,KAAO,EAAA,CAAA,CAAE,gBAAgB,CAAA,EAAI,GAAG,KAAO,EAAA,CAAA;AAAA,wBAC9C,OACE,EAAA,EAAA,QAAA,EAAA,8BAAA,CAA+B,WAAW,CACzC,mBAAA,GAAA,CAAC,cAAW,KAAO,EAAA,CAAA,CAAE,gBAAgB,CAAA,EAAG,SAAQ,SAAU,EAAA,CAAA,uBAEzD,YAAa,EAAA,EAAA,WAAA,EAAa,gCAAgC,CAE/D,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
|