Merge pull request #7219 from mstergianis/docs/software-catalog-integration
Update plugin software catalog integration docs
This commit is contained in:
@@ -10,8 +10,8 @@ description: How to integrate a plugin into software catalog
|
||||
## Steps
|
||||
|
||||
1. [Create a plugin](#create-a-plugin)
|
||||
1. [Export a router with relative routes](#export-a-router)
|
||||
1. [Import and use router in the APP](#import-and-use-router-in-the-app)
|
||||
1. [Reading entities from within your plugin](#reading-entities-from-within-your-plugin)
|
||||
1. [Import your plugin and embed in the entities page](#import-your-plugin-and-embed-in-the-entities-page)
|
||||
|
||||
### Create a plugin
|
||||
|
||||
@@ -28,98 +28,92 @@ $ yarn create-plugin
|
||||
Creating the plugin...
|
||||
```
|
||||
|
||||
### Export a router
|
||||
### Reading entities from within your plugin
|
||||
|
||||
Now in the plugin you have a `Router.tsx` file in the `src` folder. By default
|
||||
it contains only one example route. Create a routing structure needed for your
|
||||
plugin, keeping in mind that the whole set of routes defined here are going to
|
||||
be mounted under some different route in the App.
|
||||
|
||||
Example:
|
||||
|
||||
`my-plugin` consists of 2 different views - `/me` and `/about`. I envision
|
||||
people integrating it into plugin catalog as a tab named "MyPlugin". Then, my
|
||||
`Routes.tsx` for the plugin is going to look like:
|
||||
You can access the currently selected entity using the backstage api
|
||||
[`useEntity`](../reference/plugin-catalog-react.useentity.md). For example,
|
||||
|
||||
```tsx
|
||||
<Routes>
|
||||
<Route path="/me" element={<MePage />} />
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
</Routes>
|
||||
```
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
|
||||
(where MePage and AboutPage are 2 components defined in your plugin and imported
|
||||
accordingly inside `Router.tsx`)
|
||||
export const MyPluginEntityContent = () => {
|
||||
const { entity, loading, error, refresh } = useEntity();
|
||||
|
||||
> Pay attention, if your `MePage` references the `AboutPage` it needs to do it
|
||||
> through link to `about`, not `/about`. This allows react-router v6 to enable
|
||||
> its relative routing mechanism. Read more -
|
||||
> https://reacttraining.com/blog/react-router-v6-pre/#relative-route-path-and-link-to
|
||||
|
||||
### Import and use router in the APP
|
||||
|
||||
In the `app/src/components/catalog/EntityPage.tsx` (app === your folder,
|
||||
containing Backstage app) import your created Router:
|
||||
|
||||
```tsx
|
||||
import { Router as MyPluginRouter } from '@backstage/plugin-my-plugin;
|
||||
```
|
||||
|
||||
Now, you need to mount `MyPluginRouter` onto some route, for example if you had:
|
||||
|
||||
```tsx
|
||||
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<OverviewPage entity={entity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
);
|
||||
```
|
||||
|
||||
after you add your code it becomes:
|
||||
|
||||
```tsx
|
||||
const DefaultEntityPage = ({ entity }: { entity: Entity }) => (
|
||||
<EntityPageLayout>
|
||||
<EntityPageLayout.Content
|
||||
path="/"
|
||||
title="Overview"
|
||||
element={<OverviewPage entity={entity} />}
|
||||
/>
|
||||
<EntityPageLayout.Content
|
||||
path="/my-plugin"
|
||||
title="My Plugin"
|
||||
element={<MyPluginRouter entity={entity} />}
|
||||
/>
|
||||
</EntityPageLayout>
|
||||
);
|
||||
```
|
||||
|
||||
All of magic happens thanks to the `EntityPageLayout` component, which comes as
|
||||
an export from `@backstage/plugin-catalog` package.
|
||||
|
||||
```tsx
|
||||
type EntityPageLayoutContentProps = {
|
||||
/**
|
||||
* Going to be transformed into react-router v6
|
||||
* path under the hood. Read more at https://reacttraining.com/blog/react-router-v6-pre
|
||||
*/
|
||||
path: string;
|
||||
/**
|
||||
* Gets transformed into the title for the tab
|
||||
*/
|
||||
title: string;
|
||||
/**
|
||||
* Element that is rendered when the location
|
||||
* matches the path provided
|
||||
*/
|
||||
element: JSX.Element;
|
||||
// Do something with the entity data...
|
||||
};
|
||||
```
|
||||
|
||||
> You can either pass the entity from App to the plugin's router as a prop or
|
||||
> use `useEntity` hook from `@backstage/plugin-catalog` directly inside your
|
||||
> plugin.
|
||||
Internally `useEntity` makes use of
|
||||
[react `Context`s](https://reactjs.org/docs/context.html). The entity context is
|
||||
provided by the entity page into which your plugin will be embedded.
|
||||
|
||||
### Import your plugin and embed in the entities page
|
||||
|
||||
To begin, you will need to import your plugin in the entities page. Located at
|
||||
`packages/app/src/components/Catalog/EntityPage.tsx` from the root package of
|
||||
your backstage app.
|
||||
|
||||
```tsx
|
||||
import { MyPluginEntityContent } from '@backstage/plugin-my-plugin;
|
||||
```
|
||||
|
||||
To add your component to the Entity view, you will need to modify the
|
||||
`packages/app/src/components/Catalog/EntityPage.tsx`. Depending on the needs of
|
||||
your plugin, you may only care about certain kinds of
|
||||
[entities](https://backstage.io/docs/features/software-catalog/descriptor-format),
|
||||
each of which has its own
|
||||
[element](https://reactjs.org/docs/rendering-elements.html) for rendering. This
|
||||
functionality is handled by the `EntitySwitch` component:
|
||||
|
||||
```tsx
|
||||
export const entityPage = (
|
||||
<EntitySwitch>
|
||||
<EntitySwitch.Case if={isKind('component')} children={componentPage} />
|
||||
<EntitySwitch.Case if={isKind('api')} children={apiPage} />
|
||||
<EntitySwitch.Case if={isKind('group')} children={groupPage} />
|
||||
<EntitySwitch.Case if={isKind('user')} children={userPage} />
|
||||
<EntitySwitch.Case if={isKind('system')} children={systemPage} />
|
||||
<EntitySwitch.Case if={isKind('domain')} children={domainPage} />
|
||||
|
||||
<EntitySwitch.Case>{defaultEntityPage}</EntitySwitch.Case>
|
||||
</EntitySwitch>
|
||||
);
|
||||
```
|
||||
|
||||
At this point, you will need to modify the specific page where you want your
|
||||
component to appear. If you are extending the Software Catalog model you will
|
||||
need to add a new case to the `EntitySwitch`. For adding a plugin to an existing
|
||||
component type, you modify the existing page. For example, if you want to add
|
||||
your plugin to the `systemPage`, you can add a new tab by adding an
|
||||
`EntityLayout.Route` such as below:
|
||||
|
||||
```tsx
|
||||
const systemPage = (
|
||||
<EntityLayout>
|
||||
<EntityLayout.Route path="/" title="Overview">
|
||||
<Grid container spacing={3} alignItems="stretch">
|
||||
<Grid item md={6}>
|
||||
<EntityAboutCard variant="gridItem" />
|
||||
</Grid>
|
||||
<Grid item md={6}>
|
||||
<EntityHasComponentsCard variant="gridItem" />
|
||||
</Grid>
|
||||
<Grid item md={6}>
|
||||
<EntityHasApisCard variant="gridItem" />
|
||||
</Grid>
|
||||
<Grid item md={6}>
|
||||
<EntityHasResourcesCard variant="gridItem" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</EntityLayout.Route>
|
||||
<EntityLayout.Route path="/diagram" title="Diagram">
|
||||
<EntitySystemDiagramCard />
|
||||
</EntityLayout.Route>
|
||||
|
||||
{/* Adding a new tab to the system view */}
|
||||
<EntityLayout.Route path="/your-custom-route" title="CustomTitle">
|
||||
<MyPluginEntityContent />
|
||||
</EntityLayout.Route>
|
||||
</EntityLayout>
|
||||
);
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user