Skip to content

Commit 31e45c4

Browse files
committed
lazy load HomePage Layout
1 parent c60d856 commit 31e45c4

4 files changed

Lines changed: 106 additions & 54 deletions

File tree

workspaces/homepage/plugins/homepage/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
"@red-hat-developer-hub/backstage-plugin-homepage-common": "workspace:^",
6868
"@scalprum/react-core": "0.11.3",
6969
"react-grid-layout": "1.5.3",
70-
"react-use": "17.6.1"
70+
"react-use": "17.6.1",
71+
"zod": "^4.0.0"
7172
},
7273
"peerDependencies": {
7374
"react": "16.13.1 || ^17.0.0 || ^18.2.0",
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { HomePageLayoutProps } from '@backstage/plugin-home-react/alpha';
18+
19+
import { HomePageCardConfig } from '../../types';
20+
import { HomePageLayout } from './HomePageLayout';
21+
22+
/**
23+
* Widget layout configuration keyed by widget name.
24+
* @alpha
25+
*/
26+
export type WidgetLayoutConfig = Record<
27+
string,
28+
{
29+
priority?: number;
30+
breakpoints?: Record<
31+
string,
32+
{ w?: number; h?: number; x?: number; y?: number }
33+
>;
34+
}
35+
>;
36+
37+
/**
38+
* Options for creating a config-driven home page layout component.
39+
* @alpha
40+
*/
41+
export interface CustomHomePageLayoutOptions {
42+
customizable: boolean;
43+
layoutConfig: WidgetLayoutConfig;
44+
}
45+
46+
/**
47+
* Creates a home page layout component that applies widget layout config
48+
* (priority, breakpoints) before rendering the grid.
49+
*
50+
* @alpha
51+
*/
52+
export function createCustomHomePageLayout({
53+
customizable,
54+
layoutConfig,
55+
}: CustomHomePageLayoutOptions) {
56+
return function CustomHomePageLayout({ widgets }: HomePageLayoutProps) {
57+
const processedWidgets: HomePageCardConfig[] = widgets
58+
.map(widget => {
59+
const widgetConfig = layoutConfig[widget.name ?? ''];
60+
const configBreakpoints = widgetConfig?.breakpoints;
61+
62+
if (!configBreakpoints) return widget;
63+
64+
return {
65+
...widget,
66+
breakpointLayouts: configBreakpoints,
67+
};
68+
})
69+
.sort((a, b) => {
70+
if (customizable) return 0;
71+
72+
const priorityA = layoutConfig[a.name ?? '']?.priority ?? 0;
73+
const priorityB = layoutConfig[b.name ?? '']?.priority ?? 0;
74+
return priorityB - priorityA;
75+
});
76+
77+
return (
78+
<HomePageLayout widgets={processedWidgets} customizable={customizable} />
79+
);
80+
};
81+
}

workspaces/homepage/plugins/homepage/src/alpha/extensions/homePageLayoutExtension.tsx

Lines changed: 22 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,19 @@
1515
*/
1616

1717
import { HomePageLayoutBlueprint } from '@backstage/plugin-home-react/alpha';
18-
import { HomePageLayout } from '../components/HomePageLayout';
19-
import { HomePageCardConfig } from '../../types';
18+
import { z } from 'zod';
19+
20+
const breakpointLayoutSchema = z.object({
21+
w: z.number().optional(),
22+
h: z.number().optional(),
23+
x: z.number().optional(),
24+
y: z.number().optional(),
25+
});
26+
27+
const widgetLayoutEntrySchema = z.object({
28+
priority: z.number().optional(),
29+
breakpoints: z.record(z.string(), breakpointLayoutSchema).optional(),
30+
});
2031

2132
/**
2233
* Custom home page layout extension for the New Frontend System.
@@ -29,63 +40,21 @@ import { HomePageCardConfig } from '../../types';
2940
export const homePageLayoutExtension =
3041
HomePageLayoutBlueprint.makeWithOverrides({
3142
name: 'dynamic-homepage-layout',
32-
config: {
33-
schema: {
34-
customizable: z => z.boolean().optional(),
35-
widgetLayout: z =>
36-
z
37-
.record(
38-
z.object({
39-
priority: z.number().optional(),
40-
breakpoints: z
41-
.record(
42-
z.object({
43-
w: z.number().optional(),
44-
h: z.number().optional(),
45-
x: z.number().optional(),
46-
y: z.number().optional(),
47-
}),
48-
)
49-
.optional(),
50-
}),
51-
)
52-
.optional(),
53-
},
43+
configSchema: {
44+
customizable: z.boolean().optional(),
45+
widgetLayout: z.record(z.string(), widgetLayoutEntrySchema).optional(),
5446
},
5547
factory(originalFactory, { config }) {
5648
const customizable = config.customizable ?? true;
5749
const layoutConfig = config.widgetLayout ?? {};
5850

5951
return originalFactory({
60-
loader: async () =>
61-
function CustomHomePageLayout({ widgets }) {
62-
const processedWidgets: HomePageCardConfig[] = widgets
63-
.map(widget => {
64-
const widgetConfig = layoutConfig[widget.name ?? ''];
65-
const configBreakpoints = widgetConfig?.breakpoints;
66-
67-
if (!configBreakpoints) return widget;
68-
69-
return {
70-
...widget,
71-
breakpointLayouts: configBreakpoints,
72-
};
73-
})
74-
.sort((a, b) => {
75-
if (customizable) return 0; // keep original order
76-
77-
const priorityA = layoutConfig[a.name ?? '']?.priority ?? 0;
78-
const priorityB = layoutConfig[b.name ?? '']?.priority ?? 0;
79-
return priorityB - priorityA;
80-
});
81-
82-
return (
83-
<HomePageLayout
84-
widgets={processedWidgets}
85-
customizable={customizable}
86-
/>
87-
);
88-
},
52+
loader: async () => {
53+
const { createCustomHomePageLayout } = await import(
54+
'../components/CustomHomePageLayout'
55+
);
56+
return createCustomHomePageLayout({ customizable, layoutConfig });
57+
},
8958
});
9059
},
9160
});

workspaces/homepage/yarn.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9763,6 +9763,7 @@ __metadata:
97639763
react: "npm:^16.13.1 || ^17.0.0 || ^18.0.0"
97649764
react-grid-layout: "npm:1.5.3"
97659765
react-use: "npm:17.6.1"
9766+
zod: "npm:^4.0.0"
97669767
peerDependencies:
97679768
react: 16.13.1 || ^17.0.0 || ^18.2.0
97689769
react-dom: "*"

0 commit comments

Comments
 (0)