diff --git a/assemblies/dynamic-plugins/assembly-front-end-plugin-wiring.adoc b/assemblies/dynamic-plugins/assembly-front-end-plugin-wiring.adoc new file mode 100644 index 0000000000..44199db822 --- /dev/null +++ b/assemblies/dynamic-plugins/assembly-front-end-plugin-wiring.adoc @@ -0,0 +1,55 @@ +[id="assembly-front-end-plugin-wiring_{context}"] += Front-end plugin wiring +:context: assembly-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 + +// Extending the internal icon catalog +include::../modules/dynamic-plugins/proc-extending-internal-icon-catalog.adoc[leveloffset=+1] + +// Defining dynamic routes for new plugin pages +include::../modules/dynamic-plugins/proc-defining-dynamic-routes.adoc[leveloffset=+1] + +// Customizing menu items in the sidebar navigation +include::../modules/dynamic-plugins/proc-customizing-sidebar-menu-items.adoc[leveloffset=+1] + +// Bind to existing plugins +include::../modules/dynamic-plugins/proc-binding-to-existing-plugins.adoc[leveloffset=+1] + +// Using mount points +include::../modules/dynamic-plugins/proc-using-mount-points.adoc[leveloffset=+1] + +include::../modules/dynamic-plugins/proc-customizing-entity-page.adoc[leveloffset=+2] + +include::../modules/dynamic-plugins/proc-adding-application-header.adoc[leveloffset=+2] + +include::../modules/dynamic-plugins/proc-adding-application-listeners.adoc[leveloffset=+2] + +include::../modules/dynamic-plugins/proc-adding-application-providers.adoc[leveloffset=+2] + +// Customizing and extending entity tabs +include::../modules/dynamic-plugins/proc-customizing-and-extending-entity-tabs.adoc[leveloffset=+1] + +// SignIn page +include::../modules/dynamic-plugins/con-using-custom-signinpage-component.adoc[leveloffset=+1] + +// custom scaffolder extension +include::../modules/dynamic-plugins/con-providing-custom-scaffolder-field-extensions.adoc[leveloffset=+1] + +// Provide additional Utility APIs +include::../modules/dynamic-plugins/proc-provide-additional-utility-apis.adoc[leveloffset=+1] + +// Adding custom authentication provider settings +include::../modules/dynamic-plugins/proc-adding-custom-authentication-provider-settings.adoc[leveloffset=+1] + +// Provide custom techdocs addons +include::../modules/dynamic-plugins/proc-provide-custom-techdocs-addons.adoc[leveloffset=+1] + +// Customizing theme +include::../modules/dynamic-plugins/proc-customizing-theme.adoc[leveloffset=+1] diff --git a/modules/dynamic-plugins/con-providing-custom-scaffolder-field-extensions.adoc b/modules/dynamic-plugins/con-providing-custom-scaffolder-field-extensions.adoc new file mode 100644 index 0000000000..2ac5fe8f98 --- /dev/null +++ b/modules/dynamic-plugins/con-providing-custom-scaffolder-field-extensions.adoc @@ -0,0 +1,29 @@ +[id="con-providing-custom-scaffolder-field-extensions"] + += Providing custom Scaffolder field extensions + +The Scaffolder component in {product} ({product-very-short}) 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. + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # <1> + scaffolderFieldExtensions: + - importName: MyNewFieldExtension # <2> +---- +<1> Specify the plugin package name. +<2> The `importName` references the exported scaffolder field extension component from your plugin. + +[NOTE] +==== +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`. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/con-using-custom-signinpage-component.adoc b/modules/dynamic-plugins/con-using-custom-signinpage-component.adoc new file mode 100644 index 0000000000..5f8c871fdc --- /dev/null +++ b/modules/dynamic-plugins/con-using-custom-signinpage-component.adoc @@ -0,0 +1,27 @@ +[id="con-using-custom-signinpage-component"] += Using a custom SignInPage component + +In {product} ({product-very-short}), the `SignInPage` component manages the application's authentication flow. The `SignInPage` connects one or more authentication providers to the sign-in process. By default, {product-short} 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. + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # <1> + signInPage: + importName: CustomSignInPage +---- +<1> Specify the plugin package name. + +[NOTE] +==== +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. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-adding-application-header.adoc b/modules/dynamic-plugins/proc-adding-application-header.adoc new file mode 100644 index 0000000000..bac211d991 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-header.adoc @@ -0,0 +1,29 @@ +[id="proc-adding-application-header.adoc-catalog"] + += Adding application header + +You can customize global headers by specifying configurations in the `app-config.yaml` file as shown in the following example: + +[source,yaml] +---- +# app-config.yaml +dynamicPlugins: + frontend: + my-plugin: # <1> + mountPoints: + - mountPoint: application/header # <2> + importName: # <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. ++ +[NOTE] +==== +To configure multiple global headers at different positions, add entries to the `mountPoints` field. +==== diff --git a/modules/dynamic-plugins/proc-adding-application-listeners.adoc b/modules/dynamic-plugins/proc-adding-application-listeners.adoc new file mode 100644 index 0000000000..6b11dc5790 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-listeners.adoc @@ -0,0 +1,22 @@ +[id="proc-adding-application-listeners"] + += Adding application listeners + +You can add application listeners using the `application/listener` mount point as shown in the following example: + +[source,yaml] +---- +# app-config.yaml +dynamicPlugins: + frontend: + my-plugin: # <1> + mountPoints: + - mountPoint: application/listener + importName: +---- +<1> Specify the plugin package name. + +[NOTE] +==== +You can configure multiple application listeners by adding entries to the `mountPoints` field. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-adding-application-providers.adoc b/modules/dynamic-plugins/proc-adding-application-providers.adoc new file mode 100644 index 0000000000..a95e6746a7 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-providers.adoc @@ -0,0 +1,27 @@ +[id="proc-adding-application-providers"] + += 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: + +[source,yaml] +---- +# app-config.yaml +dynamicPlugins: + frontend: + my-plugin: # <1> + dynamicRoutes: + - path: / + importName: Component # <2> + mountPoints: + - mountPoint: application/provider + importName: +---- +<1> Specify the plugin package name. +<2> Specify the component you want to load on the route. + +[NOTE] +==== +. You can configure multiple application providers by adding entries to the `mountPoints` field. +. 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. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-adding-custom-authentication-provider-settings.adoc b/modules/dynamic-plugins/proc-adding-custom-authentication-provider-settings.adoc new file mode 100644 index 0000000000..d464250839 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-custom-authentication-provider-settings.adoc @@ -0,0 +1,22 @@ +[id="proc-adding-custom-authentication-provider-settings"] + += 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: + +[source,yaml] +---- +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. \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-binding-to-existing-plugins.adoc b/modules/dynamic-plugins/proc-binding-to-existing-plugins.adoc new file mode 100644 index 0000000000..16198088b5 --- /dev/null +++ b/modules/dynamic-plugins/proc-binding-to-existing-plugins.adoc @@ -0,0 +1,49 @@ +[id="proc-binding-to-existing-plugins"] + += 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: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + 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's `package.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 required `importName` to a `BackstagePlugin<{}>` 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. \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-customizing-and-extending-entity-tabs.adoc b/modules/dynamic-plugins/proc-customizing-and-extending-entity-tabs.adoc new file mode 100644 index 0000000000..a14e97126d --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-and-extending-entity-tabs.adoc @@ -0,0 +1,132 @@ +[id="proc-customizing-and-extending-entity-tabs"] + += Customizing and extending entity tabs + +You can customize and extend the set of tabs using the `entityTabs` configuration as follows: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + 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: + +.Input parameters +[cols="20%,20%,30%,30%", frame="all", options="header"] +|=== +|Route +|Title +|Mount Point +|Entity Kind + +|`/` +|Overview +|`entity.page.overview` +|Any + +|`/topology` +|Topology +|`entity.page.topology` +|Any + +|`/issues` +|Issues +|`entity.page.issues` +|Any + +|`/pr` +|CPull/Merge Requests +|`entity.page.pull-requests` +|Any + +|`/ci` +|CI +|`entity.page.ci`` +|VAny + +|`/cd` +|CD +|`entity.page.cd` +|Any + +|`/kubernetes` +|Kubernetes +|`entity.page.kubernetes` +|Any + +|`/image-registry` +|Image Registry +|`entity.page.image-registry` +|Any + +|`/monitoring` +|Monitoring +|`entity.page.monitoring` +|Any + +|`/lighthouse` +|Lighthouse +|`entity.page.lighthouse` +|Any + +|`/api` +|Api +|`entity.page.api` +|kind: Service or kind: Component + +|`/dependencies` +|Dependencies +|`entity.page.dependencies` +|kind: Component + +|`/docs` +|Docs +|`entity.page.docs` +|Any + +|`/definition` +|Definition +|`entity.page.definition` +|kind: API + +|`/system` +|Diagram +|`entity.page.diagram` +|kind: System +|=== + +[NOTE] +==== +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. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-customizing-entity-page.adoc b/modules/dynamic-plugins/proc-customizing-entity-page.adoc new file mode 100644 index 0000000000..2144863214 --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-entity-page.adoc @@ -0,0 +1,189 @@ +[id="proc-customizing-entity-page"] + += Customizing entity page + +You can extend catalog components and additional views. + +The available mount points include the following: + +.Input parameters +[cols="25%,25%,50%", frame="all", options="header"] +|=== +|Mount point +|Description +|Visible even when no plugins are enabled + +|`admin.page.plugins` +|Administration plugins page +|NO + +|`admin.page.rbac` +|Administration RBAC page +|NO + +|`entity.context.menu` +|Catalog entity context menu +|YES for all entities + +|`entity.page.overview` +|Catalog entity overview page +|YES for all entities + +|`entity.page.topology` +|Catalog entity *Topology* tab +|NO + +|`entity.page.issues` +|Catalog entity *Issues* tab +|NO + +|`entity.page.pull-requests` +|Catalog entity *Pull Requests* tab +|NO + +|`entity.page.ci` +|Catalog entity *CI* tab +|NO + +|`entity.page.cd` +|Catalog entity *CD* tab +|NO + +|`entity.page.kubernetes` +|Catalog entity *Kubernetes* tab +|NO + +|`entity.page.image-registry` +|Catalog entity *Image Registry* tab +|NO + +|`entity.page.monitoring` +|Catalog entity *Monitoring* tab +|NO + +|`entity.page.lighthouse` +|Catalog entity *Lighthouse* tab +|NO + +|`entity.page.api` +|Catalog entity *API* tab +|YES for entity of `kind: Component` and `spec.type: 'service'` + +|`entity.page.dependencies` +|Catalog entity *Dependencies* tab +|YES for entity of `kind: Component` + +|`entity.page.docs` +|Catalog entity *Documentation* tab +|YES for entity that satisfies `isTechDocsAvailable` + +|`entity.page.definition` +|Catalog entity *Definitions* tab +|YES for entity of `kind: Api` + +|`entity.page.diagram` +|Catalog entity *Diagram* tab +|YES for entity of `kind: System` + +|`search.page.types` +|Search result type +|YES, default catalog search type is available + +|`search.page.filters` +|Search filters +|YES, default catalog kind and lifecycle filters are visible + +|`search.page.results` +|Search results content +|YES, default catalog search is present +|=== + +[NOTE] +==== +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: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + my-plugin: # <1> + mountPoints: # <2> + - mountPoint: /[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 `}`. +<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 example `isKind: component` renders the component only for entity of `kind: Component`. +* `isType`: Accepts a string or a list of string with entity types. For example `isType: service` renders the component only for entities of `spec.type: 'service'`. +* `hasAnnotation`: Accepts a string or a list of string with annotation keys. For example `hasAnnotation: my-annotation` renders the component only for entities that have defined `metadata.annotations['my-annotation']`. +* Condition imported from the plugin's `module`: Must be function name exported from the same `module` within the plugin. For example `isMyPluginAvailable` renders the component only if `isMyPluginAvailable` function returns `true`. 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: + +[source,yaml] +---- +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: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + 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 +---- \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-customizing-sidebar-menu-items.adoc b/modules/dynamic-plugins/proc-customizing-sidebar-menu-items.adoc new file mode 100644 index 0000000000..8026d50141 --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-sidebar-menu-items.adoc @@ -0,0 +1,43 @@ +[id="proc-customizing-sidebar-menu-items"] + += Customizing menu items in the sidebar navigation + +Customize the order and parent-child relationships of plugin menu items in the main sidebar navigation using the menu items configuration as shown in the following example: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + my-plugin: # <1> + menuItems: + : # <2> + icon: fooIcon # <3> + title: Foo Plugin Page # <4> + priority: 10 # <5> + parent: favorites # <6> + enabled: false # <7> +---- +<1> Specify the plugin package name. +<2> Specify the unique name in the main sidebar navigation (for example, either a standalone menu item or a parent menu item). +* Handling Complex Paths: +** For simple paths like `path: /my-plugin`, the `menu_item_name` should be `my-plugin`. +** For complex paths like `/metrics/users/info`, the `menu_item_name` should represent the full path in dot notation (for example `metrics.users.info`). +** Ignore trailing and leading slashes in paths as follows: ++ +*** For `path: /docs`, the `menu_item_name` is `docs`. +*** For `path: /metrics/users`, the `menu_item_name` is `metrics.users`. +<3> Optional: Defines the icon for the menu item, which refers to a Backstage system icon. +<4> Optional: Specify the display title of the menu item. +<5> Optional: Defines the order in which menu items appear. The default priority is `0`. +<6> Optional: Defines the parent menu item to nest the current item under. +<7> Optional: Allows you to remove a `menuItem` from the sidebar when it is set to `false`. + +[NOTE] +==== +{product} supports up to 3 levels of nested menu items. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-customizing-theme.adoc b/modules/dynamic-plugins/proc-customizing-theme.adoc new file mode 100644 index 0000000000..a5794ec94f --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-theme.adoc @@ -0,0 +1,44 @@ +[id="proc-customizing-theme"] + += Customizing {product} theme + +You can customize {product-short} 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: + +[source,yaml] +---- +import { lightTheme } from './lightTheme'; +import { darkTheme } from './darkTheme'; +import { UnifiedThemeProvider } from '@backstage/theme'; +export const lightThemeProvider = ({ children }: { children: ReactNode }) => ( + +); +export const darkThemeProvider = ({ children }: { children: ReactNode }) => ( + +); +---- + +You can declare the theme using the `themes` configuration as shown in the following example: + +[source,yaml] +---- +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` or `dark` 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` or `dark`, 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` \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-defining-dynamic-routes.adoc b/modules/dynamic-plugins/proc-defining-dynamic-routes.adoc new file mode 100644 index 0000000000..ead7744757 --- /dev/null +++ b/modules/dynamic-plugins/proc-defining-dynamic-routes.adoc @@ -0,0 +1,69 @@ +[id="proc-defining-dynamic-routes"] + += Defining dynamic routes for new plugin pages + +.Procedure +. Define each route by specifying a unique `path` and, if needed, an `importName` if it is different from the `default` export. +. Expose additional routes in a dynamic plugin by configuring `dynamicRoutes` as shown in the following example: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + 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. The `menuItem` 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 exported `SidebarItem` component. +<6> Optional: Passes `props` to a custom sidebar item ++ +To configure a custom `SidebarItem` to enhance experiences such as notification badges, ensure the component accepts the following properties: + +[source,yaml] +---- +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: +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + my-dynamic-plugin-package-name: + dynamicRoutes: + - importName: CustomPage + menuItem: + config: + props: + text: Click Me! + importName: SimpleSidebarItem + path: /custom_page +---- \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-extending-internal-icon-catalog.adoc b/modules/dynamic-plugins/proc-extending-internal-icon-catalog.adoc new file mode 100644 index 0000000000..c9deda2baa --- /dev/null +++ b/modules/dynamic-plugins/proc-extending-internal-icon-catalog.adoc @@ -0,0 +1,33 @@ +[id="proc-extending-internal-icon-catalog"] + += 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: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + 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. + +[NOTE] +==== +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. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-provide-additional-utility-apis.adoc b/modules/dynamic-plugins/proc-provide-additional-utility-apis.adoc new file mode 100644 index 0000000000..7bf8fd38f0 --- /dev/null +++ b/modules/dynamic-plugins/proc-provide-additional-utility-apis.adoc @@ -0,0 +1,60 @@ +[id="proc-provide-additional-utility-apis"] + += 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: + +[source,yaml] +---- +# 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: + +[source,yaml] +---- +# 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 to `default` 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 {product-short} 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: + +[source,yaml] +---- +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 {product-short} defaults to is as shown in the following example: + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # <1> + apiFactories: + - importName: customScmAuthApiFactory +---- +<1> Specify the plugin package name. \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-provide-custom-techdocs-addons.adoc b/modules/dynamic-plugins/proc-provide-custom-techdocs-addons.adoc new file mode 100644 index 0000000000..1283f6337e --- /dev/null +++ b/modules/dynamic-plugins/proc-provide-custom-techdocs-addons.adoc @@ -0,0 +1,25 @@ +[id="proc-provide-custom-techdocs-addons"] + += 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: + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # <1> + techdocsAddons: + - importName: ExampleAddon # <2> + config: + props: ... # <3> +---- +<1> Specify the plugin package name. +<2> Specify the name of an exported Addon component +<3> (Optional): React props to pass to the addon + +[NOTE] +==== +`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. +==== \ No newline at end of file diff --git a/modules/dynamic-plugins/proc-using-mount-points.adoc b/modules/dynamic-plugins/proc-using-mount-points.adoc new file mode 100644 index 0000000000..effb998b10 --- /dev/null +++ b/modules/dynamic-plugins/proc-using-mount-points.adoc @@ -0,0 +1,5 @@ +[id="proc-using-mount-points"] + += Using mount points + +Mount points are defined identifiers available across {product}. You can use these points to extend existing pages with additional content. \ No newline at end of file diff --git a/titles/plugins-rhdh-install/master.adoc b/titles/plugins-rhdh-install/master.adoc index 91aa94aadd..37e8558398 100644 --- a/titles/plugins-rhdh-install/master.adoc +++ b/titles/plugins-rhdh-install/master.adoc @@ -22,3 +22,6 @@ include::modules/dynamic-plugins/proc-enable-plugins-rhdh-container-image.adoc[l // Extensions (marketplace) plugins include::assemblies/dynamic-plugins/assembly-extensions-plugins.adoc[leveloffset=+1] + +// frontend plugin wiring +include::assemblies/dynamic-plugins/assembly-front-end-plugin-wiring.adoc[leveloffset=+1]