techdocs: add ability to override entity content empty state

Signed-off-by: MT Lewis <mtlewis@users.noreply.github.com>
This commit is contained in:
MT Lewis
2024-07-24 21:51:54 +01:00
parent 8c6fe9401b
commit c7cb4c02f1
5 changed files with 132 additions and 19 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-techdocs': patch
---
Add `element:techdocs/entity-content-empty-state` extension to allow overriding the empty state for the entity page techdocs tab.
+60 -4
View File
@@ -164,9 +164,6 @@ const _default: FrontendPlugin<
inputs: {};
}>;
'entity-content:techdocs': ExtensionDefinition<{
kind: 'entity-content';
namespace: undefined;
name: undefined;
config: {
path: string | undefined;
title: string | undefined;
@@ -210,12 +207,71 @@ const _default: FrontendPlugin<
optional: true;
}
>;
inputs: {};
inputs: {
emptyState: ExtensionInput<
ConfigurableExtensionDataRef<
React_2.JSX.Element,
'core.reactElement',
{}
>,
{
singleton: true;
optional: true;
}
>;
};
kind: 'entity-content';
namespace: undefined;
name: undefined;
}>;
'element:techdocs/entity-content-empty-state': ExtensionDefinition<{
config: {};
configInput: {};
output: ConfigurableExtensionDataRef<
React_2.JSX.Element,
'core.reactElement',
{}
>;
inputs: {
[x: string]: ExtensionInput<
AnyExtensionDataRef,
{
optional: boolean;
singleton: boolean;
}
>;
};
kind: 'element';
namespace: undefined;
name: 'entity-content-empty-state';
}>;
}
>;
export default _default;
// @alpha (undocumented)
export const TechDocsEntityContentEmptyState: ExtensionDefinition<{
config: {};
configInput: {};
output: ConfigurableExtensionDataRef<
React_2.JSX.Element,
'core.reactElement',
{}
>;
inputs: {
[x: string]: ExtensionInput<
AnyExtensionDataRef,
{
optional: boolean;
singleton: boolean;
}
>;
};
kind: 'element';
namespace: undefined;
name: 'entity-content-empty-state';
}>;
// @alpha (undocumented)
export const techDocsSearchResultListItemExtension: ExtensionDefinition<{
config: {
+12 -4
View File
@@ -16,8 +16,10 @@ import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react';
import { FetchApi } from '@backstage/core-plugin-api';
import { IdentityApi } from '@backstage/core-plugin-api';
import { JSX as JSX_2 } from 'react';
import { JSXElementConstructor } from 'react';
import { PropsWithChildren } from 'react';
import { default as React_2 } from 'react';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { ResultHighlight } from '@backstage/plugin-search-common';
import { RouteRef } from '@backstage/core-plugin-api';
@@ -133,7 +135,9 @@ export type DocsTableRow = {
// @public
export const EmbeddedDocsRouter: (
props: PropsWithChildren<{}>,
props: PropsWithChildren<{
emptyState?: React_2.ReactElement;
}>,
) => React_2.JSX.Element | null;
// @public
@@ -190,9 +194,13 @@ export type EntityListDocsTableProps = {
};
// @public
export const EntityTechdocsContent: (props: {
children?: ReactNode;
}) => JSX_2.Element | null;
export const EntityTechdocsContent: (
props: PropsWithChildren<{
emptyState?:
| ReactElement<any, string | JSXElementConstructor<any>>
| undefined;
}>,
) => JSX_2.Element | null;
// @public
export const isTechDocsAvailable: (entity: Entity) => boolean;
+9 -3
View File
@@ -61,8 +61,10 @@ export const Router = () => {
*
* @public
*/
export const EmbeddedDocsRouter = (props: PropsWithChildren<{}>) => {
const { children } = props;
export const EmbeddedDocsRouter = (
props: PropsWithChildren<{ emptyState?: React.ReactElement }>,
) => {
const { children, emptyState } = props;
const { entity } = useEntity();
// Using objects instead of <Route> elements, otherwise "outlet" will be null on sub-pages and add-ons won't render
@@ -84,7 +86,11 @@ export const EmbeddedDocsRouter = (props: PropsWithChildren<{}>) => {
entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION];
if (!projectId) {
return <MissingAnnotationEmptyState annotation={[TECHDOCS_ANNOTATION]} />;
return (
emptyState ?? (
<MissingAnnotationEmptyState annotation={[TECHDOCS_ANNOTATION]} />
)
);
}
return element;
+46 -8
View File
@@ -21,8 +21,10 @@ import {
ApiBlueprint,
PageBlueprint,
NavItemBlueprint,
createExtensionInput,
coreExtensionData,
createExtension,
} from '@backstage/frontend-plugin-api';
import { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';
import {
configApiRef,
createApiFactory,
@@ -34,6 +36,10 @@ import {
convertLegacyRouteRef,
convertLegacyRouteRefs,
} from '@backstage/core-compat-api';
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
import { MissingAnnotationEmptyState } from '@backstage/plugin-catalog-react';
import { SearchResultListItemBlueprint } from '@backstage/plugin-search-react/alpha';
import { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';
import {
techdocsApiRef,
techdocsStorageApiRef,
@@ -44,7 +50,6 @@ import {
rootDocsRouteRef,
rootRouteRef,
} from './routes';
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
/** @alpha */
const techDocsStorageApi = ApiBlueprint.make({
@@ -152,13 +157,45 @@ const techDocsReaderPage = PageBlueprint.make({
*
* @alpha
*/
const techDocsEntityContent = EntityContentBlueprint.make({
params: {
defaultPath: 'docs',
defaultTitle: 'TechDocs',
loader: () =>
import('./Router').then(m => compatWrapper(<m.EmbeddedDocsRouter />)),
const techDocsEntityContent = EntityContentBlueprint.makeWithOverrides({
inputs: {
emptyState: createExtensionInput([coreExtensionData.reactElement], {
singleton: true,
optional: true,
}),
},
factory(originalFactory, context) {
return originalFactory(
{
defaultPath: 'docs',
defaultTitle: 'TechDocs',
loader: () =>
import('./Router').then(({ EmbeddedDocsRouter }) =>
compatWrapper(
<EmbeddedDocsRouter
emptyState={context.inputs.emptyState?.get(
coreExtensionData.reactElement,
)}
/>,
),
),
},
context,
);
},
});
/** @alpha */
export const TechDocsEntityContentEmptyState = createExtension({
kind: 'element',
name: 'entity-content-empty-state',
attachTo: { id: 'entity-content:techdocs', input: 'emptyState' },
output: [coreExtensionData.reactElement],
factory: () => [
coreExtensionData.reactElement(
<MissingAnnotationEmptyState annotation={[TECHDOCS_ANNOTATION]} />,
),
],
});
/** @alpha */
@@ -180,6 +217,7 @@ export default createFrontendPlugin({
techDocsPage,
techDocsReaderPage,
techDocsEntityContent,
TechDocsEntityContentEmptyState,
techDocsSearchResultListItemExtension,
],
routes: convertLegacyRouteRefs({