Installing and viewing plugins in Red Hat Developer Hub
Installing plugins in Red Hat Developer Hub
Abstract
- 1. Installing dynamic plugins in Red Hat Developer Hub
- 2. Third-party plugins in Red Hat Developer Hub
- 3. Enabling plugins added in the RHDH container image
- 4. Extensions in Red Hat Developer Hub
- 5. Front-end plugin wiring
- 5.1. Extending internal icon catalog
- 5.2. Defining dynamic routes for new plugin pages
- 5.3. Customizing menu items in the sidebar navigation
- 5.4. Binding to existing plugins
- 5.5. Using mount points
- 5.6. Customizing and extending entity tabs
- 5.7. Using a custom SignInPage component
- 5.8. Providing custom Scaffolder field extensions
- 5.9. Provide additional utility APIs
- 5.10. Adding custom authentication provider settings
- 5.11. Provide custom TechDocs addons
- 5.12. Customizing Red Hat Developer Hub theme
1. Installing dynamic plugins in Red Hat Developer Hub
The dynamic plugin support is based on the backend plugin manager package, which is a service that scans a configured root directory (dynamicPlugins.rootDirectory
in the app-config.yaml
file) for dynamic plugin packages and loads them dynamically.
You can use the dynamic plugins that come preinstalled with Red Hat Developer Hub or install external dynamic plugins from a public NPM registry.
1.1. Installing dynamic plugins with the Red Hat Developer Hub Operator
You can store the configuration for dynamic plugins in a ConfigMap
object that your Backstage
custom resource (CR) can reference.
If the pluginConfig
field references environment variables, you must define the variables in your <my_product_secrets>
secret.
Procedure
- From the OpenShift Container Platform web console, select the ConfigMaps tab.
- Click Create ConfigMap.
From the Create ConfigMap page, select the YAML view option in Configure via and edit the file, if needed.
Example
ConfigMap
object using the GitHub dynamic pluginkind: ConfigMap apiVersion: v1 metadata: name: dynamic-plugins-rhdh data: dynamic-plugins.yaml: | includes: - dynamic-plugins.default.yaml plugins: - package: './dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic' disabled: false pluginConfig: catalog: providers: github: organization: "${GITHUB_ORG}" schedule: frequency: { minutes: 1 } timeout: { minutes: 1 } initialDelay: { seconds: 100 }
- Click Create.
- Go to the Topology view.
Click on the overflow menu for the Red Hat Developer Hub instance that you want to use and select Edit Backstage to load the YAML view of the Red Hat Developer Hub instance.
Add the
dynamicPluginsConfigMapName
field to yourBackstage
CR. For example:apiVersion: rhdh.redhat.com/v1alpha3 kind: Backstage metadata: name: my-rhdh spec: application: # ... dynamicPluginsConfigMapName: dynamic-plugins-rhdh # ...
- Click Save.
- Navigate back to the Topology view and wait for the Red Hat Developer Hub pod to start.
- Click the Open URL icon to start using the Red Hat Developer Hub platform with the new configuration changes.
Verification
Ensure that the dynamic plugins configuration has been loaded, by appending
/api/dynamic-plugins-info/loaded-plugins
to your Red Hat Developer Hub root URL and checking the list of plugins:Example list of plugins
[ { "name": "backstage-plugin-catalog-backend-module-github-dynamic", "version": "0.5.2", "platform": "node", "role": "backend-plugin-module" }, { "name": "backstage-plugin-techdocs", "version": "1.10.0", "role": "frontend-plugin", "platform": "web" }, { "name": "backstage-plugin-techdocs-backend-dynamic", "version": "1.9.5", "platform": "node", "role": "backend-plugin" }, ]
1.2. Installing dynamic plugins using the Helm chart
You can deploy a Developer Hub instance by using a Helm chart, which is a flexible installation method. With the Helm chart, you can sideload dynamic plugins into your Developer Hub instance without having to recompile your code or rebuild the container.
To install dynamic plugins in Developer Hub using Helm, add the following global.dynamic
parameters in your Helm chart:
plugins
: the dynamic plugins list intended for installation. By default, the list is empty. You can populate the plugins list with the following fields:-
package
: a package specification for the dynamic plugin package that you want to install. You can use a package for either a local or an external dynamic plugin installation. For a local installation, use a path to the local folder containing the dynamic plugin. For an external installation, use a package specification from a public NPM repository. -
integrity
(required for external packages): an integrity checksum in the form of<alg>-<digest>
specific to the package. Supported algorithms includesha256
,sha384
andsha512
. -
pluginConfig
: an optional plugin-specificapp-config.yaml
YAML fragment. See plugin configuration for more information. -
disabled
: disables the dynamic plugin if set totrue
. Default:false
. -
forceDownload
: Set the value totrue
to force a reinstall of the plugin, bypassing the cache. The default value isfalse
. pullPolicy
: Similar to theforceDownload
parameter and is consistent with other image container platforms. You can use one of the following values for this key:-
Always
: This value compares the image digest in the remote registry and downloads the artifact if it has changed, even if the plugin was previously downloaded. IfNotPresent
: This value downloads the artifact if it is not already present in the dynamic-plugins-root folder, without checking image digests.NoteThe
pullPolicy
setting is also applied to the NPM downloading method, althoughAlways
will download the remote artifact without a digest check. The existingforceDownload
option remains functional, however, thepullPolicy
option takes precedence. TheforceDownload
option may be deprecated in a future Developer Hub release.
-
-
-
includes
: a list of YAML files utilizing the same syntax.
The plugins
list in the includes
file is merged with the plugins
list in the main Helm values. If a plugin package is mentioned in both plugins
lists, the plugins
fields in the main Helm values override the plugins
fields in the includes
file. The default configuration includes the dynamic-plugins.default.yaml
file, which contains all of the dynamic plugins preinstalled in Developer Hub, whether enabled or disabled by default.
1.2.1. Example Helm chart configurations for dynamic plugin installations
The following examples demonstrate how to configure the Helm chart for specific types of dynamic plugin installations.
Configuring a local plugin and an external plugin when the external plugin requires a specific configuration
global: dynamic: plugins: - package: <alocal package-spec used by npm pack> - package: <external package-spec used by npm pack> integrity: sha512-<some hash> pluginConfig: ...
Disabling a plugin from an included file
global: dynamic: includes: - dynamic-plugins.default.yaml plugins: - package: <some imported plugins listed in dynamic-plugins.default.yaml> disabled: true
Enabling a plugin from an included file
global: dynamic: includes: - dynamic-plugins.default.yaml plugins: - package: <some imported plugins listed in dynamic-plugins.custom.yaml> disabled: false
Enabling a plugin that is disabled in an included file
global: dynamic: includes: - dynamic-plugins.default.yaml plugins: - package: <some imported plugins listed in dynamic-plugins.custom.yaml> disabled: false
1.3. Installing dynamic plugins in an air-gapped environment
You can install external plugins in an air-gapped environment by setting up a custom NPM registry.
You can configure the NPM registry URL and authentication information for dynamic plugin packages using a Helm chart. For dynamic plugin packages obtained through npm pack
, you can use a .npmrc
file.
Using the Helm chart, add the .npmrc
file to the NPM registry by creating a secret. For example:
apiVersion: v1
kind: Secret
metadata:
name: <release_name>-dynamic-plugins-npmrc
1
type: Opaque
stringData:
.npmrc: |
registry=<registry-url>
//<registry-url>:_authToken=<auth-token>
...
- 1
- Replace
<release_name>
with your Helm release name. This name is a unique identifier for each chart installation in the Kubernetes cluster.
2. Third-party plugins in Red Hat Developer Hub
You can integrate third-party dynamic plugins into Red Hat Developer Hub to enhance its functionality without modifying its source code or rebuilding it. To add these plugins, export them as derived packages.
While exporting the plugin package, you must ensure that dependencies are correctly bundled or marked as shared, depending on their relationship to the Developer Hub environment.
To integrate a third-party plugin into Developer Hub:
- First, obtain the plugin’s source code.
- Export the plugin as a dynamic plugin package. See Section 2.1, “Exporting third-party plugins in Red Hat Developer Hub”.
- Package and publish the dynamic plugin. See Section 2.2, “Packaging and publishing third-party plugins as dynamic plugins”.
- Install the plugin in the Developer Hub environment. See Section 2.3, “Installing third-party plugins in Red Hat Developer Hub”.
2.1. Exporting third-party plugins in Red Hat Developer Hub
To use plugins in Red Hat Developer Hub, you can export plugins as derived dynamic plugin packages. These packages contain the plugin code and dependencies, ready for dynamic plugin integration into Developer Hub.
Prerequisites
-
The
@janus-idp/cli
package is installed. Use the latest version (@latest
tag) for compatibility with the most recent features and fixes. - Node.js and NPM is installed and configured.
- The third-party plugin is compatible with your Red Hat Developer Hub version. For more information, see Version compatibility matrix.
The third-party plugin must have a valid
package.json
file in its root directory, containing all required metadata and dependencies.- Backend plugins
To ensure compatibility with the dynamic plugin support and enable their use as dynamic plugins, existing backend plugins must be compatible with the new Backstage backend system. Additionally, these plugins must be rebuilt using a dedicated CLI command.
The new Backstage backend system entry point (created using
createBackendPlugin()
orcreateBackendModule()
) must be exported as the default export from either the main package or analpha
package (if the plugin instance support is still provided usingalpha
APIs). This doesn’t add any additional requirement on top of the standard plugin development guidelines of the plugin instance.The dynamic export mechanism identifies private dependencies and sets the
bundleDependencies
field in thepackage.json
file. This export mechanism ensures that the dynamic plugin package is published as a self-contained package, with its private dependencies bundled in a privatenode_modules
folder.Certain plugin dependencies require specific handling in the derived packages, such as:
Shared dependencies are provided by the RHDH application and listed as
peerDependencies
inpackage.json
file, not bundled in the dynamic plugin package. For example, by default, all@backstage
scoped packages are shared.You can use the
--shared-package
flag to specify shared dependencies, that are expected to be provided by Red Hat Developer Hub application and not bundled in the dynamic plugin package.To treat a
@backstage
package as private, use the negation prefix (!
). For example, when a plugin depends on the package in@backstage
that is not provided by the Red Hat Developer Hub application.Embedded dependencies are bundled into the dynamic plugin package with their dependencies hoisted to the top level. By default, packages with
-node
or-common
suffixes are embedded.You can use the
--embed-package
flag to specify additional embedded packages. For example, packages from the same workspace that do not follow the default naming convention.The following is an example of exporting a dynamic plugin with shared and embedded packages:
Example dynamic plugin export with shared and embedded packages
npx @janus-idp/cli@latest export-dynamic-plugin --shared-package '!/@backstage/plugin-notifications/' --embed-package @backstage/plugin-notifications-backend
In the previous example:
-
@backstage/plugin-notifications
package is treated as a private dependency and is bundled in the dynamic plugin package, despite being in the@backstage
scope. -
@backstage/plugin-notifications-backend
package is marked as an embedded dependency and is bundled in the dynamic plugin package.
- Front-end plugins
Front-end plugins can use
scalprum
for configuration, which the CLI can generate automatically during the export process. The generated default configuration is logged when running the following command:Example command to log the default configuration
npx @janus-idp/cli@latest export-dynamic
The following is an example of default
scalprum
configuration:Default
scalprum
configuration"scalprum": { "name": "<package_name>", // The Webpack container name matches the NPM package name, with "@" replaced by "." and "/" removed. "exposedModules": { "PluginRoot": "./src/index.ts" // The default module name is "PluginRoot" and doesn't need explicit specification in the app-config.yaml file. } }
You can add a
scalprum
section to thepackage.json
file. For example:Example
scalprum
customization"scalprum": { "name": "custom-package-name", "exposedModules": { "FooModuleName": "./src/foo.ts", "BarModuleName": "./src/bar.ts" // Define multiple modules here, with each exposed as a separate entry point in the Webpack container. } }
Dynamic plugins might need adjustments for Developer Hub needs, such as static JSX for mountpoints or dynamic routes. These changes are optional but might be incompatible with static plugins.
To include static JSX, define an additional export and use it as the dynamic plugin’s
importName
. For example:Example static and dynamic plugin export
// For a static plugin export const EntityTechdocsContent = () => {...} // For a dynamic plugin export const DynamicEntityTechdocsContent = { element: EntityTechdocsContent, staticJSXContent: ( <TechDocsAddons> <ReportIssue /> </TechDocsAddons> ), };
Procedure
Use the
package export-dynamic-plugin
command from the@janus-idp/cli
package to export the plugin:Example command to export a third-party plugin
npx @janus-idp/cli@latest package export-dynamic-plugin
Ensure that you execute the previous command in the root directory of the plugin’s JavaScript package (containing
package.json
file).The resulting derived package will be located in the
dist-dynamic
subfolder. The exported package name consists of the original plugin name with-dynamic
appended.WarningThe derived dynamic plugin JavaScript packages must not be published to the public NPM registry. For more appropriate packaging options, see Section 2.2, “Packaging and publishing third-party plugins as dynamic plugins”. If you must publish to the NPM registry, use a private registry.
2.2. Packaging and publishing third-party plugins as dynamic plugins
After exporting a third-party plugin, you can package the derived package into one of the following supported formats:
- Open Container Initiative (OCI) image (recommended)
- TGZ file
JavaScript package
ImportantExported dynamic plugin packages must only be published to private NPM registries.
2.2.1. Creating an OCI image with dynamic packages
Prerequisites
-
You have installed
podman
ordocker
. - You have exported a third-party dynamic plugin package. For more information, see Section 2.1, “Exporting third-party plugins in Red Hat Developer Hub”.
Procedure
-
Navigate to the plugin’s root directory (not the
dist-dynamic
directory). Run the following command to package the plugin into an OCI image:
Example command to package an exported third-party plugin
npx @janus-idp/cli@latest package package-dynamic-plugins --tag quay.io/example/image:v0.0.1
In the previous command, the
--tag
argument specifies the image name and tag.Run one of the following commands to push the image to a registry:
Example command to push an image to a registry using podman
podman push quay.io/example/image:v0.0.1
Example command to push an image to a registry using docker
docker push quay.io/example/image:v0.0.1
The output of the
package-dynamic-plugins
command provides the plugin’s path for use in thedynamic-plugin-config.yaml
file.
2.2.2. Creating a TGZ file with dynamic packages
Prerequisites
- You have exported a third-party dynamic plugin package. For more information, see Section 2.1, “Exporting third-party plugins in Red Hat Developer Hub”.
Procedure
-
Navigate to the
dist-dynamic
directory. Run the following command to create a
tgz
archive:Example command to create a
tgz
archivenpm pack
You can obtain the integrity hash from the output of the
npm pack
command by using the--json
flag as follows:Example command to obtain the integrity hash of a
tgz
archivenpm pack --json | head -n 10
Host the archive on a web server accessible to your RHDH instance, and reference its URL in the
dynamic-plugin-config.yaml
file as follows:Example
dynamic-plugin-config.yaml
fileplugins: - package: https://example.com/backstage-plugin-myplugin-1.0.0.tgz integrity: sha512-<hash>
Run the following command to package the plugins:
Example command to package a dynamic plugin
npm pack --pack-destination ~/test/dynamic-plugins-root/
TipTo create a plugin registry using HTTP server on OpenShift Container Platform, run the following commands:
Example commands to build and deploy an HTTP server in OpenShift Container Platform
oc project my-rhdh-project oc new-build httpd --name=plugin-registry --binary oc start-build plugin-registry --from-dir=dynamic-plugins-root --wait oc new-app --image-stream=plugin-registry
Configure your RHDH to use plugins from the HTTP server by editing the
dynamic-plugin-config.yaml
file:Example configuration to use packaged plugins in RHDH
plugins: - package: http://plugin-registry:8080/backstage-plugin-myplugin-1.9.6.tgz
2.2.3. Creating a JavaScript package with dynamic packages
The derived dynamic plugin JavaScript packages must not be published to the public NPM registry. If you must publish to the NPM registry, use a private registry.
Prerequisites
- You have exported a third-party dynamic plugin package. For more information, see Section 2.1, “Exporting third-party plugins in Red Hat Developer Hub”.
Procedure
-
Navigate to the
dist-dynamic
directory. Run the following command to publish the package to your private NPM registry:
Example command to publish a plugin package to an NPM registry
npm publish --registry <npm_registry_url>
TipYou can add the following to your
package.json
file before running theexport
command:Example
package.json
file{ "publishConfig": { "registry": "<npm_registry_url>" } }
If you modify
publishConfig
after exporting the dynamic plugin, re-run theexport-dynamic-plugin
command to ensure the correct configuration is included.
2.3. Installing third-party plugins in Red Hat Developer Hub
You can install a third-party plugins in Red Hat Developer Hub without rebuilding the RHDH application.
The location of the dynamic-plugin-config.yaml
file depends on the deployment method. For more details, refer to Installing dynamic plugins with the Red Hat Developer Hub Operator and Installing dynamic plugins using the Helm chart.
Plugins are defined in the plugins
array within the dynamic-plugin-config.yaml
file. Each plugin is represented as an object with the following properties:
-
package
: The plugin’s package definition, which can be an OCI image, a TGZ file, a JavaScript package, or a directory path. -
disabled
: A boolean value indicating whether the plugin is enabled or disabled. -
integrity
: The integrity hash of the package, required for TGZ file and JavaScript packages. -
pluginConfig
: The plugin’s configuration. For backend plugins, this is optional; for frontend plugins, it is required. ThepluginConfig
is a fragment of theapp-config.yaml
file, and any added properties are merged with the RHDHapp-config.yaml
file.
You can also load dynamic plugins from another directory, though this is intended for development or testing purposes and is not recommended for production, except for plugins included in the RHDH container image. For more information, see Section 3, “Enabling plugins added in the RHDH container image”.
2.3.1. Loading a plugin packaged as an OCI image
Prerequisites
The third-party plugin is packaged as a dynamic plugin in an OCI image.
For more information about packaging a third-party plugin, see Section 2.2, “Packaging and publishing third-party plugins as dynamic plugins”.
Procedure
To retrieve plugins from an authenticated registry, complete the following steps:
Log in to the container image registry.
podman login <registry>
Verify the content of the
auth.json
file created after the login.cat ${XDG_RUNTIME_DIR:-~/.config}/containers/auth.json
Create a secret file using the following example:
oc create secret generic _<secret_name>_ --from-file=auth.json=${XDG_RUNTIME_DIR:-~/.config}/containers/auth.json 1
-
For an Operator-based deployment, replace <secret_name> with
dynamic-plugins-registry-auth
. -
For a Helm-based deployment, replace <secret_name> with
<Helm_release_name>_-dynamic-plugins-registry-auth
.
-
For an Operator-based deployment, replace <secret_name> with
Define the plugin with the
oci://
prefix in the following format indynamic-plugins.yaml
file:oci://<image_name>:<tag>!<plugin_name>
Example configuration in
dynamic-plugins.yaml
fileplugins: - disabled: false package: oci://quay.io/example/image:v0.0.1!backstage-plugin-myplugin
To perform an integrity check, use the image digest in place of the tag in the
dynamic-plugins.yaml
file as shown in the following example:Example configuration in
dynamic-plugins.yaml
fileplugins: - disabled: false package: oci://quay.io/example/image@sha256:28036abec4dffc714394e4ee433f16a59493db8017795049c831be41c02eb5dc!backstage-plugin-myplugin
- To apply the changes, restart the RHDH application.
2.3.2. Loading a plugin packaged as a TGZ file
Prerequisites
The third-party plugin is packaged as a dynamic plugin in a TGZ file.
For more information about packaging a third-party plugin, see Section 2.2, “Packaging and publishing third-party plugins as dynamic plugins”.
Procedure
Specify the archive URL and its integrity hash in the
dynamic-plugins.yaml
file using the following example:Example configuration in
dynamic-plugins.yaml
fileplugins: - disabled: false package: https://example.com/backstage-plugin-myplugin-1.0.0.tgz integrity: sha512-9WlbgEdadJNeQxdn1973r5E4kNFvnT9GjLD627GWgrhCaxjCmxqdNW08cj+Bf47mwAtZMt1Ttyo+ZhDRDj9PoA==
- To apply the changes, restart the RHDH application.
2.3.3. Loading a plugin packaged as a JavaScript package
Prerequisites
The third-party plugin is packaged as a dynamic plugin in a JavaScript package.
For more information about packaging a third-party plugin, see Section 2.2, “Packaging and publishing third-party plugins as dynamic plugins”.
Procedure
Run the following command to obtain the integrity hash from the NPM registry:
npm view --registry <registry-url> <npm package>@<version> dist.integrity
Specify the package name, version, and its integrity hash in the
dynamic-plugins.yaml
file as follows:Example configuration in
dynamic-plugins.yaml
fileplugins: - disabled: false package: @example/backstage-plugin-myplugin@1.0.0 integrity: sha512-9WlbgEdadJNeQxdn1973r5E4kNFvnT9GjLD627GWgrhCaxjCmxqdNW08cj+Bf47mwAtZMt1Ttyo+ZhDRDj9PoA==
If you are using a custom NPM registry, create a
.npmrc
file with the registry URL and authentication details:Example code for
.npmrc
fileregistry=<registry-url> //<registry-url>:_authToken=<auth-token>
When using OpenShift Container Platform or Kubernetes:
Use the Helm chart to add the
.npmrc
file by creating a secret. For example:Example secret configuration
apiVersion: v1 kind: Secret metadata: name:
<release_name>-dynamic-plugins-npmrc
1 type: Opaque stringData: .npmrc: | registry=<registry-url> //<registry-url>:_authToken=<auth-token>For RHDH Helm chart, name the secret using the following format for automatic mounting:
<release_name>-dynamic-plugins-npmrc
- To apply the changes, restart the RHDH application.
2.3.4. Example of installing a third-party plugin in Red Hat Developer Hub
This section describes the process for integrating the Todo plugin into your Developer Hub.
Obtain the third-party plugin source code: Clone the plugins repository and navigate to the Todo plugin directory:
Obtain the third-party plugin source code
$ git clone https://github.com/backstage/community-plugins $ cd community-plugins/workspaces/todo $ yarn install
Export backend and front-end plugins: Run the following commands to build the backend plugin, adjust package dependencies for dynamic loading, and generate self-contained configuration schema:
Export the backend plugin
$ cd todo-backend $ npx @janus-idp/cli@latest package export-dynamic-plugin
Output of exporting the backend plugin commands
Building main package executing yarn build ✔ Packing main package to dist-dynamic/package.json Customizing main package in dist-dynamic/package.json for dynamic loading moving @backstage/backend-common to peerDependencies moving @backstage/backend-openapi-utils to peerDependencies moving @backstage/backend-plugin-api to peerDependencies moving @backstage/catalog-client to peerDependencies moving @backstage/catalog-model to peerDependencies moving @backstage/config to peerDependencies moving @backstage/errors to peerDependencies moving @backstage/integration to peerDependencies moving @backstage/plugin-catalog-node to peerDependencies Installing private dependencies of the main package executing yarn install --no-immutable ✔ Validating private dependencies Validating plugin entry points Saving self-contained config schema in /Users/user/Code/community-plugins/workspaces/todo/plugins/todo-backend/dist-dynamic/dist/configSchema.json
You can run the following commands to set default dynamic UI configurations, create front-end plugin assets, and to generate a configuration schema for a front-end plugin:
Export the front-end plugin
$ cd ../todo $ npx @janus-idp/cli@latest package export-dynamic-plugin
Output of exporting the front-end plugin commands
No scalprum config. Using default dynamic UI configuration: { "name": "backstage-community.plugin-todo", "exposedModules": { "PluginRoot": "./src/index.ts" } } If you wish to change the defaults, add "scalprum" configuration to plugin "package.json" file, or use the '--scalprum-config' option to specify an external config. Packing main package to dist-dynamic/package.json Customizing main package in dist-dynamic/package.json for dynamic loading Generating dynamic frontend plugin assets in /Users/user/Code/community-plugins/workspaces/todo/plugins/todo/dist-dynamic/dist-scalprum 263.46 kB dist-scalprum/static/1417.d5271413.chunk.js ... ... ... 250 B dist-scalprum/static/react-syntax-highlighter_languages_highlight_plaintext.0b7d6592.chunk.js Saving self-contained config schema in /Users/user/Code/community-plugins/workspaces/todo/plugins/todo/dist-dynamic/dist-scalprum/configSchema.json
Package and publish a third-party plugin: Run the following commands to navigate to the workspace directory and package the dynamic plugin to build the OCI image:
Build an OCI image
$ cd ../.. $ npx @janus-idp/cli@latest package package-dynamic-plugins --tag quay.io/user/backstage-community-plugin-todo:v0.1.1
Output of building an OCI image commands
executing podman --version ✔ Using existing 'dist-dynamic' directory at plugins/todo Using existing 'dist-dynamic' directory at plugins/todo-backend Copying 'plugins/todo/dist-dynamic' to '/var/folders/5c/67drc33d0018j6qgtzqpcsbw0000gn/T/package-dynamic-pluginsmcP4mU/backstage-community-plugin-todo No plugin configuration found at undefined create this file as needed if this plugin requires configuration Copying 'plugins/todo-backend/dist-dynamic' to '/var/folders/5c/67drc33d0018j6qgtzqpcsbw0000gn/T/package-dynamic-pluginsmcP4mU/backstage-community-plugin-todo-backend-dynamic No plugin configuration found at undefined create this file as needed if this plugin requires configuration Writing plugin registry metadata to '/var/folders/5c/67drc33d0018j6qgtzqpcsbw0000gn/T/package-dynamic-pluginsmcP4mU/index.json' Creating image using podman executing echo "from scratch COPY . . " | podman build --annotation com.redhat.rhdh.plugins='[{"backstage-community-plugin-todo":{"name":"@backstage-community/plugin-todo","version":"0.2.40","description":"A Backstage plugin that lets you browse TODO comments in your source code","backstage":{"role":"frontend-plugin","pluginId":"todo","pluginPackages":["@backstage-community/plugin-todo","@backstage-community/plugin-todo-backend"]},"homepage":"https://backstage.io","repository":{"type":"git","url":"https://github.com/backstage/community-plugins","directory":"workspaces/todo/plugins/todo"},"license":"Apache-2.0"}},{"backstage-community-plugin-todo-backend-dynamic":{"name":"@backstage-community/plugin-todo-backend","version":"0.3.19","description":"A Backstage backend plugin that lets you browse TODO comments in your source code","backstage":{"role":"backend-plugin","pluginId":"todo","pluginPackages":["@backstage-community/plugin-todo","@backstage-community/plugin-todo-backend"]},"homepage":"https://backstage.io","repository":{"type":"git","url":"https://github.com/backstage/community-plugins","directory":"workspaces/todo/plugins/todo-backend"},"license":"Apache-2.0"}}]' -t 'quay.io/user/backstage-community-plugin-todo:v0.1.1' -f - . ✔ Successfully built image quay.io/user/backstage-community-plugin-todo:v0.1.1 with following plugins: backstage-community-plugin-todo backstage-community-plugin-todo-backend-dynamic Here is an example dynamic-plugins.yaml for these plugins: plugins: - package: oci://quay.io/user/backstage-community-plugin-todo:v0.1.1!backstage-community-plugin-todo disabled: false - package: oci://quay.io/user/backstage-community-plugin-todo:v0.1.1!backstage-community-plugin-todo-backend-dynamic disabled: false
Push the OCI image to a container registry:
$ podman push quay.io/user/backstage-community-plugin-todo:v0.1.1
Output of pushing the OCI image command
Getting image source signatures Copying blob sha256:86a372c456ae6a7a305cd464d194aaf03660932efd53691998ab3403f87cacb5 Copying config sha256:3b7f074856ecfbba95a77fa87cfad341e8a30c7069447de8144aea0edfcb603e Writing manifest to image destination
Install and configure the third-party plugin: Add the following plugin definitions to your
dynamic-plugins.yaml
file:Plugin definitions in
dynamic-plugins.yaml
filepackages: - package: oci://quay.io/user/backstage-community-plugin-todo:v0.1.1!backstage-community-plugin-todo pluginConfig: dynamicPlugins: frontend: backstage-community.plugin-todo: mountPoints: - mountPoint: entity.page.todo/cards importName: EntityTodoContent entityTabs: - path: /todo title: Todo mountPoint: entity.page.todo - package: oci://quay.io/user/backstage-community-plugin-todo:v0.1.1!backstage-community-plugin-todo-backend-dynamic disabled: false
3. Enabling plugins added in the RHDH container image
In the RHDH container image, a set of dynamic plugins is preloaded to enhance functionality. However, due to mandatory configuration requirements, most of the plugins are disabled.
You can enable and configure the plugins in the RHDH container image, including how to manage the default configuration, set necessary environment variables, and ensure the proper functionality of the plugins within your application.
Prerequisites
-
You have access to the
dynamic-plugins.default.yaml
file, which lists all preloaded plugins and their default configuration. -
You have deployed the RHDH application, and have access to the logs of the
install-dynamic-plugins
init container. - You have the necessary permissions to modify plugin configurations and access the application environment.
- You have identified and set the required environment variables referenced by the plugin’s default configuration. These environment variables must be defined in the Helm Chart or Operator configuration.
Procedure
-
Start your RHDH application and access the logs of the
install-dynamic-plugins
init container within the RHDH pod. - Identify the Red Hat supported plugins that are disabled by default.
-
Copy the package configuration from the
dynamic-plugins.default.yaml
file. Open the plugin configuration file and locate the plugin entry you want to enable.
The location of the plugin configuration file varies based on the deployment method. For more details, see Installing dynamic plugins with the Red Hat Developer Hub Operator and Installing dynamic plugins using the Helm chart.
Modify the
disabled
field tofalse
and add the package name as follows:Example plugin configuration
plugins: - disabled: false package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic
For more information about how to configure dynamic plugins in Developer Hub, see Installing dynamic plugins in Red Hat Developer Hub.
Verification
- Restart the RHDH application and verify that the plugin is successfully activated and configured.
- Verify the application logs for confirmation and ensure the plugin is functioning as expected.
4. Extensions in Red Hat Developer Hub
These features are for Technology Preview only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs), might not be functionally complete, and Red Hat does not recommend using them for production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information on Red Hat Technology Preview features, see Technology Preview Features Scope.
Red Hat Developer Hub (RHDH) includes the Extensions feature which is preinstalled and enabled by default. Extensions provides users with a centralized interface to browse and manage available plugins
You can use Extensions to discover plugins that extend RHDH functionality, streamline development workflows, and improve the developer experience.
4.1. Viewing available plugins
You can view plugins available for your Red Hat Developer Hub application on the Extensions page.
Procedure
- Open your Developer Hub application and click Administration > Extensions.
Go to the Catalog tab to view a list of available plugins and related information.
4.2. Viewing installed plugins
Using the Dynamic Plugins Info front-end plugin, you can view plugins that are currently installed in your Red Hat Developer Hub application. This plugin is enabled by default.
Procedure
- Open your Developer Hub application and click Administration > Extensions.
- Go to the Installed tab to view a list of installed plugins and related information.
4.3. Search and filter the plugins
4.3.1. Search by plugin name
You can use the search bar in the header to filter the Extensions plugin cards by name. For example, if you type “A” into the search bar, Extensions shows only the plugins that contain the letter “A” in the Name field.

Optionally, you can use the search bar in conjunction with a filter to filter only plugins of the selected filter by name. For example, you can apply the Category filter and then type a character into the search bar to view only Openshift plugins that contain the typed character in the name.
The following filters are available:
- Category
- Author
- Support type
4.4. Installing a plugin by using Extensions
You can install a plugin and configure it by updating the dynamic-plugins.yaml
file by using Extensions.
4.4.1. Prerequisites
- You have the necessary permissions to modify plugin configurations and access the application environment.
- You have identified and set the required environment variables referenced by the plugin’s default configuration. These environment variables must be defined in the Helm Chart or Operator configuration.
Procedure
- Open your Developer Hub application and click Administration > Extensions.
Use the search bar on the Extensions page to find the plugin you wish to install, then click on the card. For example, search for Tekton and click Read more on the Pipelines With Tekton card.
In the plugin drawer, you can review information about the plugin and how to configure it in RHDH. To install the plugin, click Install.
On the Install Plugin page, a YAML editor and installation instructions are displayed.
- Click the About the plugin tab to view installation and configuration details for the plugin.
- Click the Examples tab to display the default plugin configuration.
- Click Apply to copy the default plugin configuration to the YAML editor.
In the YAML editor, click the copy icon to copy the plugin configuration.
NoteIn RHDH 1.7, the Install button is disabled, so you must copy the plugin configuration to the
dynamic-plugins.yaml
file.In the
dynamic-plugins.yaml
file, add the plugin configuration that you copied in the previous step to theplugins
definitions.NoteIf you have installed RHDH by using the Helm Chart, to enable the plugin, you may need to roll out your RHDH project manually.
Verification
- Click on Administration > Extensions.
- Go to the Installed tab to view a list of installed plugins.
- Search for the plugin that you installed to confirm that it is available and enabled.
4.5. Removing Extensions
The Extensions feature plugins are preinstalled in Red Hat Developer Hub (RHDH) and enabled by default. If you want to remove Extensions from your RHDH instance, you can disable the relevant plugins.
Procedure
To disable the the Extensions feature plugins, edit your
dynamic-plugins.yaml
with the following content.dynamic-plugins.yaml
fragmentplugins: - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace disabled: true - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-catalog-backend-module-marketplace-dynamic disabled: true - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace-backend-dynamic disabled: true
If you disable the Extensions feature plugins, the Catalog and Installed tabs will also be removed. You can still view installed plugins by clicking on Administration > Extensions.
5. Front-end plugin wiring
You can configure front-end plugins to do the following:
- Extend the internal library of available icons
- Declare a new full page by defining a new route
- Extend to an existing page using router bindings
- Use mount points within the application
- Provide additional utility APIs or replace existing ones
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 a plugin’s menu item by using the appIcons
configuration as shown in the following example:
# dynamic-plugins-config.yaml plugins: - plugin: <plugin_path_or_url> disabled: false pluginConfig: dynamicPlugins: frontend: my-plugin: 1 appIcons: - name: fooIcon 2 module: CustomModule 3 importName: FooIcon 4
- 1
- Specify the plugin package name.
- 2
- Specify a name for the icon catalog
- 3
- Optional: Specify the set of assets you want to access within the plugin. By default, the system uses the
PluginRoot
module if none is specified. - 4
- Optional: Specify the actual component name to be rendered as a standalone page. If not specified, the system uses the
default
export.
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
path
and, if needed, animportName
if it is different from thedefault
export. -
Expose additional routes in a dynamic plugin by configuring
dynamicRoutes
as shown in the following example:
# dynamic-plugins-config.yaml plugins: - plugin: <plugin_path_or_url> disabled: false pluginConfig: dynamicPlugins: frontend: my-plugin: 1 dynamicRoutes: - path: /my-plugin 2 module: CustomModule 3 importName: FooPluginPage 4 menuItem: 5 icon: fooIcon text: Foo Plugin Page enabled: false config: 6 props: ...
- 1
- Specify the plugin package name.
- 2
- Specify the unique path in the application. The path cannot override existing routes except the
/
home route. You can replace the main home page using the dynamic plugins mechanism. - 3
- Optional: Specify the set of assets you want to access within the plugin. By default, the system uses the
PluginRoot
module if none is specified. - 4
- Optional: Specify the actual component name as a standalone page. If not specified, the system uses the
default
export. - 5
menuItem
- Allows you to extend the main sidebar navigation and point to a new route. ThemenuItem
accepts 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 exportedSidebarItem
component.
-
- 6
- Optional: Passes
props
to a custom sidebar itemTo configure a custom
SidebarItem
to 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: 1 routeBindings: targets: 2 - name: barPlugin 3 importName: barPlugin 4 module: CustomModule 5 bindings: - bindTarget: "barPlugin.externalRoutes" 6 bindMap: 7 headerLink: "fooPlugin.routes.root"
- 1
- Specify the plugin package name.
- 2
- Declare a new bind target
- 3
- (Optional): defaults to importName. Explicit name of the plugin that exposes the bind target.
- 4
- Required. Explicit import name that reference a BackstagePlugin<{}> implementation.
- 5
- (Optional): Same as key in
scalprum.exposedModules
key in plugin’spackage.json
- 6
- (Required): One of the supported or imported bind targets
- 7
- A required map of route bindings and is similar to
bind
function options
To configure routeBindings
, complete the following steps:
-
Define new targets using
routeBindings.targets
. Set the requiredimportName
to aBackstagePlugin<{}>
implementation. Declare route bindings using the routeBindings.bindings field by setting
bindTarget
to the name of the target to bind to. This can be a dynamic or static target, such as:-
catalogPlugin.externalRoutes
-
catalogImportPlugin.externalRoutes
-
techdocsPlugin.externalRoutes
scaffolderPlugin.externalRoutes
You 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:
Table 1. Input parameters
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:
-
/context
type that serves to create React contexts -
/cards
type 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: 1 mountPoints: 2 - mountPoint: <mountPointName>/[cards|context] module: CustomModule importName: FooPluginPage config: 3 layout: {} 4 if: 5 allOf|anyOf|oneOf: - isMyPluginAvailable - isKind: component - isType: service - hasAnnotation: annotationKey props: {} 6
- 1
- Specify the plugin package name.
- 2
- (Optional): Uses existing mount points
- 3
- (Optional): Allows you to pass additional configuration to the component.
- 4
- Used only in
/cards
type which renders visible content. You can pass MUI sx properties to the component, which is useful when controlling the layout of the component.entity.page.*
mount points are rendered as CSS grid, hence with the SX property you can control the grid layout and exact positioning of the rendered component. - 5
- Used only in
/cards
type which renders visible content.if
is passed to<EntitySwitch.Case if={<here>}
. - 6
- 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 can be:
-
isKind
: Accepts a string or a list of string with entity kinds. For exampleisKind: component
renders the component only for entity ofkind: Component
. -
isType
: Accepts a string or a list of string with entity types. For exampleisType: service
renders the component only for entities ofspec.type: 'service'
. -
hasAnnotation
: Accepts a string or a list of string with annotation keys. For examplehasAnnotation: my-annotation
renders the component only for entities that have definedmetadata.annotations['my-annotation']
. -
Condition imported from the plugin’s
module
: Must be function name exported from the samemodule
within the plugin. For exampleisMyPluginAvailable
renders the component only ifisMyPluginAvailable
function returnstrue
. The function must have the following signature:(e: Entity) ⇒ boolean
The entity page also supports adding more items to the context menu at the top right of the page. The exported component should be 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 menu item’s text and icon. 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: 1 mountPoints: - mountPoint: application/header 2 importName: <header_component> 3 config: position: above-main-content 4
- 1
- Specify the plugin package name.
- 2
- Specify where to add the header. To specify it as a global header, use
application/header
. - 3
- Specify the component exported by the global header plugin (for example,
GlobalHeader
for `red-hat-developer-hub.backstage-plugin-global-header). - 4
- Specify the header’s position. The supported values include:
-
above-main-content
: Positions the header above the main content area. above-sidebar
: Positions the header above the sidebar.NoteTo 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: 1
mountPoints:
- mountPoint: application/listener
importName: <exported listener component>
- 1
- Specify the plugin package name.
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: 1 dynamicRoutes: - path: /<route> importName: Component 2 mountPoints: - mountPoint: application/provider importName: <exported provider component>
-
You can configure multiple application providers by adding entries to the
mountPoints
field. -
The
package_name
key underdynamicPlugins.frontend
must match thescalprum.name
value in your plugin’spackage.json
. This ensures your dynamic plugin loads correctly during 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: 1 entityTabs: 2 - path: /new-path title: My New Tab mountPoint: entity.page.my-new-tab 3 - path: / title: General mountPoint: entity.page.overview - path: "/pr" # 4 title: "Changed Pull/Merge Requests" 5 priority: 1 mountPoint: "entity.page.pull-requests" 6 - path: "/" title: "Changed Overview" mountPoint: "entity.page.overview" priority: -6 7
- 1
- Specify the plugin package name.
- 2
- Specify a new tab
- 3
- Change an existing tab’s title or mount point
- 4
- Specify the sub-path route in the catalog where this tab is available.
- 5
- Specify the title you want to display.
- 6
- The base mount point name that is available on the tab. This name is expanded to create two mount points per tab, one appended with` /context` and the second appended with
/cards
. - 7
- Specify the order of tabs. The tabs with higher priority values appear first.
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:
Table 2. Input parameters
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 application’s authentication flow. The SignInPage
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
importName
component from your dynamic plugin. -
The component returns a configured
SignInPage
that connects the desired authentication provider factories. -
Only one
signInPage
can be specified for the application at a time.
dynamicPlugins:
frontend:
my-plugin: 1
signInPage:
importName: CustomSignInPage
- 1
- Specify the plugin package name.
The package_name
under dynamicPlugins.frontend
must match the scalprum.name
value in your plugin’s package.json
to ensure the dynamic plugin loads correctly during runtime.
The module
field is optional and allows specifying which set of assets should 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
importName
for registration. - Multiple field extensions can be registered by listing each in the configuration.
dynamicPlugins: frontend: my-plugin: 1 scaffolderFieldExtensions: - importName: MyNewFieldExtension 2
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 your plugin’s package.json
.
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 should be registered with the createApp
API using the apiFactories
configuration as shown in the following example:
# app-config.yaml dynamicPlugins: frontend: my-plugin: 1 apiFactories: - importName: BarApi 2 module: CustomModule 3
- 1
- Specify the plugin package name.
- 2
- Optional: Specify the import name that references a
AnyApiFactory<{}>
implementation. Defaults todefault
export. - 3
- Optional: An argument which allows you to specify which set of assets you want to access within the plugin. If not provided, the default module named PluginRoot is used.
The API factories initialized by the Developer Hub application shell can be 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: 1
apiFactories:
- importName: customScmAuthApiFactory
- 1
- Specify the plugin package name.
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: 1 providerSettings: - title: My Custom Auth Provider 2 description: Sign in using My Custom Auth Provider 3 provider: core.auth.my-custom-auth-provider 4
- 1
- Specify the plugin package name.
- 2
- Specify the title for the authentication provider shown above the user’s profile image if available.
- 3
- Specify the description of the authentication provider.
- 4
- Specify the ID of the authentication provider as provided to the
createApiRef
API call. This value is used to look 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 contribute to TechDocs component, as a result, exposing the TechDocs addon component using the techdocsAddons
configuration as shown in the following example:
dynamicPlugins: frontend: my-plugin: 1 techdocsAddons: - importName: ExampleAddon 2 config: props: ... 3
module`is an optional argument which allows you to specify the set of assets you want to access within the plugin. By default, `PluginRoot
module is used.
5.12. Customizing Red Hat Developer Hub theme
You can customize Developer Hub themes from a dynamic plugin with various configurations. The dynamic plugin exports a theme provider function with a signature of ({ children }: { children: ReactNode }): React.JSX.Element
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} /> );
You can declare the theme using the themes
configuration as shown in the following example:
dynamicPlugins: frontend: my-plugin: 1 themes: - id: light 2 title: Light variant: light icon: someIconReference importName: lightThemeProvider - id: dark 3 title: Dark 4 variant: dark 5 icon: someIconReference 6 importName: darkThemeProvider 7
- 1
- Specify the plugin package name.
- 2
- Specify the theme, either
light
ordark
to replace the default theme. Using 'light' overrides the app-provided light theme - 3
- Specify the theme name displayed to the user on the Settings page. Using 'dark' overrides the app-provided dark theme
- 4
- Whether the theme is
light
ordark
, can only be one of these values. - 5
- A string reference to a system or app icon
- 6
- Specify the name of the exported theme provider function, the function signature should match
({ children }: { children: ReactNode }): React.JSX.Element