Merge pull request #30836 from backstage/blam/swappable/docs
feat: added some docs around swappable
This commit is contained in:
@@ -37,14 +37,14 @@ This extension is the first extension attached to the extension tree. It is resp
|
||||
|
||||
#### Inputs
|
||||
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| root | The app root element. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | The [`App/Root`](#app-root) extension output. | No creator available, configure or override the [`App/Root`](#app-root) extension. |
|
||||
| apis | The app apis factories. | [createApiExtension.factoryDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension.factorydataref) | false | See [default apis](#default-apis-extensions). | [createApiExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension) |
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [createComponentExtension.componentDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension.componentdataref) | false | See [default components](#default-components-extensions). | [createComponentExtension](https://backstage.io/docs/reference/frontend-plugin-api.createcomponentextension) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
| icons | The app icons list. | [IconBundleBlueprint.dataRefs.icons](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint.dataRefs.icons) | true | - | [IconBundleBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint) |
|
||||
| Name | Description | Type | Optional | Default | Extension creator |
|
||||
| ------------ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| root | The app root element. | [coreExtensionData.reactElement](https://backstage.io/docs/reference/frontend-plugin-api.coreextensiondata) | false | The [`App/Root`](#app-root) extension output. | No creator available, configure or override the [`App/Root`](#app-root) extension. |
|
||||
| apis | The app apis factories. | [createApiExtension.factoryDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension.factorydataref) | false | See [default apis](#default-apis-extensions). | [createApiExtension](https://backstage.io/docs/reference/frontend-plugin-api.createapiextension) |
|
||||
| themes | The app themes list. | [createThemeExtension.themeDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension.themedataref) | false | See [default themes](#default-theme-extensions). | [createThemeExtension](https://backstage.io/docs/reference/frontend-plugin-api.createthemeextension) |
|
||||
| components | The app components list. | [SwappableComponentBlueprint.dataRefs.component](https://backstage.io/docs/reference/frontend-plugin-api.swappablecomponentblueprint.dataRefs.component) | false | See [default components](#default-components-extensions). | [SwappableComponentBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.swappablecomponentblueprint) |
|
||||
| translations | The app translations list. | [createTranslationExtension.translationDataRef](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension.translationdataref) | false | - | [createTranslationExtension](https://backstage.io/docs/reference/frontend-plugin-api.createtranslationextension) |
|
||||
| icons | The app icons list. | [IconBundleBlueprint.dataRefs.icons](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint.dataRefs.icons) | true | - | [IconBundleBlueprint](https://backstage.io/docs/reference/frontend-plugin-api.iconbundleblueprint) |
|
||||
|
||||
#### Default theme extensions
|
||||
|
||||
@@ -59,11 +59,11 @@ Extensions that provides default theme inputs for the `App` extension.
|
||||
|
||||
Extensions that provides default components inputs for the `App` extension.
|
||||
|
||||
| kind | namespace | name | id |
|
||||
| :--------: | :-------: | :-----------------------------------: | :----------------------------------------------------: |
|
||||
| components | app | core.components.progress | `components:app/core.components.progress` |
|
||||
| components | app | core.components.notFoundErrorPage | `components:app/core.components.notFoundErrorPage` |
|
||||
| components | app | core.components.errorBoundaryFallback | `components:app/core.components.errorBoundaryFallback` |
|
||||
| kind | namespace | name | id |
|
||||
| :--------: | :-------: | :-------------------------------: | :------------------------------------------------: |
|
||||
| components | app | core.components.progress | `components:app/core.components.progress` |
|
||||
| components | app | core.components.notFoundErrorPage | `components:app/core.components.notFoundErrorPage` |
|
||||
| components | app | core.components.errorDisplay | `components:app/core.components.errorDisplay` |
|
||||
|
||||
#### Default apis extensions
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
id: swappable-components
|
||||
title: Swappable components
|
||||
sidebar_label: Swappable components
|
||||
description: Configuring or overriding Swappable Components
|
||||
---
|
||||
|
||||
# Swappable components
|
||||
|
||||
Swappable components are a feature of the frontend system that allow you to replace the implementations of components that are used in your Backstage app.
|
||||
These Swappable Components are defined using `createSwappableComponent` and then can be exported from a plugins `-react` package in order to be used in both other plugins, and to be rebound to a new implementation by the Backstage Integrator.
|
||||
|
||||
## Creating a Swappable Component
|
||||
|
||||
In order to create a Swappable Component, you need to use the `createSwappableComponent` function from the `@backstage/frontend-plugin-api` package. You can supply a default implementation for the component, as well as a way to separate both the props of the external component and in the implementation of the component.
|
||||
|
||||
```tsx title="in @internal/plugin-example-react"
|
||||
import { createSwappableComponent } from '@backstage/frontend-plugin-api';
|
||||
|
||||
export const ExampleSwappableComponent = createSwappableComponent({
|
||||
name: 'example',
|
||||
|
||||
// This is a loader for loading the default implementation of the component when there's no overriden
|
||||
// implementation created with `SwappableComponentBlueprint`.
|
||||
// It can be sync like below, but is can also be async like `loader: () => import('./DefaultImplementation').then(m => m.DefaultImplementation)`.
|
||||
loader: () => (props: { name: string }) =>
|
||||
<div>Your name is {props.name}</div>,
|
||||
|
||||
// This is an optional function that can be used to transform the props of the external component.
|
||||
// If it's not provided, the props of the external component will be passed through unchanged.
|
||||
// Typically this wouldn't be used and you don't need to define this initially,
|
||||
// this is a nice API to evolve the Swappable Component internal API without breaking usages of it in existing plugins.
|
||||
transformProps: (props: { lastName: string; firstName: string }) => ({
|
||||
name: `${props.firstName} ${props.lastName}`,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
## Using a Swappable Component
|
||||
|
||||
Using a Swappable Component is just like using any other React Component. The return of `createSwappableComponent` can be rendered directly in your plugin, or any plugins that will be consuming your `-react` package.
|
||||
|
||||
```tsx title="in @internal/plugin-example"
|
||||
import { ExampleSwappableComponent } from '@internal/plugin-example-react';
|
||||
|
||||
<ExampleSwappableComponent firstName="John" lastName="Doe" />;
|
||||
```
|
||||
|
||||
## Overriding a Swappable Component
|
||||
|
||||
In order to override a Swappable Component, you need to create a `SwappableComponentBlueprint` and install it with the `app` plugin.
|
||||
There's two different ways to add extensions to the `app` plugin, both are documented below in an example of overriding the `Progress` Swappable Component.
|
||||
|
||||
```tsx title="in packages/app/src/App.tsx"
|
||||
import {
|
||||
Progress,
|
||||
SwappableComponentBlueprint,
|
||||
createFrontendModule,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { MyCustomProgress } from './CustomProgress';
|
||||
import { createApp } from '@backstage/frontend-defaults';
|
||||
import appPlugin from '@backstage/plugin-app';
|
||||
|
||||
const app = createApp({
|
||||
features: [
|
||||
// Override an existing extension by ID provided by the app plugin:
|
||||
appPlugin.withOverrides({
|
||||
extensions: [
|
||||
appPlugin
|
||||
.getExtension('component:app/core.components.progress')
|
||||
.override({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
component: Progress,
|
||||
loader: () => MyCustomProgress,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
// OR: Add another extension but with the same component ID:
|
||||
appPlugin.withOverrides({
|
||||
extensions: [
|
||||
SwappableComponentBlueprint.make({
|
||||
name: 'core.components.progress',
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
component: Progress,
|
||||
loader: () => MyCustomProgress,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
// OR: Use a module for the app plugin:
|
||||
createFrontendModule({
|
||||
pluginId: 'app',
|
||||
extensions: [
|
||||
SwappableComponentBlueprint.make({
|
||||
name: 'core.components.progress',
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
component: Progress,
|
||||
loader: () => MyCustomProgress,
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Default Swappable Components
|
||||
|
||||
Currently there is only three different built-in Swappable Components that you can replace the implementations of, and these live in `@backstage/frontend-plugin-api`. They are as follows:
|
||||
|
||||
- `<Progress />
|
||||
- `<ErrorDisplay />
|
||||
- `<NotFoundErrorPage />
|
||||
|
||||
You can see more about these components at their [definition](https://github.com/backstage/backstage/blob/master/packages/frontend-plugin-api/src/components/DefaultSwappableComponents.tsx), and their default implementations are shipped inside the [`app-plugin`](https://github.com/backstage/backstage/blob/master/plugins/app/src/extensions/components.tsx).
|
||||
|
||||
## Implementations in tests
|
||||
|
||||
By default, if no `loader` is passed through to `createSwappableComponent` then there's a default fallback component which will be rendered, which is mainly helpful in tests. The default implementation for a Swappable Component without a `loader` is as follows:
|
||||
|
||||
```tsx
|
||||
props => <div data-testid={swappableComponentRef.id} {...props} />;
|
||||
```
|
||||
|
||||
Which means that you can use the `getByTestId` in tests to assert that these components have been rendered on the page.
|
||||
Reference in New Issue
Block a user