Add documentation for catalog customization
Signed-off-by: Tim Hansen <timbonicus@gmail.com>
This commit is contained in:
@@ -3,14 +3,22 @@
|
||||
'@backstage/plugin-catalog-react': minor
|
||||
---
|
||||
|
||||
Reworks how catalog entities are fetched from the `catalog-backend` for the main
|
||||
catalog homepage. This enables easier customization of the catalog, and supports
|
||||
showing all types of catalog entities rather than just components.
|
||||
The default `CatalogPage` has been reworked to be more composable and make
|
||||
customization easier. This change only affects those who have replaced the
|
||||
default `CatalogPage` with a custom implementation; others can safely ignore the
|
||||
rest of this changelog.
|
||||
|
||||
This change only affects those that have replaced the default `CatalogPage` with
|
||||
a custom implementation.
|
||||
If you created a custom `CatalogPage` to **add or remove tabs** from the
|
||||
catalog, a custom page is no longer necessary. The fixed tabs have been replaced
|
||||
with a `spec.type` dropdown that shows all available `Component` types in the
|
||||
catalog.
|
||||
|
||||
The `useFilteredEntities` and `useEntityFilterGroups` hooks have been replaced
|
||||
with a `useEntityListProvider` hook and wrapping `EntityListProvider` context.
|
||||
This handles querying the `catalog-backend` and applying filters that can either
|
||||
provide query parameters or a frontend filtering function.
|
||||
For other needs, customizing the `CatalogPage` should now be easier. The new
|
||||
[CatalogPage.tsx](https://github.com/backstage/backstage/blob/9a4baa74509b6452d7dc054d34cf079f9997166d/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx)
|
||||
shows the default implementation. Overriding this with your own, similar
|
||||
`CatalogPage` component in your `App.tsx` routing allows you to adjust the
|
||||
layout, header, and which filters are available.
|
||||
|
||||
See the documentation added on [Catalog
|
||||
Customization](https://backstage.io/docs/features/software-catalog/catalog-customization)
|
||||
for instructions.
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
id: catalog-customization
|
||||
title: Catalog Customization
|
||||
# prettier-ignore
|
||||
description: How to add custom filters or interface elements to the Backstage software catalog
|
||||
---
|
||||
|
||||
The Backstage software catalog comes with a default `CatalogIndexPage` to filter
|
||||
and find catalog entities. This is already set up by default by
|
||||
`@backstage/create-app`.
|
||||
|
||||
If you want to change the default index page - such as to add a custom filter to
|
||||
the catalog - you can replace the routing in `App.tsx` to point to your own
|
||||
`CatalogIndexPage`.
|
||||
|
||||
For example, suppose that I want to allow filtering by a custom annotation added
|
||||
to entities, `company.com/itgc-enabled`. To start, I'll copy the code for the
|
||||
default catalog page, either in a new plugin or just in the `app` package:
|
||||
|
||||
```tsx
|
||||
// imports, etc omitted for brevity. for full source see:
|
||||
// https://github.com/backstage/backstage/blob/master/plugins/catalog/src/components/CatalogPage/CatalogPage.tsx
|
||||
export const CustomCatalogIndexPage = () => {
|
||||
return (
|
||||
<CatalogLayout>
|
||||
<Content>
|
||||
<ContentHeader title="Components">
|
||||
<CreateComponentButton />
|
||||
<SupportButton>All your software catalog entities</SupportButton>
|
||||
</ContentHeader>
|
||||
<div className={styles.contentWrapper}>
|
||||
<EntityListProvider>
|
||||
<div>
|
||||
<EntityKindPicker initialFilter="component" hidden />
|
||||
<EntityTypePicker />
|
||||
<UserListPicker />
|
||||
<EntityTagPicker />
|
||||
</div>
|
||||
<CatalogTable />
|
||||
</EntityListProvider>
|
||||
</div>
|
||||
</Content>
|
||||
</CatalogLayout>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
The `EntityListProvider` shown here provides a list of entities from the
|
||||
`catalog-backend`, and a way to hook in filters. `EntityListProvider` has a
|
||||
[generic](https://www.typescriptlang.org/docs/handbook/2/generics.html) argument
|
||||
that can be extended to provide your own filters.
|
||||
|
||||
Now we're ready to create a new filter that implements the `EntityFilter`
|
||||
interface:
|
||||
|
||||
```ts
|
||||
import { EntityFilter } from '@backstage/catalog-react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
class ItgcEntityFilter implements EntityFilter {
|
||||
filterEntity(entity: Entity): boolean {
|
||||
return entity.metadata.annotations?.['company.com/itgc-enabled'] === true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `EntityFilter` interface permits backend filters, which are passed along to
|
||||
the `catalog-backend` - or frontend filters, which are applied after entities
|
||||
are loaded from the backend.
|
||||
|
||||
Let's create the custom filter shape extending the default and update the
|
||||
`EntityListProvider` in the custom index page to use it:
|
||||
|
||||
```diff
|
||||
+export type CustomFilters = DefaultEntityFilters & {
|
||||
+ itgc: ItgcEntityFilter;
|
||||
+};
|
||||
|
||||
export const CustomCatalogIndexPage = () => {
|
||||
...
|
||||
<div className={styles.contentWrapper}>
|
||||
- <EntityListProvider>
|
||||
+ <EntityListProvider<CustomFilters>>
|
||||
<div>
|
||||
...
|
||||
```
|
||||
|
||||
To control this filter, we can create a React component that shows a checkbox.
|
||||
This component will make use of the `useEntityListProvider` hook, which also
|
||||
accepts the same generic so we can use the added filter field:
|
||||
|
||||
```tsx
|
||||
export const ItgcPicker = () => {
|
||||
const {
|
||||
filters: { itgc: currentItgcFilter },
|
||||
updateFilters,
|
||||
} = useEntityListProvider<CustomFilters>();
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
updateFilters({ itgc: enabled ? new ItgcEntityFilter() : undefined });
|
||||
}, [enabled, updateFilters]);
|
||||
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={!!currentItgcFilter}
|
||||
onChange={() => setEnabled(isEnabled => !isEnabled)}
|
||||
name="itgc-picker"
|
||||
/>
|
||||
}
|
||||
label="ITGC Required"
|
||||
/>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Now I can add the component to `CustomCatalogIndexPage`:
|
||||
|
||||
```diff
|
||||
export const CustomCatalogIndexPage = () => {
|
||||
return (
|
||||
...
|
||||
<EntityListProvider>
|
||||
<div>
|
||||
<EntityKindPicker initialFilter="component" hidden />
|
||||
<EntityTypePicker />
|
||||
<UserListPicker />
|
||||
+ <ItgcPicker />
|
||||
<EntityTagPicker />
|
||||
</div>
|
||||
<CatalogTable />
|
||||
</EntityListProvider>
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
The same method can be used to customize the _default_ filters with a different
|
||||
interface - for such usage, the generic argument won't be needed since the
|
||||
filter shape remains the same as the default.
|
||||
@@ -43,6 +43,7 @@
|
||||
"features/software-catalog/well-known-statuses",
|
||||
"features/software-catalog/extending-the-model",
|
||||
"features/software-catalog/external-integrations",
|
||||
"features/software-catalog/catalog-customization",
|
||||
"features/software-catalog/software-catalog-api"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -40,6 +40,7 @@ nav:
|
||||
- Well-known Statuses: 'features/software-catalog/well-known-statuses.md'
|
||||
- Extending the model: 'features/software-catalog/extending-the-model.md'
|
||||
- External integrations: 'features/software-catalog/external-integrations.md'
|
||||
- Catalog Customization: 'features/software-catalog/catalog-customization.md'
|
||||
- API: 'features/software-catalog/api.md'
|
||||
- Kubernetes:
|
||||
- Overview: 'features/kubernetes/index.md'
|
||||
|
||||
@@ -39,5 +39,8 @@ export const EntityKindPicker = ({
|
||||
|
||||
if (hidden) return null;
|
||||
|
||||
// TODO(timbonicus): This should load available kinds from the catalog-backend, similar to
|
||||
// EntityTypePicker.
|
||||
|
||||
return <Alert severity="warning">Kind filter not yet available</Alert>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user