Merge pull request #34299 from backstage/rugvip/nav-item-gone
frontend-plugin-api: remove NavItemBlueprint
This commit is contained in:
@@ -60,7 +60,7 @@ Even with feature discovery enabled, you can disable specific extensions via con
|
||||
app:
|
||||
extensions:
|
||||
- page:techdocs: false
|
||||
- nav-item:search: false
|
||||
- page:search: false
|
||||
```
|
||||
|
||||
### How Discovery Works with Manual Imports
|
||||
|
||||
@@ -882,8 +882,7 @@ import { CheckboxGroup, Checkbox } from '@backstage/ui';
|
||||
|
||||
Some Backstage APIs still require MUI-compatible icon types:
|
||||
|
||||
- **NavItemBlueprint** (`@backstage/frontend-plugin-api`): The `icon` prop expects MUI `IconComponent` type. Remix icons
|
||||
are not type-compatible.
|
||||
- **PageBlueprint** (`@backstage/frontend-plugin-api`): The `icon` param on page extensions expects an `IconElement`. MUI icon components can still be used via `<Icon fontSize="inherit" />`.
|
||||
- **Timeline** (`@material-ui/lab`): No BUI equivalent exists.
|
||||
|
||||
For these cases, keep using MUI components.
|
||||
|
||||
@@ -52,16 +52,15 @@ _Example disabling the search page extension_
|
||||
app:
|
||||
extensions:
|
||||
- page:search: false # ✨
|
||||
- nav-item:search: false # ✨
|
||||
```
|
||||
|
||||
_Example setting the search sidebar item title_
|
||||
_Example setting the search page title (used in the sidebar)_
|
||||
|
||||
```yaml
|
||||
# app-config.yaml
|
||||
app:
|
||||
extensions:
|
||||
- nav-item:search: # ✨
|
||||
- page:search: # ✨
|
||||
config:
|
||||
title: 'Search Page'
|
||||
```
|
||||
|
||||
@@ -129,26 +129,20 @@ A plugin might not always behave exactly the way you want. It could be that you
|
||||
|
||||
```tsx
|
||||
import plugin from '@backstage/plugin-catalog';
|
||||
import { PageBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { RiLayoutGridLine } from '@remixicon/react';
|
||||
|
||||
export default plugin.withOverrides({
|
||||
// These overrides are merged with the original extensions
|
||||
extensions: [
|
||||
// Override the catalog nav item to use a custom icon
|
||||
plugin.getExtension('nav-item:catalog').override({
|
||||
factory: origFactory => [
|
||||
NavItemBlueprint.dataRefs.target({
|
||||
...origFactory().get(NavItemBlueprint.dataRefs.target),
|
||||
icon: CustomCatalogIcon,
|
||||
// Override the catalog index page with a custom icon and implementation
|
||||
plugin.getExtension('page:catalog').override({
|
||||
factory: origFactory =>
|
||||
origFactory({
|
||||
icon: <RiLayoutGridLine />,
|
||||
loader: () =>
|
||||
import('./CustomCatalogIndexPage').then(m => <m.Page />),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
// Override the catalog index page with a completely custom implementation
|
||||
PageBlueprint.make({
|
||||
params: {
|
||||
path: '/catalog',
|
||||
routeRef: plugin.routes.catalogIndex,
|
||||
loader: () => import('./CustomCatalogIndexPage').then(m => <m.Page />),
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -164,7 +164,6 @@ Extension responsible for rendering the logo and items in the app's sidebar.
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| content | Overrides the default content of the navbar. | [NavContentBlueprint.dataRefs.component](https://backstage.io/api/stable/variables/_backstage_plugin-app-react.NavContentBlueprint.html) | true | - | [NavContentBlueprint](https://backstage.io/api/stable/variables/_backstage_plugin-app-react.NavContentBlueprint.html) |
|
||||
| items | Nav items target objects. | [createNavItemExtension.targetDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createnavitemextension.targetdataref) | true | - | [createNavItemExtension](https://backstage.io/docs/reference/frontend-plugin-api.createnavitemextension) |
|
||||
|
||||
### App routes
|
||||
|
||||
|
||||
@@ -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. 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.
|
||||
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`, with metadata from page config 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`.
|
||||
|
||||
@@ -740,14 +740,7 @@ The deprecated `items` prop (a flat list compatible with `<SidebarItem {...item}
|
||||
|
||||
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 `nav.rest()`. To exclude an item from the remaining list, call `nav.take('page:search')` before calling `nav.rest()` — you can discard the return value. 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:
|
||||
extensions:
|
||||
- nav-item:search: false
|
||||
- nav-item:catalog: false
|
||||
```
|
||||
To hide a page from the sidebar without disabling the page itself, use `nav.take('page:...')` in your custom sidebar implementation before calling `nav.rest()`, or disable the page extension in config with `page:<plugin-id>: false`.
|
||||
|
||||
#### App Root Routes
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ The plugin ID should be a lowercase dash-separated string, while the plugin inst
|
||||
|
||||
## Adding extensions
|
||||
|
||||
The plugin that we created above is empty, and doesn't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/20-extensions.md). Let's continue by adding a standalone page to our plugin, as well as a navigation item that allows users to navigate to the page.
|
||||
The plugin that we created above is empty, and doesn't provide any actual functionality. To add functionality to a plugin you need to create and provide it with one or more [extensions](../architecture/20-extensions.md). Let's continue by adding a standalone page to our plugin, with a title and icon that appear in the app sidebar.
|
||||
|
||||
To create a new extension you typically use pre-defined [extension blueprints](../architecture/23-extension-blueprints.md), provided either by the framework itself or by other plugins. In this case we'll use `PageBlueprint` and `NavItemBlueprint`, both from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for our page, allowing us to dynamically create URLs that link to our page.
|
||||
To create a new extension you typically use pre-defined [extension blueprints](../architecture/23-extension-blueprints.md), provided either by the framework itself or by other plugins. In this case we'll use `PageBlueprint` from `@backstage/frontend-plugin-api`. We will also need to [create a route reference](../architecture/36-routes.md#creating-a-route-reference) to use as a reference for our page, allowing us to dynamically create URLs that link to our page.
|
||||
|
||||
```tsx title="in src/routes.ts"
|
||||
import { createRouteRef } from '@backstage/frontend-plugin-api';
|
||||
@@ -62,8 +62,8 @@ export const rootRouteRef = createRouteRef();
|
||||
import {
|
||||
createFrontendPlugin,
|
||||
PageBlueprint,
|
||||
NavItemBlueprint,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { RiPuzzleLine } from '@remixicon/react';
|
||||
import { rootRouteRef } from './routes';
|
||||
|
||||
// Note that these extensions aren't exported, only the plugin itself is.
|
||||
@@ -75,6 +75,10 @@ const examplePage = PageBlueprint.make({
|
||||
// This is the default path of this page, but integrators are free to override it
|
||||
path: '/example',
|
||||
|
||||
// The title and icon are used to populate the app sidebar automatically
|
||||
title: 'Example',
|
||||
icon: <RiPuzzleLine />,
|
||||
|
||||
// Page extensions are always dynamically loaded using React.lazy().
|
||||
// All of the functionality of this page is implemented in the
|
||||
// ExamplePage component, which is a regular React component.
|
||||
@@ -84,19 +88,10 @@ const examplePage = PageBlueprint.make({
|
||||
},
|
||||
});
|
||||
|
||||
// This nav item is provided to the app.nav extension, and will by default be rendered as a sidebar item
|
||||
const exampleNavItem = NavItemBlueprint.make({
|
||||
params: {
|
||||
routeRef: rootRouteRef,
|
||||
title: 'Example',
|
||||
icon: ExampleIcon, // Custom SvgIcon, or one from the Material UI icon library
|
||||
},
|
||||
});
|
||||
|
||||
// The same plugin as above, now with the extensions added
|
||||
export const examplePlugin = createFrontendPlugin({
|
||||
pluginId: 'example',
|
||||
extensions: [examplePage, exampleNavItem],
|
||||
extensions: [examplePage],
|
||||
// We can also make routes available to other plugins.
|
||||
// highlight-start
|
||||
routes: {
|
||||
@@ -106,7 +101,7 @@ export const examplePlugin = createFrontendPlugin({
|
||||
});
|
||||
```
|
||||
|
||||
What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, along with a method for navigating to that page. The implementation of the page component, in this case the highlighted `ExamplePage`, can be arbitrarily complex. It can be anything from a single simple information page, to a full-blown application with multiple sub-pages.
|
||||
What we've built here is a very common type of plugin. It's a top-level tool that provides a single page, which the app discovers and links to from the sidebar automatically. The implementation of the page component, in this case the highlighted `ExamplePage`, can be arbitrarily complex. It can be anything from a single simple information page, to a full-blown application with multiple sub-pages.
|
||||
|
||||
We have also provided external access to our route reference by passing it to the plugin `routes` option. This makes it possible for app integrators to bind an external link from a different plugin to our plugin page. You can read more about how this works in the [External Route References](../architecture/36-routes.md#external-route-references) section.
|
||||
|
||||
@@ -182,7 +177,7 @@ const exampleApi = ApiBlueprint.make({
|
||||
});
|
||||
// highlight-add-end
|
||||
|
||||
/* Omitted definitions for examplePage, exampleNavItem, and rootRouteRef. */
|
||||
/* Omitted definitions for examplePage and rootRouteRef. */
|
||||
|
||||
export const examplePlugin = createFrontendPlugin({
|
||||
pluginId: 'example',
|
||||
@@ -190,7 +185,6 @@ export const examplePlugin = createFrontendPlugin({
|
||||
// highlight-add-next-line
|
||||
exampleApi,
|
||||
examplePage,
|
||||
exampleNavItem,
|
||||
],
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
@@ -227,7 +221,6 @@ export const examplePlugin = createFrontendPlugin({
|
||||
exampleEntityContent,
|
||||
exampleApi,
|
||||
examplePage,
|
||||
exampleNavItem,
|
||||
],
|
||||
routes: {
|
||||
root: rootRouteRef,
|
||||
|
||||
@@ -15,10 +15,6 @@ These are the [extension blueprints](../architecture/23-extension-blueprints.md)
|
||||
|
||||
An API extension is used to add or override [Utility API factories](../utility-apis/01-index.md) in the app. They are commonly used by plugins for both internal and shared APIs. There are also many built-in Api extensions provided by the framework that you are able to override.
|
||||
|
||||
### NavItem (deprecated) - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.index.NavItemBlueprint.html)
|
||||
|
||||
The `NavItemBlueprint` is deprecated. The app now auto-discovers navigation items from page extensions, so explicit nav item extensions are no longer needed. To migrate, ensure your plugin and/or page extensions have a `title` and `icon` set — these are used to populate the sidebar automatically.
|
||||
|
||||
### Page - [Reference](https://backstage.io/api/stable/variables/_backstage_frontend-plugin-api.index.PageBlueprint.html)
|
||||
|
||||
Page extensions provide content for a particular route in the app. By default pages are attached to the app routes extensions, which renders the root routes. Pages automatically inherit the plugin's `title` and `icon` as defaults, which can be overridden per-page via `PageBlueprint` params.
|
||||
|
||||
Reference in New Issue
Block a user