diff --git a/.changeset/tidy-hats-begin.md b/.changeset/tidy-hats-begin.md new file mode 100644 index 0000000000..ee500408e1 --- /dev/null +++ b/.changeset/tidy-hats-begin.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs-react': minor +'@backstage/plugin-techdocs': patch +--- + +Support older versions of react-router diff --git a/plugins/techdocs-react/api-report.md b/plugins/techdocs-react/api-report.md index 09da4e012c..f1d6d3f177 100644 --- a/plugins/techdocs-react/api-report.md +++ b/plugins/techdocs-react/api-report.md @@ -32,6 +32,9 @@ export const SHADOW_DOM_STYLE_LOAD_EVENT = 'TECH_DOCS_SHADOW_DOM_STYLE_LOAD'; // @public export type SyncResult = 'cached' | 'updated'; +// @public +export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; + // @public export const TECHDOCS_ADDONS_WRAPPER_KEY = 'techdocs.addons.wrapper.v1'; diff --git a/plugins/techdocs-react/src/addons.tsx b/plugins/techdocs-react/src/addons.tsx index a562007260..d77f53a426 100644 --- a/plugins/techdocs-react/src/addons.tsx +++ b/plugins/techdocs-react/src/addons.tsx @@ -27,6 +27,10 @@ import { import { TechDocsAddonLocations, TechDocsAddonOptions } from './types'; +/** + * Key for each addon. + * @public + */ export const TECHDOCS_ADDONS_KEY = 'techdocs.addons.addon.v1'; /** diff --git a/plugins/techdocs-react/src/index.ts b/plugins/techdocs-react/src/index.ts index 00ba620651..5cbab1a326 100644 --- a/plugins/techdocs-react/src/index.ts +++ b/plugins/techdocs-react/src/index.ts @@ -25,6 +25,7 @@ export { createTechDocsAddonExtension, TechDocsAddons, TECHDOCS_ADDONS_WRAPPER_KEY, + TECHDOCS_ADDONS_KEY, } from './addons'; export { techdocsApiRef, techdocsStorageApiRef } from './api'; export type { SyncResult, TechDocsApi, TechDocsStorageApi } from './api'; diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index c3e8fdca9b..0add511f41 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -67,6 +67,7 @@ "@backstage/cli": "workspace:^", "@backstage/core-app-api": "workspace:^", "@backstage/dev-utils": "workspace:^", + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^", "@backstage/test-utils": "workspace:^", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx index 4b23075908..808cb84ccf 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.test.tsx @@ -27,6 +27,12 @@ import { techdocsApiRef, techdocsStorageApiRef } from '../../../api'; import { rootRouteRef, rootDocsRouteRef } from '../../../routes'; import { TechDocsReaderPage } from './TechDocsReaderPage'; +import { Route, useParams } from 'react-router-dom'; +import { TechDocsAddons } from '@backstage/plugin-techdocs-react'; +import { ReportIssue } from '@backstage/plugin-techdocs-module-addons-contrib'; +import { FlatRoutes } from '@backstage/core-app-api'; + +import { Page } from '@backstage/core-components'; const mockEntityMetadata = { locationMetadata: { @@ -66,6 +72,16 @@ const techdocsStorageApiMock: jest.Mocked = { syncEntityDocs: jest.fn(), }; +const PageMock = () => { + const { namespace, kind, name } = useParams(); + return <>{`PageMock: ${namespace}#${kind}#${name}`}; +}; + +jest.mock('@backstage/core-components', () => ({ + ...jest.requireActual('@backstage/core-components'), + Page: jest.fn(), +})); + const Wrapper = ({ children }: { children: React.ReactNode }) => { return ( @@ -97,6 +113,12 @@ describe('', () => { afterEach(() => { jest.resetAllMocks(); }); + + beforeEach(() => { + const realPage = jest.requireActual('@backstage/core-components').Page; + (Page as jest.Mock).mockImplementation(realPage); + }); + it('should render a techdocs reader page without children', async () => { const rendered = await renderInTestApp( @@ -146,4 +168,63 @@ describe('', () => { expect(rendered.getByText('techdocs reader page')).toBeInTheDocument(); }); }); + + it('should render techdocs reader page with addons', async () => { + (Page as jest.Mock).mockImplementation(PageMock); + const name = 'test-name'; + const namespace = 'test-namespace'; + const kind = 'test'; + + await act(async () => { + const rendered = await renderInTestApp( + + + } + > + + + + + + , + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); + + expect( + rendered.getByText(`PageMock: ${namespace}#${kind}#${name}`), + ).toBeInTheDocument(); + }); + }); + + it('should render techdocs reader page with addons and page', async () => { + (Page as jest.Mock).mockImplementation(PageMock); + await act(async () => { + const rendered = await renderInTestApp( + + + } + > +

the page

+ + + +
+
+
, + { + mountedRoutes, + routeEntries: ['/docs/test-namespace/test/test-name'], + }, + ); + + expect(rendered.getByText('the page')).toBeInTheDocument(); + }); + }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx index 0e9b244d74..ffe95e0b7e 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPage/TechDocsReaderPage.tsx @@ -21,6 +21,7 @@ import { Page } from '@backstage/core-components'; import { CompoundEntityRef } from '@backstage/catalog-model'; import { TECHDOCS_ADDONS_WRAPPER_KEY, + TECHDOCS_ADDONS_KEY, TechDocsReaderPageProvider, } from '@backstage/plugin-techdocs-react'; @@ -165,11 +166,14 @@ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => { if (!children) { const childrenList = outlet ? Children.toArray(outlet.props.children) : []; - const grandChildren = childrenList.flatMap( + const grandChildren = childrenList.flatMap( child => (child as ReactElement)?.props?.children ?? [], ); + const page: React.ReactNode = grandChildren.find( - grandChild => !getComponentData(grandChild, TECHDOCS_ADDONS_WRAPPER_KEY), + grandChild => + !getComponentData(grandChild, TECHDOCS_ADDONS_WRAPPER_KEY) && + !getComponentData(grandChild, TECHDOCS_ADDONS_KEY), ); // As explained above, "page" is configuration 4 and is 1 diff --git a/yarn.lock b/yarn.lock index 5cc879e997..b20a8ce49b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8263,6 +8263,7 @@ __metadata: "@backstage/plugin-catalog-react": "workspace:^" "@backstage/plugin-search-common": "workspace:^" "@backstage/plugin-search-react": "workspace:^" + "@backstage/plugin-techdocs-module-addons-contrib": "workspace:^" "@backstage/plugin-techdocs-react": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/theme": "workspace:^"