Review feedback 2: electric boogaloo

Co-authored-by: Otto Sichert <git@ottosichert.de>
Co-authored-by: Anders Näsman <realandersn@users.noreply.github.com>
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
Eric Peterson
2022-04-12 15:13:04 +02:00
parent a357c354af
commit 39a6eda01d
24 changed files with 271 additions and 245 deletions
+2
View File
@@ -34,6 +34,7 @@ export const techdocsStorageApiRef = createApiRef<TechDocsStorageApi>({
* Utility API reference for the {@link TechDocsApi}.
*
* @public
* @deprecated Import from `@backstage/plugin-techdocs-react` instead
*/
export const techdocsApiRef = createApiRef<TechDocsApi>({
id: 'plugin.techdocs.service',
@@ -71,6 +72,7 @@ export interface TechDocsStorageApi {
* API to talk to techdocs-backend.
*
* @public
* @deprecated Import from `@backstage/plugin-techdocs-react` instead
*/
export interface TechDocsApi {
getApiOrigin(): Promise<string>;
@@ -19,7 +19,10 @@ 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/plugin-techdocs-react';
import {
TECHDOCS_ADDONS_WRAPPER_KEY,
TechDocsReaderPageProvider,
} from '@backstage/plugin-techdocs-react';
import { TechDocsReaderPageRenderFunction } from '../../../types';
@@ -27,8 +30,6 @@ import { TechDocsReaderPageContent } from '../TechDocsReaderPageContent';
import { TechDocsReaderPageHeader } from '../TechDocsReaderPageHeader';
import { TechDocsReaderPageSubheader } from '../TechDocsReaderPageSubheader';
import { TechDocsReaderPageProvider } from './context';
type Extension = ReactChild & {
type: {
__backstage_data: {
@@ -81,14 +82,11 @@ export type TechDocsReaderPageProps = {
* An addon-aware implementation of the TechDocsReaderPage.
* @public
*/
export const TechDocsReaderPage = ({
entityRef,
children,
}: TechDocsReaderPageProps) => {
export const TechDocsReaderPage = (props: TechDocsReaderPageProps) => {
const { kind, name, namespace } = useParams();
const { children, entityRef = { kind, name, namespace } } = props;
const outlet = useOutlet();
const entityName = entityRef ?? { kind, name, namespace };
if (!children) {
const childrenList = outlet ? Children.toArray(outlet.props.children) : [];
@@ -100,7 +98,7 @@ export const TechDocsReaderPage = ({
return (
(page as JSX.Element) || (
<TechDocsReaderPageProvider entityName={entityName}>
<TechDocsReaderPageProvider entityRef={entityRef}>
<TechDocsReaderLayout />
</TechDocsReaderPageProvider>
)
@@ -108,12 +106,12 @@ export const TechDocsReaderPage = ({
}
return (
<TechDocsReaderPageProvider entityName={entityName}>
<TechDocsReaderPageProvider entityRef={entityRef}>
{({ metadata, entityMetadata, onReady }) => (
<Page themeId="documentation">
{children instanceof Function
? children({
entityRef: entityName,
entityRef,
techdocsMetadataValue: metadata.value,
entityMetadataValue: entityMetadata.value,
onReady,
@@ -22,15 +22,13 @@ import { ThemeProvider } from '@material-ui/core';
import { lightTheme } from '@backstage/theme';
import { TestApiProvider } from '@backstage/test-utils';
import { Entity, CompoundEntityRef } from '@backstage/catalog-model';
import { TechDocsMetadata } from '@backstage/plugin-techdocs-react';
import { techdocsApiRef } from '../../../api';
import {
useEntityMetadata,
useTechDocsMetadata,
techdocsApiRef,
TechDocsMetadata,
TechDocsReaderPageProvider,
} from './context';
} from '@backstage/plugin-techdocs-react';
import { useEntityMetadata, useTechDocsMetadata } from './context';
const mockEntityMetadata: Entity = {
apiVersion: 'v1',
@@ -55,19 +53,19 @@ const techdocsApiMock = {
};
const wrapper = ({
entityName = {
entityRef = {
kind: mockEntityMetadata.kind,
name: mockEntityMetadata.metadata.name,
namespace: mockEntityMetadata.metadata.namespace!!,
},
children,
}: {
entityName?: CompoundEntityRef;
entityRef?: CompoundEntityRef;
children: React.ReactNode;
}) => (
<ThemeProvider theme={lightTheme}>
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
<TechDocsReaderPageProvider entityName={entityName}>
<TechDocsReaderPageProvider entityRef={entityRef}>
{children}
</TechDocsReaderPageProvider>
</TestApiProvider>
@@ -14,103 +14,7 @@
* limitations under the License.
*/
import React, { ReactNode, memo, useState } from 'react';
import useAsync from 'react-use/lib/useAsync';
import { useApi } from '@backstage/core-plugin-api';
import { CompoundEntityRef } from '@backstage/catalog-model';
import {
TechDocsReaderPageValue,
defaultTechDocsReaderPageValue,
TechDocsReaderPageContext,
useTechDocsReaderPage,
} from '@backstage/plugin-techdocs-react';
import { createVersionedValueMap } from '@backstage/version-bridge';
import { techdocsApiRef } from '../../../api';
const areEntityNamesEqual = (
prevEntityName: CompoundEntityRef,
nextEntityName: CompoundEntityRef,
) => {
if (prevEntityName.kind !== nextEntityName.kind) {
return false;
}
if (prevEntityName.name !== nextEntityName.name) {
return false;
}
if (prevEntityName.namespace !== nextEntityName.namespace) {
return false;
}
return true;
};
/**
* render function for {@link TechDocsReaderPageProvider}
*
* @public
*/
export type TechDocsReaderPageProviderRenderFunction = (
value: TechDocsReaderPageValue,
) => JSX.Element;
/**
* Props for {@link TechDocsReaderPageProvider}
*
* @public
*/
export type TechDocsReaderPageProviderProps = {
entityName: CompoundEntityRef;
children: TechDocsReaderPageProviderRenderFunction | ReactNode;
};
/**
* A context to store the reader page state
* @public
*/
export const TechDocsReaderPageProvider = memo(
({ entityName, children }: TechDocsReaderPageProviderProps) => {
const techdocsApi = useApi(techdocsApiRef);
const metadata = useAsync(async () => {
return techdocsApi.getTechDocsMetadata(entityName);
}, [entityName]);
const entityMetadata = useAsync(async () => {
return techdocsApi.getEntityMetadata(entityName);
}, [entityName]);
const [title, setTitle] = useState(defaultTechDocsReaderPageValue.title);
const [subtitle, setSubtitle] = useState(
defaultTechDocsReaderPageValue.subtitle,
);
const [shadowRoot, setShadowRoot] = useState<ShadowRoot | undefined>(
defaultTechDocsReaderPageValue.shadowRoot,
);
const value = {
metadata,
entityName,
entityMetadata,
shadowRoot,
setShadowRoot,
title,
setTitle,
subtitle,
setSubtitle,
};
const versionedValue = createVersionedValueMap({ 1: value });
return (
<TechDocsReaderPageContext.Provider value={versionedValue}>
{children instanceof Function ? children(value) : children}
</TechDocsReaderPageContext.Provider>
);
},
(prevProps, nextProps) => {
return areEntityNamesEqual(prevProps.entityName, nextProps.entityName);
},
);
import { useTechDocsReaderPage } from '@backstage/plugin-techdocs-react';
/**
* Hook for sub-components to retrieve Entity Metadata for the current TechDocs
@@ -19,8 +19,3 @@ export type {
TechDocsReaderPageProps,
TechDocsReaderLayoutProps,
} from './TechDocsReaderPage';
export { TechDocsReaderPageProvider } from './context';
export type {
TechDocsReaderPageProviderProps,
TechDocsReaderPageProviderRenderFunction,
} from './context';
@@ -72,8 +72,8 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider(
const { withSearch = true, onReady } = props;
const classes = useStyles();
const addons = useTechDocsAddons();
const { entityName, shadowRoot, setShadowRoot } = useTechDocsReaderPage();
const dom = useTechDocsReaderDom(entityName);
const { entityRef, shadowRoot, setShadowRoot } = useTechDocsReaderPage();
const dom = useTechDocsReaderDom(entityRef);
const [jss, setJss] = useState(
create({
@@ -138,7 +138,7 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider(
</Grid>
{withSearch && (
<Grid className={classes.search} xs="auto" item>
<TechDocsSearch entityId={entityName} />
<TechDocsSearch entityId={entityRef} />
</Grid>
)}
<Grid xs={12} item>
@@ -146,13 +146,13 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider(
<StylesProvider jss={jss} sheetsManager={new Map()}>
<div ref={ref} data-testid="techdocs-native-shadowroot" />
<Portal container={primarySidebarAddonLocation}>
{addons.renderComponentsByLocation(locations.PRIMARY_SIDEBAR)}
{addons.renderComponentsByLocation(locations.PrimarySidebar)}
</Portal>
<Portal container={contentElement}>
{addons.renderComponentsByLocation(locations.CONTENT)}
{addons.renderComponentsByLocation(locations.Content)}
</Portal>
<Portal container={secondarySidebarAddonLocation}>
{addons.renderComponentsByLocation(locations.SECONDARY_SIDEBAR)}
{addons.renderComponentsByLocation(locations.SecondarySidebar)}
</Portal>
</StylesProvider>
</Grid>
@@ -62,8 +62,8 @@ export const TechDocsReaderProvider = ({
children,
}: TechDocsReaderProviderProps) => {
const { '*': path = '' } = useParams();
const { entityName } = useTechDocsReaderPage();
const { kind, namespace, name } = entityName;
const { entityRef } = useTechDocsReaderPage();
const { kind, namespace, name } = entityRef;
const value = useReaderState(kind, namespace, name, path);
return (
@@ -75,7 +75,7 @@ export const useTechDocsReaderDom = (
const techdocsStorageApi = useApi(techdocsStorageApiRef);
const scmIntegrationsApi = useApi(scmIntegrationsApiRef);
const techdocsSanitizer = useApi(configApiRef);
const { namespace = '', kind = '', name = '' } = entityRef;
const { namespace, kind, name } = entityRef;
const { state, path, content: rawPage } = useTechDocsReader();
const isDarkTheme = theme.palette.type === 'dark';
@@ -21,13 +21,14 @@ import { ThemeProvider } from '@material-ui/core';
import { lightTheme } from '@backstage/theme';
import { CompoundEntityRef } from '@backstage/catalog-model';
import { entityRouteRef } from '@backstage/plugin-catalog-react';
import {
techdocsApiRef,
TechDocsReaderPageProvider,
} from '@backstage/plugin-techdocs-react';
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
import { techdocsApiRef } from '../../../api';
import { rootRouteRef } from '../../../routes';
import { TechDocsReaderPageProvider } from '../TechDocsReaderPage';
import { TechDocsReaderPageHeader } from './TechDocsReaderPageHeader';
const mockEntityMetadata = {
@@ -60,19 +61,19 @@ const techdocsApiMock = {
};
const Wrapper = ({
entityName = {
entityRef = {
kind: mockEntityMetadata.kind,
name: mockEntityMetadata.metadata.name,
namespace: mockEntityMetadata.metadata.namespace!!,
},
children,
}: {
entityName?: CompoundEntityRef;
entityRef?: CompoundEntityRef;
children: React.ReactNode;
}) => (
<ThemeProvider theme={lightTheme}>
<TestApiProvider apis={[[techdocsApiRef, techdocsApiMock]]}>
<TechDocsReaderPageProvider entityName={entityName}>
<TechDocsReaderPageProvider entityRef={entityRef}>
{children}
</TechDocsReaderPageProvider>
</TestApiProvider>
@@ -70,7 +70,7 @@ export const TechDocsReaderPageHeader = (
setTitle,
subtitle,
setSubtitle,
entityName,
entityRef,
metadata: { value: metadata },
entityMetadata: { value: entityMetadata },
} = useTechDocsReaderPage();
@@ -109,7 +109,7 @@ export const TechDocsReaderPageHeader = (
value={
<EntityRefLink
color="inherit"
entityRef={entityName}
entityRef={entityRef}
defaultKind="Component"
/>
}
@@ -158,7 +158,7 @@ export const TechDocsReaderPageHeader = (
</Helmet>
{labels}
{children}
{addons.renderComponentsByLocation(locations.HEADER)}
{addons.renderComponentsByLocation(locations.Header)}
</Header>
);
};
@@ -37,19 +37,22 @@ export const TechDocsReaderPageSubheader = withStyles(theme => ({
},
}))(({ toolbarProps }: { toolbarProps?: ToolbarProps }) => {
const addons = useTechDocsAddons();
const subheaderAddons = addons.renderComponentsByLocation(
locations.Subheader,
);
if (!addons.renderComponentsByLocation(locations.SUBHEADER)) return null;
if (!subheaderAddons) return null;
return (
<Toolbar {...toolbarProps}>
{addons.renderComponentsByLocation(locations.SUBHEADER) && (
{subheaderAddons && (
<Box
display="flex"
justifyContent="flex-end"
width="100%"
flexWrap="wrap"
>
{addons.renderComponentsByLocation(locations.SUBHEADER)}
{subheaderAddons}
</Box>
)}
</Toolbar>
@@ -17,13 +17,8 @@
export type {
TechDocsReaderPageProps,
TechDocsReaderLayoutProps,
TechDocsReaderPageProviderProps,
TechDocsReaderPageProviderRenderFunction,
} from './TechDocsReaderPage';
export {
TechDocsReaderLayout,
TechDocsReaderPageProvider,
} from './TechDocsReaderPage';
export { TechDocsReaderLayout } from './TechDocsReaderPage';
export * from './TechDocsReaderPageHeader';
export * from './TechDocsReaderPageContent';
export * from './TechDocsReaderPageSubheader';