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..f03d12f156 --- /dev/null +++ b/assemblies/dynamic-plugins/assembly-front-end-plugin-wiring.adoc @@ -0,0 +1,49 @@ +[id="assembly-front-end-plugin-wiring.adoc_{context}"] += Front-end plugin wiring +:context: assembly-front-end-plugin-wiring + +You can configure front-end plugins to customize icons, integrate components at mount points, and provide or replace utility APIs. + +// 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-for-new-plugin-pages.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..18d2a52d51 --- /dev/null +++ b/modules/dynamic-plugins/con-providing-custom-scaffolder-field-extensions.adoc @@ -0,0 +1,26 @@ +[id="con-providing-custom-scaffolder-field-extensions.adoc_{context}"] += 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. +* You register multiple field extensions by listing each in the configuration. + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # The plugin package name + scaffolderFieldExtensions: + - importName: MyNewFieldExtension # 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 the `package.json` file of your package. +==== \ 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..1fc8b8db48 --- /dev/null +++ b/modules/dynamic-plugins/con-using-custom-signinpage-component.adoc @@ -0,0 +1,26 @@ +[id="con-using-custom-signinpage-component.adoc_{context}"] += Using a custom SignInPage component + +In {product} ({product-very-short}), the `SignInPage` component manages the authentication flow of the application. This component connects one or more authentication providers to the sign-in process. By default, {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` is specified for the application at a time. + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # The plugin package name + signInPage: + importName: CustomSignInPage +---- + +[NOTE] +==== +The `package_name` specified under `dynamicPlugins.frontend` must match the `scalprum.name` value in the `package.json` file of your plugin to ensure the dynamic plugin loads correctly at runtime. + +The `module` field is optional and allows specifying which set of assets must be accessed within the dynamic plugin. By default, the system uses the `PluginRoot` module. +==== \ 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..bb0f415b3a --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-header.adoc @@ -0,0 +1,22 @@ +[id="proc-adding-application-header.adoc_{context}"] += 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: # The plugin package name + mountPoints: + - mountPoint: application/header # Adds the header as a global header + importName: # Specifies the component exported by the global header plugin + config: + position: above-main-content # Supported values: (`above-main-content`| above-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..7da94d5eac --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-listeners.adoc @@ -0,0 +1,20 @@ +[id="proc-adding-application-listeners.adoc_{context}"] += 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: # The plugin package name + mountPoints: + - mountPoint: application/listener + importName: +---- + +[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..616e313706 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-application-providers.adoc @@ -0,0 +1,25 @@ +[id="proc-adding-application-providers.adoc_{context}"] + += 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: # The plugin package name + dynamicRoutes: + - path: / + importName: Component # The component to load on the route + mountPoints: + - mountPoint: application/provider + importName: +---- + +[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 the `package.json` file of your plugin. This ensures your dynamic plugin loads correctly at 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..c433af58a9 --- /dev/null +++ b/modules/dynamic-plugins/proc-adding-custom-authentication-provider-settings.adoc @@ -0,0 +1,25 @@ +[id="proc-adding-custom-authentication-provider-settings.adoc_{context}"] += 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: # The plugin package name + providerSettings: + # The title for the authentication provider shown above the user's profile image if available + - title: My Custom Auth Provider + # The description of the authentication provider + description: Sign in using My Custom Auth Provider + # The ID of the authentication provider as provided to the `createApiRef` API call. + provider: core.auth.my-custom-auth-provider +---- + +[NOTE] +==== +`provider` looks 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..976d745feb --- /dev/null +++ b/modules/dynamic-plugins/proc-binding-to-existing-plugins.adoc @@ -0,0 +1,44 @@ +[id="proc-binding-to-existing-plugins.adoc_{context}"] += 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: # The plugin package name + routeBindings: + targets: # A new bind target + # (Optional): Defaults to importName. Explicit name of the plugin that exposes the bind target. + - name: barPlugin + # (Required): Explicit import name that reference a BackstagePlugin<{}> implementation. + importName: barPlugin + # # (Optional): Same as key in `scalprum.exposedModules` key in the `package.json` file of the plugin. + module: CustomModule + bindings: + - bindTarget: "barPlugin.externalRoutes" # (Required): One of the supported or imported bind targets + bindMap: # A required map of route bindings similar to `bind` function options + headerLink: "fooPlugin.routes.root" +---- + +To configure `routeBindings`, complete the following steps: + +. Define new targets using `routeBindings.targets`. Set the 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 is 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..541fee45ba --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-and-extending-entity-tabs.adoc @@ -0,0 +1,128 @@ +[id="proc-customizing-and-extending-entity-tabs.adoc_{context}"] + += 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: # The plugin package name + entityTabs: + # Specify a new tab + - path: /new-path + title: My New Tab + mountPoint: entity.page.my-new-tab + # Change an existing tab's title or mount point + - path: / + title: General + mountPoint: entity.page.overview + # Specify the sub-path route in the catalog where this tab is available + - path: "/pr" + title: "Changed Pull/Merge Requests" # Specify the title you want to display + priority: 1 + # The base mount point name available on the tab. This name expands to create two mount points per tab, with` /context` and with `/cards` + mountPoint: "entity.page.pull-requests" + - path: "/" + title: "Changed Overview" + mountPoint: "entity.page.overview" + # Specify the order of tabs. The tabs with higher priority values appear first + priority: -6 +---- + +You can configure dynamic front-end plugins to target the mount points exposed by the entityTabs configuration. The following are the default catalog entity routes in the default order: + +.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..5a7b2f3c40 --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-entity-page.adoc @@ -0,0 +1,183 @@ +[id="proc-customizing-entity-page.adoc_{context}"] += 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: # The plugin package name + mountPoints: # (Optional): Uses existing mount points + - mountPoint: /[cards|context] + module: CustomModule + importName: FooPluginPage + config: # (Optional): Allows you to pass additional configuration to the component + layout: {} # Used only in `/cards` type which renders visible content + # Use only in `/cards` type which renders visible content. `if` is passed to `}`. + if: + allOf|anyOf|oneOf: + - isMyPluginAvailable + - isKind: component + - isType: service + - hasAnnotation: annotationKey + props: {} # Useful when you are passing additional data to the component +---- + +The available conditions include: + +* `allOf`: All conditions must be met +* `anyOf`: At least one condition must be met +* `oneOf`: Only one condition must be met + +Conditions are: + +* `isKind`: Accepts a string or a list of string with entity kinds. For 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 `module` of the plugin: 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 supports adding more items to the context menu at the top right of the page. The exported component is a form of dialog wrapper component that accepts an `open` boolean property and an `onClose` event handler property as shown in the following example: + +[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 text and icon of the menu item. You can use any system icon or icon added through a dynamic plugin. The following is an example configuration: + +[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..1a608e274f --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-sidebar-menu-items.adoc @@ -0,0 +1,44 @@ +[id="proc-customizing-sidebar-menu-items.adoc_{context}"] + += Customizing menu items in the sidebar navigation + +You can 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: # The plugin package name + menuItems: + # The unique name in the main sidebar navigation (for example, either a standalone menu item or a parent menu item) + : + # (Optional): The icon for the menu item, which refers to a Backstage system icon + icon: fooIcon + # (Optional): The display title of the menu item + title: Foo Plugin Page + # (Optional): The order in which menu items appear. The default priority is `0`. + priority: 10 + # (Optional): Defines the parent menu item to nest the current item under + parent: favorites + # (Optional): Allows you to remove a `menuItem` from the sidebar when it is set to `false` + enabled: false +---- + +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`. + +[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..f132391681 --- /dev/null +++ b/modules/dynamic-plugins/proc-customizing-theme.adoc @@ -0,0 +1,42 @@ +[id="proc-customizing-theme.adoc_{context}"] += Customizing {product} theme + +You can customize {product-short} themes from a dynamic plugin with various configurations 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 }) => ( + +); +---- + +For more information about creating a custom theme, see link:{customizing-book-url}#proc-loading-custom-theme-using-dynamic-plugin-_customizing-appearance[creating a custom theme]. + +You can declare the theme using the `themes` configuration as shown in the following example: + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # The plugin package name + themes: + # are `light` or `dark`. Using 'light' overrides the app-provided light theme + - id: light + title: Light + variant: light + icon: someIconReference + importName: lightThemeProvider + # The theme name displayed to the user on the *Settings* page. Using 'dark' overrides the app-provided dark theme + - id: dark + title: Dark + variant: dark + icon: someIconReference # A string reference to a system or app icon + # The name of the exported theme provider function, the function signature should match `({ children }: { children: ReactNode }): React.JSX.Element` + importName: darkThemeProvider +---- diff --git a/modules/dynamic-plugins/proc-defining-dynamic-routes-for-new-plugin-pages.adoc b/modules/dynamic-plugins/proc-defining-dynamic-routes-for-new-plugin-pages.adoc new file mode 100644 index 0000000000..e75b26bdb4 --- /dev/null +++ b/modules/dynamic-plugins/proc-defining-dynamic-routes-for-new-plugin-pages.adoc @@ -0,0 +1,71 @@ +[id="proc-defining-dynamic-routes-for-new-plugin-pages.adoc_{context}"] + += 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: # The plugin package name + dynamicRoutes: + # The unique path in the application. The path cannot override existing routes except the `/` home route. + - path: /my-plugin + # (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module. + module: CustomModule + # (Optional): The component name as a standalone page. If not specified, the system uses the `default` export. + importName: FooPluginPage + # Allows you to extend the main sidebar navigation and point to a new route. + menuItem: + icon: fooIcon + text: Foo Plugin Page + enabled: false + config: # (Optional): Passes `props` to a custom sidebar item + props: ... +---- ++ +The `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. ++ +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..d0bb49e142 --- /dev/null +++ b/modules/dynamic-plugins/proc-extending-internal-icon-catalog.adoc @@ -0,0 +1,31 @@ +[id="proc-extending-internal-icon-catalog.adoc_{context}"] + += Extending internal icon catalog + +You can use the internal catalog to fetch icons for configured routes with sidebar navigation menu entry. + +.Procedure +* Add a custom icon to the internal icon catalog for use in the menu item of a plugin by using the `appIcons` configuration as shown in the following example: + +[source,yaml] +---- +# dynamic-plugins-config.yaml +plugins: + - plugin: + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + my-plugin: # The plugin package name + appIcons: + - name: fooIcon # The icon catalog name + # (Optional): The set of assets to access within the plugin. If not specified, the system uses the `PluginRoot` module. + module: CustomModule + # (Optional): The actual component name to be rendered as a standalone page. If not specified, the system uses the `default` export. + importName: FooIcon +---- + +[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..db8a405d13 --- /dev/null +++ b/modules/dynamic-plugins/proc-provide-additional-utility-apis.adoc @@ -0,0 +1,57 @@ +[id="proc-provide-additional-utility-apis.adoc_{context}"] += 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 must 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: # The plugin package name + apiFactories: + # (Optional): Specify the import name that references a `AnyApiFactory<{}>` implementation. (Defaults to `default` export) + - importName: BarApi + # (Optional): An argument which specifies the assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used + module: CustomModule +---- + +The API factories initialized by the {product-short} application shell are overridden by an API factory provided by a dynamic plugin by specifying the same API ref ID. A dynamic plugin can export `AnyApiFactory<{}>` to cater for some specific use case as shown in the following example: + +[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: # The plugin package name + apiFactories: + - importName: customScmAuthApiFactory +---- \ 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..b0383208e3 --- /dev/null +++ b/modules/dynamic-plugins/proc-provide-custom-techdocs-addons.adoc @@ -0,0 +1,16 @@ +[id="proc-provide-custom-techdocs-addons.adoc_{context}"] += Provide custom TechDocs addons + +If a plugin provides multiple addons, each `techdocsAddon` entry specifies a unique `importName` corresponding to the addon. +Front-end plugins exposes the TechDocs addon component using the `techdocsAddons` configuration as shown in the following example: + +[source,yaml] +---- +dynamicPlugins: + frontend: + my-plugin: # The plugin package name + techdocsAddons: + - importName: ExampleAddon # The exported Addon component + config: + props: ... # (Optional): React props to pass to the addon +---- \ 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..c1cf6b4665 --- /dev/null +++ b/modules/dynamic-plugins/proc-using-mount-points.adoc @@ -0,0 +1,4 @@ +[id="proc-using-mount-points.adoc_{context}"] += 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]