mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-04 00:18:01 +01:00
Feat/groups refinement (#1190)
* Button for 0 groups * Highlight name on exist * Add hover to groups * Change avatar size to 28px * Add tooltip to project and fix error * Fix tooltip * Link to project, change to flex etc * Reuse badges better * Limit to max 50% width * Refinements * UI refinements * Update * Remove import * Refinement fixes * Refinement * Refinement * Refinement * Star to star rounded
This commit is contained in:
parent
4486901a4b
commit
d10c151dea
@ -255,7 +255,7 @@ export const Group: VFC = () => {
|
|||||||
onClick={() => setRemoveOpen(true)}
|
onClick={() => setRemoveOpen(true)}
|
||||||
permission={ADMIN}
|
permission={ADMIN}
|
||||||
tooltipProps={{
|
tooltipProps={{
|
||||||
title: 'Remove group',
|
title: 'Delete group',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StyledDelete />
|
<StyledDelete />
|
||||||
|
@ -81,6 +81,7 @@ export const GroupForm: FC<IGroupForm> = ({
|
|||||||
value={name}
|
value={name}
|
||||||
onChange={e => setName(e.target.value)}
|
onChange={e => setName(e.target.value)}
|
||||||
data-testid={UG_NAME_ID}
|
data-testid={UG_NAME_ID}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
<StyledInputDescription>
|
<StyledInputDescription>
|
||||||
How would you describe your group?
|
How would you describe your group?
|
||||||
|
@ -2,25 +2,11 @@ import { capitalize, MenuItem, Select, styled } from '@mui/material';
|
|||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||||
import { Role } from 'interfaces/group';
|
import { Role } from 'interfaces/group';
|
||||||
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledBadge = styled('div')(({ theme }) => ({
|
const StyledPopupStar = styled(StarRounded)(({ theme }) => ({
|
||||||
padding: theme.spacing(0.5, 1),
|
color: theme.palette.warning.main,
|
||||||
textDecoration: 'none',
|
|
||||||
color: theme.palette.text.secondary,
|
|
||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
|
||||||
background: theme.palette.activityIndicators.unknown,
|
|
||||||
display: 'inline-block',
|
|
||||||
borderRadius: theme.shape.borderRadius,
|
|
||||||
marginLeft: theme.spacing(1.5),
|
|
||||||
fontSize: theme.fontSizes.smallerBody,
|
|
||||||
fontWeight: theme.fontWeight.bold,
|
|
||||||
lineHeight: 1,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledOwnerBadge = styled(StyledBadge)(({ theme }) => ({
|
|
||||||
color: theme.palette.success.dark,
|
|
||||||
border: `1px solid ${theme.palette.success.border}`,
|
|
||||||
background: theme.palette.success.light,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface IGroupUserRoleCellProps {
|
interface IGroupUserRoleCellProps {
|
||||||
@ -35,8 +21,12 @@ export const GroupUserRoleCell = ({
|
|||||||
const renderBadge = () => (
|
const renderBadge = () => (
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={value === Role.Member}
|
condition={value === Role.Member}
|
||||||
show={<StyledBadge>{capitalize(value)}</StyledBadge>}
|
show={<Badge>{capitalize(value)}</Badge>}
|
||||||
elseShow={<StyledOwnerBadge>{capitalize(value)}</StyledOwnerBadge>}
|
elseShow={
|
||||||
|
<Badge color="success" icon={<StyledPopupStar />}>
|
||||||
|
{capitalize(value)}
|
||||||
|
</Badge>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { styled, Tooltip } from '@mui/material';
|
import { styled, Tooltip } from '@mui/material';
|
||||||
import { IGroup } from 'interfaces/group';
|
import { IGroup } from 'interfaces/group';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars';
|
import { GroupCardAvatars } from './GroupCardAvatars/GroupCardAvatars';
|
||||||
import { Badge } from 'component/common/Badge/Badge';
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
@ -20,9 +20,15 @@ const StyledGroupCard = styled('aside')(({ theme }) => ({
|
|||||||
border: `1px solid ${theme.palette.dividerAlternative}`,
|
border: `1px solid ${theme.palette.dividerAlternative}`,
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
boxShadow: theme.boxShadows.card,
|
boxShadow: theme.boxShadows.card,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
[theme.breakpoints.up('md')]: {
|
[theme.breakpoints.up('md')]: {
|
||||||
padding: theme.spacing(4),
|
padding: theme.spacing(4),
|
||||||
},
|
},
|
||||||
|
'&:hover': {
|
||||||
|
transition: 'background-color 0.2s ease-in-out',
|
||||||
|
backgroundColor: theme.palette.neutral.light,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledRow = styled('div')(() => ({
|
const StyledRow = styled('div')(() => ({
|
||||||
@ -31,6 +37,14 @@ const StyledRow = styled('div')(() => ({
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledTitleRow = styled(StyledRow)(() => ({
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledBottomRow = styled(StyledRow)(() => ({
|
||||||
|
marginTop: 'auto',
|
||||||
|
}));
|
||||||
|
|
||||||
const StyledHeaderTitle = styled('h2')(({ theme }) => ({
|
const StyledHeaderTitle = styled('h2')(({ theme }) => ({
|
||||||
fontSize: theme.fontSizes.mainHeader,
|
fontSize: theme.fontSizes.mainHeader,
|
||||||
fontWeight: theme.fontWeight.medium,
|
fontWeight: theme.fontWeight.medium,
|
||||||
@ -55,7 +69,13 @@ const StyledCounterDescription = styled('span')(({ theme }) => ({
|
|||||||
marginLeft: theme.spacing(1),
|
marginLeft: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const ProjectBadgeContainer = styled('div')(() => ({}));
|
const ProjectBadgeContainer = styled('div')(() => ({
|
||||||
|
maxWidth: '50%',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledBadge = styled(Badge)(() => ({
|
||||||
|
marginRight: 0.5,
|
||||||
|
}));
|
||||||
|
|
||||||
interface IGroupCardProps {
|
interface IGroupCardProps {
|
||||||
group: IGroup;
|
group: IGroup;
|
||||||
@ -63,12 +83,12 @@ interface IGroupCardProps {
|
|||||||
|
|
||||||
export const GroupCard = ({ group }: IGroupCardProps) => {
|
export const GroupCard = ({ group }: IGroupCardProps) => {
|
||||||
const [removeOpen, setRemoveOpen] = useState(false);
|
const [removeOpen, setRemoveOpen] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledLink key={group.id} to={`/admin/groups/${group.id}`}>
|
<StyledLink key={group.id} to={`/admin/groups/${group.id}`}>
|
||||||
<StyledGroupCard>
|
<StyledGroupCard>
|
||||||
<StyledRow>
|
<StyledTitleRow>
|
||||||
<StyledHeaderTitle>{group.name}</StyledHeaderTitle>
|
<StyledHeaderTitle>{group.name}</StyledHeaderTitle>
|
||||||
<StyledHeaderActions>
|
<StyledHeaderActions>
|
||||||
<GroupCardActions
|
<GroupCardActions
|
||||||
@ -76,9 +96,9 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
onRemove={() => setRemoveOpen(true)}
|
onRemove={() => setRemoveOpen(true)}
|
||||||
/>
|
/>
|
||||||
</StyledHeaderActions>
|
</StyledHeaderActions>
|
||||||
</StyledRow>
|
</StyledTitleRow>
|
||||||
<StyledDescription>{group.description}</StyledDescription>
|
<StyledDescription>{group.description}</StyledDescription>
|
||||||
<StyledRow>
|
<StyledBottomRow>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={group.users?.length > 0}
|
condition={group.users?.length > 0}
|
||||||
show={<GroupCardAvatars users={group.users} />}
|
show={<GroupCardAvatars users={group.users} />}
|
||||||
@ -92,13 +112,26 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={group.projects.length > 0}
|
condition={group.projects.length > 0}
|
||||||
show={group.projects.map(project => (
|
show={group.projects.map(project => (
|
||||||
<Badge
|
<Tooltip
|
||||||
|
key={project}
|
||||||
|
title="View project"
|
||||||
|
arrow
|
||||||
|
placement="bottom-end"
|
||||||
|
describeChild
|
||||||
|
>
|
||||||
|
<StyledBadge
|
||||||
|
onClick={e => {
|
||||||
|
e.preventDefault();
|
||||||
|
navigate(
|
||||||
|
`/projects/${project}/access`
|
||||||
|
);
|
||||||
|
}}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
icon={<TopicOutlinedIcon />}
|
icon={<TopicOutlinedIcon />}
|
||||||
sx={{ marginRight: 0.5 }}
|
|
||||||
>
|
>
|
||||||
{project}
|
{project}
|
||||||
</Badge>
|
</StyledBadge>
|
||||||
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -111,7 +144,7 @@ export const GroupCard = ({ group }: IGroupCardProps) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ProjectBadgeContainer>
|
</ProjectBadgeContainer>
|
||||||
</StyledRow>
|
</StyledBottomRow>
|
||||||
</StyledGroupCard>
|
</StyledGroupCard>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
<RemoveGroup
|
<RemoveGroup
|
||||||
|
@ -97,7 +97,7 @@ export const GroupCardActions: FC<IGroupCardActions> = ({
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText>
|
<ListItemText>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
Remove group
|
Delete group
|
||||||
</Typography>
|
</Typography>
|
||||||
</ListItemText>
|
</ListItemText>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -15,6 +15,9 @@ const StyledAvatars = styled('div')(({ theme }) => ({
|
|||||||
const StyledAvatar = styled(UserAvatar)(({ theme }) => ({
|
const StyledAvatar = styled(UserAvatar)(({ theme }) => ({
|
||||||
outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
|
outline: `${theme.spacing(0.25)} solid ${theme.palette.background.paper}`,
|
||||||
marginLeft: theme.spacing(-1),
|
marginLeft: theme.spacing(-1),
|
||||||
|
'&:hover': {
|
||||||
|
outlineColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface IGroupCardAvatarsProps {
|
interface IGroupCardAvatarsProps {
|
||||||
@ -44,6 +47,7 @@ export const GroupCardAvatars = ({ users }: IGroupCardAvatarsProps) => {
|
|||||||
<StyledAvatars>
|
<StyledAvatars>
|
||||||
{shownUsers.map(user => (
|
{shownUsers.map(user => (
|
||||||
<StyledAvatar
|
<StyledAvatar
|
||||||
|
key={user.id}
|
||||||
user={user}
|
user={user}
|
||||||
star={user.role === Role.Owner}
|
star={user.role === Role.Owner}
|
||||||
onMouseEnter={event => {
|
onMouseEnter={event => {
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
import { Badge, Popover, styled } from '@mui/material';
|
import { Popover, styled } from '@mui/material';
|
||||||
import { IGroupUser, Role } from 'interfaces/group';
|
import { IGroupUser, Role } from 'interfaces/group';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { Badge as StyledBadge } from 'component/common/Badge/Badge';
|
import { Badge } from 'component/common/Badge/Badge';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledPopover = styled(Popover)(({ theme }) => ({
|
const StyledPopover = styled(Popover)(({ theme }) => ({
|
||||||
pointerEvents: 'none',
|
pointerEvents: 'none',
|
||||||
'.MuiPaper-root': {
|
'.MuiPaper-root': {
|
||||||
padding: '12px',
|
padding: theme.spacing(2),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledPopupStar = styled(StarIcon)(({ theme }) => ({
|
const StyledPopupStar = styled(StarRounded)(({ theme }) => ({
|
||||||
color: theme.palette.warning.main,
|
color: theme.palette.warning.main,
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
marginLeft: theme.spacing(0.1),
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledName = styled('div')(({ theme }) => ({
|
const StyledName = styled('div')(({ theme }) => ({
|
||||||
@ -55,22 +52,10 @@ export const GroupPopover = ({
|
|||||||
>
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={user?.role === Role.Member}
|
condition={user?.role === Role.Member}
|
||||||
show={<StyledBadge color="success">{user?.role}</StyledBadge>}
|
show={<Badge>{user?.role}</Badge>}
|
||||||
elseShow={
|
elseShow={
|
||||||
<Badge
|
<Badge color="success" icon={<StyledPopupStar />}>
|
||||||
overlap="circular"
|
|
||||||
anchorOrigin={{
|
|
||||||
vertical: 'top',
|
|
||||||
horizontal: 'left',
|
|
||||||
}}
|
|
||||||
badgeContent={<StyledPopupStar />}
|
|
||||||
>
|
|
||||||
<StyledBadge
|
|
||||||
color="success"
|
|
||||||
sx={{ paddingLeft: '16px' }}
|
|
||||||
>
|
|
||||||
{user?.role}
|
{user?.role}
|
||||||
</StyledBadge>
|
|
||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { Button, styled, Typography } from '@mui/material';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
export const GroupEmpty = () => {
|
||||||
|
const StyledContainerDiv = styled('div')(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
margin: theme.spacing(6),
|
||||||
|
marginLeft: 'auto',
|
||||||
|
marginRight: 'auto',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledTitle = styled(Typography)(({ theme }) => ({
|
||||||
|
fontSize: theme.fontSizes.bodySize,
|
||||||
|
marginBottom: theme.spacing(2.5),
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainerDiv>
|
||||||
|
<StyledTitle>
|
||||||
|
No groups available. Get started by adding a new group.
|
||||||
|
</StyledTitle>
|
||||||
|
<Button
|
||||||
|
to="/admin/groups/create-group"
|
||||||
|
component={Link}
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
>
|
||||||
|
Create your first group
|
||||||
|
</Button>
|
||||||
|
</StyledContainerDiv>
|
||||||
|
);
|
||||||
|
};
|
@ -11,6 +11,7 @@ import theme from 'themes/theme';
|
|||||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { TablePlaceholder } from 'component/common/Table';
|
import { TablePlaceholder } from 'component/common/Table';
|
||||||
import { GroupCard } from './GroupCard/GroupCard';
|
import { GroupCard } from './GroupCard/GroupCard';
|
||||||
|
import { GroupEmpty } from './GroupEmpty/GroupEmpty';
|
||||||
|
|
||||||
type PageQueryType = Partial<Record<'search', string>>;
|
type PageQueryType = Partial<Record<'search', string>>;
|
||||||
|
|
||||||
@ -123,12 +124,7 @@ export const GroupsList: VFC = () => {
|
|||||||
”
|
”
|
||||||
</TablePlaceholder>
|
</TablePlaceholder>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={<GroupEmpty />}
|
||||||
<TablePlaceholder>
|
|
||||||
No groups available. Get started by adding a new
|
|
||||||
group.
|
|
||||||
</TablePlaceholder>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -48,10 +48,10 @@ export const RemoveGroup: FC<IRemoveGroupProps> = ({
|
|||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
title="Remove group"
|
title="Delete group"
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
Are you sure you wish to remove <strong>{group.name}</strong>?
|
Are you sure you wish to delete <strong>{group.name}</strong>?
|
||||||
If this group is currently assigned to one or more projects then
|
If this group is currently assigned to one or more projects then
|
||||||
users belonging to this group may lose access to those projects.
|
users belonging to this group may lose access to those projects.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { styled, SxProps, Theme } from '@mui/material';
|
import { styled, SxProps, Theme } from '@mui/material';
|
||||||
import {
|
import React, {
|
||||||
cloneElement,
|
cloneElement,
|
||||||
FC,
|
FC,
|
||||||
ForwardedRef,
|
ForwardedRef,
|
||||||
@ -17,6 +17,8 @@ interface IBadgeProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
title?: string;
|
||||||
|
onClick?: (event: React.SyntheticEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IBadgeIconProps {
|
interface IBadgeIconProps {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Paper, styled } from '@mui/material';
|
import { Paper, styled } from '@mui/material';
|
||||||
import { usePageTitle } from 'hooks/usePageTitle';
|
import { usePageTitle } from 'hooks/usePageTitle';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
const StyledMainHeader = styled(Paper)(({ theme }) => ({
|
const StyledMainHeader = styled(Paper)(({ theme }) => ({
|
||||||
borderRadius: theme.shape.borderRadiusLarge,
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
@ -49,7 +50,15 @@ export const MainHeader = ({
|
|||||||
<StyledTitle>{title}</StyledTitle>
|
<StyledTitle>{title}</StyledTitle>
|
||||||
<StyledActions>{actions}</StyledActions>
|
<StyledActions>{actions}</StyledActions>
|
||||||
</StyledTitleHeader>
|
</StyledTitleHeader>
|
||||||
Description:<StyledDescription>{description}</StyledDescription>
|
<ConditionallyRender
|
||||||
|
condition={Boolean(description?.length)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
Description:
|
||||||
|
<StyledDescription>{description}</StyledDescription>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</StyledMainHeader>
|
</StyledMainHeader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -9,11 +9,11 @@ import {
|
|||||||
import { IUser } from 'interfaces/user';
|
import { IUser } from 'interfaces/user';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import StarIcon from '@mui/icons-material/Star';
|
import { StarRounded } from '@mui/icons-material';
|
||||||
|
|
||||||
const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
||||||
width: theme.spacing(4),
|
width: theme.spacing(3.5),
|
||||||
height: theme.spacing(4),
|
height: theme.spacing(3.5),
|
||||||
margin: 'auto',
|
margin: 'auto',
|
||||||
backgroundColor: theme.palette.secondary.light,
|
backgroundColor: theme.palette.secondary.light,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
@ -21,7 +21,7 @@ const StyledAvatar = styled(Avatar)(({ theme }) => ({
|
|||||||
fontWeight: theme.fontWeight.bold,
|
fontWeight: theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledStar = styled(StarIcon)(({ theme }) => ({
|
const StyledStar = styled(StarRounded)(({ theme }) => ({
|
||||||
color: theme.palette.warning.main,
|
color: theme.palette.warning.main,
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
borderRadius: theme.shape.borderRadiusExtraLarge,
|
borderRadius: theme.shape.borderRadiusExtraLarge,
|
||||||
|
@ -44,27 +44,44 @@ export const ProjectRoleDescription: VFC<IProjectRoleDescriptionProps> = ({
|
|||||||
const environments = useMemo(() => {
|
const environments = useMemo(() => {
|
||||||
const environments = new Set<string>();
|
const environments = new Set<string>();
|
||||||
role.permissions
|
role.permissions
|
||||||
?.filter((permission: any) => permission.environment !== '')
|
?.filter((permission: any) => permission.environment)
|
||||||
.forEach((permission: any) => {
|
.forEach((permission: any) => {
|
||||||
environments.add(permission.environment);
|
environments.add(permission.environment);
|
||||||
});
|
});
|
||||||
return [...environments].sort();
|
return [...environments].sort();
|
||||||
}, [role]);
|
}, [role]);
|
||||||
|
|
||||||
|
const projectPermissions = useMemo(() => {
|
||||||
|
return role.permissions?.filter(
|
||||||
|
(permission: any) => !permission.environment
|
||||||
|
);
|
||||||
|
}, [role]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDescription>
|
<StyledDescription>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(projectPermissions?.length)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
<StyledDescriptionHeader>
|
<StyledDescriptionHeader>
|
||||||
Project permissions
|
Project permissions
|
||||||
</StyledDescriptionHeader>
|
</StyledDescriptionHeader>
|
||||||
<StyledDescriptionBlock>
|
<StyledDescriptionBlock>
|
||||||
{role.permissions
|
{role.permissions
|
||||||
?.filter((permission: any) => permission.environment === '')
|
?.filter(
|
||||||
.map((permission: any) => permission.displayName)
|
(permission: any) => !permission.environment
|
||||||
|
)
|
||||||
|
.map(
|
||||||
|
(permission: any) => permission.displayName
|
||||||
|
)
|
||||||
.sort()
|
.sort()
|
||||||
.map((permission: any) => (
|
.map((permission: any) => (
|
||||||
<p key={permission}>{permission}</p>
|
<p key={permission}>{permission}</p>
|
||||||
))}
|
))}
|
||||||
</StyledDescriptionBlock>
|
</StyledDescriptionBlock>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(environments.length)}
|
condition={Boolean(environments.length)}
|
||||||
show={
|
show={
|
||||||
|
Loading…
Reference in New Issue
Block a user