diff --git a/.changeset/healthy-shoes-flash.md b/.changeset/healthy-shoes-flash.md
new file mode 100644
index 0000000000..8ca1006635
--- /dev/null
+++ b/.changeset/healthy-shoes-flash.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-techdocs': minor
+---
+
+Added ability for to display a custom error page component via prop "NotFoundPage"
diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx
index b297466a62..5dfa104a25 100644
--- a/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx
+++ b/plugins/techdocs/src/reader/components/TechDocsPage.test.tsx
@@ -173,4 +173,62 @@ describe('', () => {
expect(rendered.getByText('A custom header')).toBeInTheDocument();
});
});
+
+ it('should render a custom error page if supplied', async () => {
+ const CustomErrorPage = ({ errorMessage }: { errorMessage: string }) => (
+
{errorMessage}
+ );
+
+ useParams.mockReturnValue({
+ entityRef: 'Component::backstage',
+ });
+
+ const scmIntegrationsApi: ScmIntegrationsApi =
+ ScmIntegrationsApi.fromConfig(
+ new ConfigReader({
+ integrations: {},
+ }),
+ );
+ const techdocsApi: Partial = {
+ getEntityMetadata: () =>
+ Promise.reject({
+ name: 'error',
+ message: 'error message',
+ }),
+ getTechDocsMetadata: () =>
+ Promise.resolve({
+ site_name: 'string',
+ site_description: 'string',
+ }),
+ };
+
+ const techdocsStorageApi: Partial = {
+ getEntityDocs: (): Promise => Promise.resolve('String'),
+ getBaseUrl: (): Promise => Promise.resolve('String'),
+ getApiOrigin: (): Promise => Promise.resolve('String'),
+ };
+ const searchApi = {
+ query: () =>
+ Promise.resolve({
+ results: [],
+ }),
+ };
+ const apiRegistry = TestApiRegistry.from(
+ [scmIntegrationsApiRef, scmIntegrationsApi],
+ [techdocsApiRef, techdocsApi],
+ [techdocsStorageApiRef, techdocsStorageApi],
+ [searchApiRef, searchApi],
+ );
+
+ await act(async () => {
+ const rendered = render(
+ wrapInTestApp(
+
+
+ ,
+ ),
+ );
+ expect(await rendered.findByText('error message')).toBeInTheDocument();
+ });
+ });
});
diff --git a/plugins/techdocs/src/reader/components/TechDocsPage.tsx b/plugins/techdocs/src/reader/components/TechDocsPage.tsx
index aae88d406e..1fb75f8d76 100644
--- a/plugins/techdocs/src/reader/components/TechDocsPage.tsx
+++ b/plugins/techdocs/src/reader/components/TechDocsPage.tsx
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-import React, { useCallback, useState } from 'react';
+import React, { useCallback, useState, ComponentType } from 'react';
import { useOutlet } from 'react-router';
import { useParams } from 'react-router-dom';
import useAsync from 'react-use/lib/useAsync';
@@ -39,9 +39,13 @@ export type TechDocsPageRenderFunction = ({
export type TechDocsPageProps = {
children?: TechDocsPageRenderFunction | React.ReactNode;
+ NotFoundPage?: ComponentType<{errorMessage: string}>
};
-export const TechDocsPage = ({ children }: TechDocsPageProps) => {
+export const TechDocsPage = ({
+ children,
+ NotFoundPage = TechDocsNotFound,
+}: TechDocsPageProps) => {
const outlet = useOutlet();
const [documentReady, setDocumentReady] = useState(false);
@@ -67,7 +71,7 @@ export const TechDocsPage = ({ children }: TechDocsPageProps) => {
}, [setDocumentReady]);
if (entityMetadataError) {
- return ;
+ return ;
}
if (!children) return outlet || ;