@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.
Files changed (50) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/app-config.dynamic.yaml +12 -12
  3. package/dist/components/CustomizableGrid.esm.js +48 -6
  4. package/dist/components/CustomizableGrid.esm.js.map +1 -1
  5. package/dist/components/CustomizableHomePage.esm.js +3 -7
  6. package/dist/components/CustomizableHomePage.esm.js.map +1 -1
  7. package/dist/components/EntitySection/EntitySection.esm.js +18 -13
  8. package/dist/components/EntitySection/EntitySection.esm.js.map +1 -1
  9. package/dist/components/FeaturedDocsCard.esm.js +9 -1
  10. package/dist/components/FeaturedDocsCard.esm.js.map +1 -1
  11. package/dist/components/Header.esm.js +24 -12
  12. package/dist/components/Header.esm.js.map +1 -1
  13. package/dist/components/HomePage.esm.js +4 -8
  14. package/dist/components/HomePage.esm.js.map +1 -1
  15. package/dist/components/OnboardingSection/OnboardingSection.esm.js +5 -3
  16. package/dist/components/OnboardingSection/OnboardingSection.esm.js.map +1 -1
  17. package/dist/components/QuickAccessCard.esm.js +5 -3
  18. package/dist/components/QuickAccessCard.esm.js.map +1 -1
  19. package/dist/components/SearchBar.esm.js +3 -1
  20. package/dist/components/SearchBar.esm.js.map +1 -1
  21. package/dist/components/TemplateSection/TemplateSection.esm.js +16 -12
  22. package/dist/components/TemplateSection/TemplateSection.esm.js.map +1 -1
  23. package/dist/components/Trans.esm.js +9 -0
  24. package/dist/components/Trans.esm.js.map +1 -0
  25. package/dist/defaults.esm.js +29 -0
  26. package/dist/defaults.esm.js.map +1 -0
  27. package/dist/hooks/useGreeting.esm.js +12 -8
  28. package/dist/hooks/useGreeting.esm.js.map +1 -1
  29. package/dist/hooks/useLanguage.esm.js +7 -0
  30. package/dist/hooks/useLanguage.esm.js.map +1 -0
  31. package/dist/hooks/useTranslation.esm.js +8 -0
  32. package/dist/hooks/useTranslation.esm.js.map +1 -0
  33. package/dist/index.d.ts +142 -1
  34. package/dist/index.esm.js +3 -0
  35. package/dist/index.esm.js.map +1 -1
  36. package/dist/translations/de.esm.js +52 -0
  37. package/dist/translations/de.esm.js.map +1 -0
  38. package/dist/translations/es.esm.js +52 -0
  39. package/dist/translations/es.esm.js.map +1 -0
  40. package/dist/translations/fr.esm.js +52 -0
  41. package/dist/translations/fr.esm.js.map +1 -0
  42. package/dist/translations/index.esm.js +15 -0
  43. package/dist/translations/index.esm.js.map +1 -0
  44. package/dist/translations/it.esm.js +52 -0
  45. package/dist/translations/it.esm.js.map +1 -0
  46. package/dist/translations/ref.esm.js +76 -0
  47. package/dist/translations/ref.esm.js.map +1 -0
  48. package/dist/utils/constants.esm.js +14 -14
  49. package/dist/utils/constants.esm.js.map +1 -1
  50. 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
@@ -10,22 +10,22 @@ dynamicPlugins:
10
10
  importName: OnboardingSection
11
11
  config:
12
12
  layouts:
13
- xl: { w: 12, h: 5 }
14
- lg: { w: 12, h: 5 }
15
- md: { w: 12, h: 5 }
16
- sm: { w: 12, h: 5 }
17
- xs: { w: 12, h: 7 }
18
- xxs: { w: 12, h: 13 }
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: 6 }
24
- lg: { w: 12, h: 6 }
25
- md: { w: 12, h: 6 }
26
- sm: { w: 12, h: 6 }
27
- xs: { w: 12, h: 10 }
28
- xxs: { w: 12, h: 14.5 }
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: false,
37
- isResizable: false
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: false,
49
- isResizable: false
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
- return /* @__PURE__ */ jsx(CustomHomepageGrid, { children });
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: false,\n isResizable: false,\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: false,\n isResizable: false,\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 return <CustomHomepageGrid>{children}</CustomHomepageGrid>;\n};\n"],"names":[],"mappings":"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"}
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\n title=\"No home page cards (mount points) configured or found.\"\n missing=\"content\"\n />\n ) : (\n <CustomizableGrid mountPoints={filteredAndSortedHomePageCards} />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;AA6Ba,MAAA,oBAAA,GAAuB,CAAC,KAAyB,KAAA;AAC5D,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,oBAClB,GAAA,CAAA,OAAA,EAAA,EACE,QAA+B,EAAA,8BAAA,CAAA,MAAA,KAAW,CACzC,mBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAM,EAAA,wDAAA;AAAA,QACN,OAAQ,EAAA;AAAA;AAAA,KAGV,mBAAA,GAAA,CAAC,gBAAiB,EAAA,EAAA,WAAA,EAAa,gCAAgC,CAEnE,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
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: "Could not fetch data.", children: /* @__PURE__ */ jsx(
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() ?? "Unknown error"
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: "Browse the Systems, Components, Resources, and APIs that are available in your organization." }) }),
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: "No software catalog added yet" }),
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: "Once software catalogs are added, this space will showcase relevant content tailored to your experience."
191
+ children: t("entities.emptyDescription")
189
192
  }
190
193
  ),
191
- /* @__PURE__ */ jsx(StyledLink, { to: "/catalog-import", underline: "none", children: "Register a component" })
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: "Explore Your Software Catalog"
220
+ children: t("entities.title")
218
221
  }
219
222
  ),
220
223
  content,
221
- entities?.length > 0 && /* @__PURE__ */ jsx(Box, { sx: { pt: 2 }, children: /* @__PURE__ */ jsxs(ViewMoreLink, { to: "/catalog", children: [
222
- "View all ",
223
- data?.totalItems ? data?.totalItems : "",
224
- " catalog entities"
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":";;;;;;;;;;;;;;;;;;;;;AA+CA,MAAM,aAAa,MAAO,CAAAA,IAAa,EAAE,CAAC,EAAE,OAAa,MAAA;AAAA,EACvD,cAAgB,EAAA,MAAA;AAAA,EAChB,OAAS,EAAA,KAAA,CAAM,OAAQ,CAAA,CAAA,EAAG,GAAG,CAAA;AAAA,EAC7B,QAAU,EAAA,MAAA;AAAA,EACV,OAAS,EAAA,aAAA;AAAA,EACT,MAAQ,EAAA,CAAA,UAAA,EAAa,KAAM,CAAA,OAAA,CAAQ,QAAQ,IAAI,CAAA,CAAA;AAAA,EAC/C,YAAc,EAAA;AAChB,CAAE,CAAA,CAAA;AAEK,MAAM,gBAAgB,MAAM;AACjC,EAAA,MAAM,QAAQ,QAAS,EAAA;AACvB,EAAA,MAAM,EAAE,WAAA,EAAa,OAAS,EAAA,cAAA,KAAmB,cAAe,EAAA;AAChE,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,KAAK,CAAA;AAChE,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAAS,IAAI,CAAA;AAC/D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,kBAAA,EAAoB,qBAAqB,CAAA,GAAI,SAAS,KAAK,CAAA;AAElE,EAAA,MAAM,OAAO,aAAc,CAAA,KAAA,CAAM,WAAY,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAEvD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,IAAM,EAAA;AACR,MAAA,qBAAA,CAAsB,IAAI,CAAA;AAAA,KACrB,MAAA;AACL,MAAA,qBAAA,CAAsB,KAAK,CAAA;AAAA;AAC7B,GACF,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,iCAAA,GACJ,mCAAmC,WAAW,CAAA;AAChD,IAAA,oBAAA,CAAqB,iCAAiC,CAAA;AAAA,GACxD,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,oBAAA,CAAqB,KAAK,CAAA;AAC1B,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,mCAAA,CAAoC,WAAW,CAAA;AAC/C,MAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,OACxB,GAAG,CAAA;AAAA,GACR;AAEA,EAAA,MAAM,EAAE,IAAA,EAAM,KAAO,EAAA,SAAA,KAAc,WAAY,CAAA;AAAA,IAC7C,IAAM,EAAA,CAAC,WAAa,EAAA,KAAA,EAAO,YAAY,QAAQ;AAAA,GAChD,CAAA;AAED,EAAM,MAAA,QAAA,GAAW,IAAM,EAAA,KAAA,IAAS,EAAC;AAEjC,EAAI,IAAA,OAAA;AAEJ,EAAA,IAAI,SAAW,EAAA;AACb,IACE,OAAA,mBAAA,GAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,EAAI,EAAA;AAAA,UACF,MAAQ,EAAA,MAAA;AAAA,UACR,OAAS,EAAA,MAAA;AAAA,UACT,UAAY,EAAA,QAAA;AAAA,UACZ,cAAgB,EAAA;AAAA,SAClB;AAAA,QAEA,8BAAC,gBAAiB,EAAA,EAAA;AAAA;AAAA,KACpB;AAAA,GAEJ,MAAA,IAAW,CAAC,IAAM,EAAA;AAChB,IAAA,OAAA,mBACG,GAAA,CAAA,YAAA,EAAA,EAAa,QAAS,EAAA,OAAA,EAAQ,OAAM,uBACnC,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,WAAA;AAAA,MAAA;AAAA,QACC,QAAS,EAAA,MAAA;AAAA,QACT,IAAA,EAAM,KAAO,EAAA,QAAA,EAAc,IAAA;AAAA;AAAA,KAE/B,EAAA,CAAA;AAAA,GAEG,MAAA;AACL,IAAA,IAAI,eAAkB,GAAA,CAAA;AACtB,IAAA,IAAI,oBAAsC,eAAA,GAAA,CAAA;AAE1C,IAAA,OAAA,uBACG,GAAI,EAAA,EAAA,EAAA,EAAI,EAAE,OAAA,EAAS,iBAClB,EAAA,QAAA,kBAAA,GAAA,CAAC,QACC,EAAA,EAAA,QAAA,kBAAA,IAAA,CAAC,QAAK,SAAS,EAAA,IAAA,EAAC,OAAS,EAAA,CAAA,EAAG,YAAW,SACpC,EAAA,QAAA,EAAA;AAAA,MAAA,CAAC,iBAAqB,IAAA,CAAC,cACtB,oBAAA,GAAA,CAAC,IAAK,EAAA,EAAA,IAAA,EAAI,IAAC,EAAA,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,CAAG,EAAA,EAAA,EAAI,CAC5B,EAAA,QAAA,kBAAA,IAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,SAAW,EAAA,CAAA;AAAA,UACX,EAAI,EAAA;AAAA,YACF,QAAQ,CAAa,UAAA,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,YAC5C,OAAS,EAAA,MAAA;AAAA,YACT,aAAe,EAAA,KAAA;AAAA,YACf,UAAY,EAAA,QAAA;AAAA,YACZ,QAAU,EAAA,UAAA;AAAA,YACV,UACE,EAAA,mDAAA;AAAA,YACF,OAAA,EAAS,oBAAoB,CAAI,GAAA,CAAA;AAAA,YACjC,SAAA,EAAW,oBACP,eACA,GAAA;AAAA,WACN;AAAA,UAEC,QAAA,EAAA;AAAA,YAAA,CAAC,SACA,oBAAA,GAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,OAAQ,EAAA,aAAA;AAAA,gBACR,MAAQ,EAAA,GAAA;AAAA,gBACR,EAAI,EAAA;AAAA,kBACF,YAAc,EAAA,CAAA;AAAA,kBACd,KAAO,EAAA;AAAA;AACT;AAAA,aACF;AAAA,4BAEF,GAAA;AAAA,cAAC,GAAA;AAAA,cAAA;AAAA,gBACC,SAAU,EAAA,KAAA;AAAA,gBACV,GAAK,EAAA,0BAAA;AAAA,gBACL,MAAA,EAAQ,MAAM,YAAA,CAAa,IAAI,CAAA;AAAA,gBAC/B,GAAI,EAAA,EAAA;AAAA,gBACJ,MAAQ,EAAA,GAAA;AAAA,gBACR,EAAI,EAAA;AAAA,kBACF,KAAO,EAAA;AAAA;AACT;AAAA,aACF;AAAA,iCACC,GAAI,EAAA,EAAA,EAAA,EAAI,EAAE,CAAA,EAAG,GACZ,EAAA,QAAA,EAAA;AAAA,8BAAC,GAAA,CAAA,GAAA,EAAA,EACC,8BAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,SAAS,EAAA,IAAA,EAAC,0GAGtC,CACF,EAAA,CAAA;AAAA,cACC,QAAA,EAAU,SAAS,CAClB,oBAAA,GAAA;AAAA,gBAAC,UAAA;AAAA,gBAAA;AAAA,kBACC,OAAS,EAAA,WAAA;AAAA,kBACT,YAAW,EAAA,OAAA;AAAA,kBACX,KAAO,EAAA;AAAA,oBACL,QAAU,EAAA,UAAA;AAAA,oBACV,GAAK,EAAA,KAAA;AAAA,oBACL,KAAO,EAAA;AAAA,mBACT;AAAA,kBAEA,QAAA,kBAAA,GAAA,CAAC,aAAU,KAAO,EAAA,EAAE,OAAO,MAAQ,EAAA,MAAA,EAAQ,QAAU,EAAA;AAAA;AAAA;AACvD,aAEJ,EAAA;AAAA;AAAA;AAAA,WAzDiC,uBA2DrC,CAAA;AAAA,MAED,QAAA,EACG,MAAM,CAAG,EAAA,iBAAA,GAAoB,IAAI,eAAe,CAAA,CACjD,GAAI,CAAA,CAAC,IACJ,qBAAA,GAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,IAAI,EAAA,IAAA;AAAA,UACJ,EAAI,EAAA,EAAA;AAAA,UACJ,EAAI,EAAA,CAAA;AAAA,UACJ,EAAA,EAAI,oBAAoB,CAAI,GAAA,GAAA;AAAA,UAG5B,QAAA,kBAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,MAAQ,EAAA,IAAA;AAAA,cACR,OACE,IAAK,CAAA,IAAA,EAAM,OAAS,EAAA,WAAA,IAAe,KAAK,QAAS,CAAA,IAAA;AAAA,cAEnD,OAAQ,EAAA,QAAA;AAAA,cACR,WAAA,EAAa,IAAK,CAAA,QAAA,CAAS,WAAe,IAAA,EAAA;AAAA,cAC1C,IAAM,EAAA,IAAA,CAAK,QAAU,EAAA,IAAA,IAAQ,EAAC;AAAA,cAC9B,MAAM,IAAK,CAAA;AAAA;AAAA;AACb,SAAA;AAAA,QAXK,KAAK,QAAS,CAAA;AAAA,OAatB,CAAA;AAAA,MACF,QAAA,EAAU,MAAW,KAAA,CAAA,oBACnB,GAAA,CAAA,IAAA,EAAA,EAAK,MAAI,IAAC,EAAA,EAAA,EAAI,iBAAoB,GAAA,EAAA,GAAK,CACtC,EAAA,QAAA,kBAAA,GAAA;AAAA,QAAC,GAAA;AAAA,QAAA;AAAA,UACC,EAAI,EAAA;AAAA,YACF,OAAS,EAAA,MAAA;AAAA,YACT,UAAY,EAAA,QAAA;AAAA,YACZ,cAAgB,EAAA,QAAA;AAAA,YAChB,SAAW,EAAA,GAAA;AAAA,YACX,QAAQ,CACN,QAAA,KAAA,CAAA,UAAA,EAAa,SAAS,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,YACzC,YAAc,EAAA,CAAA;AAAA,YACd,QAAU,EAAA;AAAA,WACZ;AAAA,UAEA,+BAAC,WACC,EAAA,EAAA,QAAA,EAAA;AAAA,4BAAC,GAAA,CAAA,UAAA,EAAA,EAAW,IAAI,EAAE,QAAA,EAAU,YAAY,UAAY,EAAA,GAAA,IAAO,QAE3D,EAAA,+BAAA,EAAA,CAAA;AAAA,4BACA,GAAA;AAAA,cAAC,UAAA;AAAA,cAAA;AAAA,gBACC,EAAI,EAAA;AAAA,kBACF,QAAU,EAAA,UAAA;AAAA,kBACV,UAAY,EAAA,GAAA;AAAA,kBACZ,EAAI,EAAA,MAAA;AAAA,kBACJ,EAAI,EAAA;AAAA,iBACN;AAAA,gBACD,QAAA,EAAA;AAAA;AAAA,aAGD;AAAA,gCACC,UAAW,EAAA,EAAA,EAAA,EAAG,iBAAkB,EAAA,SAAA,EAAU,QAAO,QAElD,EAAA,sBAAA,EAAA;AAAA,WACF,EAAA;AAAA;AAAA,OAEJ,EAAA;AAAA,KAAA,EAEJ,GACF,CACF,EAAA,CAAA;AAAA;AAIJ,EACE,uBAAA,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,SAAW,EAAA,CAAA;AAAA,MACX,EAAI,EAAA;AAAA,QACF,OAAS,EAAA,MAAA;AAAA,QACT,QAAQ,CAAY,QAAA,KAAA,CAAA,UAAA,EAAa,SAAS,OAAQ,CAAA,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,QAC3D,QAAU,EAAA;AAAA,OACZ;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,OAAQ,EAAA,IAAA;AAAA,YACR,EAAI,EAAA;AAAA,cACF,OAAS,EAAA,MAAA;AAAA,cACT,UAAY,EAAA,QAAA;AAAA,cACZ,UAAY,EAAA,KAAA;AAAA,cACZ,QAAU,EAAA;AAAA,aACZ;AAAA,YACD,QAAA,EAAA;AAAA;AAAA,SAED;AAAA,QACC,OAAA;AAAA,QACA,QAAU,EAAA,MAAA,GAAS,CAClB,oBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,EAAE,EAAA,EAAI,CAAE,EAAA,EACf,QAAC,kBAAA,IAAA,CAAA,YAAA,EAAA,EAAa,IAAG,UAAW,EAAA,QAAA,EAAA;AAAA,UAAA,WAAA;AAAA,UAChB,IAAA,EAAM,UAAa,GAAA,IAAA,EAAM,UAAa,GAAA,EAAA;AAAA,UAAG;AAAA,SAAA,EACrD,CACF,EAAA;AAAA;AAAA;AAAA,GAEJ;AAEJ;;;;"}
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
- return /* @__PURE__ */ jsx(FeaturedDocsCard$1, { subLinkText: " Learn more", ...props });
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 subLinkText=\" Learn more\" {...props} />;\n};\n"],"names":["PluginHomeFeaturedDocsCard"],"mappings":";;;AA4Ba,MAAA,gBAAA,GAAmB,CAAC,KAAiC,KAAA;AAChE,EAAA,uBAAQ,GAAA,CAAAA,kBAAA,EAAA,EAA2B,WAAY,EAAA,aAAA,EAAe,GAAG,KAAO,EAAA,CAAA;AAC1E;;;;"}
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 getPersonalizedTitle = (title, displayName) => {
10
- const firstName = displayName?.split(" ")[0];
11
- const replacedTitle = title.replace("{{firstName}}", firstName ?? "").replace("{{displayName}}", displayName ?? "");
12
- return replacedTitle;
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 getPersonalizedTitle(props.personalizedTitle, profile.displayName);
20
- } else if (props.title) {
21
- return getPersonalizedTitle(props.title, profile?.displayName);
24
+ return interpolateUserTitle(props.personalizedTitle, profile.displayName);
22
25
  }
23
- return getPersonalizedTitle("Welcome back!", profile?.displayName);
24
- }, [profile?.displayName, props.personalizedTitle, props.title]);
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
- return props.subtitle ? getPersonalizedTitle(props.subtitle, profile?.displayName) : undefined;
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 ? "Local" : undefined),
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, getPersonalizedTitle };
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\nexport const getPersonalizedTitle = (\n title: string,\n displayName: string | undefined,\n) => {\n const firstName = displayName?.split(' ')[0];\n const replacedTitle = title\n .replace('{{firstName}}', firstName ?? '')\n .replace('{{displayName}}', displayName ?? '');\n return replacedTitle;\n};\n\nexport const Header = (props: HeaderProps) => {\n const identityApi = useApi(identityApiRef);\n const { value: profile } = useAsync(() => identityApi.getProfileInfo());\n\n const title = useMemo<string>(() => {\n if (profile?.displayName && props.personalizedTitle) {\n return getPersonalizedTitle(props.personalizedTitle, profile.displayName);\n } else if (props.title) {\n return getPersonalizedTitle(props.title, profile?.displayName);\n }\n // return getPersonalizedTitle(getTimeBasedTitle(), profile?.displayName);\n return getPersonalizedTitle('Welcome back!', profile?.displayName);\n }, [profile?.displayName, props.personalizedTitle, props.title]);\n\n const subtitle = useMemo<string | undefined>(() => {\n return props.subtitle\n ? getPersonalizedTitle(props.subtitle, profile?.displayName)\n : 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 ? '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":";;;;;;;;AA8Ca,MAAA,oBAAA,GAAuB,CAClC,KAAA,EACA,WACG,KAAA;AACH,EAAA,MAAM,SAAY,GAAA,WAAA,EAAa,KAAM,CAAA,GAAG,EAAE,CAAC,CAAA;AAC3C,EAAM,MAAA,aAAA,GAAgB,KACnB,CAAA,OAAA,CAAQ,eAAiB,EAAA,SAAA,IAAa,EAAE,CACxC,CAAA,OAAA,CAAQ,iBAAmB,EAAA,WAAA,IAAe,EAAE,CAAA;AAC/C,EAAO,OAAA,aAAA;AACT;AAEa,MAAA,MAAA,GAAS,CAAC,KAAuB,KAAA;AAC5C,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAM,MAAA,EAAE,OAAO,OAAQ,EAAA,GAAI,SAAS,MAAM,WAAA,CAAY,gBAAgB,CAAA;AAEtE,EAAM,MAAA,KAAA,GAAQ,QAAgB,MAAM;AAClC,IAAI,IAAA,OAAA,EAAS,WAAe,IAAA,KAAA,CAAM,iBAAmB,EAAA;AACnD,MAAA,OAAO,oBAAqB,CAAA,KAAA,CAAM,iBAAmB,EAAA,OAAA,CAAQ,WAAW,CAAA;AAAA,KAC1E,MAAA,IAAW,MAAM,KAAO,EAAA;AACtB,MAAA,OAAO,oBAAqB,CAAA,KAAA,CAAM,KAAO,EAAA,OAAA,EAAS,WAAW,CAAA;AAAA;AAG/D,IAAO,OAAA,oBAAA,CAAqB,eAAiB,EAAA,OAAA,EAAS,WAAW,CAAA;AAAA,GACnE,EAAG,CAAC,OAAS,EAAA,WAAA,EAAa,MAAM,iBAAmB,EAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAE/D,EAAM,MAAA,QAAA,GAAW,QAA4B,MAAM;AACjD,IAAA,OAAO,MAAM,QACT,GAAA,oBAAA,CAAqB,MAAM,QAAU,EAAA,OAAA,EAAS,WAAW,CACzD,GAAA,SAAA;AAAA,KACH,CAAC,KAAA,CAAM,QAAU,EAAA,OAAA,EAAS,WAAW,CAAC,CAAA;AAEzC,EACE,uBAAA,IAAA;AAAA,IAACA,QAAA;AAAA,IAAA;AAAA,MACC,KAAA;AAAA,MACA,QAAA;AAAA,MACA,mBAAmB,KAAM,CAAA,SAAA;AAAA,MAExB,QAAA,EAAA;AAAA,QAAA,KAAA,CAAM,UAAY,EAAA,MAAA,IAAU,KAAM,CAAA,UAAA,EAAY,WAAW,MACxD,mBAAA,GAAA;AAAA,UAAC,UAAA;AAAA,UAAA;AAAA,YACC,KAAA,EACE,KAAM,CAAA,UAAA,EAAY,KACjB,KAAA,KAAA,CAAM,eAAe,KAAM,CAAA,WAAA,CAAY,MAAS,GAAA,CAAA,GAC7C,OACA,GAAA,SAAA,CAAA;AAAA,YAEN,MAAA,EACE,KAAM,CAAA,UAAA,EAAY,MACjB,KAAA,KAAA,CAAM,eAAe,KAAM,CAAA,WAAA,CAAY,MAAS,GAAA,CAAA,GAC7C,MACA,GAAA,SAAA,CAAA;AAAA,YAEN,IAAA,EAAM,MAAM,UAAY,EAAA;AAAA;AAAA,SAExB,GAAA,IAAA;AAAA,QAEH,KAAA,CAAM,WAAe,IAAA,KAAA,CAAM,WAAY,CAAA,MAAA,GAAS,CAC/C,mBAAA,GAAA,CAAC,gBAAiB,EAAA,EAAA,YAAA,EAAc,KAAM,CAAA,WAAA,EAAa,CACjD,GAAA;AAAA;AAAA;AAAA,GACN;AAEJ;;;;"}
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: "Welcome back!", ...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(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=\"Welcome back!\" {...props} />\n <Content>\n {filteredAndSortedHomePageCards.length === 0 ? (\n <EmptyState\n title=\"No home page cards (mount points) configured or found.\"\n missing=\"content\"\n />\n ) : (\n <ReadOnlyGrid mountPoints={filteredAndSortedHomePageCards} />\n )}\n </Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;AA6Ba,MAAA,QAAA,GAAW,CAAC,KAAyB,KAAA;AAChD,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,MAAO,EAAA,EAAA,KAAA,EAAM,eAAiB,EAAA,GAAG,KAAO,EAAA,CAAA;AAAA,oBACxC,GAAA,CAAA,OAAA,EAAA,EACE,QAA+B,EAAA,8BAAA,CAAA,MAAA,KAAW,CACzC,mBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAM,EAAA,wDAAA;AAAA,QACN,OAAQ,EAAA;AAAA;AAAA,KAGV,mBAAA,GAAA,CAAC,YAAa,EAAA,EAAA,WAAA,EAAa,gCAAgC,CAE/D,EAAA;AAAA,GACF,EAAA,CAAA;AAEJ;;;;"}
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;;;;"}