diff --git a/.changeset/nasty-humans-give.md b/.changeset/nasty-humans-give.md new file mode 100644 index 0000000000..85ce3149ba --- /dev/null +++ b/.changeset/nasty-humans-give.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Added the prop `NotFoundComponent` to `EntityLayout` which can be used to include a custom component when an entity is not found in the catalog diff --git a/plugins/catalog/api-report.md b/plugins/catalog/api-report.md index d1e733a553..f9c0df5abc 100644 --- a/plugins/catalog/api-report.md +++ b/plugins/catalog/api-report.md @@ -247,6 +247,8 @@ export const EntityLayout: { export interface EntityLayoutProps { // (undocumented) children?: React_2.ReactNode; + // (undocumented) + NotFoundComponent?: React_2.ReactNode; // Warning: (ae-forgotten-export) The symbol "contextMenuOptions" needs to be exported by the entry point index.d.ts // // (undocumented) diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx index c1deaf4b74..0a3f443d3e 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.test.tsx @@ -106,7 +106,7 @@ describe('EntityLayout', () => { expect(rendered.getByText('tabbed-test-content')).toBeInTheDocument(); }); - it('renders error message when entity is not found', async () => { + it('renders default error message when entity is not found', async () => { const rendered = await renderInTestApp( @@ -130,6 +130,34 @@ describe('EntityLayout', () => { expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); }); + it('renders custom message when entity is not found', async () => { + const rendered = await renderInTestApp( + + + Oppps.. Your entity was not found} + > + +
tabbed-test-content
+
+
+
+
, + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, + ); + + expect( + rendered.getByText('Oppps.. Your entity was not found'), + ).toBeInTheDocument(); + expect(rendered.queryByText('my-entity')).not.toBeInTheDocument(); + expect(rendered.queryByText('tabbed-test-title')).not.toBeInTheDocument(); + expect(rendered.queryByText('tabbed-test-content')).not.toBeInTheDocument(); + }); + it('navigates when user clicks different tab', async () => { const rendered = await renderInTestApp( diff --git a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx index d4244419cb..693137fe21 100644 --- a/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/components/EntityLayout/EntityLayout.tsx @@ -152,6 +152,7 @@ export interface EntityLayoutProps { UNSTABLE_extraContextMenuItems?: ExtraContextMenuItem[]; UNSTABLE_contextMenuOptions?: contextMenuOptions; children?: React.ReactNode; + NotFoundComponent?: React.ReactNode; } /** @@ -176,6 +177,7 @@ export const EntityLayout = (props: EntityLayoutProps) => { UNSTABLE_extraContextMenuItems, UNSTABLE_contextMenuOptions, children, + NotFoundComponent, } = props; const { kind, namespace, name } = useRouteRefParams(entityRouteRef); const { entity, loading, error } = useAsyncEntity(); @@ -265,13 +267,17 @@ export const EntityLayout = (props: EntityLayoutProps) => { {!loading && !error && !entity && ( - - There is no {kind} with the requested{' '} - - kind, namespace, and name - - . - + {NotFoundComponent ? ( + NotFoundComponent + ) : ( + + There is no {kind} with the requested{' '} + + kind, namespace, and name + + . + + )} )}