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:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-explore': patch
|
||||
---
|
||||
|
||||
Display the owner of a domain on the domain card.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
'@backstage/plugin-catalog-react': patch
|
||||
---
|
||||
|
||||
Forward link styling of `EntityRefLink` and `EnriryRefLinks` into the underling
|
||||
`Link`.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/core': patch
|
||||
---
|
||||
|
||||
Deprecate `type` of `ItemCard` and introduce new `subtitle` which allows passing
|
||||
react nodes.
|
||||
@@ -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),
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user