Refactored all FieldDisplay types for performance optimization (#5768)

This PR is the second part of
https://github.com/twentyhq/twenty/pull/5693.

It optimizes all remaining field types.

The observed improvements are :
- x2 loading time improvement on table rows
- more consistent render time

Here's a summary of measured improvements, what's given here is the
average of hundreds of renders with a React Profiler component. (in our
Storybook performance stories)

| Component | Before (µs) | After (µs) |
| ----- | ------------- | --- |
| TextFieldDisplay | 127 | 83 |
| EmailFieldDisplay | 117 | 83 |
| NumberFieldDisplay | 97 | 56 |
| DateFieldDisplay | 240 | 52 |
| CurrencyFieldDisplay | 236 | 110 |
| FullNameFieldDisplay | 131 | 85 |
| AddressFieldDisplay | 118 | 81 |
| BooleanFieldDisplay | 130 | 100 |
| JSONFieldDisplay | 248 | 49 |
| LinksFieldDisplay | 1180 | 140 |
| LinkFieldDisplay | 140 | 78 |
| MultiSelectFieldDisplay | 770 | 130 |
| SelectFieldDisplay | 230 | 87 |
This commit is contained in:
Lucas Bordeau
2024-06-12 18:36:25 +02:00
committed by GitHub
parent 007e0e8b0e
commit 03b3c8a67a
101 changed files with 17167 additions and 15795 deletions

View File

@ -1,50 +1,71 @@
import * as React from 'react';
import { Link as ReactLink } from 'react-router-dom';
import styled from '@emotion/styled';
import { Chip, ChipSize, ChipVariant } from 'twenty-ui';
import { MouseEvent } from 'react';
import { styled } from '@linaria/react';
import { isNonEmptyString } from '@sniptt/guards';
import { FONT_COMMON, THEME_COMMON } from 'twenty-ui';
type RoundedLinkProps = {
href: string;
children?: React.ReactNode;
className?: string;
label?: string;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
const StyledLink = styled(ReactLink)`
font-size: ${({ theme }) => theme.font.size.md};
const fontSizeMd = FONT_COMMON.size.md;
const spacing1 = THEME_COMMON.spacing(1);
const spacing3 = THEME_COMMON.spacing(3);
const spacingMultiplicator = THEME_COMMON.spacingMultiplicator;
const StyledLink = styled.a`
align-items: center;
background-color: var(--twentycrm-background-transparent-light);
border: 1px solid var(--twentycrm-border-color-medium);
border-radius: 50px;
color: var(--twentycrm-font-color-primary);
cursor: pointer;
display: inline-flex;
font-weight: ${fontSizeMd};
gap: ${spacing1};
height: ${spacing3};
justify-content: center;
max-width: calc(100% - ${spacingMultiplicator} * 2px);
max-width: 100%;
height: ${({ theme }) => theme.spacing(5)};
min-width: fit-content;
overflow: hidden;
padding: ${spacing1} ${spacing1};
text-decoration: none;
text-overflow: ellipsis;
user-select: none;
white-space: nowrap;
`;
const StyledChip = styled(Chip)`
border-color: ${({ theme }) => theme.border.color.strong};
box-sizing: border-box;
padding: ${({ theme }) => theme.spacing(0, 2)};
max-width: 100%;
height: ${({ theme }) => theme.spacing(5)};
min-width: 40px;
`;
export const RoundedLink = ({ label, href, onClick }: RoundedLinkProps) => {
if (!isNonEmptyString(label)) {
return <></>;
}
export const RoundedLink = ({
children,
className,
href,
onClick,
}: RoundedLinkProps) => {
if (!children) return null;
const handleClick = (event: MouseEvent<HTMLElement>) => {
event.stopPropagation();
onClick?.(event);
};
return (
<StyledLink
className={className}
href={href}
target="_blank"
to={href}
onClick={onClick}
rel="noreferrer"
onClick={handleClick}
>
<StyledChip
label={`${children}`}
variant={ChipVariant.Rounded}
size={ChipSize.Large}
/>
{label}
</StyledLink>
);
};

View File

@ -11,24 +11,15 @@ export enum LinkType {
}
type SocialLinkProps = {
label: string;
href: string;
children?: React.ReactNode;
type: LinkType;
onClick?: (event: React.MouseEvent<HTMLElement>) => void;
};
export const SocialLink = ({
children,
href,
onClick,
type,
}: SocialLinkProps) => {
export const SocialLink = ({ label, href, onClick, type }: SocialLinkProps) => {
const displayValue =
getDisplayValueByUrlType({ type: type, href: href }) ?? children;
getDisplayValueByUrlType({ type: type, href: href }) ?? label;
return (
<RoundedLink href={href} onClick={onClick}>
{displayValue}
</RoundedLink>
);
return <RoundedLink href={href} onClick={onClick} label={displayValue} />;
};

View File

@ -11,7 +11,7 @@ const meta: Meta<typeof RoundedLink> = {
decorators: [ComponentWithRouterDecorator],
args: {
href: '/test',
children: 'Rounded chip',
label: 'Rounded chip',
},
};

View File

@ -11,7 +11,7 @@ const meta: Meta<typeof SocialLink> = {
decorators: [ComponentWithRouterDecorator],
args: {
href: '/test',
children: 'Social Link',
label: 'Social Link',
},
};
@ -25,7 +25,7 @@ const twitter: LinkType = LinkType.Twitter;
export const LinkedIn: Story = {
args: {
href: '/LinkedIn',
children: 'LinkedIn',
label: 'LinkedIn',
onClick: clickJestFn,
type: linkedin,
},
@ -34,7 +34,7 @@ export const LinkedIn: Story = {
export const Twitter: Story = {
args: {
href: '/Twitter',
children: 'Twitter',
label: 'Twitter',
onClick: clickJestFn,
type: twitter,
},