diff --git a/plugins/scaffolder/src/next/TemplateListPage/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/next/TemplateListPage/TemplateCard/TemplateCard.tsx index 10039115e0..67b50ba8d6 100644 --- a/plugins/scaffolder/src/next/TemplateListPage/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder/src/next/TemplateListPage/TemplateCard/TemplateCard.tsx @@ -13,8 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import { + DEFAULT_NAMESPACE, + parseEntityRef, + RELATION_OWNED_BY, + stringifyEntityRef, +} from '@backstage/catalog-model'; +import { Button, MarkdownContent, UserIcon } from '@backstage/core-components'; +import { IconComponent, useApp, useRouteRef } from '@backstage/core-plugin-api'; +import { + EntityRefLinks, + getEntityRelations, +} from '@backstage/plugin-catalog-react'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; +import { BackstageTheme } from '@backstage/theme'; import { Box, Card, @@ -22,22 +34,17 @@ import { CardContent, Chip, Divider, + Grid, makeStyles, } from '@material-ui/core'; +import LanguageIcon from '@material-ui/icons/Language'; +import React from 'react'; +import { + nextSelectedTemplateRouteRef, + viewTechDocRouteRef, +} from '../../../routes'; import { CardHeader } from './CardHeader'; -import { MarkdownContent, UserIcon, Button } from '@backstage/core-components'; -import { - parseEntityRef, - RELATION_OWNED_BY, - stringifyEntityRef, -} from '@backstage/catalog-model'; -import { - EntityRefLinks, - getEntityRelations, -} from '@backstage/plugin-catalog-react'; -import { useRouteRef } from '@backstage/core-plugin-api'; -import { nextSelectedTemplateRouteRef } from '../../../routes'; -import { BackstageTheme } from '@backstage/theme'; +import { CardLink } from './CardLink'; const useStyles = makeStyles(theme => ({ box: { @@ -50,7 +57,7 @@ const useStyles = makeStyles(theme => ({ markdown: { /** to make the styles for React Markdown not leak into the description */ '& :first-child': { - marginTop: 0, + margin: 0, }, }, label: { @@ -61,9 +68,6 @@ const useStyles = makeStyles(theme => ({ lineHeight: 1, fontSize: '0.75rem', }, - margin: { - marginBottom: theme.spacing(2), - }, footer: { display: 'flex', justifyContent: 'space-between', @@ -104,34 +108,96 @@ export const TemplateCard = (props: TemplateCardProps) => { namespace: namespace, }); + const app = useApp(); + const iconResolver = (key?: string): IconComponent => + key ? app.getSystemIcon(key) ?? LanguageIcon : LanguageIcon; + + // TechDocs Link + const viewTechDoc = useRouteRef(viewTechDocRouteRef); + const viewTechDocsAnnotation = + template.metadata.annotations?.['backstage.io/techdocs-ref']; + const viewTechDocsLink = + !!viewTechDocsAnnotation && + !!viewTechDoc && + viewTechDoc({ + namespace: template.metadata.namespace || DEFAULT_NAMESPACE, + kind: template.kind, + name: template.metadata.name, + }); + return ( - - - - {(template.metadata.tags?.length ?? 0) > 0 && ( - <> - - - {template.metadata.tags?.map(tag => ( - - ))} + + + + - - )} + + {(template.metadata.tags?.length ?? 0) > 0 && ( + <> + + + + + + {template.metadata.tags?.map(tag => ( + + + + ))} + + + + )} + {(!!viewTechDocsLink || template.metadata.links?.length) && ( + <> + + + + + + {viewTechDocsLink && ( + + + + )} + {template.metadata.links?.map(({ url, icon, title }) => ( + + + + ))} + + + + )} + - +
{ownedByRelations.length > 0 && ( <> - +