Merge pull request #14323 from agentbellnorm/fix-techdocs-cli-serve
[TechDocs] Fix techdocs cli serve
This commit is contained in:
@@ -35,6 +35,82 @@ import {
|
||||
useRouteRefParams,
|
||||
} from '@backstage/core-plugin-api';
|
||||
|
||||
/* An explanation for the multiple ways of customizing the TechDocs reader page
|
||||
|
||||
Please refer to this page on the microsite for the latest recommended approach:
|
||||
https://backstage.io/docs/features/techdocs/how-to-guides#how-to-customize-the-techdocs-reader-page
|
||||
|
||||
The <TechDocsReaderPage> component is responsible for rendering the <TechDocsReaderPageProvider> and
|
||||
its contained version of a <Page>, which in turn renders the <TechDocsReaderPageContent>.
|
||||
|
||||
Historically, there have been different approaches on how this <Page> can be customized, and how the
|
||||
<TechDocsReaderPageContent> inside could be exchanged for a custom implementation (which was not
|
||||
possible before). Also, the current implementation supports every scenario to avoid breaking default
|
||||
configurations of TechDocs.
|
||||
|
||||
In particular, there are 4 different TechDocs page configurations:
|
||||
|
||||
CONFIGURATION 1: <TechDocsReaderPage> only, no children
|
||||
|
||||
<Route path="/docs/:namespace/:kind/:name/*" element={<TechDocsReaderPage />} >
|
||||
|
||||
This is the simplest way to use TechDocs. Only a full page is passed, assuming that it comes with
|
||||
its content inside. Since we allowed customizing it, we started providing <TechDocsReaderLayout> as
|
||||
a default implementation (which contains <TechDocsReaderPageContent>).
|
||||
|
||||
CONFIGURATION 2 (not advised): <TechDocsReaderPage> with element children
|
||||
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={
|
||||
<TechDocsReaderPage>
|
||||
{techdocsPage}
|
||||
</TechDocsReaderPage>
|
||||
}
|
||||
/>
|
||||
|
||||
Previously, there were two ways of passing children to <TechDocsReaderPage>: either as elements (as
|
||||
shown above), or as a render function (described below in CONFIGURATION 3). The "techdocsPage" is
|
||||
located in packages/app/src/components/techdocs and is the default implementation of the content
|
||||
inside.
|
||||
|
||||
CONFIGURATION 3 (not advised): <TechDocsReaderPage> with render function as child
|
||||
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={
|
||||
<TechDocsReaderPage>
|
||||
{({ metadata, entityMetadata, onReady }) => (
|
||||
techdocsPage
|
||||
)}
|
||||
</TechDocsReaderPage>
|
||||
}
|
||||
/>
|
||||
|
||||
Similar to CONFIGURATION 2, the direct children will be passed to the <TechDocsReaderPage> but in
|
||||
this case interpreted as render prop.
|
||||
|
||||
CONFIGURATION 4: <TechDocsReaderPage> and provided content in <Route>
|
||||
|
||||
<Route
|
||||
path="/docs/:namespace/:kind/:name/*"
|
||||
element={<TechDocsReaderPage />}
|
||||
>
|
||||
{techDocsPage}
|
||||
<TechDocsAddons>
|
||||
<ExpandableNavigation />
|
||||
<ReportIssue />
|
||||
<TextSize />
|
||||
</TechDocsAddons>
|
||||
</Route>
|
||||
|
||||
This is the current state in packages/app/src/App.tsx and moved the location of children from inside
|
||||
the element prop in the <Route> to the children of the <Route>. Then, in <TechDocsReaderPage> they
|
||||
are retrieved using the useOutlet hook from React Router.
|
||||
|
||||
NOTE: Render functions are no longer supported in this approach.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Props for {@link TechDocsReaderLayout}
|
||||
* @public
|
||||
@@ -77,6 +153,7 @@ export type TechDocsReaderPageProps = {
|
||||
|
||||
/**
|
||||
* An addon-aware implementation of the TechDocsReaderPage.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
|
||||
@@ -88,21 +165,14 @@ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
|
||||
if (!children) {
|
||||
const childrenList = outlet ? Children.toArray(outlet.props.children) : [];
|
||||
|
||||
const page = childrenList.find(child => {
|
||||
if (getComponentData(child, TECHDOCS_ADDONS_WRAPPER_KEY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// react-router 6 stable wraps children in a routing context provider, so check one level deeper
|
||||
const nestedChildren = (child as ReactElement)?.props?.children;
|
||||
if (nestedChildren) {
|
||||
return !Children.toArray(nestedChildren).some(nested =>
|
||||
getComponentData(nested, TECHDOCS_ADDONS_WRAPPER_KEY),
|
||||
);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const grandChildren = childrenList.flatMap(
|
||||
child => (child as ReactElement)?.props?.children ?? [],
|
||||
);
|
||||
const page: React.ReactNode = grandChildren.find(
|
||||
grandChild => !getComponentData(grandChild, TECHDOCS_ADDONS_WRAPPER_KEY),
|
||||
);
|
||||
|
||||
// As explained above, "page" is configuration 4 and <TechDocsReaderLayout> is 1
|
||||
return (
|
||||
<TechDocsReaderPageProvider entityRef={entityRef}>
|
||||
{(page as JSX.Element) || <TechDocsReaderLayout />}
|
||||
@@ -110,6 +180,7 @@ export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
|
||||
);
|
||||
}
|
||||
|
||||
// As explained above, a render function is configuration 3 and React element is 2
|
||||
return (
|
||||
<TechDocsReaderPageProvider entityRef={entityRef}>
|
||||
{({ metadata, entityMetadata, onReady }) => (
|
||||
|
||||
Reference in New Issue
Block a user