add props to customize CustomHome
Signed-off-by: nikolar <reyna.nikolayev@autodesk.com>
This commit is contained in:
@@ -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 {}
|
||||
}
|
||||
Reference in New Issue
Block a user