mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +02:00
chore: users actions menu (#9525)
https://linear.app/unleash/issue/2-3342/new-entrance-point-create-dot-dot-dot-menu-instead-of-icons Adds a new users actions menu. Should this change be behind a flag? I'm leaning towards no, but if you think otherwise let me know. ### Previous  ### After  ### If user is SCIM-managed 
This commit is contained in:
parent
1b7f91cd4b
commit
8ab24fd3bf
@ -1,101 +1,145 @@
|
|||||||
import Delete from '@mui/icons-material/Delete';
|
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||||
import Edit from '@mui/icons-material/Edit';
|
import {
|
||||||
import Key from '@mui/icons-material/Key';
|
IconButton,
|
||||||
import Lock from '@mui/icons-material/Lock';
|
ListItemText,
|
||||||
import LockReset from '@mui/icons-material/LockReset';
|
MenuItem,
|
||||||
import { Box, styled } from '@mui/material';
|
MenuList,
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
Popover,
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
styled,
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
Tooltip,
|
||||||
import type { VFC } from 'react';
|
Typography,
|
||||||
|
} from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
const StyledBox = styled(Box)(() => ({
|
const StyledActions = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
margin: theme.spacing(-1),
|
||||||
|
marginLeft: theme.spacing(-0.5),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledPopover = styled(Popover)(({ theme }) => ({
|
||||||
|
borderRadius: theme.shape.borderRadiusLarge,
|
||||||
|
padding: theme.spacing(1, 1.5),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface IUsersActionsCellProps {
|
interface IUsersActionsCellProps {
|
||||||
onEdit: (event: React.SyntheticEvent) => void;
|
onEdit: () => void;
|
||||||
onViewAccess?: (event: React.SyntheticEvent) => void;
|
onViewAccess?: () => void;
|
||||||
onChangePassword: (event: React.SyntheticEvent) => void;
|
onChangePassword: () => void;
|
||||||
onResetPassword: (event: React.SyntheticEvent) => void;
|
onResetPassword: () => void;
|
||||||
onDelete: (event: React.SyntheticEvent) => void;
|
onDelete: () => void;
|
||||||
isScimUser?: boolean;
|
isScimUser?: boolean;
|
||||||
|
userId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
|
export const UsersActionsCell = ({
|
||||||
onEdit,
|
onEdit,
|
||||||
onViewAccess,
|
onViewAccess,
|
||||||
onChangePassword,
|
onChangePassword,
|
||||||
onResetPassword,
|
onResetPassword,
|
||||||
onDelete,
|
onDelete,
|
||||||
isScimUser,
|
isScimUser,
|
||||||
}) => {
|
userId,
|
||||||
|
}: IUsersActionsCellProps) => {
|
||||||
|
const [anchorEl, setAnchorEl] = useState<Element | null>(null);
|
||||||
|
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
setAnchorEl(event.currentTarget);
|
||||||
|
};
|
||||||
|
const handleClose = () => {
|
||||||
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const id = `user-${userId}-actions`;
|
||||||
|
const menuId = `${id}-menu`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledActions>
|
||||||
|
<Tooltip title='User actions' arrow describeChild>
|
||||||
|
<IconButton
|
||||||
|
id={id}
|
||||||
|
aria-controls={open ? 'actions-menu' : undefined}
|
||||||
|
aria-haspopup='true'
|
||||||
|
aria-expanded={open ? 'true' : undefined}
|
||||||
|
onClick={handleClick}
|
||||||
|
type='button'
|
||||||
|
size='small'
|
||||||
|
>
|
||||||
|
<MoreVertIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<StyledPopover
|
||||||
|
id={menuId}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||||
|
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||||
|
disableScrollLock={true}
|
||||||
|
>
|
||||||
|
<MenuList aria-labelledby={id}>
|
||||||
|
<UserAction onClick={onEdit} isScimUser={isScimUser}>
|
||||||
|
Edit user
|
||||||
|
</UserAction>
|
||||||
|
{onViewAccess && (
|
||||||
|
<UserAction onClick={onViewAccess}>
|
||||||
|
Access overview
|
||||||
|
</UserAction>
|
||||||
|
)}
|
||||||
|
<UserAction
|
||||||
|
onClick={() => {
|
||||||
|
onChangePassword();
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
isScimUser={isScimUser}
|
||||||
|
>
|
||||||
|
Change password
|
||||||
|
</UserAction>
|
||||||
|
<UserAction
|
||||||
|
onClick={() => {
|
||||||
|
onResetPassword();
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
isScimUser={isScimUser}
|
||||||
|
>
|
||||||
|
Reset password
|
||||||
|
</UserAction>
|
||||||
|
<UserAction
|
||||||
|
onClick={() => {
|
||||||
|
onDelete();
|
||||||
|
handleClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove user
|
||||||
|
</UserAction>
|
||||||
|
</MenuList>
|
||||||
|
</StyledPopover>
|
||||||
|
</StyledActions>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IUserActionProps {
|
||||||
|
onClick: () => void;
|
||||||
|
isScimUser?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserAction = ({ onClick, isScimUser, children }: IUserActionProps) => {
|
||||||
const scimTooltip =
|
const scimTooltip =
|
||||||
'This user is managed by your SCIM provider and cannot be changed manually';
|
'This user is managed by your SCIM provider and cannot be changed manually';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledBox>
|
<Tooltip title={isScimUser ? scimTooltip : ''} arrow placement='left'>
|
||||||
<PermissionIconButton
|
<div>
|
||||||
data-loading
|
<MenuItem onClick={onClick} disabled={isScimUser}>
|
||||||
onClick={onEdit}
|
<ListItemText>
|
||||||
permission={ADMIN}
|
<Typography variant='body2'>{children}</Typography>
|
||||||
tooltipProps={{
|
</ListItemText>
|
||||||
title: isScimUser ? scimTooltip : 'Edit user',
|
</MenuItem>
|
||||||
}}
|
</div>
|
||||||
disabled={isScimUser}
|
</Tooltip>
|
||||||
>
|
|
||||||
<Edit />
|
|
||||||
</PermissionIconButton>
|
|
||||||
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(onViewAccess)}
|
|
||||||
show={
|
|
||||||
<PermissionIconButton
|
|
||||||
data-loading
|
|
||||||
onClick={onViewAccess!}
|
|
||||||
permission={ADMIN}
|
|
||||||
tooltipProps={{
|
|
||||||
title: 'Access matrix',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Key />
|
|
||||||
</PermissionIconButton>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PermissionIconButton
|
|
||||||
data-loading
|
|
||||||
onClick={onChangePassword}
|
|
||||||
permission={ADMIN}
|
|
||||||
tooltipProps={{
|
|
||||||
title: isScimUser ? scimTooltip : 'Change password',
|
|
||||||
}}
|
|
||||||
disabled={isScimUser}
|
|
||||||
>
|
|
||||||
<Lock />
|
|
||||||
</PermissionIconButton>
|
|
||||||
<PermissionIconButton
|
|
||||||
data-loading
|
|
||||||
onClick={onResetPassword}
|
|
||||||
permission={ADMIN}
|
|
||||||
tooltipProps={{
|
|
||||||
title: isScimUser ? scimTooltip : 'Reset password',
|
|
||||||
}}
|
|
||||||
disabled={isScimUser}
|
|
||||||
>
|
|
||||||
<LockReset />
|
|
||||||
</PermissionIconButton>
|
|
||||||
<PermissionIconButton
|
|
||||||
data-loading
|
|
||||||
onClick={onDelete}
|
|
||||||
permission={ADMIN}
|
|
||||||
tooltipProps={{
|
|
||||||
title: 'Remove user',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Delete />
|
|
||||||
</PermissionIconButton>
|
|
||||||
</StyledBox>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import type React from 'react';
|
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
|
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
|
||||||
import ChangePassword from './ChangePassword/ChangePassword';
|
import ChangePassword from './ChangePassword/ChangePassword';
|
||||||
@ -82,21 +81,15 @@ const UsersList = () => {
|
|||||||
setDelUser(undefined);
|
setDelUser(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openDelDialog =
|
const openDelDialog = (user: IUser) => () => {
|
||||||
(user: IUser) => (e: React.SyntheticEvent<Element, Event>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setDelDialog(true);
|
setDelDialog(true);
|
||||||
setDelUser(user);
|
setDelUser(user);
|
||||||
};
|
};
|
||||||
const openPwDialog =
|
const openPwDialog = (user: IUser) => () => {
|
||||||
(user: IUser) => (e: React.SyntheticEvent<Element, Event>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setPwDialog({ open: true, user });
|
setPwDialog({ open: true, user });
|
||||||
};
|
};
|
||||||
|
|
||||||
const openResetPwDialog =
|
const openResetPwDialog = (user: IUser) => () => {
|
||||||
(user: IUser) => (e: React.SyntheticEvent<Element, Event>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setResetPwDialog({ open: true, user });
|
setResetPwDialog({ open: true, user });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -215,7 +208,7 @@ const UsersList = () => {
|
|||||||
sortType: 'boolean',
|
sortType: 'boolean',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Actions',
|
Header: '',
|
||||||
id: 'Actions',
|
id: 'Actions',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
Cell: ({
|
Cell: ({
|
||||||
@ -238,9 +231,10 @@ const UsersList = () => {
|
|||||||
onResetPassword={openResetPwDialog(user)}
|
onResetPassword={openResetPwDialog(user)}
|
||||||
onDelete={openDelDialog(user)}
|
onDelete={openDelDialog(user)}
|
||||||
isScimUser={scimEnabled && Boolean(user.scimId)}
|
isScimUser={scimEnabled && Boolean(user.scimId)}
|
||||||
|
userId={user.id}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
width: userAccessUIEnabled ? 240 : 200,
|
width: 80,
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
// Always hidden -- for search
|
// Always hidden -- for search
|
||||||
|
Loading…
Reference in New Issue
Block a user