Improve security settings card grouping and description overflow (#17928)

# After

- Added a separtor between the two audit logs cards
- Rename the audit log card to avoid repetition
- Grouped "Invite by link" and "2 factor auth" in one group
- Changed the card component description to always be one line max with
truncation & tooltips

<img width="777" height="1278" alt="CleanShot 2026-02-13 at 17 02 36"
src="https://github.com/user-attachments/assets/685c792a-c85b-4521-8c1b-bd9adedc75d9"
/>

<img width="976" height="690"
alt="b49f2eb043b6712d013618bb0a4ef7f011cf2316e1163fbdee4c293bed036ac9"
src="https://github.com/user-attachments/assets/6e17aa11-ecdb-4f98-ba50-5cd9b9c5def6"
/>

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Thomas des Francs
2026-02-18 22:33:37 +01:00
committed by GitHub
parent 42108e0611
commit 612f7c37a5
10 changed files with 76 additions and 87 deletions
@@ -32,6 +32,11 @@ export const StyledSettingsCardTitle = styled.div`
margin-bottom: ${({ theme }) => theme.spacing(1)};
`;
export const StyledSettingsCardTextContainer = styled.div`
flex: 1;
min-width: 0;
`;
export const StyledSettingsCardDescription = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.sm};
@@ -2,21 +2,26 @@ import {
StyledSettingsCardContent,
StyledSettingsCardDescription,
StyledSettingsCardIcon,
StyledSettingsCardTextContainer,
StyledSettingsCardTitle,
} from '@/settings/components/SettingsOptions/SettingsCardContentBase';
import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer';
import styled from '@emotion/styled';
import { type IconComponent } from 'twenty-ui/display';
import {
type IconComponent,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
type SettingsOptionCardContentButtonProps = {
Icon?: IconComponent;
title: React.ReactNode;
description?: string | React.ReactNode;
description?: string;
disabled?: boolean;
Button?: React.ReactNode;
};
const StyledButtonContainer = styled.div`
flex-shrink: 0;
margin-left: auto;
`;
@@ -34,12 +39,14 @@ export const SettingsOptionCardContentButton = ({
<SettingsOptionIconCustomizer Icon={Icon} />
</StyledSettingsCardIcon>
)}
<div>
<StyledSettingsCardTextContainer>
<StyledSettingsCardTitle>{title}</StyledSettingsCardTitle>
<StyledSettingsCardDescription>
{description}
</StyledSettingsCardDescription>
</div>
{description && (
<StyledSettingsCardDescription>
<OverflowingTextWithTooltip text={description} />
</StyledSettingsCardDescription>
)}
</StyledSettingsCardTextContainer>
{Button && <StyledButtonContainer>{Button}</StyledButtonContainer>}
</StyledSettingsCardContent>
);
@@ -3,10 +3,14 @@ import {
StyledSettingsCardContent,
StyledSettingsCardDescription,
StyledSettingsCardIcon,
StyledSettingsCardTextContainer,
StyledSettingsCardTitle,
} from '@/settings/components/SettingsOptions/SettingsCardContentBase';
import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer';
import { type IconComponent } from 'twenty-ui/display';
import {
type IconComponent,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
type SettingsOptionCardContentCounterProps = {
Icon?: IconComponent;
@@ -38,14 +42,14 @@ export const SettingsOptionCardContentCounter = ({
<SettingsOptionIconCustomizer Icon={Icon} />
</StyledSettingsCardIcon>
)}
<div>
<StyledSettingsCardTextContainer>
<StyledSettingsCardTitle>{title}</StyledSettingsCardTitle>
{description && (
<StyledSettingsCardDescription>
{description}
<OverflowingTextWithTooltip text={description} />
</StyledSettingsCardDescription>
)}
</div>
</StyledSettingsCardTextContainer>
<SettingsCounter
value={value}
onChange={onChange}
@@ -2,21 +2,26 @@ import {
StyledSettingsCardContent,
StyledSettingsCardDescription,
StyledSettingsCardIcon,
StyledSettingsCardTextContainer,
StyledSettingsCardTitle,
} from '@/settings/components/SettingsOptions/SettingsCardContentBase';
import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer';
import styled from '@emotion/styled';
import { type IconComponent } from 'twenty-ui/display';
import {
type IconComponent,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
type SettingsOptionCardContentSelectProps = {
Icon?: IconComponent;
title: React.ReactNode;
description?: string | React.ReactNode;
description?: string;
disabled?: boolean;
children?: React.ReactNode;
};
const StyledSelectContainer = styled.div`
flex-shrink: 0;
justify-content: flex-end;
margin-left: auto;
max-width: 120px;
@@ -36,12 +41,14 @@ export const SettingsOptionCardContentSelect = ({
<SettingsOptionIconCustomizer Icon={Icon} />
</StyledSettingsCardIcon>
)}
<div>
<StyledSettingsCardTextContainer>
<StyledSettingsCardTitle>{title}</StyledSettingsCardTitle>
<StyledSettingsCardDescription>
{description}
</StyledSettingsCardDescription>
</div>
{description && (
<StyledSettingsCardDescription>
<OverflowingTextWithTooltip text={description} />
</StyledSettingsCardDescription>
)}
</StyledSettingsCardTextContainer>
<StyledSelectContainer>{children}</StyledSelectContainer>
</StyledSettingsCardContent>
);
@@ -3,13 +3,17 @@ import {
StyledSettingsCardContent,
StyledSettingsCardDescription,
StyledSettingsCardIcon,
StyledSettingsCardTextContainer,
StyledSettingsCardTitle,
} from '@/settings/components/SettingsOptions/SettingsCardContentBase';
import { SettingsOptionIconCustomizer } from '@/settings/components/SettingsOptions/SettingsOptionIconCustomizer';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useId } from 'react';
import { type IconComponent } from 'twenty-ui/display';
import {
type IconComponent,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
import { Toggle } from 'twenty-ui/input';
const StyledSettingsCardToggleContent = styled(StyledSettingsCardContent)`
@@ -27,6 +31,7 @@ const StyledSettingsCardToggleButton = styled(Toggle)<{
}>`
align-self: ${({ toggleCentered }) =>
toggleCentered ? 'center' : 'flex-start'};
flex-shrink: 0;
margin-left: auto;
`;
@@ -39,7 +44,7 @@ const StyledSettingsCardToggleCover = styled.span`
type SettingsOptionCardContentToggleProps = {
Icon?: IconComponent;
title: React.ReactNode;
description?: React.ReactNode;
description?: string;
divider?: boolean;
disabled?: boolean;
advancedMode?: boolean;
@@ -70,17 +75,19 @@ export const SettingsOptionCardContentToggle = ({
<SettingsOptionIconCustomizer Icon={Icon} />
</StyledSettingsCardIcon>
)}
<div>
<StyledSettingsCardTextContainer>
<StyledSettingsCardTitle>
<label htmlFor={toggleId}>
{title}
<StyledSettingsCardToggleCover />
</label>
</StyledSettingsCardTitle>
<StyledSettingsCardDescription>
{description}
</StyledSettingsCardDescription>
</div>
{description && (
<StyledSettingsCardDescription>
<OverflowingTextWithTooltip text={description} />
</StyledSettingsCardDescription>
)}
</StyledSettingsCardTextContainer>
<StyledSettingsCardToggleButton
id={toggleId}
value={checked}