1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: add popover to users in flags list (#7344)

This PR adds a popover to the user avatars in the flag list.

The popover is similar to the one used for projects and groups, but it
differs in a few ways:
- There's less padding. There's quite a lot of padding in the other
popovers, and it felt like too much for this table.
- It only shows one bit of text (the user's name/username/email). The
other popovers show email and name/username, but we don't have all that
information, so this is a stripped down version.

Flag list popover:

![image](https://github.com/Unleash/unleash/assets/17786332/6a86f638-ba6d-48e0-87e2-078b582697cf)

Group popover:

![image](https://github.com/Unleash/unleash/assets/17786332/d5fc7172-8fcb-4fac-87c4-05f211c0938c)

or if no email

![image](https://github.com/Unleash/unleash/assets/17786332/51955ead-849f-4bfc-81aa-e1852677647c)
This commit is contained in:
Thomas Heartman 2024-06-11 09:40:48 +02:00 committed by GitHub
parent c7842aefd0
commit 24c0976d56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 100 additions and 5 deletions

View File

@ -25,7 +25,7 @@ const StyledAvatar = styled(Avatar, {
};
});
interface IUserAvatarProps extends AvatarProps {
export interface IUserAvatarProps extends AvatarProps {
user?: Partial<
Pick<IUser, 'id' | 'name' | 'email' | 'username' | 'imageUrl'>
>;
@ -77,7 +77,7 @@ export const UserAvatar: FC<IUserAvatarProps> = ({
sx={sx}
{...props}
data-loading
alt='Gravatar'
alt={user?.name || user?.email || user?.username || 'Gravatar'}
src={src}
title={title}
onMouseEnter={onMouseEnter}

View File

@ -0,0 +1,92 @@
import { styled, Popover } from '@mui/material';
import { useState, type FC } from 'react';
import type React from 'react';
import { type IUserAvatarProps, UserAvatar } from './UserAvatar';
type PopoverProps = {
mainText: string;
open: boolean;
anchorEl: HTMLElement | null;
onPopoverClose(event: React.MouseEvent<HTMLElement>): void;
};
const StyledPopover = styled(Popover)(({ theme }) => ({
pointerEvents: 'none',
'.MuiPaper-root': {
padding: theme.spacing(1),
},
}));
const AvatarPopover = ({
mainText,
open,
anchorEl,
onPopoverClose,
}: PopoverProps) => {
return (
<StyledPopover
open={open}
anchorEl={anchorEl}
onClose={onPopoverClose}
disableScrollLock={true}
disableRestoreFocus={true}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
>
<p>{mainText}</p>
</StyledPopover>
);
};
type UserAvatarWithPopoverProps = Omit<
IUserAvatarProps,
'user' | 'onMouseEnter' | 'onMouseLeave'
> & {
user: {
name: string;
id?: number;
imageUrl?: string;
};
};
export const UserAvatarWithPopover: FC<UserAvatarWithPopoverProps> = ({
user,
...userAvatarProps
}) => {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const onPopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const onPopoverClose = () => {
setAnchorEl(null);
};
const avatarOpen = Boolean(anchorEl);
return (
<>
<UserAvatar
{...userAvatarProps}
user={user}
data-loading
onMouseEnter={(event) => {
onPopoverOpen(event);
}}
onMouseLeave={onPopoverClose}
/>
<AvatarPopover
mainText={user.name}
open={avatarOpen}
anchorEl={anchorEl}
onPopoverClose={onPopoverClose}
/>
</>
);
};

View File

@ -39,7 +39,8 @@ import {
useProjectFeatureSearch,
useProjectFeatureSearchActions,
} from './useProjectFeatureSearch';
import { UserAvatar } from '../../../common/UserAvatar/UserAvatar';
import { UserAvatarWithPopover } from '../../../common/UserAvatar/UserAvatarWithPopover';
import type { Theme } from '@mui/material';
interface IPaginatedProjectFeatureTogglesProps {
environments: string[];
@ -176,13 +177,15 @@ export const ProjectFeatureToggles = ({
header: 'By',
cell: ({ row: { original } }) => {
return (
<UserAvatar
<UserAvatarWithPopover
user={{
id: original.createdBy.id,
name: original.createdBy.name,
imageUrl: original.createdBy.imageUrl,
}}
avatarWidth={(theme) => theme.spacing(3)}
avatarWidth={(theme: Theme) =>
theme.spacing(3)
}
/>
);
},