@red-hat-developer-hub/backstage-plugin-dynamic-home-page 1.10.6 → 1.12.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 +25 -0
- package/README.md +93 -1
- package/dist/alpha/components/CustomizableGridLayout.esm.js +70 -0
- package/dist/alpha/components/CustomizableGridLayout.esm.js.map +1 -0
- package/dist/alpha/components/HomePageLayout.esm.js +25 -0
- package/dist/alpha/components/HomePageLayout.esm.js.map +1 -0
- package/dist/alpha/components/ReadOnlyGirdLayout.esm.js +137 -0
- package/dist/alpha/components/ReadOnlyGirdLayout.esm.js.map +1 -0
- package/dist/alpha/extensions/apis.esm.js +19 -0
- package/dist/alpha/extensions/apis.esm.js.map +1 -0
- package/dist/alpha/extensions/homePageCards.esm.js +117 -0
- package/dist/alpha/extensions/homePageCards.esm.js.map +1 -0
- package/dist/alpha/extensions/homePageLayoutExtension.esm.js +57 -0
- package/dist/alpha/extensions/homePageLayoutExtension.esm.js.map +1 -0
- package/dist/alpha/utils.esm.js +6 -0
- package/dist/alpha/utils.esm.js.map +1 -0
- package/dist/alpha.d.ts +77 -0
- package/dist/alpha.esm.js +39 -0
- package/dist/alpha.esm.js.map +1 -0
- package/dist/components/CustomizableGrid.esm.js +17 -7
- package/dist/components/CustomizableGrid.esm.js.map +1 -1
- package/dist/components/EntitySection/EntityCard.esm.js +6 -1
- package/dist/components/EntitySection/EntityCard.esm.js.map +1 -1
- package/dist/components/EntitySection/EntitySection.esm.js +143 -100
- package/dist/components/EntitySection/EntitySection.esm.js.map +1 -1
- package/dist/components/OnboardingSection/OnboardingCard.esm.js +3 -0
- package/dist/components/OnboardingSection/OnboardingCard.esm.js.map +1 -1
- package/dist/components/OnboardingSection/OnboardingSection.esm.js +33 -17
- package/dist/components/OnboardingSection/OnboardingSection.esm.js.map +1 -1
- package/dist/components/TemplateSection/TemplateSection.esm.js +87 -47
- package/dist/components/TemplateSection/TemplateSection.esm.js.map +1 -1
- package/dist/hooks/useContainerQuery.esm.js +78 -0
- package/dist/hooks/useContainerQuery.esm.js.map +1 -0
- package/dist/index.d.ts +11 -67
- package/dist/index.esm.js +0 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/translations/de.esm.js +1 -1
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +1 -1
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +1 -1
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/index.esm.js.map +1 -1
- package/dist/translations/it.esm.js +1 -1
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +1 -1
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +1 -1
- package/dist/translations/ref.esm.js.map +1 -1
- package/dist/utils/GridItem.esm.js +31 -0
- package/dist/utils/GridItem.esm.js.map +1 -0
- package/package.json +48 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @red-hat-developer-hub/backstage-plugin-dynamic-home-page
|
|
2
2
|
|
|
3
|
+
## 1.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e8780ce: Backstage version bump to v1.49.3
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 7ea283a: fixes the responsiveness issue of the customizable home-page
|
|
12
|
+
- 4e40bf1: Fix misleading entity count in EntitySection card link
|
|
13
|
+
|
|
14
|
+
## 1.11.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- abc7289: Migrate dynamic homepage to NFS
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- cf8ee79: Enhance home page layout adaptability when QuickStart is displayed.
|
|
23
|
+
|
|
24
|
+
Updated the homepage layout logic to utilize container width monitoring rather than relying on viewport-based Grid breakpoints. This change ensures the illustration card seamlessly switches to a vertical stack when the QuickStart drawer is open, independent of the user's screen resolution.
|
|
25
|
+
|
|
26
|
+
Additionally, introduced scrollbars to the onboarding, software catalog, and template sections for improved navigation and usability.
|
|
27
|
+
|
|
3
28
|
## 1.10.6
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -2,4 +2,96 @@
|
|
|
2
2
|
|
|
3
3
|
This is a dynamic version of the upstream [home page plugin](https://github.com/backstage/backstage/tree/master/plugins/home).
|
|
4
4
|
|
|
5
|
-
Instead of manually adding supported "home page cards" to a custom route, it allows dynamic plugins to expose such cards.
|
|
5
|
+
Instead of manually adding supported "home page cards" to a custom route, it allows dynamic plugins to expose such cards. The plugin supports both the **New Frontend System (NFS)** and the **legacy** dynamic plugin model (Scalprum).
|
|
6
|
+
|
|
7
|
+
## New Frontend System
|
|
8
|
+
|
|
9
|
+
If you're using Backstage's new frontend system, add the plugin to your app:
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
// packages/app/src/App.tsx
|
|
13
|
+
import { createApp } from '@backstage/frontend-defaults';
|
|
14
|
+
import {
|
|
15
|
+
homePageDevModule,
|
|
16
|
+
homepageTranslationsModule,
|
|
17
|
+
} from '@red-hat-developer-hub/backstage-plugin-dynamic-home-page/alpha';
|
|
18
|
+
|
|
19
|
+
export default createApp({
|
|
20
|
+
features: [
|
|
21
|
+
// ... other plugins (nav, signIn, etc.)
|
|
22
|
+
homePageDevModule,
|
|
23
|
+
homepageTranslationsModule,
|
|
24
|
+
],
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The plugin will automatically provide:
|
|
29
|
+
|
|
30
|
+
- A homepage at `/home` (or the path configured via `page:home`)
|
|
31
|
+
- Default widgets: Onboarding, Entity Catalog, Templates, Quick Access, Search, Recently Visited, Top Visited, and more
|
|
32
|
+
- Customizable or read-only layout based on configuration, default layout being customizable
|
|
33
|
+
|
|
34
|
+
### Configuration
|
|
35
|
+
|
|
36
|
+
Add the following to your `app-config.yaml`:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
app:
|
|
40
|
+
extensions:
|
|
41
|
+
# Register the home page route (default: /)
|
|
42
|
+
- page:home:
|
|
43
|
+
config:
|
|
44
|
+
path: /
|
|
45
|
+
# Enable visit tracking (optional)
|
|
46
|
+
- api:home/visits: true
|
|
47
|
+
- app-root-element:home/visit-listener: true
|
|
48
|
+
# Configure the dynamic homepage layout
|
|
49
|
+
- home-page-layout:home/dynamic-homepage-layout:
|
|
50
|
+
config:
|
|
51
|
+
customizable: true # or false for read-only layout
|
|
52
|
+
widgetLayout:
|
|
53
|
+
RhdhTemplateSection:
|
|
54
|
+
priority: 300 # priority is considered for only Read-only Grid layout
|
|
55
|
+
breakpoints:
|
|
56
|
+
xl: { w: 12, h: 5 }
|
|
57
|
+
lg: { w: 12, h: 5 }
|
|
58
|
+
# ... md, sm, xs, xxs
|
|
59
|
+
RhdhEntitySection:
|
|
60
|
+
priority: 200
|
|
61
|
+
breakpoints:
|
|
62
|
+
xl: { w: 12, h: 7 }
|
|
63
|
+
# ...
|
|
64
|
+
RhdhOnboardingSection:
|
|
65
|
+
priority: 100
|
|
66
|
+
breakpoints:
|
|
67
|
+
xl: { w: 12, h: 6 }
|
|
68
|
+
# ...
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Modules
|
|
72
|
+
|
|
73
|
+
The following modules are available from the alpha export:
|
|
74
|
+
|
|
75
|
+
| Module | Description |
|
|
76
|
+
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| `homePageDevModule` | Home page layout and widgets (Onboarding, Entity, Templates, Quick Access, Search, Recently Visited, Top Visited, etc.) |
|
|
78
|
+
| `homepageTranslationsModule` | i18n translations (en, de, es, fr, it, ja) |
|
|
79
|
+
|
|
80
|
+
### Extensions
|
|
81
|
+
|
|
82
|
+
The `homePageDevModule` extends the `home` plugin (`@backstage/plugin-home`) with:
|
|
83
|
+
|
|
84
|
+
- `home-page-layout:home/dynamic-homepage-layout` – Custom layout with config-driven widget arrangement and priority
|
|
85
|
+
- `home-page-widget:home/rhdh-onboarding-section` – Onboarding section
|
|
86
|
+
- `home-page-widget:home/rhdh-entity-section` – Software catalog section
|
|
87
|
+
- `home-page-widget:home/rhdh-template-section` – Templates section
|
|
88
|
+
- `home-page-widget:home/quick-access-card` – Quick access card
|
|
89
|
+
- `home-page-widget:home/search-bar` – Search bar
|
|
90
|
+
- `home-page-widget:home/featured-docs-card` – Featured docs
|
|
91
|
+
- `home-page-widget:home/recently-visited` – Recently visited
|
|
92
|
+
- `home-page-widget:home/top-visited` – Top visited
|
|
93
|
+
- `api:home/quickaccess` – Quick access API
|
|
94
|
+
|
|
95
|
+
## Legacy System (Dynamic Plugins)
|
|
96
|
+
|
|
97
|
+
For the legacy Scalprum-based dynamic plugin model, use the main export and configure via `app-config.dynamic.yaml`. See `app-config.dynamic.yaml` in this package for the mount point configuration.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useMemo, Fragment as Fragment$1 } from 'react';
|
|
3
|
+
import { CustomHomepageGrid } from '@backstage/plugin-home';
|
|
4
|
+
import { useTheme } from '@mui/material/styles';
|
|
5
|
+
import GlobalStyles from '@mui/material/GlobalStyles';
|
|
6
|
+
import { useContainerQuery } from '../../hooks/useContainerQuery.esm.js';
|
|
7
|
+
import 'react-grid-layout/css/styles.css';
|
|
8
|
+
import { isCardADefaultConfiguration } from '../utils.esm.js';
|
|
9
|
+
|
|
10
|
+
const CustomizableGridLayout = ({
|
|
11
|
+
homepageCards
|
|
12
|
+
}) => {
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
const gridContainerRef = useRef(null);
|
|
15
|
+
useContainerQuery(gridContainerRef, { notifyWindowResize: true });
|
|
16
|
+
const config = useMemo(() => {
|
|
17
|
+
const defaultConfig = [];
|
|
18
|
+
homepageCards.forEach((homepageCard) => {
|
|
19
|
+
if (!homepageCard.node) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (isCardADefaultConfiguration(homepageCard)) {
|
|
23
|
+
const layout = homepageCard.breakpointLayouts?.xl || {};
|
|
24
|
+
defaultConfig.push({
|
|
25
|
+
component: homepageCard.component,
|
|
26
|
+
x: layout.x ?? 0,
|
|
27
|
+
y: layout.y ?? 0,
|
|
28
|
+
width: layout.w ?? 12,
|
|
29
|
+
height: layout.h ?? 4,
|
|
30
|
+
movable: true,
|
|
31
|
+
deletable: true,
|
|
32
|
+
resizable: true
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return defaultConfig;
|
|
37
|
+
}, [homepageCards]);
|
|
38
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
GlobalStyles,
|
|
41
|
+
{
|
|
42
|
+
styles: {
|
|
43
|
+
'[class*="makeStyles-settingsOverlay"]': {
|
|
44
|
+
backgroundColor: theme.palette.mode === "dark" ? "rgba(20, 20, 20, 0.95) !important" : "rgba(40, 40, 40, 0.93) !important"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
),
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
"div",
|
|
51
|
+
{
|
|
52
|
+
ref: gridContainerRef,
|
|
53
|
+
style: { width: "100%", minWidth: 0, boxSizing: "border-box" },
|
|
54
|
+
children: /* @__PURE__ */ jsx(
|
|
55
|
+
CustomHomepageGrid,
|
|
56
|
+
{
|
|
57
|
+
config,
|
|
58
|
+
preventCollision: false,
|
|
59
|
+
compactType: "vertical",
|
|
60
|
+
style: { margin: "-10px" },
|
|
61
|
+
children: homepageCards.map((card, index) => /* @__PURE__ */ jsx(Fragment$1, { children: card.component }, card.name ?? index))
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
] });
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export { CustomizableGridLayout };
|
|
70
|
+
//# sourceMappingURL=CustomizableGridLayout.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CustomizableGridLayout.esm.js","sources":["../../../src/alpha/components/CustomizableGridLayout.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 { Fragment, useMemo, useRef } from 'react';\n\nimport {\n CustomHomepageGrid,\n LayoutConfiguration,\n} from '@backstage/plugin-home';\nimport { useTheme } from '@mui/material/styles';\nimport GlobalStyles from '@mui/material/GlobalStyles';\nimport { HomePageCardConfig } from '../../types';\nimport { useContainerQuery } from '../../hooks/useContainerQuery';\n\nimport 'react-grid-layout/css/styles.css';\nimport { isCardADefaultConfiguration } from '../utils';\n\n/**\n * Props for the customizable grid layout.\n * @alpha\n */\nexport interface CustomizableGridLayoutProps {\n homepageCards: HomePageCardConfig[];\n}\n\n/**\n * Customizable grid layout for the NFS home page (drag, drop, resize).\n *\n * @alpha\n */\nexport const CustomizableGridLayout = ({\n homepageCards,\n}: CustomizableGridLayoutProps) => {\n const theme = useTheme();\n const gridContainerRef = useRef<HTMLDivElement>(null);\n useContainerQuery(gridContainerRef, { notifyWindowResize: true });\n\n const config = useMemo(() => {\n const defaultConfig: LayoutConfiguration[] = [];\n\n homepageCards.forEach(homepageCard => {\n if (!homepageCard.node) {\n return;\n }\n\n if (isCardADefaultConfiguration(homepageCard)) {\n const layout = homepageCard.breakpointLayouts?.xl || {};\n\n defaultConfig.push({\n component: homepageCard.component,\n x: layout.x ?? 0,\n y: layout.y ?? 0,\n width: layout.w ?? 12,\n height: layout.h ?? 4,\n movable: true,\n deletable: true,\n resizable: true,\n });\n }\n });\n\n return defaultConfig;\n }, [homepageCards]);\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 <div\n ref={gridContainerRef}\n style={{ width: '100%', minWidth: 0, boxSizing: 'border-box' }}\n >\n <CustomHomepageGrid\n config={config}\n preventCollision={false}\n compactType=\"vertical\"\n style={{ margin: '-10px' }}\n >\n {homepageCards.map((card, index) => (\n <Fragment key={card.name ?? index}>{card.component}</Fragment>\n ))}\n </CustomHomepageGrid>\n </div>\n </>\n );\n};\n"],"names":["Fragment"],"mappings":";;;;;;;;;AAiDO,MAAM,yBAAyB,CAAC;AAAA,EACrC;AACF,CAAmC,KAAA;AACjC,EAAA,MAAM,QAAQ,QAAS,EAAA;AACvB,EAAM,MAAA,gBAAA,GAAmB,OAAuB,IAAI,CAAA;AACpD,EAAA,iBAAA,CAAkB,gBAAkB,EAAA,EAAE,kBAAoB,EAAA,IAAA,EAAM,CAAA;AAEhE,EAAM,MAAA,MAAA,GAAS,QAAQ,MAAM;AAC3B,IAAA,MAAM,gBAAuC,EAAC;AAE9C,IAAA,aAAA,CAAc,QAAQ,CAAgB,YAAA,KAAA;AACpC,MAAI,IAAA,CAAC,aAAa,IAAM,EAAA;AACtB,QAAA;AAAA;AAGF,MAAI,IAAA,2BAAA,CAA4B,YAAY,CAAG,EAAA;AAC7C,QAAA,MAAM,MAAS,GAAA,YAAA,CAAa,iBAAmB,EAAA,EAAA,IAAM,EAAC;AAEtD,QAAA,aAAA,CAAc,IAAK,CAAA;AAAA,UACjB,WAAW,YAAa,CAAA,SAAA;AAAA,UACxB,CAAA,EAAG,OAAO,CAAK,IAAA,CAAA;AAAA,UACf,CAAA,EAAG,OAAO,CAAK,IAAA,CAAA;AAAA,UACf,KAAA,EAAO,OAAO,CAAK,IAAA,EAAA;AAAA,UACnB,MAAA,EAAQ,OAAO,CAAK,IAAA,CAAA;AAAA,UACpB,OAAS,EAAA,IAAA;AAAA,UACT,SAAW,EAAA,IAAA;AAAA,UACX,SAAW,EAAA;AAAA,SACZ,CAAA;AAAA;AACH,KACD,CAAA;AAED,IAAO,OAAA,aAAA;AAAA,GACT,EAAG,CAAC,aAAa,CAAC,CAAA;AAElB,EAAA,uBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,MAAQ,EAAA;AAAA,UACN,uCAAyC,EAAA;AAAA,YACvC,eACE,EAAA,KAAA,CAAM,OAAQ,CAAA,IAAA,KAAS,SACnB,mCACA,GAAA;AAAA;AACR;AACF;AAAA,KACF;AAAA,oBACA,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,gBAAA;AAAA,QACL,OAAO,EAAE,KAAA,EAAO,QAAQ,QAAU,EAAA,CAAA,EAAG,WAAW,YAAa,EAAA;AAAA,QAE7D,QAAA,kBAAA,GAAA;AAAA,UAAC,kBAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,gBAAkB,EAAA,KAAA;AAAA,YAClB,WAAY,EAAA,UAAA;AAAA,YACZ,KAAA,EAAO,EAAE,MAAA,EAAQ,OAAQ,EAAA;AAAA,YAExB,QAAc,EAAA,aAAA,CAAA,GAAA,CAAI,CAAC,IAAA,EAAM,KACxB,qBAAA,GAAA,CAACA,UAAA,EAAA,EAAmC,QAAK,EAAA,IAAA,CAAA,SAAA,EAAA,EAA1B,IAAK,CAAA,IAAA,IAAQ,KAAuB,CACpD;AAAA;AAAA;AACH;AAAA;AACF,GACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { EmptyState, Page, Content } from '@backstage/core-components';
|
|
3
|
+
import { useTranslation } from '../../hooks/useTranslation.esm.js';
|
|
4
|
+
import { Header } from '../../components/Header.esm.js';
|
|
5
|
+
import { ReadOnlyGridLayout } from './ReadOnlyGirdLayout.esm.js';
|
|
6
|
+
import { CustomizableGridLayout } from './CustomizableGridLayout.esm.js';
|
|
7
|
+
|
|
8
|
+
const HomePageLayout = ({ widgets, customizable }) => {
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
let content;
|
|
11
|
+
if (widgets.length === 0) {
|
|
12
|
+
content = /* @__PURE__ */ jsx(EmptyState, { title: t("homePage.empty"), missing: "content" });
|
|
13
|
+
} else if (customizable) {
|
|
14
|
+
content = /* @__PURE__ */ jsx(CustomizableGridLayout, { homepageCards: widgets });
|
|
15
|
+
} else {
|
|
16
|
+
content = /* @__PURE__ */ jsx(ReadOnlyGridLayout, { homepageCards: widgets });
|
|
17
|
+
}
|
|
18
|
+
return /* @__PURE__ */ jsxs(Page, { themeId: "home", children: [
|
|
19
|
+
/* @__PURE__ */ jsx(Header, { title: t("header.welcome") }),
|
|
20
|
+
/* @__PURE__ */ jsx(Content, { children: content })
|
|
21
|
+
] });
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { HomePageLayout };
|
|
25
|
+
//# sourceMappingURL=HomePageLayout.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HomePageLayout.esm.js","sources":["../../../src/alpha/components/HomePageLayout.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 { Content, EmptyState, Page } from '@backstage/core-components';\nimport { useTranslation } from '../../hooks/useTranslation';\nimport { HeaderProps, Header } from '../../components/Header';\nimport { ReadOnlyGridLayout } from './ReadOnlyGirdLayout';\nimport { CustomizableGridLayout } from './CustomizableGridLayout';\nimport { HomePageCardConfig } from '../../types';\n\n/**\n * Props for the NFS home page layout component.\n * @alpha\n */\nexport interface HomePageProps extends HeaderProps {\n widgets: HomePageCardConfig[];\n customizable: boolean;\n}\n\n/**\n * NFS home page layout that renders widgets in a read-only or customizable grid.\n * Used by the dynamic-homepage-layout extension.\n *\n * @alpha\n */\nexport const HomePageLayout = ({ widgets, customizable }: HomePageProps) => {\n const { t } = useTranslation();\n\n let content: React.ReactNode;\n if (widgets.length === 0) {\n content = <EmptyState title={t('homePage.empty')} missing=\"content\" />;\n } else if (customizable) {\n content = <CustomizableGridLayout homepageCards={widgets} />;\n } else {\n content = <ReadOnlyGridLayout homepageCards={widgets} />;\n }\n\n return (\n <Page themeId=\"home\">\n <Header title={t('header.welcome')} />\n <Content>{content}</Content>\n </Page>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsCO,MAAM,cAAiB,GAAA,CAAC,EAAE,OAAA,EAAS,cAAkC,KAAA;AAC1E,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,cAAe,EAAA;AAE7B,EAAI,IAAA,OAAA;AACJ,EAAI,IAAA,OAAA,CAAQ,WAAW,CAAG,EAAA;AACxB,IAAA,OAAA,uBAAW,UAAW,EAAA,EAAA,KAAA,EAAO,EAAE,gBAAgB,CAAA,EAAG,SAAQ,SAAU,EAAA,CAAA;AAAA,aAC3D,YAAc,EAAA;AACvB,IAAU,OAAA,mBAAA,GAAA,CAAC,sBAAuB,EAAA,EAAA,aAAA,EAAe,OAAS,EAAA,CAAA;AAAA,GACrD,MAAA;AACL,IAAU,OAAA,mBAAA,GAAA,CAAC,kBAAmB,EAAA,EAAA,aAAA,EAAe,OAAS,EAAA,CAAA;AAAA;AAGxD,EACE,uBAAA,IAAA,CAAC,IAAK,EAAA,EAAA,OAAA,EAAQ,MACZ,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAO,EAAA,EAAA,KAAA,EAAO,CAAE,CAAA,gBAAgB,CAAG,EAAA,CAAA;AAAA,oBACpC,GAAA,CAAC,WAAS,QAAQ,EAAA,OAAA,EAAA;AAAA,GACpB,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { Responsive } from 'react-grid-layout';
|
|
4
|
+
import { ErrorBoundary } from '@backstage/core-components';
|
|
5
|
+
import { makeStyles } from 'tss-react/mui';
|
|
6
|
+
import 'react-grid-layout/css/styles.css';
|
|
7
|
+
import useMeasure from 'react-use/lib/useMeasure';
|
|
8
|
+
import { isCardADefaultConfiguration } from '../utils.esm.js';
|
|
9
|
+
|
|
10
|
+
const gridGap = 16;
|
|
11
|
+
const defaultProps = {
|
|
12
|
+
// Aligned with the 1.0-1.2 home page gap.
|
|
13
|
+
margin: [gridGap, gridGap],
|
|
14
|
+
// Same as in home-plugin CustomHomepageGrid
|
|
15
|
+
rowHeight: 60,
|
|
16
|
+
// We use always a 12-column grid, but each cards can define
|
|
17
|
+
// their number of columns (width) and start column (x) per breakpoint.
|
|
18
|
+
breakpoints: {
|
|
19
|
+
xl: 1600,
|
|
20
|
+
lg: 1200,
|
|
21
|
+
md: 996,
|
|
22
|
+
sm: 768,
|
|
23
|
+
xs: 480,
|
|
24
|
+
xxs: 0
|
|
25
|
+
},
|
|
26
|
+
cols: {
|
|
27
|
+
xl: 12,
|
|
28
|
+
lg: 12,
|
|
29
|
+
md: 12,
|
|
30
|
+
sm: 12,
|
|
31
|
+
xs: 12,
|
|
32
|
+
xxs: 12
|
|
33
|
+
},
|
|
34
|
+
isDraggable: false,
|
|
35
|
+
isResizable: false,
|
|
36
|
+
compactType: null
|
|
37
|
+
};
|
|
38
|
+
const useStyles = makeStyles()({
|
|
39
|
+
// Make card content scrollable (so that cards don't overlap)
|
|
40
|
+
cardWrapper: {
|
|
41
|
+
'& > div[class*="MuiCard-root"]': {
|
|
42
|
+
width: "100%",
|
|
43
|
+
height: "100%"
|
|
44
|
+
},
|
|
45
|
+
'& div[class*="MuiCardContent-root"]': {
|
|
46
|
+
overflow: "auto"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const ReadOnlyGridLayout = ({
|
|
51
|
+
homepageCards
|
|
52
|
+
}) => {
|
|
53
|
+
const { classes } = useStyles();
|
|
54
|
+
const [measureRef, measureRect] = useMeasure();
|
|
55
|
+
const cards = useMemo(() => {
|
|
56
|
+
return homepageCards.filter(isCardADefaultConfiguration).map((cardData, index) => {
|
|
57
|
+
const id = (index + 1).toString();
|
|
58
|
+
const layouts2 = {};
|
|
59
|
+
if (cardData.breakpointLayouts) {
|
|
60
|
+
for (const [breakpoint, layout] of Object.entries(
|
|
61
|
+
cardData.breakpointLayouts
|
|
62
|
+
)) {
|
|
63
|
+
layouts2[breakpoint] = {
|
|
64
|
+
i: id,
|
|
65
|
+
x: layout.x ?? 0,
|
|
66
|
+
y: layout.y ?? 0,
|
|
67
|
+
w: layout.w ?? 12,
|
|
68
|
+
h: layout.h ?? 4,
|
|
69
|
+
isDraggable: false,
|
|
70
|
+
isResizable: false
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
["xl", "lg", "md", "sm", "xs", "xxs"].forEach((breakpoint) => {
|
|
75
|
+
layouts2[breakpoint] = {
|
|
76
|
+
i: id,
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0,
|
|
79
|
+
w: 12,
|
|
80
|
+
h: 4,
|
|
81
|
+
isDraggable: false,
|
|
82
|
+
isResizable: false
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const component = cardData.component;
|
|
87
|
+
const RenderContent = typeof component === "object" && component !== null && "Content" in component ? component.Content : component;
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
Component: RenderContent,
|
|
91
|
+
layouts: layouts2
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
}, [homepageCards]);
|
|
95
|
+
const layouts = useMemo(() => {
|
|
96
|
+
const result = {};
|
|
97
|
+
for (const card of cards) {
|
|
98
|
+
for (const [breakpoint, layoutPerBreakpoint] of Object.entries(
|
|
99
|
+
card.layouts
|
|
100
|
+
)) {
|
|
101
|
+
if (!result[breakpoint]) {
|
|
102
|
+
result[breakpoint] = [];
|
|
103
|
+
}
|
|
104
|
+
result[breakpoint].push(layoutPerBreakpoint);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}, [cards]);
|
|
109
|
+
const children = useMemo(() => {
|
|
110
|
+
return cards.map((card) => /* @__PURE__ */ jsx(
|
|
111
|
+
"div",
|
|
112
|
+
{
|
|
113
|
+
"data-cardid": card.id,
|
|
114
|
+
"data-testid": `home-page card ${card.id}`,
|
|
115
|
+
"data-layout": JSON.stringify(card.layouts),
|
|
116
|
+
className: classes.cardWrapper,
|
|
117
|
+
children: /* @__PURE__ */ jsx(ErrorBoundary, { children: typeof card.Component === "function" ? /* @__PURE__ */ jsx(card.Component, {}) : card.Component })
|
|
118
|
+
},
|
|
119
|
+
card.id
|
|
120
|
+
));
|
|
121
|
+
}, [cards, classes.cardWrapper]);
|
|
122
|
+
return /* @__PURE__ */ jsxs("div", { style: { margin: -16 }, children: [
|
|
123
|
+
/* @__PURE__ */ jsx("div", { ref: measureRef }),
|
|
124
|
+
measureRect.width ? /* @__PURE__ */ jsx(
|
|
125
|
+
Responsive,
|
|
126
|
+
{
|
|
127
|
+
...defaultProps,
|
|
128
|
+
width: measureRect.width,
|
|
129
|
+
layouts,
|
|
130
|
+
children
|
|
131
|
+
}
|
|
132
|
+
) : null
|
|
133
|
+
] });
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export { ReadOnlyGridLayout };
|
|
137
|
+
//# sourceMappingURL=ReadOnlyGirdLayout.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReadOnlyGirdLayout.esm.js","sources":["../../../src/alpha/components/ReadOnlyGirdLayout.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, ReactNode } from 'react';\n\nimport { useMemo } from 'react';\nimport {\n Layout,\n Layouts,\n Responsive,\n ResponsiveProps,\n} from 'react-grid-layout';\n\nimport { ErrorBoundary } from '@backstage/core-components';\n\nimport { makeStyles } from 'tss-react/mui';\n\n// Removes the doubled scrollbar\nimport 'react-grid-layout/css/styles.css';\n\nimport useMeasure from 'react-use/lib/useMeasure';\nimport { HomePageCardConfig } from '../../types';\nimport { isCardADefaultConfiguration } from '../utils';\n\ninterface Card {\n id: string;\n Component: ComponentType<any> | ReactNode;\n layouts: Record<string, Layout>;\n}\n\nconst gridGap = 16;\n\nconst defaultProps: ResponsiveProps = {\n // Aligned with the 1.0-1.2 home page gap.\n margin: [gridGap, gridGap],\n // Same as in home-plugin CustomHomepageGrid\n rowHeight: 60,\n\n // We use always a 12-column grid, but each cards can define\n // their number of columns (width) and start column (x) per breakpoint.\n breakpoints: {\n xl: 1600,\n lg: 1200,\n md: 996,\n sm: 768,\n xs: 480,\n xxs: 0,\n },\n cols: {\n xl: 12,\n lg: 12,\n md: 12,\n sm: 12,\n xs: 12,\n xxs: 12,\n },\n\n isDraggable: false,\n isResizable: false,\n compactType: null,\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 * Props for the read-only grid layout.\n * @alpha\n */\nexport interface ReadOnlyGridLayoutProps {\n homepageCards: HomePageCardConfig[];\n}\n\n/**\n * Read-only grid layout for the NFS home page.\n * Respects layout configuration (breakpoints) when provided via app config.\n *\n * @alpha\n */\nexport const ReadOnlyGridLayout = ({\n homepageCards,\n}: ReadOnlyGridLayoutProps) => {\n const { classes } = useStyles();\n const [measureRef, measureRect] = useMeasure<HTMLDivElement>();\n\n const cards = useMemo<Card[]>(() => {\n return homepageCards\n .filter(isCardADefaultConfiguration)\n .map<Card>((cardData, index) => {\n const id = (index + 1).toString();\n const layouts: Record<string, Layout> = {};\n if (cardData.breakpointLayouts) {\n for (const [breakpoint, layout] of Object.entries(\n cardData.breakpointLayouts,\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 // component can be a React element or { Content: ComponentType }; extract renderable node\n const component = cardData.component;\n const RenderContent =\n typeof component === 'object' &&\n component !== null &&\n 'Content' in component\n ? (component as { Content: ComponentType<any> }).Content\n : component;\n\n return {\n id,\n Component: RenderContent,\n layouts,\n };\n });\n }, [homepageCards]);\n\n const layouts = useMemo<Layouts>(() => {\n const result: Layouts = {};\n for (const card of cards) {\n for (const [breakpoint, layoutPerBreakpoint] of Object.entries(\n card.layouts,\n )) {\n if (!result[breakpoint]) {\n result[breakpoint] = [];\n }\n result[breakpoint].push(layoutPerBreakpoint);\n }\n }\n return result;\n }, [cards]);\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 {typeof card.Component === 'function' ? (\n <card.Component />\n ) : (\n card.Component\n )}\n </ErrorBoundary>\n </div>\n ));\n }, [cards, classes.cardWrapper]);\n\n return (\n <div style={{ margin: -gridGap }}>\n <div ref={measureRef} />\n {measureRect.width ? (\n <Responsive\n {...defaultProps}\n width={measureRect.width}\n layouts={layouts}\n >\n {children}\n </Responsive>\n ) : null}\n </div>\n );\n};\n"],"names":["layouts"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ApiBlueprint, discoveryApiRef, configApiRef, identityApiRef } from '@backstage/frontend-plugin-api';
|
|
2
|
+
import { quickAccessApiRef, QuickAccessApiClient } from '../../api/QuickAccessApiClient.esm.js';
|
|
3
|
+
|
|
4
|
+
const quickAccessApi = ApiBlueprint.make({
|
|
5
|
+
name: "quickaccess",
|
|
6
|
+
disabled: false,
|
|
7
|
+
params: (defineParams) => defineParams({
|
|
8
|
+
api: quickAccessApiRef,
|
|
9
|
+
deps: {
|
|
10
|
+
discoveryApi: discoveryApiRef,
|
|
11
|
+
configApi: configApiRef,
|
|
12
|
+
identityApi: identityApiRef
|
|
13
|
+
},
|
|
14
|
+
factory: ({ discoveryApi, configApi, identityApi }) => new QuickAccessApiClient({ discoveryApi, configApi, identityApi })
|
|
15
|
+
})
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export { quickAccessApi };
|
|
19
|
+
//# sourceMappingURL=apis.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apis.esm.js","sources":["../../../src/alpha/extensions/apis.ts"],"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 ApiBlueprint,\n configApiRef,\n discoveryApiRef,\n identityApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { QuickAccessApiClient, quickAccessApiRef } from '../../api';\n\n/**\n * Quick access API for the New Frontend System.\n * Provides access to quick access links from app config.\n *\n * @alpha\n */\nconst quickAccessApi = ApiBlueprint.make({\n name: 'quickaccess',\n disabled: false,\n params: defineParams =>\n defineParams({\n api: quickAccessApiRef,\n deps: {\n discoveryApi: discoveryApiRef,\n configApi: configApiRef,\n identityApi: identityApiRef,\n },\n factory: ({ discoveryApi, configApi, identityApi }) =>\n new QuickAccessApiClient({ discoveryApi, configApi, identityApi }),\n }),\n});\n\nexport { quickAccessApi };\n"],"names":[],"mappings":";;;AA8BM,MAAA,cAAA,GAAiB,aAAa,IAAK,CAAA;AAAA,EACvC,IAAM,EAAA,aAAA;AAAA,EACN,QAAU,EAAA,KAAA;AAAA,EACV,MAAA,EAAQ,kBACN,YAAa,CAAA;AAAA,IACX,GAAK,EAAA,iBAAA;AAAA,IACL,IAAM,EAAA;AAAA,MACJ,YAAc,EAAA,eAAA;AAAA,MACd,SAAW,EAAA,YAAA;AAAA,MACX,WAAa,EAAA;AAAA,KACf;AAAA,IACA,OAAS,EAAA,CAAC,EAAE,YAAA,EAAc,SAAW,EAAA,WAAA,EACnC,KAAA,IAAI,oBAAqB,CAAA,EAAE,YAAc,EAAA,SAAA,EAAW,aAAa;AAAA,GACpE;AACL,CAAC;;;;"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';
|
|
3
|
+
import homePlugin from '@backstage/plugin-home/alpha';
|
|
4
|
+
import { compatWrapper } from '@backstage/core-compat-api';
|
|
5
|
+
|
|
6
|
+
const defaultCardLayout = {
|
|
7
|
+
width: {
|
|
8
|
+
minColumns: 4,
|
|
9
|
+
maxColumns: 12,
|
|
10
|
+
defaultColumns: 12
|
|
11
|
+
},
|
|
12
|
+
height: {
|
|
13
|
+
minRows: 2,
|
|
14
|
+
maxRows: 12,
|
|
15
|
+
defaultRows: 4
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const onboardingSectionWidget = HomePageWidgetBlueprint.make({
|
|
19
|
+
name: "rhdh-onboarding-section",
|
|
20
|
+
params: {
|
|
21
|
+
name: "Red Hat Developer Hub - Onboarding",
|
|
22
|
+
layout: defaultCardLayout,
|
|
23
|
+
components: () => import('../../components/OnboardingSection/index.esm.js').then((m) => ({
|
|
24
|
+
Content: m.OnboardingSection
|
|
25
|
+
}))
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const entitySectionWidget = HomePageWidgetBlueprint.make({
|
|
29
|
+
name: "rhdh-entity-section",
|
|
30
|
+
params: {
|
|
31
|
+
name: "Red Hat Developer Hub - Software Catalog",
|
|
32
|
+
layout: defaultCardLayout,
|
|
33
|
+
components: () => import('../../components/EntitySection/index.esm.js').then((m) => ({
|
|
34
|
+
Content: () => compatWrapper(/* @__PURE__ */ jsx(m.EntitySection, {}))
|
|
35
|
+
}))
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const templateSectionWidget = HomePageWidgetBlueprint.make({
|
|
39
|
+
name: "rhdh-template-section",
|
|
40
|
+
params: {
|
|
41
|
+
name: "Red Hat Developer Hub - Explore templates",
|
|
42
|
+
layout: defaultCardLayout,
|
|
43
|
+
components: () => import('../../components/TemplateSection/index.esm.js').then((m) => ({
|
|
44
|
+
Content: m.TemplateSection
|
|
45
|
+
}))
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const quickAccessCardWidget = HomePageWidgetBlueprint.make({
|
|
49
|
+
name: "quick-access-card",
|
|
50
|
+
params: {
|
|
51
|
+
name: "Quick Access Card",
|
|
52
|
+
layout: defaultCardLayout,
|
|
53
|
+
components: () => import('../../components/QuickAccessCard.esm.js').then((m) => ({
|
|
54
|
+
Content: () => compatWrapper(/* @__PURE__ */ jsx(m.QuickAccessCard, {}))
|
|
55
|
+
}))
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const searchBarWidget = HomePageWidgetBlueprint.make({
|
|
59
|
+
name: "search-bar",
|
|
60
|
+
params: {
|
|
61
|
+
name: "Search",
|
|
62
|
+
layout: {
|
|
63
|
+
...defaultCardLayout,
|
|
64
|
+
height: {
|
|
65
|
+
...defaultCardLayout.height,
|
|
66
|
+
defaultRows: 2,
|
|
67
|
+
minRows: 1,
|
|
68
|
+
maxRows: 1
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
components: () => import('../../components/SearchBar.esm.js').then((m) => ({
|
|
72
|
+
Content: () => compatWrapper(/* @__PURE__ */ jsx(m.SearchBar, {}))
|
|
73
|
+
}))
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
const featuredDocsCardWidget = HomePageWidgetBlueprint.make({
|
|
77
|
+
name: "featured-docs-card",
|
|
78
|
+
params: {
|
|
79
|
+
name: "Featured docs",
|
|
80
|
+
layout: defaultCardLayout,
|
|
81
|
+
components: () => import('../../components/FeaturedDocsCard.esm.js').then((m) => ({
|
|
82
|
+
Content: m.FeaturedDocsCard
|
|
83
|
+
}))
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
const catalogStarredWidget = homePlugin.getExtension("home-page-widget:home/starred-entities").override({
|
|
87
|
+
params: {
|
|
88
|
+
name: "CatalogStarred",
|
|
89
|
+
title: "Starred catalog entities"
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
const disableToolkit = homePlugin.getExtension("home-page-widget:home/toolkit").override({
|
|
93
|
+
disabled: true
|
|
94
|
+
});
|
|
95
|
+
const RecentlyVisitedWidget = HomePageWidgetBlueprint.make({
|
|
96
|
+
name: "recently-visited",
|
|
97
|
+
params: {
|
|
98
|
+
layout: defaultCardLayout,
|
|
99
|
+
name: "Recently visited",
|
|
100
|
+
components: () => import('@backstage/plugin-home').then((m) => ({
|
|
101
|
+
Content: m.HomePageRecentlyVisited
|
|
102
|
+
}))
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const TopVisitedWidget = HomePageWidgetBlueprint.make({
|
|
106
|
+
name: "top-visited",
|
|
107
|
+
params: {
|
|
108
|
+
layout: defaultCardLayout,
|
|
109
|
+
name: "Top visited",
|
|
110
|
+
components: () => import('@backstage/plugin-home').then((m) => ({
|
|
111
|
+
Content: () => /* @__PURE__ */ jsx(m.HomePageTopVisited, {})
|
|
112
|
+
}))
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export { RecentlyVisitedWidget, TopVisitedWidget, catalogStarredWidget, disableToolkit, entitySectionWidget, featuredDocsCardWidget, onboardingSectionWidget, quickAccessCardWidget, searchBarWidget, templateSectionWidget };
|
|
117
|
+
//# sourceMappingURL=homePageCards.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"homePageCards.esm.js","sources":["../../../src/alpha/extensions/homePageCards.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 { HomePageWidgetBlueprint } from '@backstage/plugin-home-react/alpha';\nimport homePlugin from '@backstage/plugin-home/alpha';\nimport { compatWrapper } from '@backstage/core-compat-api';\n\nconst defaultCardLayout = {\n width: {\n minColumns: 4,\n maxColumns: 12,\n defaultColumns: 12,\n },\n height: {\n minRows: 2,\n maxRows: 12,\n defaultRows: 4,\n },\n} as const;\n\n/**\n * NFS widget: OnboardingSection (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const onboardingSectionWidget = HomePageWidgetBlueprint.make({\n name: 'rhdh-onboarding-section',\n params: {\n name: 'Red Hat Developer Hub - Onboarding',\n layout: defaultCardLayout,\n components: () =>\n import('../../components/OnboardingSection').then(m => ({\n Content: m.OnboardingSection,\n })),\n },\n});\n\n/**\n * NFS widget: EntitySection (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const entitySectionWidget = HomePageWidgetBlueprint.make({\n name: 'rhdh-entity-section',\n params: {\n name: 'Red Hat Developer Hub - Software Catalog',\n layout: defaultCardLayout,\n components: () =>\n import('../../components/EntitySection').then(m => ({\n Content: () => compatWrapper(<m.EntitySection />),\n })),\n },\n});\n\n/**\n * NFS widget: TemplateSection (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const templateSectionWidget = HomePageWidgetBlueprint.make({\n name: 'rhdh-template-section',\n params: {\n name: 'Red Hat Developer Hub - Explore templates',\n layout: defaultCardLayout,\n components: () =>\n import('../../components/TemplateSection').then(m => ({\n Content: m.TemplateSection,\n })),\n },\n});\n\n/**\n * NFS widget: QuickAccessCard (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const quickAccessCardWidget = HomePageWidgetBlueprint.make({\n name: 'quick-access-card',\n params: {\n name: 'Quick Access Card',\n layout: defaultCardLayout,\n components: () =>\n import('../../components/QuickAccessCard').then(m => ({\n Content: () => compatWrapper(<m.QuickAccessCard />),\n })),\n },\n});\n\n/**\n * NFS widget: SearchBar (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const searchBarWidget = HomePageWidgetBlueprint.make({\n name: 'search-bar',\n params: {\n name: 'Search',\n layout: {\n ...defaultCardLayout,\n height: {\n ...defaultCardLayout.height,\n defaultRows: 2,\n minRows: 1,\n maxRows: 1,\n },\n },\n components: () =>\n import('../../components/SearchBar').then(m => ({\n Content: () => compatWrapper(<m.SearchBar />),\n })),\n },\n});\n\n/**\n * NFS widget: FeaturedDocsCard (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const featuredDocsCardWidget = HomePageWidgetBlueprint.make({\n name: 'featured-docs-card',\n params: {\n name: 'Featured docs',\n layout: defaultCardLayout,\n components: () =>\n import('../../components/FeaturedDocsCard').then(m => ({\n Content: m.FeaturedDocsCard,\n })),\n },\n});\n\n/**\n * NFS widget: CatalogStarred (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const catalogStarredWidget = homePlugin\n .getExtension('home-page-widget:home/starred-entities')\n .override({\n params: {\n name: 'CatalogStarred',\n title: 'Starred catalog entities',\n },\n });\n\n/**\n * Disables the default home plugin toolkit widget.\n * @alpha\n */\nexport const disableToolkit = homePlugin\n .getExtension('home-page-widget:home/toolkit')\n .override({\n disabled: true,\n });\n\n/**\n * NFS widget: RecentlyVisited (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const RecentlyVisitedWidget = HomePageWidgetBlueprint.make({\n name: 'recently-visited',\n params: {\n layout: defaultCardLayout,\n name: 'Recently visited',\n components: () =>\n import('@backstage/plugin-home').then(m => ({\n Content: m.HomePageRecentlyVisited,\n })),\n },\n});\n\n/**\n * NFS widget: TopVisited (migrated from mountPoint home.page/cards).\n * @alpha\n */\nexport const TopVisitedWidget = HomePageWidgetBlueprint.make({\n name: 'top-visited',\n params: {\n layout: defaultCardLayout,\n name: 'Top visited',\n components: () =>\n import('@backstage/plugin-home').then(m => ({\n Content: () => <m.HomePageTopVisited />,\n })),\n },\n});\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { HomePageLayoutBlueprint } from '@backstage/plugin-home-react/alpha';
|
|
3
|
+
import { HomePageLayout } from '../components/HomePageLayout.esm.js';
|
|
4
|
+
|
|
5
|
+
const homePageLayoutExtension = HomePageLayoutBlueprint.makeWithOverrides({
|
|
6
|
+
name: "dynamic-homepage-layout",
|
|
7
|
+
config: {
|
|
8
|
+
schema: {
|
|
9
|
+
customizable: (z) => z.boolean().optional(),
|
|
10
|
+
widgetLayout: (z) => z.record(
|
|
11
|
+
z.object({
|
|
12
|
+
priority: z.number().optional(),
|
|
13
|
+
breakpoints: z.record(
|
|
14
|
+
z.object({
|
|
15
|
+
w: z.number().optional(),
|
|
16
|
+
h: z.number().optional(),
|
|
17
|
+
x: z.number().optional(),
|
|
18
|
+
y: z.number().optional()
|
|
19
|
+
})
|
|
20
|
+
).optional()
|
|
21
|
+
})
|
|
22
|
+
).optional()
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
factory(originalFactory, { config }) {
|
|
26
|
+
const customizable = config.customizable ?? true;
|
|
27
|
+
const layoutConfig = config.widgetLayout ?? {};
|
|
28
|
+
return originalFactory({
|
|
29
|
+
loader: async () => function CustomHomePageLayout({ widgets }) {
|
|
30
|
+
const processedWidgets = widgets.map((widget) => {
|
|
31
|
+
const widgetConfig = layoutConfig[widget.name ?? ""];
|
|
32
|
+
const configBreakpoints = widgetConfig?.breakpoints;
|
|
33
|
+
if (!configBreakpoints) return widget;
|
|
34
|
+
return {
|
|
35
|
+
...widget,
|
|
36
|
+
breakpointLayouts: configBreakpoints
|
|
37
|
+
};
|
|
38
|
+
}).sort((a, b) => {
|
|
39
|
+
if (customizable) return 0;
|
|
40
|
+
const priorityA = layoutConfig[a.name ?? ""]?.priority ?? 0;
|
|
41
|
+
const priorityB = layoutConfig[b.name ?? ""]?.priority ?? 0;
|
|
42
|
+
return priorityB - priorityA;
|
|
43
|
+
});
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
HomePageLayout,
|
|
46
|
+
{
|
|
47
|
+
widgets: processedWidgets,
|
|
48
|
+
customizable
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export { homePageLayoutExtension };
|
|
57
|
+
//# sourceMappingURL=homePageLayoutExtension.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"homePageLayoutExtension.esm.js","sources":["../../../src/alpha/extensions/homePageLayoutExtension.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 { HomePageLayoutBlueprint } from '@backstage/plugin-home-react/alpha';\nimport { HomePageLayout } from '../components/HomePageLayout';\nimport { HomePageCardConfig } from '../../types';\n\n/**\n * Custom home page layout extension for the New Frontend System.\n *\n * Config-driven layout with `widgetLayout` (priority, breakpoints per widget),\n * supports both customizable (drag/drop) and read-only modes.\n *\n * @alpha\n */\nexport const homePageLayoutExtension =\n HomePageLayoutBlueprint.makeWithOverrides({\n name: 'dynamic-homepage-layout',\n config: {\n schema: {\n customizable: z => z.boolean().optional(),\n widgetLayout: z =>\n z\n .record(\n z.object({\n priority: z.number().optional(),\n breakpoints: z\n .record(\n z.object({\n w: z.number().optional(),\n h: z.number().optional(),\n x: z.number().optional(),\n y: z.number().optional(),\n }),\n )\n .optional(),\n }),\n )\n .optional(),\n },\n },\n factory(originalFactory, { config }) {\n const customizable = config.customizable ?? true;\n const layoutConfig = config.widgetLayout ?? {};\n\n return originalFactory({\n loader: async () =>\n function CustomHomePageLayout({ widgets }) {\n const processedWidgets: HomePageCardConfig[] = widgets\n .map(widget => {\n const widgetConfig = layoutConfig[widget.name ?? ''];\n const configBreakpoints = widgetConfig?.breakpoints;\n\n if (!configBreakpoints) return widget;\n\n return {\n ...widget,\n breakpointLayouts: configBreakpoints,\n };\n })\n .sort((a, b) => {\n if (customizable) return 0; // keep original order\n\n const priorityA = layoutConfig[a.name ?? '']?.priority ?? 0;\n const priorityB = layoutConfig[b.name ?? '']?.priority ?? 0;\n return priorityB - priorityA;\n });\n\n return (\n <HomePageLayout\n widgets={processedWidgets}\n customizable={customizable}\n />\n );\n },\n });\n },\n });\n"],"names":[],"mappings":";;;;AA4Ba,MAAA,uBAAA,GACX,wBAAwB,iBAAkB,CAAA;AAAA,EACxC,IAAM,EAAA,yBAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,YAAc,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MACxC,YAAA,EAAc,OACZ,CACG,CAAA,MAAA;AAAA,QACC,EAAE,MAAO,CAAA;AAAA,UACP,QAAU,EAAA,CAAA,CAAE,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,UAC9B,aAAa,CACV,CAAA,MAAA;AAAA,YACC,EAAE,MAAO,CAAA;AAAA,cACP,CAAG,EAAA,CAAA,CAAE,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,cACvB,CAAG,EAAA,CAAA,CAAE,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,cACvB,CAAG,EAAA,CAAA,CAAE,MAAO,EAAA,CAAE,QAAS,EAAA;AAAA,cACvB,CAAG,EAAA,CAAA,CAAE,MAAO,EAAA,CAAE,QAAS;AAAA,aACxB;AAAA,YAEF,QAAS;AAAA,SACb;AAAA,QAEF,QAAS;AAAA;AAChB,GACF;AAAA,EACA,OAAQ,CAAA,eAAA,EAAiB,EAAE,MAAA,EAAU,EAAA;AACnC,IAAM,MAAA,YAAA,GAAe,OAAO,YAAgB,IAAA,IAAA;AAC5C,IAAM,MAAA,YAAA,GAAe,MAAO,CAAA,YAAA,IAAgB,EAAC;AAE7C,IAAA,OAAO,eAAgB,CAAA;AAAA,MACrB,QAAQ,YACN,SAAS,oBAAqB,CAAA,EAAE,SAAW,EAAA;AACzC,QAAM,MAAA,gBAAA,GAAyC,OAC5C,CAAA,GAAA,CAAI,CAAU,MAAA,KAAA;AACb,UAAA,MAAM,YAAe,GAAA,YAAA,CAAa,MAAO,CAAA,IAAA,IAAQ,EAAE,CAAA;AACnD,UAAA,MAAM,oBAAoB,YAAc,EAAA,WAAA;AAExC,UAAI,IAAA,CAAC,mBAA0B,OAAA,MAAA;AAE/B,UAAO,OAAA;AAAA,YACL,GAAG,MAAA;AAAA,YACH,iBAAmB,EAAA;AAAA,WACrB;AAAA,SACD,CAAA,CACA,IAAK,CAAA,CAAC,GAAG,CAAM,KAAA;AACd,UAAA,IAAI,cAAqB,OAAA,CAAA;AAEzB,UAAA,MAAM,YAAY,YAAa,CAAA,CAAA,CAAE,IAAQ,IAAA,EAAE,GAAG,QAAY,IAAA,CAAA;AAC1D,UAAA,MAAM,YAAY,YAAa,CAAA,CAAA,CAAE,IAAQ,IAAA,EAAE,GAAG,QAAY,IAAA,CAAA;AAC1D,UAAA,OAAO,SAAY,GAAA,SAAA;AAAA,SACpB,CAAA;AAEH,QACE,uBAAA,GAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YACC,OAAS,EAAA,gBAAA;AAAA,YACT;AAAA;AAAA,SACF;AAAA;AAEJ,KACH,CAAA;AAAA;AAEL,CAAC;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.esm.js","sources":["../../src/alpha/utils.ts"],"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 { HomePageCardConfig } from '../types';\n\nexport function isCardADefaultConfiguration(\n cardData: HomePageCardConfig,\n): boolean {\n return (\n !!cardData.breakpointLayouts ||\n Object.entries(cardData.breakpointLayouts ?? {}).length === 0\n );\n}\n"],"names":[],"mappings":"AAkBO,SAAS,4BACd,QACS,EAAA;AACT,EACE,OAAA,CAAC,CAAC,QAAA,CAAS,iBACX,IAAA,MAAA,CAAO,OAAQ,CAAA,QAAA,CAAS,iBAAqB,IAAA,EAAE,CAAA,CAAE,MAAW,KAAA,CAAA;AAEhE;;;;"}
|