diff --git a/.changeset/pink-countries-pump.md b/.changeset/pink-countries-pump.md index 01c75b01e7..b7a79238fd 100644 --- a/.changeset/pink-countries-pump.md +++ b/.changeset/pink-countries-pump.md @@ -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. diff --git a/docs/features/software-catalog/catalog-customization.md b/docs/features/software-catalog/catalog-customization.md new file mode 100644 index 0000000000..bdad78a35c --- /dev/null +++ b/docs/features/software-catalog/catalog-customization.md @@ -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 ( + + + + + All your software catalog entities + +
+ +
+
+ +
+
+
+
+ ); +}; +``` + +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 = () => { +... +
+- ++ > +
+... +``` + +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(); + const [enabled, setEnabled] = useState(false); + + useEffect(() => { + updateFilters({ itgc: enabled ? new ItgcEntityFilter() : undefined }); + }, [enabled, updateFilters]); + + return ( + setEnabled(isEnabled => !isEnabled)} + name="itgc-picker" + /> + } + label="ITGC Required" + /> + ); +}; +``` + +Now I can add the component to `CustomCatalogIndexPage`: + +```diff +export const CustomCatalogIndexPage = () => { + return ( + ... + +
+
+ +
+ ... +}; +``` + +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. diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 6c42614a61..b8ed72596d 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -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" ] }, diff --git a/mkdocs.yml b/mkdocs.yml index 574b04f8f7..a87acc91c8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -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' diff --git a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx index e8c783de39..86980d098f 100644 --- a/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx +++ b/plugins/catalog-react/src/components/EntityKindPicker/EntityKindPicker.tsx @@ -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 Kind filter not yet available; };