Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions workspaces/homepage/.changeset/home-plugin-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@red-hat-developer-hub/backstage-plugin-homepage': minor
---

Give the homepage NFS plugin its own configurable page (`page:homepage`) so it works without community `@backstage/plugin-home`, and apply persona-based `homepage.defaultWidgets` filtering only on that page via homepage-backend. When `homepageHomeModule` is installed, the same widgets are also registered on community `page:home` (without the RH layout / homepage-backend filtering). Community `page:home` and `page:homepage` can be enabled or disabled independently via app-config.
9 changes: 8 additions & 1 deletion workspaces/homepage/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,17 @@ app:
# Disable the nav items that we're manually rendering in packages/app/src/modules/nav/Sidebar.tsx
- api:home/visits: true
- app-root-element:home/visit-listener: true
# Community home page (optional). Disable when using page:homepage alone.
- page:home:
config:
path: /home
title: Home
# Homepage-owned page (configurable path). Disable with page:homepage: false.
- page:homepage:
config:
path: /
- home-page-layout:home/dynamic-homepage-layout:
title: Dynamic Homepage
- home-page-layout:homepage/dynamic-homepage-layout:
config:
customizable: true # false for read-only homepage layout
widgetLayout:
Expand Down
6 changes: 3 additions & 3 deletions workspaces/homepage/e2e-tests/homepageCustomizable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,11 @@ test.describe.serial('Dynamic Home Page Customization', () => {

test.describe('Persona-Based Homepages', () => {
test('Groups filters default widgets by persona', async ({ browser }) => {
// The `if: groups:` condition in `homepage.defaultWidgets` is a legacy-only
// feature — NFS does not implement group-based widget filtering.
// NFS applies `homepage.defaultWidgets` persona filtering in HomePageLayout,
// but this suite exercises the legacy `/customizable` mount-point page.
test.skip(
process.env.APP_MODE === 'nfs',
'`if: groups:` filtering is not supported in NFS mode',
'Persona e2e still targets the legacy /customizable route',
);

const loginUrl = '/customizable';
Expand Down
3 changes: 1 addition & 2 deletions workspaces/homepage/packages/app/knip-report.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Knip report

## Unused dependencies (17)
## Unused dependencies (16)

| Name | Location | Severity |
| :----------------------------------------------- | :---------------- | :------- |
Expand All @@ -18,7 +18,6 @@
| @backstage/plugin-techdocs | package.json:43:6 | error |
| @backstage/plugin-catalog | package.json:33:6 | error |
| @backstage/plugin-signals | package.json:42:6 | error |
| @backstage/plugin-home | package.json:36:6 | error |
| @backstage/plugin-org | package.json:39:6 | error |
| react-router | package.json:53:6 | error |

Expand Down
6 changes: 4 additions & 2 deletions workspaces/homepage/packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { createApp } from '@backstage/frontend-defaults';
import { navModule } from './modules/nav';
import { signInModule } from './modules/signIn';
import {
homePageModule,
homepagePlugin,
homepageHomeModule,
homepageTranslationsModule,
} from '@red-hat-developer-hub/backstage-plugin-homepage';
import { rhdhThemeModule } from '@red-hat-developer-hub/backstage-plugin-theme/alpha';
Expand All @@ -28,7 +29,8 @@ export default createApp({
rhdhThemeModule,
navModule,
signInModule,
homePageModule,
homepagePlugin,
homepageHomeModule,
homepageTranslationsModule,
],
});
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const SidebarContent = NavContentBlueprint.make({
<SidebarDivider />
<SidebarGroup label="Menu" icon={<MenuIcon />}>
{nav.take('page:home')}
{nav.take('page:homepage')}
{nav.take('page:catalog')}
{nav.take('page:scaffolder')}
<SidebarDivider />
Expand Down
94 changes: 39 additions & 55 deletions workspaces/homepage/plugins/homepage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,95 +6,79 @@ The plugin supports both the **New Frontend System (NFS)** and the **legacy** dy

## New Frontend System

If you're using Backstage's new frontend system, add the plugin to your app:
The homepage package is its **own** frontend plugin (`pluginId: homepage`) with its own page (`page:homepage`). It works **without** community `@backstage/plugin-home`.

Widgets/layout attach to `page:homepage` on the homepage plugin. Persona-based defaults (`homepage.defaultWidgets` / homepage-backend) are applied only by that layout. When `homepageHomeModule` is installed, the same widgets are mirrored onto community `page:home` (NFS allows only one `attachTo` per extension), but community home keeps the upstream layout and does not call homepage-backend.

```tsx
// packages/app/src/App.tsx
import { createApp } from '@backstage/frontend-defaults';
import {
homePageModule,
homepagePlugin,
homepageHomeModule, // optional: only if community home is also installed
homepageTranslationsModule,
} from '@red-hat-developer-hub/backstage-plugin-homepage';

export default createApp({
features: [
// ... other plugins (nav, signIn, etc.)
homePageModule,
homepagePlugin,
homepageTranslationsModule,
// homepageHomeModule, // optional when using community home alongside
],
});
```

The plugin will automatically provide:

- A homepage at `/home` (or the path configured via `page:home`)
- Default widgets: Onboarding, Entity Catalog, Templates, Quick Access, Search, Recently Visited, Top Visited, and more
- Customizable or read-only layout based on configuration, default layout being customizable

### Configuration

Add the following to your `app-config.yaml`:

```yaml
app:
extensions:
# Register the home page route (default: /)
- page:home:
# Disable community home when using homepage alone (avoids two home pages)
- page:home: false

# Homepage-owned route (configurable)
- page:homepage:
config:
path: /
# Enable visit tracking (optional)
- api:home/visits: true
- app-root-element:home/visit-listener: true
# Configure the dynamic homepage layout
- home-page-layout:home/dynamic-homepage-layout:
path: / # or /home, /start, etc.

# Optional: disable homepage instead of community home
# - page:homepage: false

- home-page-layout:homepage/dynamic-homepage-layout:
config:
customizable: true # or false for read-only layout
customizable: true
widgetLayout:
RhdhTemplateSection:
priority: 300 # priority is considered for only Read-only Grid layout
breakpoints:
xl: { w: 12, h: 5 }
lg: { w: 12, h: 5 }
# ... md, sm, xs, xxs
RhdhEntitySection:
priority: 200
breakpoints:
xl: { w: 12, h: 7 }
# ...
RhdhOnboardingSection:
priority: 100
breakpoints:
xl: { w: 12, h: 6 }
# ...
# keys match widget `name` / layout config
...
```

### Modules
Visit tracking (for recently/top visited) still uses community home APIs when that package is installed:

```yaml
app:
extensions:
- api:home/visits: true
- app-root-element:home/visit-listener: true
```

The following modules are available from the primary package entry point:
### Plugins / modules

| Module | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `homePageModule` (default) | Home page layout and widgets (Onboarding, Entity, Templates, Quick Access, Search, Recently Visited, Top Visited, etc.) |
| `homepageTranslationsModule` | i18n translations (en, de, es, fr, it, ja) |
| Export | Type | Description |
| ---------------------------- | ---------------- | --------------------------------------------------------------------------- |
| `homepagePlugin` (default) | `FrontendPlugin` | Own plugin with `page:homepage` + widgets/layout/APIs. |
| `homepageHomeModule` | `FrontendModule` | Optional: mirror RH widgets onto `page:home`; disable toolkit/joke/starred. |
| `homepageTranslationsModule` | `FrontendModule` | i18n translations |

`homepageTranslationsModule` (`pluginId: 'app'`) is also available as a dedicated Module Federation entry:

- `@red-hat-developer-hub/backstage-plugin-homepage/homepage-translations-module`

### Extensions

The `homePageModule` extends the `home` plugin (`@backstage/plugin-home`) with:

- `home-page-layout:home/dynamic-homepage-layout` – Custom layout with config-driven widget arrangement and priority
- `home-page-widget:home/rhdh-onboarding-section` – Onboarding section
- `home-page-widget:home/rhdh-entity-section` – Software catalog section
- `home-page-widget:home/rhdh-template-section` – Templates section
- `home-page-widget:home/quick-access-card` – Quick access card
- `home-page-widget:home/search-bar` – Search bar
- `home-page-widget:home/featured-docs-card` – Featured docs
- `home-page-widget:home/recently-visited` – Recently visited
- `home-page-widget:home/top-visited` – Top visited
- `api:home/quickaccess` – Quick access API
- `page:homepage` – Homepage route (config: `path`)
- `home-page-layout:homepage/dynamic-homepage-layout` – persona filtering via homepage-backend (`page:homepage` only)
- `home-page-widget:homepage/...` – Onboarding, Entity, Templates, Quick Access, Search, Featured docs, Recently/Top visited, Catalog starred (mirrored as `home-page-widget:home/...` via `homepageHomeModule`, without RH layout filtering)
- `api:homepage/quickaccess`, `api:homepage/default-widgets`

## Legacy System (Dynamic Plugins)

Expand Down
8 changes: 6 additions & 2 deletions workspaces/homepage/plugins/homepage/dev/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ import {
catalogApiRef,
starredEntitiesApiRef,
} from '@backstage/plugin-catalog-react';
import homePlugin from '@backstage/plugin-home/alpha';
import {
homePageModule,
homepagePlugin,
homepageHomeModule,
homepageTranslationsModule,
} from '@red-hat-developer-hub/backstage-plugin-homepage';
import { rhdhThemeModule } from '@red-hat-developer-hub/backstage-plugin-theme/alpha';
Expand Down Expand Up @@ -153,7 +155,9 @@ const app = createApp({
devNavModule,
catalogPlugin,
searchPlugin,
homePageModule,
homePlugin,
homepagePlugin,
homepageHomeModule,
homepageTranslationsModule,
homepageApiMocksModule,
catalogDevModule,
Expand Down
Loading
Loading