Update profile cards to display more information if relevant
Signed-off-by: Joe Patterson <jrwpatterson@gmail.com>
This commit is contained in:
@@ -87,3 +87,46 @@ export default {
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
const extraDetailsEntity: GroupEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Group',
|
||||
metadata: {
|
||||
name: 'team-a',
|
||||
description: 'Team A',
|
||||
links: [
|
||||
{
|
||||
url: 'slack://user?team=T00000000&id=U00000000',
|
||||
title: 'Slack',
|
||||
icon: 'message',
|
||||
},
|
||||
{
|
||||
url: 'https://www.google.com',
|
||||
title: 'Google',
|
||||
},
|
||||
],
|
||||
},
|
||||
spec: {
|
||||
profile: {
|
||||
displayName: 'Team A',
|
||||
email: 'team-a@example.com',
|
||||
picture:
|
||||
'https://avatars.dicebear.com/api/identicon/team-a@example.com.svg?background=%23fff&margin=25',
|
||||
Telephone: '123456789',
|
||||
Location: 'London',
|
||||
},
|
||||
type: 'group',
|
||||
children: [],
|
||||
},
|
||||
relations: [dummyDepartment],
|
||||
};
|
||||
|
||||
export const ExtraDetails = () => (
|
||||
<EntityProvider entity={extraDetailsEntity}>
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<GroupProfileCard variant="gridItem" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</EntityProvider>
|
||||
);
|
||||
|
||||
@@ -37,10 +37,13 @@ import {
|
||||
ListItemText,
|
||||
Tooltip,
|
||||
IconButton,
|
||||
Divider,
|
||||
} from '@material-ui/core';
|
||||
import Icon from '@material-ui/core/Icon';
|
||||
import AccountTreeIcon from '@material-ui/icons/AccountTree';
|
||||
import EmailIcon from '@material-ui/icons/Email';
|
||||
import GroupIcon from '@material-ui/icons/Group';
|
||||
import LinkIcon from '@material-ui/icons/Link';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import CachedIcon from '@material-ui/icons/Cached';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
@@ -53,6 +56,8 @@ import {
|
||||
} from '@backstage/core-components';
|
||||
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
|
||||
const staticProfileKeys = ['displayName', 'email', 'picture'];
|
||||
|
||||
const CardTitle = (props: { title: string }) => (
|
||||
<Box display="flex" alignItems="center">
|
||||
<GroupIcon fontSize="inherit" />
|
||||
@@ -76,7 +81,7 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
}
|
||||
|
||||
const {
|
||||
metadata: { name, description, annotations },
|
||||
metadata: { name, description, annotations, links },
|
||||
spec: { profile },
|
||||
} = group;
|
||||
|
||||
@@ -94,6 +99,11 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
const entityMetadataEditUrl =
|
||||
group.metadata.annotations?.[ANNOTATION_EDIT_URL];
|
||||
|
||||
const profileKeys =
|
||||
profile !== undefined
|
||||
? Object.keys(profile).filter(key => !staticProfileKeys.includes(key))
|
||||
: [];
|
||||
|
||||
const displayName = profile?.displayName ?? name;
|
||||
const emailHref = profile?.email ? `mailto:${profile.email}` : '#';
|
||||
const infoCardAction = entityMetadataEditUrl ? (
|
||||
@@ -190,6 +200,42 @@ export const GroupProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
secondary="Child Groups"
|
||||
/>
|
||||
</ListItem>
|
||||
{links !== undefined && <Divider />}
|
||||
{links !== undefined &&
|
||||
links.map(link => {
|
||||
return (
|
||||
<ListItem button component="a" key={link.url} href={link.url}>
|
||||
{link.icon ? (
|
||||
<ListItemIcon>
|
||||
<Tooltip title={link.icon}>
|
||||
<Icon>{link.icon}</Icon>
|
||||
</Tooltip>
|
||||
</ListItemIcon>
|
||||
) : (
|
||||
<ListItemIcon>
|
||||
<LinkIcon />
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<ListItemText>{link.title}</ListItemText>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
{profile !== undefined && profileKeys.length > 0 && <Divider />}
|
||||
{profile !== undefined &&
|
||||
profileKeys.length > 0 &&
|
||||
profileKeys.map(key => {
|
||||
const value = profile[key];
|
||||
|
||||
return (
|
||||
<ListItem key={key}>
|
||||
<ListItemText style={{ width: '25%', flexGrow: 0 }}>
|
||||
{key}
|
||||
</ListItemText>
|
||||
|
||||
<ListItemText>{value}</ListItemText>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -102,3 +102,46 @@ export default {
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
const extraDetailsEntity: UserEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
name: 'guest',
|
||||
description: 'Description for guest',
|
||||
links: [
|
||||
{
|
||||
url: 'slack://user?team=T00000000&id=U00000000',
|
||||
title: 'Slack',
|
||||
icon: 'message',
|
||||
},
|
||||
{
|
||||
url: 'https://www.google.com',
|
||||
title: 'Google',
|
||||
},
|
||||
],
|
||||
},
|
||||
spec: {
|
||||
profile: {
|
||||
displayName: 'Guest User',
|
||||
email: 'guest@example.com',
|
||||
picture:
|
||||
'https://avatars.dicebear.com/api/avataaars/guest@example.com.svg?background=%23fff',
|
||||
'Job Title': 'Software Engineer',
|
||||
Department: 'Engineering',
|
||||
Location: 'San Francisco, CA',
|
||||
},
|
||||
memberOf: ['team-a'],
|
||||
},
|
||||
relations: [dummyGroup],
|
||||
};
|
||||
|
||||
export const ExtraDetails = () => (
|
||||
<EntityProvider entity={extraDetailsEntity}>
|
||||
<Grid container spacing={4}>
|
||||
<Grid item xs={12} md={4}>
|
||||
<UserProfileCard variant="gridItem" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</EntityProvider>
|
||||
);
|
||||
|
||||
@@ -155,4 +155,65 @@ describe('Edit Button', () => {
|
||||
);
|
||||
expect(rendered.getByRole('button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Should show the extra fields if either links or extra profile are filled', async () => {
|
||||
const annotations: Record<string, string> = {
|
||||
'backstage.io/edit-url': 'https://example.com/user.yaml',
|
||||
};
|
||||
const userEntity: UserEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'User',
|
||||
metadata: {
|
||||
name: 'calum.leavy',
|
||||
description: 'Super awesome human',
|
||||
annotations,
|
||||
links: [
|
||||
{
|
||||
url: 'slack://user?team=T00000000&id=U00000000',
|
||||
title: 'Slack',
|
||||
icon: 'message',
|
||||
},
|
||||
{
|
||||
url: 'https://www.google.com',
|
||||
title: 'Google',
|
||||
},
|
||||
],
|
||||
},
|
||||
spec: {
|
||||
profile: {
|
||||
displayName: 'Calum Leavy',
|
||||
email: 'calum-leavy@example.com',
|
||||
'Job Title': 'Software Engineer',
|
||||
Department: 'Engineering',
|
||||
Location: 'San Francisco, CA',
|
||||
},
|
||||
memberOf: ['ExampleGroup'],
|
||||
},
|
||||
relations: [
|
||||
{
|
||||
type: 'memberOf',
|
||||
targetRef: 'group:default/examplegroup',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const rendered = await renderWithEffects(
|
||||
wrapInTestApp(
|
||||
<EntityProvider entity={userEntity}>
|
||||
<UserProfileCard variant="gridItem" />
|
||||
</EntityProvider>,
|
||||
{
|
||||
mountedRoutes: {
|
||||
'/catalog/:namespace/:kind/:name': entityRouteRef,
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
expect(rendered.getByText('Software Engineer')).toBeInTheDocument();
|
||||
expect(rendered.getByText('Department')).toBeInTheDocument();
|
||||
expect(rendered.getByText('San Francisco, CA')).toBeInTheDocument();
|
||||
expect(rendered.getByText('Location')).toBeInTheDocument();
|
||||
expect(rendered.getByText('Slack')).toBeInTheDocument();
|
||||
expect(rendered.getByText('Google')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,12 +33,15 @@ import {
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Tooltip,
|
||||
Divider,
|
||||
} from '@material-ui/core';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import EmailIcon from '@material-ui/icons/Email';
|
||||
import GroupIcon from '@material-ui/icons/Group';
|
||||
import PersonIcon from '@material-ui/icons/Person';
|
||||
import LinkIcon from '@material-ui/icons/Link';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import Icon from '@material-ui/core/Icon';
|
||||
import React from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
@@ -47,6 +50,8 @@ import {
|
||||
Link,
|
||||
} from '@backstage/core-components';
|
||||
|
||||
const staticProfileKeys = ['displayName', 'email', 'picture'];
|
||||
|
||||
const CardTitle = (props: { title?: string }) =>
|
||||
props.title ? (
|
||||
<Box display="flex" alignItems="center">
|
||||
@@ -66,7 +71,7 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
user.metadata.annotations?.[ANNOTATION_EDIT_URL];
|
||||
|
||||
const {
|
||||
metadata: { name: metaName, description },
|
||||
metadata: { name: metaName, description, links },
|
||||
spec: { profile },
|
||||
} = user;
|
||||
const displayName = profile?.displayName ?? metaName;
|
||||
@@ -75,6 +80,11 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
kind: 'Group',
|
||||
});
|
||||
|
||||
const profileKeys =
|
||||
profile !== undefined
|
||||
? Object.keys(profile).filter(key => !staticProfileKeys.includes(key))
|
||||
: [];
|
||||
|
||||
return (
|
||||
<InfoCard
|
||||
title={<CardTitle title={displayName} />}
|
||||
@@ -128,6 +138,44 @@ export const UserProfileCard = (props: { variant?: InfoCardVariants }) => {
|
||||
/>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
|
||||
{links !== undefined && <Divider />}
|
||||
{links !== undefined &&
|
||||
links.map(link => {
|
||||
return (
|
||||
<ListItem button component="a" key={link.url} href={link.url}>
|
||||
{link.icon ? (
|
||||
<ListItemIcon>
|
||||
<Tooltip title={link.icon}>
|
||||
<Icon>{link.icon}</Icon>
|
||||
</Tooltip>
|
||||
</ListItemIcon>
|
||||
) : (
|
||||
<ListItemIcon>
|
||||
<LinkIcon />
|
||||
</ListItemIcon>
|
||||
)}
|
||||
<ListItemText>{link.title}</ListItemText>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
|
||||
{profile !== undefined && profileKeys.length > 0 && <Divider />}
|
||||
{profile !== undefined &&
|
||||
profileKeys.length > 0 &&
|
||||
profileKeys.map(key => {
|
||||
const value = profile[key];
|
||||
|
||||
return (
|
||||
<ListItem key={key}>
|
||||
<ListItemText style={{ width: '100px', flexGrow: 0 }}>
|
||||
{key}
|
||||
</ListItemText>
|
||||
|
||||
<ListItemText>{value}</ListItemText>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
Reference in New Issue
Block a user