fix(techdocs): add backwards compatibility
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
@@ -24,11 +24,11 @@ import { TechDocsReaderLayout } from './reader';
|
||||
type EntityPageDocsProps = { entity: Entity };
|
||||
|
||||
export const EntityPageDocs = ({ entity }: EntityPageDocsProps) => {
|
||||
const entityName = getCompoundEntityRef(entity);
|
||||
const entityRef = getCompoundEntityRef(entity);
|
||||
|
||||
return (
|
||||
<TechDocsReaderPage entityName={entityName}>
|
||||
<TechDocsReaderLayout hideHeader />
|
||||
<TechDocsReaderPage entityRef={entityRef}>
|
||||
<TechDocsReaderLayout withHeader={false} />
|
||||
</TechDocsReaderPage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import React, { ReactNode, ReactChild, Children } from 'react';
|
||||
import { useOutlet, useParams } from 'react-router-dom';
|
||||
|
||||
import { Page } from '@backstage/core-components';
|
||||
import { CompoundEntityRef } from '@backstage/catalog-model';
|
||||
import { TECHDOCS_ADDONS_WRAPPER_KEY } from '@backstage/techdocs-addons';
|
||||
|
||||
import { TechDocsReaderPageRenderFunction } from '../../../types';
|
||||
|
||||
@@ -28,27 +29,37 @@ import { TechDocsReaderPageSubheader } from '../TechDocsReaderPageSubheader';
|
||||
|
||||
import { TechDocsReaderPageProvider } from './context';
|
||||
|
||||
type Extension = ReactChild & {
|
||||
type: {
|
||||
__backstage_data: {
|
||||
map: Map<string, boolean>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type TechDocsReaderLayoutProps = {
|
||||
hideHeader?: boolean;
|
||||
withHeader?: boolean;
|
||||
withSearch?: boolean;
|
||||
};
|
||||
|
||||
export const TechDocsReaderLayout = ({
|
||||
hideHeader = false,
|
||||
withSearch,
|
||||
}: TechDocsReaderLayoutProps) => (
|
||||
<>
|
||||
{!hideHeader && <TechDocsReaderPageHeader />}
|
||||
<TechDocsReaderPageSubheader />
|
||||
<TechDocsReaderPageContent withSearch={withSearch} />
|
||||
</>
|
||||
);
|
||||
withHeader = true,
|
||||
}: TechDocsReaderLayoutProps) => {
|
||||
return (
|
||||
<>
|
||||
{withHeader && <TechDocsReaderPageHeader />}
|
||||
<TechDocsReaderPageSubheader />
|
||||
<TechDocsReaderPageContent withSearch={withSearch} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type TechDocsReaderPageProps = {
|
||||
entityName?: CompoundEntityRef;
|
||||
entityRef?: CompoundEntityRef;
|
||||
children?: TechDocsReaderPageRenderFunction | ReactNode;
|
||||
};
|
||||
|
||||
@@ -57,12 +68,31 @@ export type TechDocsReaderPageProps = {
|
||||
* @public
|
||||
*/
|
||||
export const TechDocsReaderPage = ({
|
||||
entityName: defaultEntityName,
|
||||
children = <TechDocsReaderLayout />,
|
||||
entityRef,
|
||||
children,
|
||||
}: TechDocsReaderPageProps) => {
|
||||
const { kind, name, namespace } = useParams();
|
||||
const route = useOutlet() || { props: { children: [] } };
|
||||
const entityName = entityRef ?? { kind, name, namespace };
|
||||
|
||||
const entityName = defaultEntityName || { kind, name, namespace };
|
||||
if (!children) {
|
||||
const outlet = Children.toArray(route.props.children);
|
||||
|
||||
const page = outlet.find(child => {
|
||||
const { type } = child as Extension;
|
||||
return !type?.__backstage_data?.map?.get(TECHDOCS_ADDONS_WRAPPER_KEY);
|
||||
});
|
||||
|
||||
return (
|
||||
(page as JSX.Element) || (
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
<Page themeId="documentation">
|
||||
<TechDocsReaderLayout />
|
||||
</Page>
|
||||
</TechDocsReaderPageProvider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
|
||||
@@ -30,8 +30,6 @@ import {
|
||||
useEntityMetadata,
|
||||
useTechDocsMetadata,
|
||||
useTechDocsReaderPage,
|
||||
TechDocsEntityProvider,
|
||||
TechDocsMetadataProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
} from './context';
|
||||
|
||||
@@ -65,7 +63,6 @@ const techdocsApiMock = {
|
||||
};
|
||||
|
||||
const wrapper = ({
|
||||
path = '',
|
||||
entityName = {
|
||||
kind: mockEntityMetadata.kind,
|
||||
name: mockEntityMetadata.metadata.name,
|
||||
@@ -73,19 +70,14 @@ const wrapper = ({
|
||||
},
|
||||
children,
|
||||
}: {
|
||||
path?: string;
|
||||
entityName?: CompoundEntityRef;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider path={path} entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TestApiProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
+29
-24
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useRef, useState, useEffect, useCallback } from 'react';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { create } from 'jss';
|
||||
|
||||
import { makeStyles, Grid, Portal } from '@material-ui/core';
|
||||
@@ -45,16 +45,16 @@ const useStyles = makeStyles({
|
||||
|
||||
export type TechDocsReaderPageContentProps = {
|
||||
withSearch?: boolean;
|
||||
onReady?: () => void;
|
||||
};
|
||||
|
||||
export const TechDocsReaderPageContent = withTechDocsReaderProvider(
|
||||
({ withSearch = true }: TechDocsReaderPageContentProps) => {
|
||||
({ withSearch = true, onReady }: TechDocsReaderPageContentProps) => {
|
||||
const classes = useStyles();
|
||||
const addons = useTechDocsAddons();
|
||||
const { entityName, setShadowRoot } = useTechDocsReaderPage();
|
||||
const { entityName, shadowRoot, setShadowRoot } = useTechDocsReaderPage();
|
||||
const dom = useTechDocsReaderDom(entityName);
|
||||
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
const [jss, setJss] = useState(
|
||||
create({
|
||||
...jssPreset(),
|
||||
@@ -62,31 +62,36 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider(
|
||||
}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const shadowHost = ref.current;
|
||||
if (!dom || !shadowHost) return;
|
||||
const ref = useCallback(
|
||||
(shadowHost: HTMLDivElement) => {
|
||||
if (!dom || !shadowHost) return;
|
||||
|
||||
setJss(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: dom.querySelector('head') || undefined,
|
||||
}),
|
||||
);
|
||||
setJss(
|
||||
create({
|
||||
...jssPreset(),
|
||||
insertionPoint: dom.querySelector('head') || undefined,
|
||||
}),
|
||||
);
|
||||
|
||||
const shadowRoot =
|
||||
shadowHost.shadowRoot ?? shadowHost.attachShadow({ mode: 'open' });
|
||||
shadowRoot.innerHTML = '';
|
||||
shadowRoot.appendChild(dom);
|
||||
setShadowRoot(shadowRoot);
|
||||
}, [dom, setShadowRoot]);
|
||||
|
||||
const contentElement = ref.current?.querySelector(
|
||||
'[data-md-component="container"]',
|
||||
const newShadowRoot =
|
||||
shadowHost.shadowRoot ?? shadowHost.attachShadow({ mode: 'open' });
|
||||
newShadowRoot.innerHTML = '';
|
||||
newShadowRoot.appendChild(dom);
|
||||
setShadowRoot(newShadowRoot);
|
||||
if (onReady instanceof Function) {
|
||||
onReady();
|
||||
}
|
||||
},
|
||||
[dom, setShadowRoot, onReady],
|
||||
);
|
||||
const primarySidebarElement = ref.current?.querySelector(
|
||||
|
||||
const contentElement = shadowRoot?.querySelector(
|
||||
'[data-md-component="content"]',
|
||||
);
|
||||
const primarySidebarElement = shadowRoot?.querySelector(
|
||||
'div[data-md-component="sidebar"][data-md-type="navigation"], div[data-md-component="navigation"]',
|
||||
);
|
||||
const secondarySidebarElement = ref.current?.querySelector(
|
||||
const secondarySidebarElement = shadowRoot?.querySelector(
|
||||
'div[data-md-component="sidebar"][data-md-type="toc"], div[data-md-component="toc"]',
|
||||
);
|
||||
|
||||
|
||||
+4
-14
@@ -26,11 +26,7 @@ import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
|
||||
import { techdocsApiRef } from '../../../api';
|
||||
import { rootRouteRef } from '../../../routes';
|
||||
|
||||
import {
|
||||
TechDocsEntityProvider,
|
||||
TechDocsMetadataProvider,
|
||||
TechDocsReaderPageProvider,
|
||||
} from '../TechDocsReaderPage';
|
||||
import { TechDocsReaderPageProvider } from '../TechDocsReaderPage';
|
||||
|
||||
import { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader';
|
||||
|
||||
@@ -64,7 +60,6 @@ const techdocsApiMock = {
|
||||
};
|
||||
|
||||
const Wrapper = ({
|
||||
path = '',
|
||||
entityName = {
|
||||
kind: mockEntityMetadata.kind,
|
||||
name: mockEntityMetadata.metadata.name,
|
||||
@@ -72,19 +67,14 @@ const Wrapper = ({
|
||||
},
|
||||
children,
|
||||
}: {
|
||||
path?: string;
|
||||
entityName?: CompoundEntityRef;
|
||||
children: React.ReactNode;
|
||||
}) => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
|
||||
<TechDocsMetadataProvider entityName={entityName}>
|
||||
<TechDocsEntityProvider entityName={entityName}>
|
||||
<TechDocsReaderPageProvider path={path} entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TechDocsEntityProvider>
|
||||
</TechDocsMetadataProvider>
|
||||
<TechDocsReaderPageProvider entityName={entityName}>
|
||||
{children}
|
||||
</TechDocsReaderPageProvider>
|
||||
</TestApiProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
+1
-2
@@ -39,7 +39,7 @@ import { rootRouteRef } from '../../../routes';
|
||||
|
||||
const skeleton = <Skeleton animation="wave" variant="text" height={40} />;
|
||||
|
||||
export const TechDocsReaderPageHeader: FC = ({ children }) => {
|
||||
export const TechDocsReaderPageHeader = () => {
|
||||
const addons = useTechDocsAddons();
|
||||
const configApi = useApi(configApiRef);
|
||||
|
||||
@@ -135,7 +135,6 @@ export const TechDocsReaderPageHeader: FC = ({ children }) => {
|
||||
<title>{tabTitle}</title>
|
||||
</Helmet>
|
||||
{labels}
|
||||
{children}
|
||||
{addons.renderComponentsByLocation(locations.HEADER)}
|
||||
</Header>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user