add props to customize CustomHome

Signed-off-by: nikolar <reyna.nikolayev@autodesk.com>
This commit is contained in:
nikolar
2024-11-26 17:15:40 -08:00
parent 5dd3de3649
commit cffde24a15
9 changed files with 227 additions and 34 deletions
@@ -46,15 +46,28 @@ export type DefaultTechDocsHomeProps = TechDocsIndexPageProps;
* @public
*/
export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {
const { initialFilter = 'owned', columns, actions, ownerPickerMode } = props;
const {
initialFilter = 'owned',
columns,
actions,
ownerPickerMode,
showHeader,
options,
title,
subtitle,
hideSupport,
} = props;
const Wrapper = showHeader !== false ? TechDocsPageWrapper : React.Fragment;
return (
<TechDocsPageWrapper>
<Wrapper title={title} subtitle={subtitle}>
<Content>
<ContentHeader title="">
<SupportButton>
Discover documentation in your ecosystem.
</SupportButton>
</ContentHeader>
{hideSupport !== true && (
<ContentHeader title="">
<SupportButton>
Discover documentation in your ecosystem.
</SupportButton>
</ContentHeader>
)}
<EntityListProvider>
<CatalogFilterLayout>
<CatalogFilterLayout.Filters>
@@ -64,11 +77,15 @@ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => {
<EntityTagPicker />
</CatalogFilterLayout.Filters>
<CatalogFilterLayout.Content>
<EntityListDocsTable actions={actions} columns={columns} />
<EntityListDocsTable
actions={actions}
columns={columns}
options={options}
/>
</CatalogFilterLayout.Content>
</CatalogFilterLayout>
</EntityListProvider>
</Content>
</TechDocsPageWrapper>
</Wrapper>
);
};
@@ -0,0 +1,94 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { rootDocsRouteRef } from '../../../routes';
import { toLowerMaybe } from '../../../helpers';
import { Entity } from '@backstage/catalog-model';
import { useApi, useRouteRef, configApiRef } from '@backstage/core-plugin-api';
import { ItemCardGrid, InfoCard, Link } from '@backstage/core-components';
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
/** @public */
export type InfoCardGridClassKey = 'linkSpacer' | 'readMoreLink';
const useStyles = makeStyles(
theme => ({
linkSpacer: {
paddingTop: theme.spacing(0.2),
},
readMoreLink: {
paddingTop: theme.spacing(0.2),
},
}),
{ name: 'BackstageInfoCardGrid' },
);
/**
* Props for {@link InfoCardGird}
*
* @public
*/
export type InfoCardGirdProps = {
entities: Entity[] | undefined;
linkContent?: string | JSX.Element;
linkDest?: (entity: Entity) => string;
};
/**
* Component which accepts a list of entities and renders a info card for each entity
*
* @public
*/
export const InfoCardGird = (props: InfoCardGirdProps) => {
const { entities, linkContent, linkDest } = props;
const classes = useStyles();
const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef);
const config = useApi(configApiRef);
if (!entities) return null;
return (
<ItemCardGrid data-testid="docs-card-container">
{!entities?.length
? null
: entities.map(entity => (
<InfoCard
data-cy={entity?.metadata?.title}
title={entity?.metadata?.title}
>
<div>{entity?.metadata?.description}</div>
<div className={classes.linkSpacer} />
<Link
to={
typeof linkDest === 'function'
? linkDest(entity)
: getRouteToReaderPageFor({
namespace: toLowerMaybe(
entity.metadata.namespace ?? 'default',
config,
),
kind: toLowerMaybe(entity.kind, config),
name: toLowerMaybe(entity.metadata.name, config),
})
}
className={classes.readMoreLink}
>
{linkContent || 'Read Docs'}
</Link>
</InfoCard>
))}
</ItemCardGrid>
);
};
@@ -16,3 +16,4 @@
export * from './EntityListDocsGrid';
export * from './DocsCardGrid';
export * from './InfoCardGrid';
@@ -26,8 +26,9 @@ import {
} from '@backstage/plugin-catalog-react';
import { Entity } from '@backstage/catalog-model';
import { DocsTable } from './Tables';
import { DocsCardGrid } from './Grids';
import { DocsCardGrid, InfoCardGird } from './Grids';
import { TechDocsPageWrapper } from './TechDocsPageWrapper';
import { TechDocsIndexPage } from './TechDocsIndexPage';
import {
CodeSnippet,
@@ -40,10 +41,13 @@ import {
} from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
import { TECHDOCS_ANNOTATION } from '@backstage/plugin-techdocs-common';
import { EntityFilterQuery } from '@backstage/catalog-client';
const panels = {
DocsTable: DocsTable,
DocsCardGrid: DocsCardGrid,
TechDocsIndexPage: TechDocsIndexPage,
InfoCardGird: InfoCardGird,
};
/**
@@ -51,7 +55,11 @@ const panels = {
*
* @public
*/
export type PanelType = 'DocsCardGrid' | 'DocsTable';
export type PanelType =
| 'DocsCardGrid'
| 'DocsTable'
| 'TechDocsIndexPage'
| 'InfoCardGird';
/**
* Type representing a TechDocsCustomHome panel.
@@ -64,6 +72,7 @@ export interface PanelConfig {
panelType: PanelType;
panelCSS?: CSSProperties;
filterPredicate: ((entity: Entity) => boolean) | string;
panelProps?: Record<string, any>;
}
/**
@@ -119,15 +128,21 @@ const CustomPanel = ({
return (
<>
<ContentHeader title={config.title} description={config.description}>
{index === 0 ? (
<SupportButton>
Discover documentation in your ecosystem.
</SupportButton>
) : null}
</ContentHeader>
{config.panelProps?.showHeader !== false && (
<ContentHeader title={config.title} description={config.description}>
{index === 0 && config.panelProps?.hideSupport !== true && (
<SupportButton>
Discover documentation in your ecosystem.
</SupportButton>
)}
</ContentHeader>
)}
<div className={classes.panelContainer}>
<Panel data-testid="techdocs-custom-panel" entities={shownEntities} />
<Panel
data-testid="techdocs-custom-panel"
entities={shownEntities}
{...config.panelProps}
/>
</div>
</>
);
@@ -140,10 +155,14 @@ const CustomPanel = ({
*/
export type TechDocsCustomHomeProps = {
tabsConfig: TabsConfig;
filter?: EntityFilterQuery;
title?: string;
subtitle?: string;
hideSubtitle?: boolean;
};
export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
const { tabsConfig } = props;
const { tabsConfig, filter, title, subtitle, hideSubtitle } = props;
const [selectedTab, setSelectedTab] = useState<number>(0);
const catalogApi: CatalogApi = useApi(catalogApiRef);
@@ -153,7 +172,7 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
error,
} = useAsync(async () => {
const response = await catalogApi.getEntities({
filter: {
filter: filter || {
[`metadata.annotations.${TECHDOCS_ANNOTATION}`]: CATALOG_FILTER_EXISTS,
},
fields: [
@@ -165,16 +184,18 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
'spec.type',
],
});
return response.items.filter((entity: Entity) => {
return !!entity.metadata.annotations?.[TECHDOCS_ANNOTATION];
});
return response.items;
});
const currentTabConfig = tabsConfig[selectedTab];
if (loading) {
return (
<TechDocsPageWrapper>
<TechDocsPageWrapper
title={title}
subtitle={subtitle}
hideSubtitle={hideSubtitle}
>
<Content>
<Progress />
</Content>
@@ -184,7 +205,11 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
if (error) {
return (
<TechDocsPageWrapper>
<TechDocsPageWrapper
title={title}
subtitle={subtitle}
hideSubtitle={hideSubtitle}
>
<Content>
<WarningPanel
severity="error"
@@ -198,7 +223,11 @@ export const TechDocsCustomHome = (props: TechDocsCustomHomeProps) => {
}
return (
<TechDocsPageWrapper>
<TechDocsPageWrapper
title={title}
subtitle={subtitle}
hideSubtitle={hideSubtitle}
>
<HeaderTabs
selectedIndex={selectedTab}
onChange={index => setSelectedTab(index)}
@@ -16,7 +16,11 @@
import React from 'react';
import { useOutlet } from 'react-router-dom';
import { TableColumn, TableProps } from '@backstage/core-components';
import {
TableColumn,
TableProps,
TableOptions,
} from '@backstage/core-components';
import {
EntityOwnerPickerProps,
UserListFilterKind,
@@ -34,6 +38,11 @@ export type TechDocsIndexPageProps = {
columns?: TableColumn<DocsTableRow>[];
actions?: TableProps<DocsTableRow>['actions'];
ownerPickerMode?: EntityOwnerPickerProps['mode'];
showHeader?: boolean;
hideSupport?: boolean;
options?: TableOptions<DocsTableRow>;
title?: string;
subtitle?: string;
};
export const TechDocsIndexPage = (props: TechDocsIndexPageProps) => {
@@ -26,6 +26,9 @@ import { useApi, configApiRef } from '@backstage/core-plugin-api';
*/
export type TechDocsPageWrapperProps = {
children?: React.ReactNode;
title?: string;
subtitle?: string;
hideSubtitle?: boolean;
};
/**
@@ -34,16 +37,18 @@ export type TechDocsPageWrapperProps = {
* @public
*/
export const TechDocsPageWrapper = (props: TechDocsPageWrapperProps) => {
const { children } = props;
const { children, title, subtitle, hideSubtitle } = props;
const configApi = useApi(configApiRef);
const generatedSubtitle = `Documentation available in ${
configApi.getOptionalString('organization.name') ?? 'Backstage'
}`;
const generatedSubtitle =
subtitle ||
`Documentation available in ${
configApi.getOptionalString('organization.name') ?? 'Backstage'
}`;
return (
<PageWithHeader
title="Documentation"
subtitle={generatedSubtitle}
title={title || 'Documentation'}
subtitle={hideSubtitle ? undefined : generatedSubtitle}
themeId="documentation"
>
{children}
@@ -0,0 +1,36 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Overrides } from '@material-ui/core/styles/overrides';
import { StyleRules } from '@material-ui/core/styles/withStyles';
import { InfoCardGridClassKey } from './home/components/Grids/InfoCardGrid';
/** @public */
export type CatalogReactComponentsNameToClassKey = {
BackstageInfoCardGrid: InfoCardGridClassKey;
};
/** @public */
export type BackstageOverrides = Overrides & {
[Name in keyof CatalogReactComponentsNameToClassKey]?: Partial<
StyleRules<CatalogReactComponentsNameToClassKey[Name]>
>;
};
declare module '@backstage/theme' {
interface OverrideComponentNameToClassKeys
extends CatalogReactComponentsNameToClassKey {}
}