Skip to content

Commit 8ddf68b

Browse files
committed
feat(header): add new NFS header
Signed-off-by: Rohit Rai <rohitkrai03@gmail.com>
1 parent 29571f6 commit 8ddf68b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+4567
-135
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-global-header': minor
3+
---
4+
5+
Added a new frontend system based header

workspaces/global-header/app-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
app:
22
title: RHDH Global Header Test App
33
baseUrl: http://localhost:3000
4+
5+
packages: all
6+
7+
extensions:
8+
- page:catalog:
9+
config:
10+
path: /
11+
412
support:
513
url: https://access.redhat.com/products/red-hat-developer-hub
614
items:
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
# Global header
1+
# Global Header
22

3-
Red Hat Developer Hub includes a new configable and highly extendable global header plugin starting with RHDH 1.5.
3+
Red Hat Developer Hub includes a configurable and highly extensible global header plugin starting with RHDH 1.5.
44

55
By default it includes a Search input field, Create, Starred[^1], Support[^2] and Notifications[^3] icon buttons and a user profile dropdown.
66

7-
[^1]: Only when an enitity is starred.
7+
The plugin supports two integration modes:
8+
9+
- **New Frontend System** -- Extension blueprints (`GlobalHeaderComponentBlueprint`, `GlobalHeaderMenuItemBlueprint`) allow any plugin to contribute toolbar items and dropdown menu items. See the [New Frontend System Guide](new-frontend-system.md) for full details, including architecture, code examples, and API reference.
10+
- **Legacy Mount Points** -- Dynamic plugin mount points for traditional Backstage apps. See [Configuration](configuration.md).
11+
12+
Deployers can also add menu items directly via `app-config.yaml` without writing any plugin code. See [Config-Driven Menu Items](new-frontend-system.md#config-driven-menu-items).
13+
14+
[^1]: Only when an entity is starred.
815
[^2]: Only when the Support URL is configured in the `app-config.yaml`.
916
[^3]: Only when the notifications plugin is installed.
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
# Extending the Global Header (New Frontend System)
2+
3+
The global header is the top-level navigation bar in Red Hat Developer Hub. It ships with sensible defaults -- a company logo, search, notifications, and user profile -- but is designed to be extended by other plugins and configured by deployers.
4+
5+
This guide explains how to:
6+
7+
- [Set up the header in your app](#setup)
8+
- [Add a button or widget to the toolbar](#add-a-toolbar-component)
9+
- [Add a link or section to a dropdown menu](#add-a-menu-item)
10+
- [Add items from app-config.yaml (no code)](#add-items-from-app-configyaml)
11+
- [Reorder, override, or disable defaults](#customize-defaults)
12+
13+
## How it works
14+
15+
The header uses two extension kinds:
16+
17+
| Kind | What it contributes | Example |
18+
| -------------- | -------------------------------------------------------- | --------------------------------------- |
19+
| `gh-component` | A toolbar-level element (button, dropdown, logo, spacer) | Search bar, notifications icon |
20+
| `gh-menu-item` | An item inside a dropdown menu | "Settings" link in the profile dropdown |
21+
22+
Extensions are collected at startup, sorted by `priority` (higher = first), and rendered. Menu items from `app-config.yaml` are merged in at runtime.
23+
24+
```mermaid
25+
flowchart LR
26+
plugins["Your plugins"] -->|"gh-component / gh-menu-item"| module["globalHeaderModule"]
27+
config["app-config.yaml"] -->|"globalHeader.menuItems"| module
28+
module --> header["Rendered header bar"]
29+
```
30+
31+
## Setup
32+
33+
```bash
34+
yarn --cwd packages/app add @red-hat-developer-hub/backstage-plugin-global-header
35+
```
36+
37+
```typescript
38+
// packages/app/src/App.tsx
39+
import { createApp } from '@backstage/frontend-defaults';
40+
import globalHeaderPlugin, {
41+
globalHeaderModule,
42+
} from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
43+
44+
export default createApp({
45+
features: [
46+
globalHeaderModule, // Collects extensions and renders the header
47+
globalHeaderPlugin, // Ships the default toolbar + menu items
48+
// ...your other plugins
49+
],
50+
});
51+
```
52+
53+
Both are required. The **module** provides the wrapper; the **plugin** provides the default set of components and menu items.
54+
55+
## Add a toolbar component
56+
57+
Import `GlobalHeaderComponentBlueprint` and call `.make()`. There are three ways to define what renders.
58+
59+
### Option A: Provide data, let the framework render
60+
61+
Supply `icon`, `title`, and `link` (or `onClick`). The framework renders a styled icon button for you.
62+
63+
```typescript
64+
import { GlobalHeaderComponentBlueprint } from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
65+
66+
export const myButton = GlobalHeaderComponentBlueprint.make({
67+
name: 'my-button',
68+
params: {
69+
icon: 'dashboard',
70+
title: 'Dashboard',
71+
link: '/dashboard',
72+
priority: 75,
73+
},
74+
});
75+
```
76+
77+
### Option B: Use building-block components
78+
79+
For dropdowns or more control, provide a `component` that uses the exported building blocks (`GlobalHeaderIconButton`, `GlobalHeaderDropdown`).
80+
81+
```typescript
82+
import {
83+
GlobalHeaderComponentBlueprint,
84+
GlobalHeaderDropdown,
85+
} from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
86+
87+
const MyDropdown = () => (
88+
<GlobalHeaderDropdown
89+
target="my-links"
90+
isIconButton
91+
tooltip="My links"
92+
buttonContent={<MyIcon />}
93+
/>
94+
);
95+
96+
export const myDropdown = GlobalHeaderComponentBlueprint.make({
97+
name: 'my-dropdown',
98+
params: { component: MyDropdown, priority: 75 },
99+
});
100+
```
101+
102+
### Option C: Fully custom component
103+
104+
Pass any React component. You own the rendering entirely.
105+
106+
```typescript
107+
export const myWidget = GlobalHeaderComponentBlueprint.make({
108+
name: 'my-widget',
109+
params: {
110+
component: () => <div>Anything you want</div>,
111+
priority: 60,
112+
layout: { flexGrow: 1 }, // MUI sx overrides on the wrapper
113+
},
114+
});
115+
```
116+
117+
### Parameters reference
118+
119+
| Param | Type | Description |
120+
| ----------- | ------------------------- | ----------------------------------------------- |
121+
| `icon` | `string` | Icon name, inline SVG, or URL |
122+
| `title` | `string` | Display title (also tooltip and aria-label) |
123+
| `titleKey` | `string` | i18n translation key for the title |
124+
| `tooltip` | `string` | Explicit tooltip (overrides `title`) |
125+
| `link` | `string` | Navigation URL |
126+
| `onClick` | `() => void` | Click handler (mutually exclusive with `link`) |
127+
| `component` | `ComponentType` | Custom React component (options B/C) |
128+
| `priority` | `number` | Sort order -- higher values appear further left |
129+
| `layout` | `Record<string, unknown>` | MUI `sx` overrides on the wrapper |
130+
131+
## Add a menu item
132+
133+
Import `GlobalHeaderMenuItemBlueprint`. The `target` field routes the item to the right dropdown:
134+
135+
| Target | Dropdown |
136+
| -------------- | -------------------- |
137+
| `profile` | User profile |
138+
| `help` | Help / support |
139+
| `app-launcher` | Application launcher |
140+
141+
### Data-driven item
142+
143+
Provide `title`, `link`, and optionally `icon` / `sectionLabel`. Items that share a `sectionLabel` are grouped under that heading.
144+
145+
```typescript
146+
import { GlobalHeaderMenuItemBlueprint } from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
147+
148+
export const docsItem = GlobalHeaderMenuItemBlueprint.make({
149+
name: 'my-docs',
150+
params: {
151+
target: 'help',
152+
title: 'API Docs',
153+
icon: 'description',
154+
link: 'https://api.example.com/docs',
155+
sectionLabel: 'Documentation',
156+
priority: 50,
157+
},
158+
});
159+
```
160+
161+
### Custom component item
162+
163+
For full control, provide only `component` (no `title`/`link`). The dropdown renders it directly. The component receives `handleClose` and `hideDivider` as props.
164+
165+
```typescript
166+
const MySection = ({ handleClose }: { handleClose: () => void }) => (
167+
<div onClick={handleClose}>Custom content</div>
168+
);
169+
170+
export const mySection = GlobalHeaderMenuItemBlueprint.make({
171+
name: 'my-section',
172+
params: { target: 'profile', component: MySection, priority: 50 },
173+
});
174+
```
175+
176+
> If you provide `component` **together with** data fields like `title` or `link`, the item is grouped normally but your component replaces the default renderer.
177+
178+
### Parameters reference
179+
180+
| Param | Type | Description |
181+
| ---------------------------------- | --------------- | ----------------------------------------------- |
182+
| `target` | `string` | **Required.** Which dropdown to add the item to |
183+
| `title` / `titleKey` | `string` | Display title / i18n key |
184+
| `subTitle` / `subTitleKey` | `string` | Secondary line / i18n key |
185+
| `icon` | `string` | Icon identifier |
186+
| `link` | `string` | Navigation URL |
187+
| `onClick` | `() => void` | Click handler |
188+
| `component` | `ComponentType` | Custom React component |
189+
| `priority` | `number` | Sort order -- higher values appear first |
190+
| `sectionLabel` | `string` | Groups items under a shared heading |
191+
| `sectionLink` / `sectionLinkLabel` | `string` | Optional link in the section heading |
192+
193+
## Registering extensions in your plugin
194+
195+
Include your extensions in `createFrontendPlugin`. They are automatically picked up when the plugin is added to the app.
196+
197+
```typescript
198+
import { createFrontendPlugin } from '@backstage/frontend-plugin-api';
199+
import {
200+
GlobalHeaderComponentBlueprint,
201+
GlobalHeaderMenuItemBlueprint,
202+
} from '@red-hat-developer-hub/backstage-plugin-global-header/alpha';
203+
204+
export default createFrontendPlugin({
205+
pluginId: 'my-plugin',
206+
extensions: [
207+
GlobalHeaderComponentBlueprint.make({
208+
name: 'launch-button',
209+
params: {
210+
icon: 'rocket',
211+
title: 'Launch',
212+
link: '/launch',
213+
priority: 75,
214+
},
215+
}),
216+
GlobalHeaderMenuItemBlueprint.make({
217+
name: 'faq-link',
218+
params: {
219+
target: 'help',
220+
title: 'FAQ',
221+
link: '/faq',
222+
icon: 'help',
223+
priority: 50,
224+
},
225+
}),
226+
],
227+
});
228+
```
229+
230+
## Add items from app-config.yaml
231+
232+
Deployers can add toolbar buttons and dropdown menu items directly in `app-config.yaml` without writing plugin code.
233+
234+
### Toolbar components
235+
236+
Each entry renders an icon button in the header bar.
237+
238+
```yaml
239+
globalHeader:
240+
components:
241+
- title: Dashboard
242+
icon: dashboard
243+
link: /dashboard
244+
tooltip: Open dashboard
245+
priority: 75
246+
```
247+
248+
`title`, `icon`, and `link` are required. Optional fields: `titleKey`, `tooltip`, `priority`.
249+
250+
### Menu items
251+
252+
Each entry is injected into the dropdown identified by `target`.
253+
254+
```yaml
255+
globalHeader:
256+
menuItems:
257+
- target: app-launcher
258+
title: Internal Wiki
259+
icon: article
260+
link: https://wiki.internal.example.com
261+
sectionLabel: Resources
262+
priority: 80
263+
```
264+
265+
`target`, `title`, and `link` are required. Optional fields: `titleKey`, `icon`, `sectionLabel`, `sectionLink`, `sectionLinkLabel`, `priority`.
266+
267+
## Customize defaults
268+
269+
Every default extension can be reconfigured, reordered, or disabled via `app-config.yaml`. Extension IDs follow the pattern `<kind>:<plugin-id>/<name>`.
270+
271+
```yaml
272+
app:
273+
extensions:
274+
# Change the position of the search bar
275+
- gh-component:global-header/search:
276+
config:
277+
priority: 50
278+
279+
# Remove notifications
280+
- gh-component:global-header/notification-button:
281+
disabled: true
282+
283+
# Change a menu item's title and link
284+
- gh-menu-item:global-header/app-launcher-devhub:
285+
config:
286+
title: Custom Title
287+
link: https://custom.example.com
288+
```
289+
290+
### Default toolbar components
291+
292+
Extension ID pattern: `gh-component:global-header/<name>`
293+
294+
| Name | Priority | Description |
295+
| ----------------------- | -------- | ---------------------------- |
296+
| `company-logo` | 200 | Company logo |
297+
| `search` | 100 | Search field |
298+
| `spacer` | 99 | Flexible spacer |
299+
| `self-service-button` | 90 | Create / self-service button |
300+
| `starred-dropdown` | 85 | Starred entities dropdown |
301+
| `app-launcher-dropdown` | 82 | Application launcher |
302+
| `help-dropdown` | 80 | Help / support dropdown |
303+
| `notification-button` | 70 | Notifications indicator |
304+
| `divider` | 50 | Vertical divider |
305+
| `profile-dropdown` | 10 | User profile dropdown |
306+
307+
### Default menu items
308+
309+
Extension ID pattern: `gh-menu-item:global-header/<name>`
310+
311+
| Name | Target | Priority |
312+
| ------------------------- | -------------- | -------- |
313+
| `settings` | `profile` | 100 |
314+
| `my-profile` | `profile` | 90 |
315+
| `logout` | `profile` | 10 |
316+
| `support-button` | `help` | 10 |
317+
| `app-launcher-devhub` | `app-launcher` | 150 |
318+
| `app-launcher-rhdh-local` | `app-launcher` | 100 |
319+
320+
## Advanced: building blocks and hooks
321+
322+
For plugin authors building custom toolbar components or dropdowns, the plugin exports lower-level building blocks and React hooks:
323+
324+
**Building-block components** (consistent styling without starting from scratch):
325+
326+
| Component | Key props | Purpose |
327+
| ------------------------ | ------------------------- | ---------------------------------------------------------------------------- |
328+
| `GlobalHeaderIconButton` | `title`, `icon`, `to` | Icon button that navigates to a URL |
329+
| `GlobalHeaderMenuItem` | `to`, `title`, `icon` | Styled menu item link |
330+
| `GlobalHeaderDropdown` | `target`, `buttonContent` | Dropdown that auto-collects `gh-menu-item` extensions for the given `target` |
331+
332+
**Context hooks** (direct access to collected extension data):
333+
334+
| Hook | Returns |
335+
| ---------------------------------- | ------------------------------------------ |
336+
| `useGlobalHeaderComponents()` | All toolbar components, sorted by priority |
337+
| `useGlobalHeaderMenuItems(target)` | Menu items for a specific dropdown target |
338+
339+
**Translations:** Use `titleKey` / `subTitleKey` for i18n. Keys containing dots (e.g. `'applicationLauncher.sections.documentation'`) are auto-resolved. The plugin exports `globalHeaderTranslationRef` and `globalHeaderTranslations` for overrides.
340+
341+
All exports are available from `@red-hat-developer-hub/backstage-plugin-global-header/alpha`.

0 commit comments

Comments
 (0)