Merge pull request #4571 from SDA-SE/feat/domain-owner

Display the owner of the domain on the domain card
This commit is contained in:
Oliver Sand
2021-02-19 11:07:09 +01:00
committed by GitHub
11 changed files with 93 additions and 46 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-explore': patch
---
Display the owner of a domain on the domain card.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/core': patch
'@backstage/plugin-catalog-react': patch
---
Forward link styling of `EntityRefLink` and `EnriryRefLinks` into the underling
`Link`.
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core': patch
---
Deprecate `type` of `ItemCard` and introduce new `subtitle` which allows passing
react nodes.
+3 -3
View File
@@ -14,17 +14,17 @@
* limitations under the License.
*/
import React, { ElementType } from 'react';
import {
Link as MaterialLink,
LinkProps as MaterialLinkProps,
} from '@material-ui/core';
import React, { ElementType } from 'react';
import {
Link as RouterLink,
LinkProps as RouterLinkProps,
} from 'react-router-dom';
type Props = MaterialLinkProps &
export type LinkProps = MaterialLinkProps &
RouterLinkProps & {
component?: ElementType<any>;
};
@@ -33,7 +33,7 @@ type Props = MaterialLinkProps &
* Thin wrapper on top of material-ui's Link component
* Makes the Link to utilise react-router
*/
export const Link = React.forwardRef<any, Props>((props, ref) => {
export const Link = React.forwardRef<any, LinkProps>((props, ref) => {
const to = String(props.to);
return /^https?:\/\//.test(to) ? (
// External links
@@ -15,3 +15,4 @@
*/
export { Link } from './Link';
export type { LinkProps } from './Link';
@@ -30,7 +30,7 @@ export const Default = () => (
title="Item Card"
description="This is the description of an Item Card"
label="Button"
type="Pretitle"
subtitle="Pretitle"
onClick={() => {}}
/>
</Grid>
@@ -39,7 +39,7 @@ export const Default = () => (
title="Item Card"
description="This is the description of an Item Card"
label="Button"
type="Pretitle"
subtitle="Pretitle"
onClick={() => {}}
/>
</Grid>
@@ -14,25 +14,35 @@
* limitations under the License.
*/
import React from 'react';
import { renderInTestApp } from '@backstage/test-utils';
import React from 'react';
import { ItemCard } from './ItemCard';
const minProps = {
description: 'This is the description of an Item Card',
label: 'Button',
title: 'Item Card',
type: 'Pretitle',
};
describe('<InfoCard />', () => {
it('renders default without exploding', async () => {
const { description, label, title, type } = minProps;
const { description, label, title } = minProps;
const { getByText } = await renderInTestApp(<ItemCard {...minProps} />);
expect(getByText(description)).toBeInTheDocument();
expect(getByText(title)).toBeInTheDocument();
expect(getByText(label)).toBeInTheDocument();
expect(getByText(type)).toBeInTheDocument();
});
it('renders with subtitle without exploding', async () => {
const { description, label, title } = minProps;
const subtitle = 'Pretitle';
const { getByText } = await renderInTestApp(
<ItemCard {...minProps} subtitle={subtitle} />,
);
expect(getByText(description)).toBeInTheDocument();
expect(getByText(title)).toBeInTheDocument();
expect(getByText(label)).toBeInTheDocument();
expect(getByText(subtitle)).toBeInTheDocument();
});
it('renders with tags without exploding', async () => {
@@ -15,7 +15,7 @@
*/
import { Button, Card, Chip, makeStyles, Typography } from '@material-ui/core';
import clsx from 'clsx';
import React from 'react';
import React, { ReactNode } from 'react';
import { Link } from '../../components';
const useStyles = makeStyles(theme => ({
@@ -45,7 +45,9 @@ type ItemCardProps = {
description?: string;
tags?: string[];
title: string;
/** @deprecated Use subtitle instead */
type?: string;
subtitle?: ReactNode;
label: string;
onClick?: () => void;
href?: string;
@@ -56,6 +58,7 @@ export const ItemCard = ({
tags,
title,
type,
subtitle,
label,
onClick,
href,
@@ -65,7 +68,9 @@ export const ItemCard = ({
return (
<Card>
<div className={classes.header}>
{type ?? <Typography variant="subtitle2">{type}</Typography>}
{(subtitle || type) && (
<Typography variant="subtitle2">{subtitle ?? type}</Typography>
)}
<Typography variant="h6">{title}</Typography>
</div>
<div className={classes.content}>
@@ -15,22 +15,22 @@
*/
import {
Entity,
ENTITY_DEFAULT_NAMESPACE,
EntityName,
ENTITY_DEFAULT_NAMESPACE,
} from '@backstage/catalog-model';
import { Link } from '@backstage/core';
import React from 'react';
import { Link, LinkProps } from '@backstage/core';
import React, { forwardRef } from 'react';
import { generatePath } from 'react-router';
import { entityRoute } from '../../routes';
import { formatEntityRefTitle } from './format';
type EntityRefLinkProps = {
export type EntityRefLinkProps = {
entityRef: Entity | EntityName;
defaultKind?: string;
children?: React.ReactNode;
};
} & Omit<LinkProps, 'to'>;
export const EntityRefLink = React.forwardRef<any, EntityRefLinkProps>(
export const EntityRefLink = forwardRef<any, EntityRefLinkProps>(
(props, ref) => {
const { entityRef, defaultKind, children, ...linkProps } = props;
@@ -59,9 +59,9 @@ export const EntityRefLink = React.forwardRef<any, EntityRefLinkProps>(
// TODO: Use useRouteRef here to generate the path
return (
<Link
{...linkProps}
ref={ref}
to={generatePath(`/catalog/${entityRoute.path}`, routeParams)}
{...linkProps}
>
{children}
{!children && formatEntityRefTitle(entityRef, { defaultKind })}
@@ -14,26 +14,26 @@
* limitations under the License.
*/
import { Entity, EntityName } from '@backstage/catalog-model';
import { LinkProps } from '@backstage/core';
import React from 'react';
import { EntityRefLink } from './EntityRefLink';
type EntityRefLinksProps = {
export type EntityRefLinksProps = {
entityRefs: (Entity | EntityName)[];
defaultKind?: string;
};
} & Omit<LinkProps, 'to'>;
export const EntityRefLinks = ({
entityRefs,
defaultKind,
}: EntityRefLinksProps) => {
return (
<>
{entityRefs.map((r, i) => (
<React.Fragment key={i}>
{i > 0 && ', '}
<EntityRefLink entityRef={r} defaultKind={defaultKind} />
</React.Fragment>
))}
</>
);
};
...linkProps
}: EntityRefLinksProps) => (
<>
{entityRefs.map((r, i) => (
<React.Fragment key={i}>
{i > 0 && ', '}
<EntityRefLink {...linkProps} entityRef={r} defaultKind={defaultKind} />
</React.Fragment>
))}
</>
);
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DomainEntity } from '@backstage/catalog-model';
import { DomainEntity, RELATION_OWNED_BY } from '@backstage/catalog-model';
import { ItemCard } from '@backstage/core';
import {
EntityRefLinks,
entityRoute,
entityRouteParams,
getEntityRelations,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { generatePath } from 'react-router-dom';
@@ -26,16 +28,27 @@ type DomainCardProps = {
entity: DomainEntity;
};
export const DomainCard = ({ entity }: DomainCardProps) => (
<ItemCard
title={entity.metadata.name}
description={entity.metadata.description}
tags={entity.metadata.tags}
label="Explore"
// TODO: Use useRouteRef here to generate the path
href={generatePath(
`/catalog/${entityRoute.path}`,
entityRouteParams(entity),
)}
/>
);
export const DomainCard = ({ entity }: DomainCardProps) => {
const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);
return (
<ItemCard
title={entity.metadata.name}
description={entity.metadata.description}
tags={entity.metadata.tags}
subtitle={
<EntityRefLinks
entityRefs={ownedByRelations}
defaultKind="group"
color="inherit"
/>
}
label="Explore"
// TODO: Use useRouteRef here to generate the path
href={generatePath(
`/catalog/${entityRoute.path}`,
entityRouteParams(entity),
)}
/>
);
};