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:
@@ -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';
|
||||
|
||||
+6
-6
@@ -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';
|
||||
|
||||
|
||||
+7
-6
@@ -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>
|
||||
|
||||
+3
-3
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
+6
-3
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user