[Fix] - Trim Names in Settings > Members table #7509 (#7525)

Issue: Long names in the Members table were overflowing, affecting the
layout.

Fix:
- Trimmed long names with ellipses.
- Added tooltips to display the full content on hover.
- Max-width of the text dynamically set to 90px on large screens, and
60px on mobile.

![image](https://github.com/user-attachments/assets/3b5d1c08-fe0e-4c0b-952a-0fc0f9e513bc)

---------

Co-authored-by: karankhatik <karan13699@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Karan Khatik 2024-10-13 22:02:50 +05:30 committed by GitHub
parent 1e2c5bb8de
commit 1e6346febd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 61 deletions

View File

@ -1,6 +1,7 @@
import { Link } from 'react-router-dom';
import isPropValid from '@emotion/is-prop-valid';
import styled from '@emotion/styled';
import { Link } from 'react-router-dom';
import { MOBILE_VIEWPORT } from 'twenty-ui';
const StyledTableRow = styled('div', {
shouldForwardProp: (prop) =>
@ -10,12 +11,19 @@ const StyledTableRow = styled('div', {
onClick?: () => void;
to?: string;
gridAutoColumns?: string;
mobileGridAutoColumns?: string;
}>`
background-color: ${({ isSelected, theme }) =>
isSelected ? theme.accent.quaternary : 'transparent'};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: grid;
grid-auto-columns: ${({ gridAutoColumns }) => gridAutoColumns ?? '1fr'};
@media (max-width: ${MOBILE_VIEWPORT}px) {
grid-auto-columns: ${({ mobileGridAutoColumns, gridAutoColumns }) =>
mobileGridAutoColumns ?? gridAutoColumns ?? '1fr'};
}
grid-auto-flow: column;
transition: background-color
${({ theme }) => theme.animation.duration.normal}s;
@ -35,6 +43,7 @@ type TableRowProps = {
to?: string;
className?: string;
gridAutoColumns?: string;
mobileGridAutoColumns?: string;
};
export const TableRow = ({
@ -44,12 +53,14 @@ export const TableRow = ({
className,
children,
gridAutoColumns,
mobileGridAutoColumns,
}: React.PropsWithChildren<TableRowProps>) => (
<StyledTableRow
isSelected={isSelected}
onClick={onClick}
gridAutoColumns={gridAutoColumns}
className={className}
mobileGridAutoColumns={mobileGridAutoColumns}
to={to}
as={to ? Link : 'div'}
>

View File

@ -4,12 +4,13 @@ import { isNonEmptyArray } from '@sniptt/guards';
import { useState } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import {
AppTooltip,
Avatar,
H2Title,
IconMail,
IconReload,
IconTrash,
MOBILE_VIEWPORT,
TooltipDelay,
} from 'twenty-ui';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
@ -52,51 +53,22 @@ const StyledTable = styled(Table)`
margin-top: ${({ theme }) => theme.spacing(0.5)};
`;
const StyledTableRow = styled(TableRow)`
@media (max-width: ${MOBILE_VIEWPORT}px) {
display: grid;
grid-template-columns: 3fr;
}
`;
const StyledTableCell = styled(TableCell)`
padding: ${({ theme }) => theme.spacing(1)};
@media (max-width: ${MOBILE_VIEWPORT}px) {
&:first-child {
max-width: 100%;
padding-top: 2px;
white-space: nowrap;
overflow: scroll;
scroll-behavior: smooth;
}
}
`;
const StyledIconWrapper = styled.div`
left: 2px;
margin-right: ${({ theme }) => theme.spacing(2)};
position: relative;
top: 1px;
`;
const StyledScrollableTextContainer = styled.div`
max-width: 100%;
overflow-x: auto;
white-space: pre-line;
`;
const StyledTextContainer = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
max-width: max-content;
overflow-x: auto;
position: absolute;
@media (min-width: 360px) and (max-width: 420px) {
max-width: 150px;
margin-top: ${({ theme }) => theme.spacing(1)};
}
`;
const StyledTableHeaderRow = styled(Table)`
margin-bottom: ${({ theme }) => theme.spacing(1.5)};
`;
const StyledIconWrapper = styled.div`
display: flex;
align-items: center;
margin-right: ${({ theme }) => theme.spacing(2)};
`;
const StyledTextContainerWithEllipsis = styled.div`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export const SettingsWorkspaceMembers = () => {
const { enqueueSnackBar } = useSnackBar();
const theme = useTheme();
@ -194,7 +166,10 @@ export const SettingsWorkspaceMembers = () => {
/>
<Table>
<StyledTableHeaderRow>
<TableRow>
<TableRow
gridAutoColumns="150px 1fr 1fr"
mobileGridAutoColumns="100px 1fr 1fr"
>
<TableHeader>Name</TableHeader>
<TableHeader>Email</TableHeader>
<TableHeader align={'right'}></TableHeader>
@ -202,7 +177,10 @@ export const SettingsWorkspaceMembers = () => {
</StyledTableHeaderRow>
{workspaceMembers?.map((workspaceMember) => (
<StyledTable key={workspaceMember.id}>
<TableRow>
<TableRow
gridAutoColumns="150px 1fr 1fr"
mobileGridAutoColumns="100px 1fr 1fr"
>
<TableCell>
<StyledIconWrapper>
<Avatar
@ -213,16 +191,26 @@ export const SettingsWorkspaceMembers = () => {
size="sm"
/>
</StyledIconWrapper>
<StyledScrollableTextContainer>
<StyledTextContainerWithEllipsis
id={`hover-text-${workspaceMember.id}`}
>
{workspaceMember.name.firstName +
' ' +
workspaceMember.name.lastName}
</StyledScrollableTextContainer>
</StyledTextContainerWithEllipsis>
<AppTooltip
anchorSelect={`#hover-text-${workspaceMember.id}`}
content={`${workspaceMember.name.firstName} ${workspaceMember.name.lastName}`}
noArrow
place="top"
positionStrategy="fixed"
delay={TooltipDelay.shortDelay}
/>
</TableCell>
<TableCell>
<StyledTextContainer>
<StyledTextContainerWithEllipsis>
{workspaceMember.userEmail}
</StyledTextContainer>
</StyledTextContainerWithEllipsis>
</TableCell>
<TableCell align={'right'}>
{currentWorkspaceMember?.id !== workspaceMember.id && (
@ -253,7 +241,10 @@ export const SettingsWorkspaceMembers = () => {
{isNonEmptyArray(workspaceInvitations) && (
<Table>
<StyledTableHeaderRow>
<TableRow gridAutoColumns={`1fr 1fr ${theme.spacing(22)}`}>
<TableRow
gridAutoColumns="150px 1fr 1fr"
mobileGridAutoColumns="100px 1fr 1fr"
>
<TableHeader>Email</TableHeader>
<TableHeader align={'right'}>Expires in</TableHeader>
<TableHeader></TableHeader>
@ -261,27 +252,28 @@ export const SettingsWorkspaceMembers = () => {
</StyledTableHeaderRow>
{workspaceInvitations?.map((workspaceInvitation) => (
<StyledTable key={workspaceInvitation.id}>
<StyledTableRow
gridAutoColumns={`1fr 1fr ${theme.spacing(22)}`}
<TableRow
gridAutoColumns="150px 1fr 1fr"
mobileGridAutoColumns="100px 1fr 1fr"
>
<StyledTableCell>
<TableCell>
<StyledIconWrapper>
<IconMail
size={theme.icon.size.md}
stroke={theme.icon.stroke.sm}
/>
</StyledIconWrapper>
<StyledScrollableTextContainer>
<StyledTextContainerWithEllipsis>
{workspaceInvitation.email}
</StyledScrollableTextContainer>
</StyledTableCell>
<StyledTableCell align={'right'}>
</StyledTextContainerWithEllipsis>
</TableCell>
<TableCell align={'right'}>
<Status
color={'gray'}
text={getExpiresAtText(workspaceInvitation.expiresAt)}
/>
</StyledTableCell>
<StyledTableCell align={'right'}>
</TableCell>
<TableCell align={'right'}>
<StyledButtonContainer>
<IconButton
onClick={() => {
@ -304,8 +296,8 @@ export const SettingsWorkspaceMembers = () => {
Icon={IconTrash}
/>
</StyledButtonContainer>
</StyledTableCell>
</StyledTableRow>
</TableCell>
</TableRow>
</StyledTable>
))}
</Table>