Skip to content

Commit 9101271

Browse files
authored
chore(docs): fill in some missing documentation (#1852)
This change adds documentation for a few changes to the frontendi application that have been available, namely the ability to add additional custom context menu items to the entity page from a dynamic plugin, the ability to supply a custom sidebar item component from a dynamic plugin and finally the changes related to how API factories can be discovered from a frontend dynamic plugin if it exports it's plugin object vs. the need to explicitly configure frontend API factories. Signed-off-by: Stan Lewis <gashcrumb@gmail.com>
1 parent 6f6e6b6 commit 9101271

File tree

1 file changed

+75
-7
lines changed

1 file changed

+75
-7
lines changed

docs/dynamic-plugins/dynamic-plugins.md

+75-7
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ global:
542542

543543
Compared to the backend plugins, where mount points are defined in code and consumed by the backend plugin manager, frontend plugins require additional configuration in the `app-config.yaml`. A plugin missing this configuration will not be loaded into the application and will not be displayed.
544544

545-
Similarly to traditional Backstage instances, there are 3 types of functionality a dynamic frontend plugin can offer:
545+
Similarly to traditional Backstage instances, there are various kinds of functionality a dynamic frontend plugin can offer:
546546

547547
- Full new page that declares a completely new route in the app
548548
- Extension to existing page via router `bind`ings
@@ -631,8 +631,37 @@ Each plugin can expose multiple routes and each route is required to define its
631631
- `path` - Unique path in the app. Cannot override existing routes with the exception of the `/` home route: the main home page can be replaced via the dynamic plugins mechanism.
632632
- `module` - Optional. Since dynamic plugins can expose multiple distinct modules, you may need to specify which set of assets you want to access within the plugin. If not provided, the default module named `PluginRoot` is used. This is the same as the key in `scalprum.exposedModules` key in plugin's `package.json`.
633633
- `importName` - Optional. The actual component name that should be rendered as a standalone page. If not specified the `default` export is used.
634-
- `menuItem` - This property allows users to extend the main sidebar navigation and point to their new route. It accepts `text` and `icon` properties. `icon` refers to a Backstage system icon name. See [Backstage system icons](https://backstage.io/docs/getting-started/app-custom-theme/#icons) for the list of default icons and [Extending Icons Library](#extend-internal-library-of-available-icons) to extend this with dynamic plugins.
635-
- `config.props` - Optional. Additionally you can pass React props to the component.
634+
- `menuItem` - This property allows users to extend the main sidebar navigation and point to their new route. It accepts the following properties:
635+
- `text`: The label shown to the user
636+
- `icon`: refers to a Backstage system icon name. See [Backstage system icons](https://backstage.io/docs/getting-started/app-custom-theme/#icons) for the list of default icons and [Extending Icons Library](#extend-internal-library-of-available-icons) to extend this with dynamic plugins.
637+
- `importName`: optional name of an exported SidebarItem component. The component will receive a `to` property as well as any properties specified in `config.props`
638+
- `config` - An optional field which is a holder to pass `props` to a custom sidebar item
639+
640+
A custom SidebarItem offers opportunities to provide a richer user experience such as notification badges. The component should accept the following properties:
641+
642+
```typescript
643+
export type MySidebarItemProps = {
644+
to: string; // supplied by the sidebar during rendering, this will be the path configured for the dynamicRoute
645+
};
646+
```
647+
648+
Other properties can be specified as well and configured using the `config.props` property on the dynamic route.
649+
650+
Here is an example configuration specifying a custom SidebarItem component:
651+
652+
```yaml
653+
dynamicPlugins:
654+
frontend:
655+
my-dynamic-plugin-package-name:
656+
dynamicRoutes:
657+
- importName: CustomPage
658+
menuItem:
659+
config:
660+
props:
661+
text: Click Me!
662+
importName: SimpleSidebarItem
663+
path: /custom_page
664+
```
636665

637666
#### Menu items
638667

@@ -749,6 +778,7 @@ The following mount points are available:
749778
| ---------------------------- | ----------------------------------- | -------------------------------------------------------------- |
750779
| `admin.page.plugins` | Administration plugins page | NO |
751780
| `admin.page.rbac` | Administration RBAC page | NO |
781+
| `entity.context.menu` | Catalog entity context menu | YES for all entities |
752782
| `entity.page.overview` | Catalog entity overview page | YES for all entities |
753783
| `entity.page.topology` | Catalog entity "Topology" tab | NO |
754784
| `entity.page.issues` | Catalog entity "Issues" tab | NO |
@@ -768,13 +798,15 @@ The following mount points are available:
768798
| `search.page.filters` | Search filters | YES, default catalog kind and lifecycle filters are visible |
769799
| `search.page.results` | Search results content | YES, default catalog search is present |
770800

771-
Note: Mount points within Catalog aka `entity.page.*` are rendered as tabs. They become visible only if at least one plugin contributes to them or they can render static content (see column 3 in previous table).
801+
Mount points within Catalog aka `entity.page.*` are rendered as tabs. They become visible only if at least one plugin contributes to them or they can render static content (see column 3 in previous table).
772802

773803
Each `entity.page.*` mount point has 2 complementary variations:
774804

775805
- `*/context` type that serves to create React contexts
776806
- `*/cards` type for regular React components
777807

808+
Here is an example of the overall configuration structure of a mount point:
809+
778810
```yaml
779811
# app-config.yaml
780812
dynamicPlugins:
@@ -814,6 +846,33 @@ Each mount point supports additional configuration:
814846
- `hasAnnotation`: Accepts a string or a list of string with annotation keys. For example `hasAnnotation: my-annotation` will render the component only for entities that have `metadata.annotations['my-annotation']` defined.
815847
- condition imported from the plugin's `module`: Must be function name exported from the same `module` within the plugin. For example `isMyPluginAvailable` will render the component only if `isMyPluginAvailable` function returns `true`. The function must have following signature: `(e: Entity) => boolean`
816848

849+
The entity page also supports adding more items to the context menu at the top right of the page. Components targeting the `entity.context.menu` mount point have some constraints to follow. The exported component should be some form of dialog wrapper component that accepts an `open` boolean property and an `onClose` event handler property, like so:
850+
851+
```typescript
852+
export type SimpleDialogProps = {
853+
open: boolean;
854+
onClose: () => void;
855+
};
856+
```
857+
858+
The context menu entry can be configured via the `props` configuration entry for the mount point. The `title` and `icon` properties will set the menu item's text and icon. Any system icon or icon added via a dynamic plugin can be used. Here is an example configuration:
859+
860+
```yaml
861+
dynamicPlugins:
862+
frontend:
863+
my-dynamic-plugin-package:
864+
appIcons:
865+
- name: dialogIcon
866+
importName: DialogIcon
867+
mountPoints:
868+
- mountPoint: entity.context.menu
869+
importName: SimpleDialog
870+
config:
871+
props:
872+
title: Open Simple Dialog
873+
icon: dialogIcon
874+
```
875+
817876
#### Customizing and Adding Entity tabs
818877

819878
Out of the box the frontend system provides an opinionated set of tabs for catalog entity views. This set of tabs can be further customized and extended as needed via the `entityTabs` configuration:
@@ -872,7 +931,18 @@ Backstage offers an Utility API mechanism that provide ways for plugins to commu
872931
- Custom plugin-made API that can be already self contained within any plugin (including dynamic plugins)
873932
- [App API implementations and overrides](https://backstage.io/docs/api/utility-apis/#app-apis) which needs to be added separately.
874933

875-
Dynamic plugins provides you with a way to utilize the App API concept via `apiFactories` configuration:
934+
and a plugin can potentially expose multiple API Factories. Dynamic plugins allow a couple different ways to take advantage of this functionality.
935+
936+
If a dynamic plugin exports the plugin object returned by `createPlugin`, it will be supplied to the `createApp` API and all API factories exported by the plugin will be automatically registered and available in the frontend application. Dynamic plugins that follow this pattern should not use the `apiFactories` configuration. Also, if a dynamic plugin only contains API factories and follows this pattern, it will just be necessary to add an entry to the `dynamicPlugins.frontend` config for the dynamic plugin package name, for example:
937+
938+
```yaml
939+
# app-config.yaml
940+
dynamicPlugins:
941+
frontend:
942+
my-dynamic-plugin-package-with-api-factories: {}
943+
```
944+
945+
However if the dynamic plugin doesn't export it's plugin object then it will be necessary to explicitly configure each API factory that should be registered with the `createApp` API via the `apiFactories` configuration:
876946

877947
```yaml
878948
# app-config.yaml
@@ -884,8 +954,6 @@ dynamicPlugins:
884954
module: CustomModule # Optional, same as key in `scalprum.exposedModules` key in plugin's `package.json`
885955
```
886956
887-
Each plugin can expose multiple API Factories and each factory is required to define its `importName` (if it differs from the default export).
888-
889957
- `importName` is an optional import name that reference a `AnyApiFactory<{}>` implementation. Defaults to `default` export.
890958
- `module` is an optional 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. This is the same as the key in `scalprum.exposedModules` key in plugin's `package.json`.
891959

0 commit comments

Comments
 (0)