diff --git a/.changeset/warm-masks-ring.md b/.changeset/warm-masks-ring.md
index aefbcf8013..bfb521a005 100644
--- a/.changeset/warm-masks-ring.md
+++ b/.changeset/warm-masks-ring.md
@@ -20,7 +20,7 @@ const techDocsTabsConfig = [
title: 'Golden Path',
description: 'Documentation about standards to follow',
panelType: 'DocsCardGrid',
- panelProps: { showHeader: false, showSupport: false },
+ panelProps: { CustomHeader: () => },
filterPredicate: entity =>
entity?.metadata?.tags?.includes('golden-path') ?? false,
},
@@ -29,8 +29,7 @@ const techDocsTabsConfig = [
description: 'Useful documentation',
panelType: 'InfoCardGrid',
panelProps: {
- showHeader: false,
- showSupport: false,
+ CustomHeader: () =>
linkDestination: linkDestination,
},
filterPredicate: entity =>
@@ -46,7 +45,7 @@ const techDocsTabsConfig = [
filterPredicate: filterEntity,
panelType: 'TechDocsIndexPage',
title: 'All',
- panelProps: { showHeader: false, showSupport: false, options: options },
+ panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options },
},
],
},
@@ -59,12 +58,11 @@ const AppRoutes = () => {
element={
) => ({children})}
/>
}
/>
@@ -92,10 +90,9 @@ const panels: PanelConfig[] = [
panelType: 'InfoCardGrid',
title: 'Standards',
panelProps: {
- showSupport: false,
- linkContent: 'Read more',
- linkDestination: entity => {},
- },
+ CustomHeader: () =>
+ linkDestination: linkDestination,
+ },
},
{
description: '',
diff --git a/docs/features/techdocs/how-to-guides.md b/docs/features/techdocs/how-to-guides.md
index ea1ac7a372..5a9b8ba140 100644
--- a/docs/features/techdocs/how-to-guides.md
+++ b/docs/features/techdocs/how-to-guides.md
@@ -149,7 +149,7 @@ const techDocsTabsConfig = [
title: 'Golden Path',
description: 'Documentation about standards to follow',
panelType: 'DocsCardGrid',
- panelProps: { showHeader: false, showSupport: false },
+ panelProps: { CustomHeader: () => },
filterPredicate: entity =>
entity?.metadata?.tags?.includes('golden-path') ?? false,
},
@@ -158,8 +158,7 @@ const techDocsTabsConfig = [
description: 'Useful documentation',
panelType: 'InfoCardGrid',
panelProps: {
- showHeader: false,
- showSupport: false,
+ CustomHeader: () =>
linkDestination: linkDestination,
},
filterPredicate: entity =>
@@ -175,7 +174,7 @@ const techDocsTabsConfig = [
filterPredicate: filterEntity,
panelType: 'TechDocsIndexPage',
title: 'All',
- panelProps: { showHeader: false, showSupport: false, options: options },
+ panelProps: { PageWrapper: React.Fragment, CustomHeader: React.Fragment, options: options },
},
],
},
@@ -188,12 +187,11 @@ const AppRoutes = () => {
element={
) => ({children})}
/>
}
/>
diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx
index 2f79455ad3..f44bc8eca0 100644
--- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx
+++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx
@@ -51,24 +51,27 @@ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {
columns,
actions,
ownerPickerMode,
- showHeader = true,
- options,
- title,
- subtitle,
- showSupport = true,
pagination,
+ options,
+ PageWrapper,
+ CustomHeader,
} = props;
- const Wrapper = showHeader ? TechDocsPageWrapper : React.Fragment;
+ const Wrapper: React.FC<{
+ children: React.ReactNode;
+ title?: string;
+ subtitle?: string;
+ }> = PageWrapper ? PageWrapper : TechDocsPageWrapper;
+ const Header: React.FC =
+ CustomHeader ||
+ (() => (
+
+ Discover documentation in your ecosystem.
+
+ ));
return (
-
+
- {showSupport && (
-
-
- Discover documentation in your ecosystem.
-
-
- )}
+
diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx
index a366cc7269..bd9725d9a0 100644
--- a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx
+++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx
@@ -19,6 +19,7 @@ import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
} from '@backstage/plugin-catalog-react';
+import { PageWithHeader } from '@backstage/core-components';
import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils';
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
import { screen } from '@testing-library/react';
@@ -103,7 +104,7 @@ describe('TechDocsCustomHome', () => {
await screen.findByText('Second Tab Description'),
).toBeInTheDocument();
});
- it('should render ContentHeader based on showHeader prop', async () => {
+ it('should render ContentHeader based on CustomHeader prop', async () => {
const tabsConfig = [
{
label: 'First Tab',
@@ -112,7 +113,7 @@ describe('TechDocsCustomHome', () => {
title: 'First Tab',
description: 'First Tab Description',
panelType: 'DocsCardGrid' as PanelType,
- panelProps: { showHeader: false },
+ panelProps: { CustomHeader: React.Fragment },
filterPredicate: () => true,
},
],
@@ -134,71 +135,6 @@ describe('TechDocsCustomHome', () => {
screen.queryByText('Discover documentation in your ecosystem.'),
).not.toBeInTheDocument();
});
- it('should render SupportButton based on showSupport prop', async () => {
- const tabsConfig = [
- {
- label: 'First Tab',
- panels: [
- {
- title: 'First Tab',
- description: 'First Tab Description',
- panelType: 'DocsCardGrid' as PanelType,
- filterPredicate: () => true,
- panelProps: { showSupport: false },
- },
- ],
- },
- ];
-
- await renderInTestApp(
-
-
- ,
- {
- mountedRoutes: {
- '/docs/:namespace/:kind/:name/*': rootDocsRouteRef,
- },
- },
- );
-
- expect(
- screen.queryByText('Discover documentation in your ecosystem.'),
- ).not.toBeInTheDocument();
- });
- it('should hide subtitle when showSubtitle is false', async () => {
- const tabsConfig = [
- {
- label: 'First Tab',
- panels: [
- {
- title: 'First Tab',
- description: 'First Tab Description',
- panelType: 'DocsCardGrid' as PanelType,
- filterPredicate: () => true,
- },
- ],
- },
- ];
-
- await renderInTestApp(
-
-
- ,
- {
- mountedRoutes: {
- '/docs/:namespace/:kind/:name/*': rootDocsRouteRef,
- },
- },
- );
-
- expect(screen.getByText('Custom Title')).toBeInTheDocument();
- expect(screen.queryByText('Custom Subtitle')).not.toBeInTheDocument();
- });
it('should render title and subtitle', async () => {
const tabsConfig = [
{
@@ -218,8 +154,15 @@ describe('TechDocsCustomHome', () => {
) => (
+
+ {children}
+
+ )}
/>
,
{
diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx
index b8998b8655..e1c5a93161 100644
--- a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx
+++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx
@@ -69,11 +69,11 @@ export type PanelType =
* @public
*/
export interface PanelProps {
- showHeader?: boolean;
- showSupport?: boolean;
options?: TableOptions;
linkContent?: string | JSX.Element;
linkDestination?: (entity: Entity) => string | undefined;
+ PageWrapper?: React.FC;
+ CustomHeader?: React.FC;
}
/**
@@ -146,17 +146,21 @@ export const CustomDocsPanel = ({
);
});
+ const Header: React.FC =
+ config.panelProps?.CustomHeader ||
+ (() => (
+
+ {index === 0 ? (
+
+ Discover documentation in your ecosystem.
+
+ ) : null}
+
+ ));
+
return (
<>
- {(config.panelProps?.showHeader ?? true) && (
-
- {index === 0 && (config.panelProps?.showSupport ?? true) && (
-
- Discover documentation in your ecosystem.
-
- )}
-
- )}
+
{
- const { tabsConfig, filter, title, subtitle, showSubtitle = true } = props;
+ const { tabsConfig, filter, CustomPageWrapper } = props;
const [selectedTab, setSelectedTab] = useState(0);
const catalogApi: CatalogApi = useApi(catalogApiRef);
@@ -216,11 +218,7 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
if (loading) {
return (
-
+
@@ -230,11 +228,7 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
if (error) {
return (
-
+
{
}
return (
-
+
setSelectedTab(index)}
diff --git a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx
index 50388519ba..221839c492 100644
--- a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx
+++ b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx
@@ -39,12 +39,10 @@ export type TechDocsIndexPageProps = {
columns?: TableColumn[];
actions?: TableProps['actions'];
ownerPickerMode?: EntityOwnerPickerProps['mode'];
- showHeader?: boolean;
- showSupport?: boolean;
- options?: TableOptions;
- title?: string;
- subtitle?: string;
pagination?: EntityListPagination;
+ options?: TableOptions;
+ PageWrapper?: React.FC;
+ CustomHeader?: React.FC;
};
export const TechDocsIndexPage = (props: TechDocsIndexPageProps) => {
diff --git a/plugins/techdocs/src/home/components/TechDocsPageWrapper.tsx b/plugins/techdocs/src/home/components/TechDocsPageWrapper.tsx
index 84f8eee327..c07876f7f9 100644
--- a/plugins/techdocs/src/home/components/TechDocsPageWrapper.tsx
+++ b/plugins/techdocs/src/home/components/TechDocsPageWrapper.tsx
@@ -26,9 +26,7 @@ import { useApi, configApiRef } from '@backstage/core-plugin-api';
*/
export type TechDocsPageWrapperProps = {
children?: React.ReactNode;
- title?: string;
- subtitle?: string;
- showSubtitle?: boolean;
+ CustomPageWrapper?: React.FC<{ children?: React.ReactNode }>;
};
/**
@@ -37,21 +35,25 @@ export type TechDocsPageWrapperProps = {
* @public
*/
export const TechDocsPageWrapper = (props: TechDocsPageWrapperProps) => {
- const { children, title, subtitle, showSubtitle = true } = props;
+ const { children, CustomPageWrapper } = props;
const configApi = useApi(configApiRef);
- const generatedSubtitle =
- subtitle ||
- `Documentation available in ${
- configApi.getOptionalString('organization.name') ?? 'Backstage'
- }`;
+ const generatedSubtitle = `Documentation available in ${
+ configApi.getOptionalString('organization.name') ?? 'Backstage'
+ }`;
return (
-
- {children}
-
+ <>
+ {CustomPageWrapper ? (
+ {children}
+ ) : (
+
+ {children}
+
+ )}
+ >
);
};
diff --git a/plugins/techdocs/src/index.ts b/plugins/techdocs/src/index.ts
index 522bcd0c99..713efc17c6 100644
--- a/plugins/techdocs/src/index.ts
+++ b/plugins/techdocs/src/index.ts
@@ -67,3 +67,5 @@ export type {
DeprecatedTechDocsEntityMetadata as TechDocsEntityMetadata,
DeprecatedTechDocsMetadata as TechDocsMetadata,
};
+
+export * from './overridableComponents';