このコンテンツは選択した言語では利用できません。
Chapter 5. Front-end plugin wiring
You can configure front-end plugins to customize icons, integrate components at mount points, and provide or replace utility APIs.
5.1. Extending internal icon catalog リンクのコピーリンクがクリップボードにコピーされました!
You can use the internal catalog to fetch icons for configured routes with sidebar navigation menu entry.
Procedure
-
Add a custom icon to the internal icon catalog for use in the menu item of a plugin by using the
appIconsconfiguration as shown in the following example:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
appIcons:
- name: fooIcon # The icon catalog name
# (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module.
module: CustomModule
# (Optional): The actual component name to be rendered as a standalone page. If not specified, the system uses the `default` export.
importName: FooIcon
The package_name key under dynamicPlugins.frontend must match the scalprum.name value in your plugin’s package.json. This ensures your dynamic plugin loads correctly during runtime.
5.2. Defining dynamic routes for new plugin pages リンクのコピーリンクがクリップボードにコピーされました!
Procedure
-
Define each route by specifying a unique
pathand, if needed, animportNameif it is different from thedefaultexport. Expose additional routes in a dynamic plugin by configuring
dynamicRoutesas shown in the following example:# dynamic-plugins-config.yaml plugins: - plugin: <plugin_path_or_url> disabled: false pluginConfig: dynamicPlugins: frontend: my-plugin: # The plugin package name dynamicRoutes: # The unique path in the application. The path cannot override existing routes except the `/` home route. - path: /my-plugin # (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module. module: CustomModule # (Optional): The component name as a standalone page. If not specified, the system uses the `default` export. importName: FooPluginPage # Allows you to extend the main sidebar navigation and point to a new route. menuItem: icon: fooIcon text: Foo Plugin Page enabled: false config: # (Optional): Passes `props` to a custom sidebar item props: ...The
menuItemaccepts the following properties:-
text: The label shown to the user. -
icon: The Backstage system icon name. -
enabled: Optional: Allows the user to remove a menuItem from the sidebar when it is set to false. importName: Specifies the optional name of an exportedSidebarItemcomponent.To configure a custom
SidebarItemto enhance experiences such as notification badges, ensure the component accepts the following properties:
-
export type MySidebarItemProps = {
to: string; // supplied by the sidebar during rendering, this will be the path configured for the dynamicRoute
};
Example specifying a custom SidebarItem component:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-dynamic-plugin-package-name:
dynamicRoutes:
- importName: CustomPage
menuItem:
config:
props:
text: Click Me!
importName: SimpleSidebarItem
path: /custom_page
5.4. Binding to existing plugins リンクのコピーリンクがクリップボードにコピーされました!
You can bind to existing plugins and their routes, and declare new targets sourced from dynamic plugins as shown in the following routeBindings configuration:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
routeBindings:
targets: # A new bind target
# (Optional): Defaults to importName. Explicit name of the plugin that exposes the bind target.
- name: barPlugin
# (Required): Explicit import name that reference a BackstagePlugin<{}> implementation.
importName: barPlugin
# # (Optional): Same as key in `scalprum.exposedModules` key in the `package.json` file of the plugin.
module: CustomModule
bindings:
- bindTarget: "barPlugin.externalRoutes" # (Required): One of the supported or imported bind targets
bindMap: # A required map of route bindings similar to `bind` function options
headerLink: "fooPlugin.routes.root"
To configure routeBindings, complete the following steps:
-
Define new targets using
routeBindings.targets. Set the requiredimportNameto aBackstagePlugin<{}>implementation. Declare route bindings using the routeBindings.bindings field by setting
bindTargetto the name of the target to bind to. This is a dynamic or static target, such as:-
catalogPlugin.externalRoutes -
catalogImportPlugin.externalRoutes -
techdocsPlugin.externalRoutes scaffolderPlugin.externalRoutesYou can extend existing pages with additional content using mount points, which are predefined identifiers available throughout the application.
-
5.5. Using mount points リンクのコピーリンクがクリップボードにコピーされました!
Mount points are defined identifiers available across Red Hat Developer Hub. You can use these points to extend existing pages with additional content.
5.5.1. Customizing entity page リンクのコピーリンクがクリップボードにコピーされました!
You can extend catalog components and additional views.
The available mount points include the following:
| Mount point | Description | Visible even when no plugins are enabled |
|---|---|---|
|
| Administration plugins page | NO |
|
| Administration RBAC page | NO |
|
| Catalog entity context menu | YES for all entities |
|
| Catalog entity overview page | YES for all entities |
|
| Catalog entity Topology tab | NO |
|
| Catalog entity Issues tab | NO |
|
| Catalog entity Pull Requests tab | NO |
|
| Catalog entity CI tab | NO |
|
| Catalog entity CD tab | NO |
|
| Catalog entity Kubernetes tab | NO |
|
| Catalog entity Image Registry tab | NO |
|
| Catalog entity Monitoring tab | NO |
|
| Catalog entity Lighthouse tab | NO |
|
| Catalog entity API tab |
YES for entity of |
|
| Catalog entity Dependencies tab |
YES for entity of |
|
| Catalog entity Documentation tab |
YES for entity that satisfies |
|
| Catalog entity Definitions tab |
YES for entity of |
|
| Catalog entity Diagram tab |
YES for entity of |
|
| Search result type | YES, default catalog search type is available |
|
| Search filters | YES, default catalog kind and lifecycle filters are visible |
|
| Search results content | YES, default catalog search is present |
Mount points within catalog such as entity.page. are rendered as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.
Each entity.page. mount point contains the following variations:
-
/contexttype that serves to create React contexts -
/cardstype for regular React components
The following is an example of the overall configuration structure of a mount point:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
mountPoints: # (Optional): Uses existing mount points
- mountPoint: <mountPointName>/[cards|context]
module: CustomModule
importName: FooPluginPage
config: # (Optional): Allows you to pass additional configuration to the component
layout: {} # Used only in `/cards` type which renders visible content
# Use only in `/cards` type which renders visible content. `if` is passed to `<EntitySwitch.Case if={<here>}`.
if:
allOf|anyOf|oneOf:
- isMyPluginAvailable
- isKind: component
- isType: service
- hasAnnotation: annotationKey
props: {} # Useful when you are passing additional data to the component
The available conditions include:
-
allOf: All conditions must be met -
anyOf: At least one condition must be met -
oneOf: Only one condition must be met
Conditions are:
-
isKind: Accepts a string or a list of string with entity kinds. For exampleisKind: componentrenders the component only for entity ofkind: Component. -
isType: Accepts a string or a list of string with entity types. For exampleisType: servicerenders the component only for entities ofspec.type: 'service'. -
hasAnnotation: Accepts a string or a list of string with annotation keys. For examplehasAnnotation: my-annotationrenders the component only for entities that have definedmetadata.annotations['my-annotation']. -
Condition imported from the
moduleof the plugin: Must be function name exported from the samemodulewithin the plugin. For exampleisMyPluginAvailablerenders the component only ifisMyPluginAvailablefunction returnstrue. The function must have the following signature:(e: Entity) ⇒ boolean.
The entity page supports adding more items to the context menu at the top right of the page. The exported component is a form of dialog wrapper component that accepts an open boolean property and an onClose event handler property as shown in the following example:
export type SimpleDialogProps = {
open: boolean;
onClose: () => void;
};
You can configure the context menu entry using the props configuration entry for the mount point. The title and icon properties sets the text and icon of the menu item. You can use any system icon or icon added through a dynamic plugin. The following is an example configuration:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-dynamic-plugin-package:
appIcons:
- name: dialogIcon
importName: DialogIcon
mountPoints:
- mountPoint: entity.context.menu
importName: SimpleDialog
config:
props:
title: Open Simple Dialog
icon: dialogIcon
5.5.2. Adding application header リンクのコピーリンクがクリップボードにコピーされました!
You can customize global headers by specifying configurations in the app-config.yaml file as shown in the following example:
# app-config.yaml
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
mountPoints:
- mountPoint: application/header # Adds the header as a global header
importName: <header_component> # Specifies the component exported by the global header plugin
config:
position: above-main-content # Supported values: (`above-main-content`| above-sidebar`)
To configure multiple global headers at different positions, add entries to the mountPoints field.
5.5.3. Adding application listeners リンクのコピーリンクがクリップボードにコピーされました!
You can add application listeners using the application/listener mount point as shown in the following example:
# app-config.yaml
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
mountPoints:
- mountPoint: application/listener
importName: <exported listener component>
You can configure multiple application listeners by adding entries to the mountPoints field.
5.5.4. Adding application providers リンクのコピーリンクがクリップボードにコピーされました!
You can add application providers using the application/provider mount point. You can use a mount point to configure a context provider as shown in the following example:
# app-config.yaml
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
dynamicRoutes:
- path: /<route>
importName: Component # The component to load on the route
mountPoints:
- mountPoint: application/provider
importName: <exported provider component>
-
You can configure multiple application providers by adding entries to the
mountPointsfield. -
The
package_namekey underdynamicPlugins.frontendmust match thescalprum.namevalue in thepackage.jsonfile of your plugin. This ensures your dynamic plugin loads correctly at runtime.
5.6. Customizing and extending entity tabs リンクのコピーリンクがクリップボードにコピーされました!
You can customize and extend the set of tabs using the entityTabs configuration as follows:
# dynamic-plugins-config.yaml
plugins:
- plugin: <plugin_path_or_url>
disabled: false
pluginConfig:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
entityTabs:
# Specify a new tab
- path: /new-path
title: My New Tab
mountPoint: entity.page.my-new-tab
# Change an existing tab's title or mount point
- path: /
title: General
mountPoint: entity.page.overview
# Specify the sub-path route in the catalog where this tab is available
- path: "/pr"
title: "Changed Pull/Merge Requests" # Specify the title you want to display
priority: 1
# The base mount point name available on the tab. This name expands to create two mount points per tab, with` /context` and with `/cards`
mountPoint: "entity.page.pull-requests"
- path: "/"
title: "Changed Overview"
mountPoint: "entity.page.overview"
# Specify the order of tabs. The tabs with higher priority values appear first
priority: -6
You can configure dynamic front-end plugins to target the mount points exposed by the entityTabs configuration. The following are the default catalog entity routes in the default order:
| Route | Title | Mount Point | Entity Kind |
|---|---|---|---|
|
| Overview |
| Any |
|
| Topology |
| Any |
|
| Issues |
| Any |
|
| CPull/Merge Requests |
| Any |
|
| CI |
| VAny |
|
| CD |
| Any |
|
| Kubernetes |
| Any |
|
| Image Registry |
| Any |
|
| Monitoring |
| Any |
|
| Lighthouse |
| Any |
|
| Api |
| kind: Service or kind: Component |
|
| Dependencies |
| kind: Component |
|
| Docs |
| Any |
|
| Definition |
| kind: API |
|
| Diagram |
| kind: System |
Mount points within Catalog such as `entity.page.*` are rendered as tabs and become visible only if at least one plugin contributes to them, or if they can render static content.
5.7. Using a custom SignInPage component リンクのコピーリンクがクリップボードにコピーされました!
In Red Hat Developer Hub (RHDH), the SignInPage component manages the authentication flow of the application. This component connects one or more authentication providers to the sign-in process. By default, Developer Hub uses a static SignInPage that supports all built-in authentication providers.
When you configure a custom SignInPage:
-
The system loads the specified
importNamecomponent from your dynamic plugin. -
The component returns a configured
SignInPagethat connects the desired authentication provider factories. -
Only one
signInPageis specified for the application at a time.
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
signInPage:
importName: CustomSignInPage
The package_name specified under dynamicPlugins.frontend must match the scalprum.name value in the package.json file of your plugin to ensure the dynamic plugin loads correctly at runtime.
The module field is optional and allows specifying which set of assets must be accessed within the dynamic plugin. By default, the system uses the PluginRoot module.
5.8. Providing custom Scaffolder field extensions リンクのコピーリンクがクリップボードにコピーされました!
The Scaffolder component in Red Hat Developer Hub (RHDH) enables users to create software components using templates through a guided wizard. You can extend the functionality of the Scaffolder by providing custom form fields as dynamic plugins using the scaffolderFieldExtensions configuration.
Custom field extensions allow you to add specialized form fields that capture domain-specific data during the scaffolding process, such as environment selectors, input validations, or repository checks.
When you configure custom scaffolder field extensions:
-
The dynamic plugin exposes the field extension component using
createScaffolderFieldExtension. -
Each field extension requires a unique
importNamefor registration. - You register multiple field extensions by listing each in the configuration.
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
scaffolderFieldExtensions:
- importName: MyNewFieldExtension # References the exported scaffolder field extension component from your plugin
The module field is optional and specifies which set of assets to access within the plugin. By default, the system uses the PluginRoot module, consistent with the scalprum.exposedModules key in the package.json file of your package.
5.9. Provide additional utility APIs リンクのコピーリンクがクリップボードにコピーされました!
If a dynamic plugin exports the plugin object returned by createPlugin, it is supplied to the createApp API. All API factories exported by the plugin are automatically registered and available in the front-end application.
You can add an entry to the dynamicPlugins.frontend configuration when a dynamic plugin contains only API factories as shown in the following example:
# app-config.yaml
dynamicPlugins:
frontend:
my-dynamic-plugin-package-with-api-factories: {}
However, when the dynamic plugin is not exporting the plugin object, explicitly configure each API factory that must be registered with the createApp API using the apiFactories configuration as shown in the following example:
# app-config.yaml
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
apiFactories:
# (Optional): Specify the import name that references a `AnyApiFactory<{}>` implementation. (Defaults to `default` export)
- importName: BarApi
# (Optional): An argument which specifies the assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used
module: CustomModule
The API factories initialized by the Developer Hub application shell are overridden by an API factory provided by a dynamic plugin by specifying the same API ref ID. A dynamic plugin can export AnyApiFactory<{}> to cater for some specific use case as shown in the following example:
export const customScmAuthApiFactory = createApiFactory({
api: scmAuthApiRef,
deps: { githubAuthApi: githubAuthApiRef },
factory: ({ githubAuthApi }) =>
ScmAuth.merge(
ScmAuth.forGithub(githubAuthApi, { host: "github.someinstance.com" }),
ScmAuth.forGithub(githubAuthApi, {
host: "github.someotherinstance.com",
}),
),
});
The corresponding configuration which overrides the default ScmAuth API factory that Developer Hub defaults to is as shown in the following example:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
apiFactories:
- importName: customScmAuthApiFactory
5.10. Adding custom authentication provider settings リンクのコピーリンクがクリップボードにコピーされました!
You can install new authentication providers from a dynamic plugin that either adds additional configuration support for an existing provider or adds a new authentication provider. These providers are listed in the user settings section under the Authentication Providers tab.
You can use the providerSettings configuration to add entries for an authentication provider from a dynamic plugin, as shown in the following example:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
providerSettings:
# The title for the authentication provider shown above the user's profile image if available
- title: My Custom Auth Provider
# The description of the authentication provider
description: Sign in using My Custom Auth Provider
# The ID of the authentication provider as provided to the `createApiRef` API call.
provider: core.auth.my-custom-auth-provider
provider looks up the corresponding API factory for the authentication provider to connect the provider’s Sign In/Sign Out button.
5.11. Provide custom TechDocs addons リンクのコピーリンクがクリップボードにコピーされました!
If a plugin provides multiple addons, each techdocsAddon entry specifies a unique importName corresponding to the addon. Front-end plugins exposes the TechDocs addon component using the techdocsAddons configuration as shown in the following example:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
techdocsAddons:
- importName: ExampleAddon # The exported Addon component
config:
props: ... # (Optional): React props to pass to the addon
5.12. Customizing Red Hat Developer Hub theme リンクのコピーリンクがクリップボードにコピーされました!
You can customize Developer Hub themes from a dynamic plugin with various configurations as shown in the following example:
import { lightTheme } from './lightTheme';
import { darkTheme } from './darkTheme';
import { UnifiedThemeProvider } from '@backstage/theme';
export const lightThemeProvider = ({ children }: { children: ReactNode }) => (
<UnifiedThemeProvider theme={lightTheme} children={children} />
);
export const darkThemeProvider = ({ children }: { children: ReactNode }) => (
<UnifiedThemeProvider theme={darkTheme} children={children} />
);
For more information about creating a custom theme, see creating a custom theme.
You can declare the theme using the themes configuration as shown in the following example:
dynamicPlugins:
frontend:
my-plugin: # The plugin package name
themes:
# are `light` or `dark`. Using 'light' overrides the app-provided light theme
- id: light
title: Light
variant: light
icon: someIconReference
importName: lightThemeProvider
# The theme name displayed to the user on the *Settings* page. Using 'dark' overrides the app-provided dark theme
- id: dark
title: Dark
variant: dark
icon: someIconReference # A string reference to a system or app icon
# The name of the exported theme provider function, the function signature should match `({ children }: { children: ReactNode }): React.JSX.Element`
importName: darkThemeProvider