docs: document new nav content extensibility
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -686,7 +686,7 @@ createApp({
|
||||
|
||||
#### App Root Sidebar
|
||||
|
||||
New apps feature a built-in sidebar extension which is created by using the `NavContentBlueprint` in `src/modules/nav/Sidebar.tsx`. The default implementation of the sidebar in this blueprint will render some items explicitly in different groups, and then render the rest of the items which are the other `NavItem` extensions provided by the system.
|
||||
New apps feature a built-in sidebar extension which is created by using the `NavContentBlueprint` in `src/modules/nav/Sidebar.tsx`. The default implementation of the sidebar in this blueprint will render some items explicitly in different groups, and then render the rest of the items. Nav items are auto-discovered from page extensions registered under `app/routes` (no explicit `NavItemBlueprint` required), with metadata from page config, nav item extensions, or plugin defaults.
|
||||
|
||||
In order to migrate your existing sidebar, you will want to create an override for the `app/nav` extension. You can do this by copying the standard of having a `src/modules/nav/` folder, which can contain an extension which you can install into the `app` in the form of a `module`.
|
||||
|
||||
@@ -702,38 +702,56 @@ export const navModule = createFrontendModule({
|
||||
|
||||
Then in the actual implementation for the `SidebarContent` extension, you can provide something like the following, where you implement the entire `Sidebar` component.
|
||||
|
||||
The component receives a `navItems` prop with `take(id)` and `rest()` methods for placing specific items in custom positions. Use `navItems.take('page:home')` to take a specific item by extension ID (e.g. for a header slot), and `navItems.rest()` to get all remaining items.
|
||||
|
||||
```tsx title="in packages/app/src/modules/nav/Sidebar.tsx"
|
||||
import { NavContentBlueprint } from '@backstage/plugin-app-react';
|
||||
|
||||
export const SidebarContent = NavContentBlueprint.make({
|
||||
params: {
|
||||
component: ({ items }) => (
|
||||
<Sidebar>
|
||||
<SidebarLogo />
|
||||
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
|
||||
<SidebarSearchModal />
|
||||
</SidebarGroup>
|
||||
<SidebarDivider />
|
||||
<SidebarGroup label="Menu" icon={<MenuIcon />}>
|
||||
...
|
||||
</SidebarGroup>
|
||||
<SidebarGroup label="Plugins">
|
||||
<SidebarScrollWrapper>
|
||||
{/* Items in this group will be scrollable if they run out of space */}
|
||||
{items.map((item, index) => (
|
||||
<SidebarItem {...item} key={index} />
|
||||
))}
|
||||
</SidebarScrollWrapper>
|
||||
</SidebarGroup>
|
||||
</Sidebar>
|
||||
),
|
||||
component: ({ navItems }) => {
|
||||
// Take specific items for custom placement
|
||||
const home = navItems.take('page:home');
|
||||
// Get all remaining items
|
||||
const rest = navItems.rest();
|
||||
|
||||
return (
|
||||
<Sidebar>
|
||||
<SidebarLogo />
|
||||
{home && (
|
||||
<SidebarItem to={home.href} text={home.title} icon={home.icon} />
|
||||
)}
|
||||
<SidebarGroup label="Search" icon={<SearchIcon />} to="/search">
|
||||
<SidebarSearchModal />
|
||||
</SidebarGroup>
|
||||
<SidebarDivider />
|
||||
<SidebarGroup label="Menu" icon={<MenuIcon />}>
|
||||
...
|
||||
</SidebarGroup>
|
||||
<SidebarGroup label="Plugins">
|
||||
<SidebarScrollWrapper>
|
||||
{rest.map(item => (
|
||||
<SidebarItem
|
||||
key={item.node.spec.id}
|
||||
to={item.href}
|
||||
text={item.title}
|
||||
icon={item.icon}
|
||||
/>
|
||||
))}
|
||||
</SidebarScrollWrapper>
|
||||
</SidebarGroup>
|
||||
</Sidebar>
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The `items` property is a list of all extensions provided by the `NavItemBlueprint` that are currently installed in the App. If you don't want to auto populate this list you can simply remove the rendering of that `SidebarGroup`, but otherwise you can see from the above example how a `SidebarItem` element is rendered for each of the items in the list.
|
||||
The deprecated `items` prop (a flat list compatible with `<SidebarItem {...item} />`) remains supported for backward compatibility. If you don't want to auto-populate the list, simply remove the rendering of that `SidebarGroup`.
|
||||
|
||||
You might also notice that when you're rendering additional fixed icons for plugins that these might become duplicated as the plugin provides a `NavItem` extension and you're also rendering one in the `Sidebar` manually. In order to remove the item from the list of `items` which is passed through, we recommend that you disable that extension using config:
|
||||
You might also notice that when you're rendering additional fixed icons for plugins (e.g. Search in a dedicated group) these might become duplicated, since that page is also included in `navItems.rest()`. To exclude an item from the remaining list, use `navItems.take('page:search')` before calling `navItems.rest()`. Items that have been taken will not appear in `rest()`.
|
||||
|
||||
You can also use the old `NavItemBlueprint`-based nav item extensions to disable items from the nav bar, these can be disabled in config without affecting the page itself:
|
||||
|
||||
```yaml title="in app-config.yaml"
|
||||
app:
|
||||
@@ -742,15 +760,6 @@ app:
|
||||
- nav-item:catalog: false
|
||||
```
|
||||
|
||||
You can also determine the order of the provided auto installed `NavItems` that you get from the system in config. The below example ensures that the `catalog` navigation item will proceed the `search` navigation item when being passed through as the `item` prop.
|
||||
|
||||
```yaml title="in app-config.yaml"
|
||||
app:
|
||||
extensions:
|
||||
- nav-item:catalog
|
||||
- nav-item:search
|
||||
```
|
||||
|
||||
#### App Root Routes
|
||||
|
||||
Your top-level routes are the routes directly under the `AppRouter` component with the `<FlatRoutes>` element. In a small app they might look something like this:
|
||||
|
||||
Reference in New Issue
Block a user