Skip to content

Commit

Permalink
fix: multi project roles UI improvements (#4646)
Browse files Browse the repository at this point in the history
https://linear.app/unleash/issue/2-1373/small-ui-fixes-and-improvements

- Update group root role `HelpIcon` tooltip to reflect the new behavior;
- Fixes a crash on groups search where `description` could be
`undefined`;
 - Improves `RoleDescription` design;
 - Fixes the role label in `ProjectGroupView`;
 

![image](https://github.com/Unleash/unleash/assets/14320932/f16ebe98-9408-4edd-8e2b-1e56ba2ad5c6)
  • Loading branch information
nunogois committed Sep 8, 2023
1 parent 10a6264 commit 61174a1
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 37 deletions.
Expand Up @@ -179,7 +179,7 @@ export const GroupForm: FC<IGroupForm> = ({
<StyledInputDescription>
<Box sx={{ display: 'flex' }}>
Do you want to associate a root role with this group?
<HelpIcon tooltip="When you associate an Admin or Editor role with this group, users in this group will automatically inherit the role globally. Note that groups with a root role association cannot be assigned to projects." />
<HelpIcon tooltip="When you associate a root role with this group, users in this group will automatically inherit the role globally." />
</Box>
</StyledInputDescription>
<StyledAutocompleteWrapper>
Expand Down
Expand Up @@ -30,7 +30,7 @@ const groupsSearch = (group: IGroup, searchValue: string) => {
};
return (
group.name.toLowerCase().includes(search) ||
group.description.toLowerCase().includes(search) ||
group.description?.toLowerCase().includes(search) ||
users.names?.some(name => name.includes(search)) ||
users.usernames?.some(username => username.includes(search)) ||
users.emails?.some(email => email.includes(search))
Expand Down
78 changes: 57 additions & 21 deletions frontend/src/component/common/RoleDescription/RoleDescription.tsx
@@ -1,4 +1,5 @@
import { SxProps, Theme, styled } from '@mui/material';
import { SupervisedUserCircle } from '@mui/icons-material';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { useRole } from 'hooks/api/getters/useRole/useRole';
import {
Expand All @@ -24,20 +25,45 @@ const StyledDescription = styled('div', {
borderRadius: tooltip ? 0 : theme.shape.borderRadiusMedium,
}));

const StyledDescriptionBlock = styled('div')(({ theme }) => ({
const StyledPermissionsLabel = styled('p')(({ theme }) => ({
color: theme.palette.text.primary,
marginTop: theme.spacing(2),
marginBottom: theme.spacing(0.5),
}));

const StyledDescriptionHeader = styled('p')(({ theme }) => ({
const StyledPermissions = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}));

const StyledRoleHeader = styled('p')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(0.5),
color: theme.palette.text.primary,
fontSize: theme.fontSizes.smallBody,
fontSize: theme.fontSizes.bodySize,
fontWeight: theme.fontWeight.bold,
}));

const StyledSupervisedUserCircle = styled(SupervisedUserCircle)(
({ theme }) => ({
fontSize: theme.fontSizes.mainHeader,
})
);

const StyledDescriptionHeader = styled('p')(({ theme }) => ({
color: theme.palette.text.secondary,
fontWeight: theme.fontWeight.bold,
marginBottom: theme.spacing(1),
}));

const StyledDescriptionSubHeader = styled('p')(({ theme }) => ({
fontSize: theme.fontSizes.smallBody,
marginTop: theme.spacing(1),
marginTop: theme.spacing(0.5),
}));

const StyledPermissionsList = styled('ul')(({ theme }) => ({
margin: 0,
paddingLeft: theme.spacing(2),
}));

interface IRoleDescriptionProps {
Expand Down Expand Up @@ -66,28 +92,38 @@ export const RoleDescription = ({

return (
<StyledDescription tooltip={tooltip} {...rest}>
<StyledDescriptionHeader sx={{ mb: 0 }}>
<StyledRoleHeader>
<StyledSupervisedUserCircle color="disabled" />
{name}
</StyledDescriptionHeader>
</StyledRoleHeader>
<StyledDescriptionSubHeader>
{description}
</StyledDescriptionSubHeader>
<ConditionallyRender
condition={!PREDEFINED_ROLE_TYPES.includes(role.type)}
show={() =>
categories.map(({ label, permissions }) => (
<StyledDescriptionBlock key={label}>
<StyledDescriptionHeader>
{label}
</StyledDescriptionHeader>
{permissions.map(permission => (
<p key={permission.id}>
{permission.displayName}
</p>
show={() => (
<>
<StyledPermissionsLabel>
Role permissions:
</StyledPermissionsLabel>
<StyledPermissions>
{categories.map(({ label, permissions }) => (
<div key={label}>
<StyledDescriptionHeader>
{label}
</StyledDescriptionHeader>
<StyledPermissionsList>
{permissions.map(permission => (
<li key={permission.id}>
{permission.displayName}
</li>
))}
</StyledPermissionsList>
</div>
))}
</StyledDescriptionBlock>
))
}
</StyledPermissions>
</>
)}
/>
</StyledDescription>
);
Expand Down
Expand Up @@ -98,6 +98,11 @@ export const ProjectAccessTable: VFC = () => {
const [groupOpen, setGroupOpen] = useState(false);
const [selectedRow, setSelectedRow] = useState<IProjectAccess>();

const roleText = (roles: number[]): string =>
roles.length > 1
? `${roles.length} roles`
: access?.roles.find(({ id }) => id === roles[0])?.name || '';

const columns = useMemo(
() => [
{
Expand Down Expand Up @@ -150,14 +155,7 @@ export const ProjectAccessTable: VFC = () => {
{
id: 'role',
Header: 'Role',
accessor: (row: IProjectAccess) =>
row.entity.roles
? row.entity.roles.length > 1
? `${row.entity.roles.length} roles`
: access?.roles.find(
({ id }) => id === row.entity.roleId
)?.name
: 'No Roles!',
accessor: (row: IProjectAccess) => roleText(row.entity.roles),
Cell: ({
value,
row: { original: row },
Expand Down Expand Up @@ -490,11 +488,17 @@ export const ProjectAccessTable: VFC = () => {
setOpen={setGroupOpen}
group={selectedRow?.entity as IGroup}
projectId={projectId}
subtitle={`Role: ${
access?.roles.find(
({ id }) => id === selectedRow?.entity.roleId
)?.name
}`}
subtitle={
<>
{selectedRow && selectedRow.entity.roles.length > 1
? 'Roles:'
: 'Role:'}
<RoleCell
value={roleText(selectedRow?.entity.roles || [])}
roles={selectedRow?.entity.roles || []}
/>
</>
}
onEdit={() => {
navigate(`edit/group/${selectedRow?.entity.id}`);
}}
Expand Down
Expand Up @@ -41,6 +41,8 @@ const StyledTitle = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
'& > span': {
display: 'flex',
alignItems: 'center',
color: theme.palette.text.secondary,
fontSize: theme.fontSizes.bodySize,
},
Expand Down Expand Up @@ -113,7 +115,7 @@ interface IProjectGroupViewProps {
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
group: IGroup;
projectId: string;
subtitle: string;
subtitle: React.ReactNode;
onEdit: () => void;
onRemove: () => void;
}
Expand Down

0 comments on commit 61174a1

Please sign in to comment.