diff --git a/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx b/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx
index df077c1b8f..2240825f54 100644
--- a/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx
+++ b/packages/twenty-front/src/modules/error-handler/components/AppRootErrorFallback.tsx
@@ -1,15 +1,13 @@
import { type AppErrorDisplayProps } from '@/error-handler/types/AppErrorDisplayProps';
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
-import { motion } from 'framer-motion';
import { IconReload } from 'twenty-ui/display';
-import { THEME_DARK } from 'twenty-ui/theme';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
+import { ICON_SIZES, themeCssVariables } from 'twenty-ui/theme-constants';
type AppRootErrorFallbackProps = AppErrorDisplayProps;
const StyledContainer = styled.div`
- background: ${THEME_DARK.background.noisy};
+ background: ${themeCssVariables.background.noisy};
box-sizing: border-box;
display: flex;
height: 100vh;
@@ -27,7 +25,7 @@ const StyledPanel = styled.div`
width: 100%;
`;
-const StyledEmptyContainer = styled(motion.div)`
+const StyledEmptyContainer = styled.div`
align-items: center;
width: 100%;
height: 100%;
@@ -94,8 +92,9 @@ const StyledButton = styled.button`
padding: 8px;
`;
-const StyledIcon = styled(IconReload)`
+const StyledIconContainer = styled.span`
color: ${themeCssVariables.grayScale.gray12};
+ display: inline-flex;
margin-right: 8px;
`;
@@ -124,7 +123,9 @@ export const AppRootErrorFallback = ({
-
+
+
+
{t`Reload`}
diff --git a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx
index c168c59793..8aee475a5e 100644
--- a/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx
+++ b/packages/twenty-front/src/modules/favorites/favorite-folder-picker/components/FavoriteFolderPickerList.tsx
@@ -12,7 +12,7 @@ const StyledItemsContainer = styled.div`
width: 100%;
`;
-const StyledDropdownMenuSeparator = styled(DropdownMenuSeparator)`
+const StyledSeparatorContainer = styled.div`
margin-bottom: ${themeCssVariables.spacing[1]};
margin-top: ${themeCssVariables.spacing[1]};
`;
@@ -59,7 +59,9 @@ export const FavoriteFolderPickerList = ({
/>
)}
{showNoFolderOption && filteredFolders.length > 0 && (
-
+
+
+
)}
{filteredFolders.length > 0
? filteredFolders.map((folder) => (
diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx
index 368655b073..a3e0a81738 100644
--- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardBody.tsx
@@ -17,13 +17,8 @@ import { RecordInlineCell } from '@/object-record/record-inline-cell/components/
import { getRecordFieldInputInstanceId } from '@/object-record/utils/getRecordFieldInputId';
import { useAtomComponentSelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorValue';
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
-import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-const StyledRecordCardBodyContainer = styled(RecordCardBodyContainer)`
- padding: ${themeCssVariables.spacing[1]};
-`;
-
type RecordCalendarCardBodyProps = {
recordId: string;
isRecordReadOnly: boolean;
@@ -73,7 +68,7 @@ export const RecordCalendarCardBody = ({
};
return (
-
+
{visibleRecordFieldsExceptLabelIdentifier.map((recordField, index) => {
const correspondingFieldDefinition =
fieldDefinitionByFieldMetadataItemId[recordField.fieldMetadataItemId];
@@ -120,6 +115,6 @@ export const RecordCalendarCardBody = ({
);
})}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx
index 6567c577e9..23b83f78fa 100644
--- a/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-calendar/record-calendar-card/components/RecordCalendarCardHeader.tsx
@@ -9,12 +9,12 @@ import { useAtomComponentFamilyState } from '@/ui/utilities/state/jotai/hooks/us
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { styled } from '@linaria/react';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
import { isDefined } from 'twenty-shared/utils';
import { ChipVariant } from 'twenty-ui/components';
import { Checkbox, CheckboxVariant } from 'twenty-ui/input';
import { isRecordCalendarCardSelectedComponentFamilyState } from '@/object-record/record-calendar/record-calendar-card/states/isRecordCalendarCardSelectedComponentFamilyState';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledCheckboxContainer = styled.div`
margin-left: auto;
@@ -27,10 +27,6 @@ const StyledRecordChipContainer = styled.div`
padding: ${themeCssVariables.spacing[1]};
`;
-const StyledRecordCardHeaderContainer = styled(RecordCardHeaderContainer)`
- padding: ${themeCssVariables.spacing[1]};
-`;
-
type RecordCalendarCardHeaderProps = {
recordId: string;
};
@@ -68,7 +64,10 @@ export const RecordCalendarCardHeader = ({
}
return (
-
+
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardBodyContainer.tsx b/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardBodyContainer.tsx
index bb7bcfacec..7a6a4d375e 100644
--- a/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardBodyContainer.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardBodyContainer.tsx
@@ -1,13 +1,13 @@
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-const StyledCardBodyContainer = styled.div`
+const StyledCardBodyContainer = styled.div<{ padding?: string }>`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing['0.5']};
- padding-bottom: ${themeCssVariables.spacing[2]};
- padding-left: 10px;
- padding-right: ${themeCssVariables.spacing[2]};
+ padding: ${({ padding }) =>
+ padding ??
+ `0 ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]} 10px`};
span {
align-items: center;
display: flex;
diff --git a/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardHeaderContainer.tsx b/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardHeaderContainer.tsx
index 292d31922d..58d26ba674 100644
--- a/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardHeaderContainer.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-card/components/RecordCardHeaderContainer.tsx
@@ -3,6 +3,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
export const StyledBoardCardHeaderContainer = styled.div<{
isCompact: boolean;
+ padding?: string;
}>`
align-items: center;
display: flex;
@@ -10,11 +11,9 @@ export const StyledBoardCardHeaderContainer = styled.div<{
justify-content: space-between;
font-weight: ${themeCssVariables.font.weight.medium};
height: 24px;
- padding-bottom: ${({ isCompact }) =>
- isCompact ? themeCssVariables.spacing[2] : themeCssVariables.spacing[1]};
- padding-left: ${themeCssVariables.spacing[2]};
- padding-right: ${themeCssVariables.spacing[2]};
- padding-top: ${themeCssVariables.spacing[2]};
+ padding: ${({ padding, isCompact }) =>
+ padding ??
+ `${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]} ${isCompact ? themeCssVariables.spacing[2] : themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]}`};
transition: padding ease-in-out 160ms;
img {
diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordFieldChip.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordFieldChip.tsx
index 6e88154453..e63d9123d5 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordFieldChip.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/ui/form-types/components/FormSingleRecordFieldChip.tsx
@@ -11,11 +11,11 @@ import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-const StyledRecordChip = styled(RecordChip)`
+const StyledRecordChipContainer = styled.div`
margin: ${themeCssVariables.spacing[2]};
`;
-const StyledPlaceholder = styled(FormFieldPlaceholder)`
+const StyledPlaceholderContainer = styled.div`
margin: ${themeCssVariables.spacing[2]};
`;
@@ -58,12 +58,18 @@ export const FormSingleRecordFieldChip = ({
if (!!draftValue && draftValue.type === 'static' && !!selectedRecord) {
return (
-
+
+
+
);
}
- return {t`Select`};
+ return (
+
+ {t`Select`}
+
+ );
};
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
index 837ae06ba6..5514cc3264 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItem.tsx
@@ -1,16 +1,8 @@
-import { styled } from '@linaria/react';
-
import { useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId } from '@/object-record/record-picker/hooks/useRecordPickerGetSearchRecordAndObjectMetadataItemFromRecordId';
import { MultipleRecordPickerMenuItemContent } from '@/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent';
import { type RecordPickerPickableMorphItem } from '@/object-record/record-picker/types/RecordPickerPickableMorphItem';
-import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
import { isDefined } from 'twenty-shared/utils';
-export const StyledSelectableItem = styled(SelectableListItem)`
- height: 100%;
- width: 100%;
-`;
-
type MultipleRecordPickerMenuItemProps = {
recordId: string;
onChange: (morphItem: RecordPickerPickableMorphItem) => void;
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
index 8a97314b2a..da9e6a91fc 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/multiple-record-picker/components/MultipleRecordPickerMenuItemContent.tsx
@@ -1,5 +1,4 @@
import { t } from '@lingui/core/macro';
-import { styled } from '@linaria/react';
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getAvatarType } from '@/object-metadata/utils/getAvatarType';
@@ -20,11 +19,6 @@ import { MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from '@/object-record/record-picker/multiple-record-picker/states/multipleRecordPickerSearchableObjectMetadataItemsComponentState';
import { type SearchRecord } from '~/generated/graphql';
-export const StyledSelectableItem = styled(SelectableListItem)`
- height: 100%;
- width: 100%;
-`;
-
type MultipleRecordPickerMenuItemContentProps = {
searchRecord: SearchRecord;
objectMetadataItem: ObjectMetadataItem;
@@ -78,7 +72,7 @@ export const MultipleRecordPickerMenuItemContent = ({
multipleRecordPickerSearchableObjectMetadataItems.length > 1;
return (
- handleSelectChange(!isRecordSelectedWithObjectItem)}
@@ -103,6 +97,6 @@ export const MultipleRecordPickerMenuItemContent = ({
: undefined
}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
index a127079af8..cb2f074b10 100644
--- a/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-picker/single-record-picker/components/SingleRecordPickerMenuItem.tsx
@@ -1,5 +1,3 @@
-import { styled } from '@linaria/react';
-
import { getAvatarType } from '@/object-metadata/utils/getAvatarType';
import { searchRecordStoreFamilyState } from '@/object-record/record-picker/multiple-record-picker/states/searchRecordStoreComponentFamilyState';
import { SingleRecordPickerComponentInstanceContext } from '@/object-record/record-picker/single-record-picker/states/contexts/SingleRecordPickerComponentInstanceContext';
@@ -22,10 +20,6 @@ type SingleRecordPickerMenuItemProps = {
isRecordSelected: boolean;
};
-const StyledSelectableItem = styled(SelectableListItem)`
- width: 100%;
-`;
-
export const SingleRecordPickerMenuItem = ({
morphItem,
onMorphItemSelected,
@@ -64,7 +58,7 @@ export const SingleRecordPickerMenuItem = ({
singleRecordPickerSearchableObjectMetadataItems.length > 1;
return (
- {
@@ -94,6 +88,6 @@ export const SingleRecordPickerMenuItem = ({
: undefined
}
/>
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/HorizontalScrollBoxShadowCSS.ts b/packages/twenty-front/src/modules/object-record/record-table/components/HorizontalScrollBoxShadowCSS.ts
new file mode 100644
index 0000000000..e19de57414
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-table/components/HorizontalScrollBoxShadowCSS.ts
@@ -0,0 +1,21 @@
+import { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableHorizontalScrollShadowVisibilityCssVariableName';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+export const HorizontalScrollBoxShadowCSS = `
+ &::after {
+ content: '';
+ position: absolute;
+ top: -1px;
+ height: calc(100% + 2px);
+ width: 4px;
+ right: -1px;
+ box-shadow:
+ 2px 0px 4px 0px ${themeCssVariables.boxShadow.color},
+ 0px 0px 4px 0px ${themeCssVariables.boxShadow.color};
+ clip-path: inset(0px -4px 0px 0px);
+ visibility: var(
+ ${RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME},
+ hidden
+ );
+ }
+`;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx
index a11d0237a7..c0f4b0e69d 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableStyleWrapper.tsx
@@ -9,51 +9,15 @@ import { RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_CLASS_NAME } from '@/object
import { RECORD_TABLE_COLUMN_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnLastEmptyColumnWidthVariableName';
import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_CLASS_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthClassName';
import { RECORD_TABLE_COLUMN_WITH_GROUP_LAST_EMPTY_COLUMN_WIDTH_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableColumnWithGroupLastEmptyColumnWidthVariableName';
-import { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableHorizontalScrollShadowVisibilityCssVariableName';
-import { RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableVerticalScrollShadowVisibilityCssVariableName';
-
import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex';
+import { HorizontalScrollBoxShadowCSS } from '@/object-record/record-table/components/HorizontalScrollBoxShadowCSS';
+import { VerticalScrollBoxShadowCSS } from '@/object-record/record-table/components/VerticalScrollBoxShadowCSS';
import { getRecordTableColumnFieldWidthClassName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthClassName';
import { getRecordTableColumnFieldWidthCSSVariableName } from '@/object-record/record-table/utils/getRecordTableColumnFieldWidthCSSVariableName';
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-export const VerticalScrollBoxShadowCSS = `
- &::before {
- bottom: -1px;
- box-shadow:
- 0px 2px 4px 0px ${themeCssVariables.boxShadow.color},
- 0px 0px 4px 0px ${themeCssVariables.boxShadow.color};
- clip-path: inset(0px 0px -4px 0px);
- content: '';
- height: 4px;
- position: absolute;
- visibility: var(
- ${RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME},
- hidden
- );
- width: 100%;
- }
-`;
-
-export const HorizontalScrollBoxShadowCSS = `
- &::after {
- content: '';
- position: absolute;
- top: -1px;
- height: calc(100% + 2px);
- width: 4px;
- right: -1px;
- box-shadow:
- 2px 0px 4px 0px ${themeCssVariables.boxShadow.color},
- 0px 0px 4px 0px ${themeCssVariables.boxShadow.color};
- clip-path: inset(0px -4px 0px 0px);
- visibility: var(
- ${RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME},
- hidden
- );
- }
-`;
+export { HorizontalScrollBoxShadowCSS, VerticalScrollBoxShadowCSS };
const MAX_COLUMNS = 100;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/VerticalScrollBoxShadowCSS.ts b/packages/twenty-front/src/modules/object-record/record-table/components/VerticalScrollBoxShadowCSS.ts
new file mode 100644
index 0000000000..16c29dfcc8
--- /dev/null
+++ b/packages/twenty-front/src/modules/object-record/record-table/components/VerticalScrollBoxShadowCSS.ts
@@ -0,0 +1,20 @@
+import { RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableVerticalScrollShadowVisibilityCssVariableName';
+import { themeCssVariables } from 'twenty-ui/theme-constants';
+
+export const VerticalScrollBoxShadowCSS = `
+ &::before {
+ bottom: -1px;
+ box-shadow:
+ 0px 2px 4px 0px ${themeCssVariables.boxShadow.color},
+ 0px 0px 4px 0px ${themeCssVariables.boxShadow.color};
+ clip-path: inset(0px 0px -4px 0px);
+ content: '';
+ height: 4px;
+ position: absolute;
+ visibility: var(
+ ${RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME},
+ hidden
+ );
+ width: 100%;
+ }
+`;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx
index 525794c2bc..ed668b5a87 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyVirtualizedDraggableClone.tsx
@@ -1,7 +1,5 @@
-import {
- getRecordTableColumnWidthInlineStyles,
- HorizontalScrollBoxShadowCSS,
-} from '@/object-record/record-table/components/RecordTableStyleWrapper';
+import { getRecordTableColumnWidthInlineStyles } from '@/object-record/record-table/components/RecordTableStyleWrapper';
+import { HorizontalScrollBoxShadowCSS } from '@/object-record/record-table/components/HorizontalScrollBoxShadowCSS';
import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidth';
import { RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH_CLASS_NAME } from '@/object-record/record-table/constants/RecordTableColumnAddColumnButtonWidthClassName';
import { RECORD_TABLE_COLUMN_CHECKBOX_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnCheckboxWidth';
@@ -34,10 +32,9 @@ import {
type DraggableRubric,
type DraggableStateSnapshot,
} from '@hello-pangea/dnd';
-import { useContext, useMemo } from 'react';
+import { useMemo } from 'react';
import { isDefined } from 'twenty-shared/utils';
-import { ThemeContext } from 'twenty-ui/theme';
-import { MOBILE_VIEWPORT } from 'twenty-ui/theme-constants';
+import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
const MAX_COLUMNS = 100;
@@ -139,8 +136,6 @@ export const RecordTableBodyVirtualizedDraggableClone = ({
}) => {
const realIndex = rubric.source.index;
- const { theme } = useContext(ThemeContext);
-
const recordId = useAtomComponentFamilySelectorValue(
recordIdByRealIndexComponentFamilySelector,
realIndex,
@@ -178,10 +173,10 @@ export const RecordTableBodyVirtualizedDraggableClone = ({
style={{
...draggableProvided.draggableProps.style,
background: draggableSnapshot.isDragging
- ? theme.background.transparent.light
+ ? themeCssVariables.background.transparent.light
: undefined,
borderColor: draggableSnapshot.isDragging
- ? `${theme.border.color.medium}`
+ ? themeCssVariables.border.color.medium
: 'transparent',
opacity: isSecondaryDragged ? 0.3 : undefined,
}}
diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx
index de62a1a47f..e32099ac9f 100644
--- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx
+++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx
@@ -2,52 +2,10 @@ import { Table } from '@/ui/layout/table/components/Table';
import { TableBody } from '@/ui/layout/table/components/TableBody';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
-import { styled } from '@linaria/react';
-import { useContext } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { type IconComponent } from 'twenty-ui/display';
import { Card } from 'twenty-ui/layout';
-import { ThemeContext } from 'twenty-ui/theme';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
-
-const StyledCard = styled(Card)`
- background-color: ${themeCssVariables.background.secondary};
- border: 1px solid ${themeCssVariables.border.color.medium};
-`;
-
-const StyledTableRow = styled(TableRow)`
- height: ${themeCssVariables.spacing[6]};
-`;
-
-const StyledTableCellLabel = styled(TableCell)<{
- align?: 'left' | 'center' | 'right';
-}>`
- color: ${themeCssVariables.font.color.tertiary};
- height: ${themeCssVariables.spacing[6]};
- display: flex;
- gap: ${themeCssVariables.spacing[2]};
- justify-content: ${({ align }) =>
- align === 'right'
- ? 'flex-end'
- : align === 'center'
- ? 'center'
- : 'flex-start'};
-`;
-
-const StyledTableCellValue = styled(TableCell)<{
- align?: 'left' | 'center' | 'right';
- clickable?: boolean;
-}>`
- color: ${themeCssVariables.font.color.primary};
- cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')};
- height: ${themeCssVariables.spacing[6]};
- justify-content: ${({ align }) =>
- align === 'left'
- ? 'flex-start'
- : align === 'center'
- ? 'center'
- : 'flex-end'};
-`;
+import { ICON_SIZES, themeCssVariables } from 'twenty-ui/theme-constants';
type TableItem = {
Icon?: IconComponent;
@@ -73,32 +31,42 @@ export const SettingsAdminTableCard = ({
valueAlign = 'left',
className,
}: SettingsAdminTableCardProps) => {
- const { theme } = useContext(ThemeContext);
-
return (
-
+
{items.map((item, index) => (
-
-
- {item.Icon && }
+
+ {item.Icon && }
{item.label}
-
-
+
{item.value}
-
-
+
+
))}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
index ac890916e5..dec51d123e 100644
--- a/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
+++ b/packages/twenty-front/src/modules/settings/admin-panel/health-status/components/SettingsAdminQueueJobsTable.tsx
@@ -61,42 +61,10 @@ const StyledPaginationContainer = styled.div`
padding: ${themeCssVariables.spacing[2]};
`;
-const StyledTableCell = styled(TableCell)`
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-`;
-
-const StyledExpandableTableRow = styled(TableRow)<{ isExpanded: boolean }>`
- cursor: pointer;
- background-color: ${({ isExpanded }) =>
- isExpanded
- ? themeCssVariables.background.transparent.light
- : 'transparent'};
-
- &:hover {
- background-color: ${themeCssVariables.background.transparent.light};
- }
-`;
-
const StyledJobRowWrapper = styled.div`
display: contents;
`;
-const StyledCheckboxCell = styled(TableCell)`
- justify-content: center;
- padding: 0;
- padding-left: ${themeCssVariables.spacing[1]};
-`;
-
-const StyledHeaderCheckboxCell = styled(TableHeader)`
- align-items: center;
- display: flex;
- justify-content: center;
- padding-right: ${themeCssVariables.spacing[1]};
-`;
-
const StyledButtonGroup = styled.div`
display: flex;
gap: ${themeCssVariables.spacing[2]};
@@ -299,7 +267,10 @@ export const SettingsAdminQueueJobsTable = ({
<>
-
+
{jobs.length > 0 && (
)}
-
+
{t`Job Name`}
{t`State`}
{t`Timestamp`}
@@ -320,22 +291,34 @@ export const SettingsAdminQueueJobsTable = ({
return (
- handleRowClick(job.id)}
isExpanded={isExpanded}
+ cursor="pointer"
+ hoverBackgroundColor={
+ themeCssVariables.background.transparent.light
+ }
>
- {
e.stopPropagation();
handleToggleJob(e, job.id);
}}
>
-
-
+
+
{job.name}
-
+
handleDeleteOne(job.id)}
/>
-
+
{
- const { theme } = useContext(ThemeContext);
const { labelIdentifierFieldMetadataItem } =
useLabelIdentifierFieldMetadataItem({
objectNameSingular: objectNameSingular,
@@ -114,10 +115,7 @@ export const SettingsDataModelFieldPreview = ({
{!!withFieldLabel && (
-
+
{fieldMetadataItem.label}:
)}
diff --git a/packages/twenty-front/src/modules/ui/layout/table/components/TableCell.tsx b/packages/twenty-front/src/modules/ui/layout/table/components/TableCell.tsx
index 17391ce758..b48dee0bb4 100644
--- a/packages/twenty-front/src/modules/ui/layout/table/components/TableCell.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/table/components/TableCell.tsx
@@ -4,21 +4,37 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
type TableCellProps = {
align?: 'left' | 'center' | 'right';
color?: string;
+ gap?: string;
+ height?: string;
+ maxWidth?: string;
+ minWidth?: string;
+ overflow?: string;
+ padding?: string;
+ textOverflow?: string;
+ whiteSpace?: string;
+ clickable?: boolean;
};
const StyledTableCell = styled.div`
align-items: center;
color: ${({ color }) => color || themeCssVariables.font.color.secondary};
+ cursor: ${({ clickable }) => (clickable === true ? 'pointer' : 'default')};
display: flex;
- height: ${themeCssVariables.spacing[8]};
+ gap: ${({ gap }) => gap ?? 'normal'};
+ height: ${({ height }) => height ?? themeCssVariables.spacing[8]};
justify-content: ${({ align }) =>
align === 'right'
? 'flex-end'
: align === 'center'
? 'center'
: 'flex-start'};
- padding: 0 ${themeCssVariables.spacing[2]};
+ max-width: ${({ maxWidth }) => maxWidth ?? 'none'};
+ min-width: ${({ minWidth }) => minWidth ?? 'auto'};
+ overflow: ${({ overflow }) => overflow ?? 'visible'};
+ padding: ${({ padding }) => padding ?? `0 ${themeCssVariables.spacing[2]}`};
text-align: ${({ align }) => align ?? 'left'};
+ text-overflow: ${({ textOverflow }) => textOverflow ?? 'clip'};
+ white-space: ${({ whiteSpace }) => whiteSpace ?? 'normal'};
`;
export { StyledTableCell as TableCell };
diff --git a/packages/twenty-front/src/modules/ui/layout/table/components/TableHeader.tsx b/packages/twenty-front/src/modules/ui/layout/table/components/TableHeader.tsx
index 7d9f130179..bd09ba93de 100644
--- a/packages/twenty-front/src/modules/ui/layout/table/components/TableHeader.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/table/components/TableHeader.tsx
@@ -4,6 +4,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledTableHeader = styled.div<{
align?: 'left' | 'center' | 'right';
onClick?: () => void;
+ padding?: string;
}>`
gap: ${themeCssVariables.spacing[1]};
align-items: center;
@@ -18,7 +19,7 @@ const StyledTableHeader = styled.div<{
: align === 'center'
? 'center'
: 'flex-start'};
- padding: 0 ${themeCssVariables.spacing[2]};
+ padding: ${({ padding }) => padding ?? `0 ${themeCssVariables.spacing[2]}`};
text-align: ${({ align }) => align ?? 'left'};
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
`;
diff --git a/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx b/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx
index 813e7085db..6f9fa259c7 100644
--- a/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx
+++ b/packages/twenty-front/src/modules/ui/layout/table/components/TableRow.tsx
@@ -4,15 +4,24 @@ import { MOBILE_VIEWPORT, themeCssVariables } from 'twenty-ui/theme-constants';
const StyledTableRow = styled.div<{
isSelected?: boolean;
+ isExpanded?: boolean;
onClick?: () => void;
to?: string;
gridAutoColumns?: string;
gridTemplateColumns?: string;
mobileGridAutoColumns?: string;
+ height?: string;
+ cursor?: string;
+ hoverBackgroundColor?: string;
}>`
- background-color: ${({ isSelected }) =>
- isSelected ? themeCssVariables.accent.quaternary : 'transparent'};
+ background-color: ${({ isSelected, isExpanded }) =>
+ isSelected
+ ? themeCssVariables.accent.quaternary
+ : isExpanded === true
+ ? themeCssVariables.background.transparent.light
+ : 'transparent'};
border-radius: ${themeCssVariables.border.radius.sm};
+ cursor: ${({ cursor }) => cursor ?? 'default'};
display: grid;
grid-auto-columns: ${({ gridAutoColumns }) => gridAutoColumns ?? '1fr'};
grid-template-columns: ${({ gridTemplateColumns }) =>
@@ -23,6 +32,7 @@ const StyledTableRow = styled.div<{
mobileGridAutoColumns ?? gridAutoColumns ?? '1fr'};
}
+ height: ${({ height }) => height ?? 'auto'};
grid-auto-flow: column;
transition: background-color
calc(${themeCssVariables.animation.duration.normal} * 1s);
@@ -30,11 +40,13 @@ const StyledTableRow = styled.div<{
text-decoration: none;
&:hover {
- background-color: ${({ onClick, to }) =>
- onClick || to
+ background-color: ${({ onClick, to, hoverBackgroundColor }) =>
+ hoverBackgroundColor ??
+ (onClick || to
? themeCssVariables.background.transparent.light
- : 'transparent'};
- cursor: ${({ onClick, to }) => (onClick || to ? 'pointer' : 'default')};
+ : 'transparent')};
+ cursor: ${({ onClick, to, cursor }) =>
+ cursor ?? (onClick || to ? 'pointer' : 'default')};
}
&[data-clickable='true'] {
@@ -44,6 +56,7 @@ const StyledTableRow = styled.div<{
type TableRowProps = {
isSelected?: boolean;
+ isExpanded?: boolean;
isClickable?: boolean;
onClick?: () => void;
to?: string;
@@ -52,10 +65,14 @@ type TableRowProps = {
gridAutoColumns?: string;
gridTemplateColumns?: string;
mobileGridAutoColumns?: string;
+ height?: string;
+ cursor?: string;
+ hoverBackgroundColor?: string;
};
export const TableRow = ({
isSelected,
+ isExpanded,
isClickable,
onClick,
to,
@@ -65,9 +82,13 @@ export const TableRow = ({
gridAutoColumns,
gridTemplateColumns,
mobileGridAutoColumns,
+ height,
+ cursor,
+ hoverBackgroundColor,
}: React.PropsWithChildren) => (
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx
index 91069ae443..551bf916fd 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepJsonContainer.tsx
@@ -1,11 +1,18 @@
import { WorkflowStepBody } from '@/workflow/workflow-steps/components/WorkflowStepBody';
-import { styled } from '@linaria/react';
-const StyledWorkflowRunStepJsonContainer = styled(WorkflowStepBody)`
- grid-template-rows: max-content;
- gap: 0;
- display: grid;
- overflow: auto;
-`;
+const WorkflowRunStepJsonContainerInner = ({
+ children,
+}: {
+ children: React.ReactNode;
+}) => (
+
+ {children}
+
+);
-export { StyledWorkflowRunStepJsonContainer as WorkflowRunStepJsonContainer };
+export { WorkflowRunStepJsonContainerInner as WorkflowRunStepJsonContainer };
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx
index 04093415b5..77dd58f878 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowStepBody.tsx
@@ -4,27 +4,54 @@ import { type AppErrorDisplayProps } from '@/error-handler/types/AppErrorDisplay
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
-const StyledWorkflowStepBody = styled.div`
+const StyledWorkflowStepBody = styled.div<{
+ rowGap?: string;
+ display?: string;
+ overflow?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ gridTemplateRows?: string;
+}>`
background: ${themeCssVariables.background.primary};
- display: flex;
+ display: ${({ display }) => display ?? 'flex'};
flex: 1 1 auto;
flex-direction: column;
height: 100%;
- overflow-y: scroll;
- padding-block: ${themeCssVariables.spacing[4]};
- padding-inline: ${themeCssVariables.spacing[3]};
- row-gap: ${themeCssVariables.spacing[4]};
+ overflow: ${({ overflow }) => overflow ?? 'hidden scroll'};
+ padding-block: ${({ paddingBlock }) =>
+ paddingBlock ?? themeCssVariables.spacing[4]};
+ padding-inline: ${({ paddingInline }) =>
+ paddingInline ?? themeCssVariables.spacing[3]};
+ row-gap: ${({ rowGap }) => rowGap ?? themeCssVariables.spacing[4]};
+ grid-template-rows: ${({ gridTemplateRows }) => gridTemplateRows ?? 'none'};
`;
export const WorkflowStepBody = ({
children,
- className,
+ rowGap,
+ display,
+ overflow,
+ paddingBlock,
+ paddingInline,
+ gridTemplateRows,
}: {
children: React.ReactNode;
- className?: string;
+ rowGap?: string;
+ display?: string;
+ overflow?: string;
+ paddingBlock?: string;
+ paddingInline?: string;
+ gridTemplateRows?: string;
}) => {
return (
-
+
{currentTabId === WORKFLOW_AI_AGENT_TABS.PERMISSIONS ? (
-
+
-
+
) : (
-
+
{t`Conditions`}
{isDefined(rootStepFilterGroup) ? (
@@ -119,7 +115,7 @@ export const WorkflowEditActionFilterBody = ({
) : (
)}
-
+
);
};
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx
index 20be88f7d1..8645fd3eac 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/form-action/components/WorkflowEditActionFormBuilder.tsx
@@ -18,7 +18,7 @@ import { styled } from '@linaria/react';
import { type OnDragEndResponder } from '@hello-pangea/dnd';
import { useLingui } from '@lingui/react/macro';
import { isNonEmptyString } from '@sniptt/guards';
-import { useContext, useEffect, useState } from 'react';
+import { useEffect, useState } from 'react';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import {
@@ -32,8 +32,7 @@ import {
import { LightIconButton } from 'twenty-ui/input';
import { useDebouncedCallback } from 'use-debounce';
import { v4 } from 'uuid';
-import { ThemeContext } from 'twenty-ui/theme';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
+import { ICON_SIZES, themeCssVariables } from 'twenty-ui/theme-constants';
export type WorkflowEditActionFormBuilderProps = {
triggerType: WorkflowTriggerType | undefined;
@@ -50,12 +49,6 @@ export type WorkflowEditActionFormBuilderProps = {
type FormData = WorkflowFormActionField[];
-const StyledWorkflowStepBody = styled(WorkflowStepBody)`
- display: block;
- padding-left: ${themeCssVariables.spacing[2]};
- padding-right: ${themeCssVariables.spacing[2]};
-`;
-
const StyledFormFieldContainer = styled.div`
align-items: flex-end;
column-gap: ${themeCssVariables.spacing[1]};
@@ -74,17 +67,21 @@ const StyledDraggingIndicator = styled.div`
background-color: ${themeCssVariables.background.transparent.light};
`;
-const StyledLightGripIconButton = styled(LightIconButton)`
+const StyledGripButtonContainer = styled.div`
+ align-items: flex-end;
+ display: flex;
grid-area: grip;
margin-bottom: ${themeCssVariables.spacing[1]};
`;
-const StyledLightTrashIconButton = styled(LightIconButton)`
+const StyledTrashButtonContainer = styled.div`
+ align-items: flex-end;
+ display: flex;
grid-area: delete;
margin-bottom: ${themeCssVariables.spacing[1]};
`;
-const StyledFormFieldInputContainer = styled(FormFieldInputContainer)`
+const StyledFormFieldInputContainerWrapper = styled.div`
grid-area: input;
`;
@@ -115,7 +112,7 @@ const StyledFieldContainer = styled.div<{
}
`;
-const StyledPlaceholder = styled(FormFieldPlaceholder)`
+const StyledPlaceholderContainer = styled.div`
width: 100%;
`;
@@ -151,7 +148,6 @@ export const WorkflowEditActionFormBuilder = ({
action,
actionOptions,
}: WorkflowEditActionFormBuilderProps) => {
- const { theme } = useContext(ThemeContext);
const { t } = useLingui();
const [formData, setFormData] = useState(action.settings.input);
@@ -233,7 +229,10 @@ export const WorkflowEditActionFormBuilder = ({
return (
<>
-
+
{triggerType && triggerType !== 'MANUAL' && isCalloutVisible && (
}
{showButtons && (
-
+
+
+
)}
-
+
{field.label || ''}
@@ -316,44 +317,51 @@ export const WorkflowEditActionFormBuilder = ({
-
- {isDefined(field.placeholder) &&
- isNonEmptyString(field.placeholder)
- ? field.placeholder
- : getDefaultFormFieldSettings(field.type)
- .placeholder}
-
+
+
+ {isDefined(field.placeholder) &&
+ isNonEmptyString(field.placeholder)
+ ? field.placeholder
+ : getDefaultFormFieldSettings(field.type)
+ .placeholder}
+
+
{field.type === 'RECORD' && (
)}
-
+
{showButtons && (
- {
- const updatedFormData = formData.filter(
- (currentField) => currentField.id !== field.id,
- );
+
+ {
+ const updatedFormData = formData.filter(
+ (currentField) =>
+ currentField.id !== field.id,
+ );
- setFormData(updatedFormData);
+ setFormData(updatedFormData);
- actionOptions.onActionUpdate({
- ...action,
- settings: {
- ...action.settings,
- input: updatedFormData,
- },
- });
- }}
- />
+ actionOptions.onActionUpdate({
+ ...action,
+ settings: {
+ ...action.settings,
+ input: updatedFormData,
+ },
+ });
+ }}
+ />
+
)}
{isFieldSelected(field.id) && (
@@ -410,7 +418,7 @@ export const WorkflowEditActionFormBuilder = ({
>
-
+
{t`Add Field`}
@@ -419,7 +427,7 @@ export const WorkflowEditActionFormBuilder = ({
)}
-
+
{!actionOptions.readonly && }
>
);
diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx
index 5758c39faf..6402a0a825 100644
--- a/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx
+++ b/packages/twenty-front/src/modules/workflow/workflow-steps/workflow-actions/if-else-action/components/WorkflowEditActionIfElseBody.tsx
@@ -38,10 +38,6 @@ const StyledContainer = styled.div`
gap: ${themeCssVariables.spacing[4]};
`;
-const StyledBodyContainer = styled(WorkflowStepBody)`
- gap: ${themeCssVariables.spacing[2]};
-`;
-
type WorkflowEditActionIfElseBodyProps = {
action: WorkflowIfElseAction;
actionOptions:
@@ -250,7 +246,7 @@ export const WorkflowEditActionIfElseBody = ({
};
return (
-
+
{t`Conditions`}
{branches.map((branch, branchIndex) => {
@@ -303,6 +299,6 @@ export const WorkflowEditActionIfElseBody = ({
);
})}
-
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx
index d8d68593cc..cfe4a35d1e 100644
--- a/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsAIModelsTab.tsx
@@ -32,10 +32,6 @@ const StyledSearchContainer = styled.div`
padding-bottom: ${themeCssVariables.spacing[2]};
`;
-const StyledSearchInput = styled(SettingsTextInput)`
- width: 100%;
-`;
-
export const SettingsAIModelsTab = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const [currentWorkspace, setCurrentWorkspace] = useAtomState(
@@ -358,12 +354,13 @@ export const SettingsAIModelsTab = () => {
/>
-
diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx
index c4629bd908..7df14e443d 100644
--- a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillTableRow.tsx
@@ -5,7 +5,7 @@ import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useIcons, OverflowingTextWithTooltip } from 'twenty-ui/display';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
+import { ICON_SIZES, themeCssVariables } from 'twenty-ui/theme-constants';
import { type Skill } from '~/generated-metadata/graphql';
@@ -15,28 +15,12 @@ export type SettingsSkillTableRowProps = {
link?: string;
};
-export const StyledSkillTableRow = styled(TableRow)`
- grid-template-columns: 1fr 120px 36px;
-`;
-
-const StyledNameTableCell = styled(TableCell)`
- color: ${themeCssVariables.font.color.primary};
- gap: ${themeCssVariables.spacing[2]};
- min-width: 0;
- overflow: hidden;
-`;
-
const StyledIconContainer = styled.div`
align-items: center;
display: flex;
flex-shrink: 0;
`;
-const StyledActionTableCell = styled(TableCell)`
- justify-content: flex-end;
- padding-right: ${themeCssVariables.spacing[2]};
-`;
-
export const SettingsSkillTableRow = ({
skill,
action,
@@ -46,21 +30,27 @@ export const SettingsSkillTableRow = ({
const Icon = getIcon(skill.icon ?? 'IconSparkles');
return (
-
-
+
-
+
-
+
- {action}
-
+ {action}
+
);
};
diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx
index 6138864930..5cd243967a 100644
--- a/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx
+++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsSkillsTable.tsx
@@ -1,6 +1,6 @@
import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
-import { useContext, useMemo, useState } from 'react';
+import { useMemo, useState } from 'react';
import Skeleton from 'react-loading-skeleton';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
@@ -11,6 +11,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
import { SortableTableHeader } from '@/ui/layout/table/components/SortableTableHeader';
import { Table } from '@/ui/layout/table/components/Table';
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
+import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useSortedArray } from '@/ui/layout/table/hooks/useSortedArray';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
@@ -23,8 +24,11 @@ import {
} from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { MenuItemToggle, UndecoratedLink } from 'twenty-ui/navigation';
-import { ThemeContext } from 'twenty-ui/theme';
-import { themeCssVariables } from 'twenty-ui/theme-constants';
+import {
+ ICON_SIZES,
+ ICON_STROKES,
+ themeCssVariables,
+} from 'twenty-ui/theme-constants';
import {
useActivateSkillMutation,
@@ -34,10 +38,7 @@ import {
import { SettingsSkillInactiveMenuDropDown } from '~/pages/settings/ai/components/SettingsSkillInactiveMenuDropDown';
import { SETTINGS_SKILL_TABLE_METADATA } from '~/pages/settings/ai/constants/SettingsSkillTableMetadata';
import { normalizeSearchText } from '~/utils/normalizeSearchText';
-import {
- SettingsSkillTableRow,
- StyledSkillTableRow,
-} from './SettingsSkillTableRow';
+import { SettingsSkillTableRow } from './SettingsSkillTableRow';
const StyledSearchAndFilterContainer = styled.div`
display: flex;
@@ -46,12 +47,11 @@ const StyledSearchAndFilterContainer = styled.div`
padding-bottom: ${themeCssVariables.spacing[2]};
`;
-const StyledSearchInput = styled(SettingsTextInput)`
+const StyledSearchInputWrapper = styled.div`
flex: 1;
- width: 100%;
`;
-const StyledTableHeaderRow = styled(StyledSkillTableRow)`
+const StyledTableHeaderRowContainer = styled.div`
margin-bottom: ${themeCssVariables.spacing[2]};
`;
@@ -68,7 +68,6 @@ export const SettingsSkillsTable = () => {
const [deleteSkill] = useDeleteSkillMutation();
const { t } = useLingui();
- const { theme } = useContext(ThemeContext);
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const [searchTerm, setSearchTerm] = useState('');
const [showDeactivated, setShowDeactivated] = useState(true);
@@ -123,13 +122,16 @@ export const SettingsSkillsTable = () => {
return (
<>
-
+
+
+
{
-
- {SETTINGS_SKILL_TABLE_METADATA.fields.map(
- (settingsSkillTableMetadataField) => (
-
- ),
- )}
-
-
+
+
+ {SETTINGS_SKILL_TABLE_METADATA.fields.map(
+ (settingsSkillTableMetadataField) => (
+
+ ),
+ )}
+
+
+
{showSkeleton
? Array.from({ length: 3 }).map((_, index) => (
@@ -186,8 +190,8 @@ export const SettingsSkillsTable = () => {
action={
skill.isActive ? (
) : (
{
- const slowThresholdMs = options?.slowThresholdMs ?? 50;
+ const devSlowThresholdMs = options?.devSlowThresholdMs ?? 200;
const topSlowFilesCount = options?.topSlowFilesCount ?? 10;
- const progressIntervalFiles = options?.progressIntervalFiles ?? 50;
+ const warmupThresholdMs = options?.warmupThresholdMs ?? 500;
let totalMs = 0;
let fileCount = 0;
let skippedCount = 0;
- const slowFiles: { id: string; ms: number }[] = [];
+ let isDevMode = false;
+ let warmupId = `${process.cwd()}/src/__wyw_warmup__.tsx`;
+ const allTransforms: { id: string; ms: number }[] = [];
const originalTransform = wywPlugin.transform;
- console.log(
- `[linaria/wyw] CSS pre-build profiling enabled (slow threshold: ${slowThresholdMs}ms)`,
- );
-
return {
...wywPlugin,
enforce: 'pre' as const,
+ configResolved(config) {
+ isDevMode = config.command === 'serve';
+ warmupId = `${config.root}/src/__wyw_warmup__.tsx`;
+ if (typeof wywPlugin.configResolved === 'function') {
+ (wywPlugin.configResolved as Function).call(this, config);
+ }
+ },
+ async buildStart() {
+ console.log(`[linaria/wyw] Starting CSS pre-build`);
+
+ const warmupStart = performance.now();
+ try {
+ const warmupResult = (originalTransform as Function).call(
+ this,
+ WARMUP_CODE,
+ warmupId,
+ );
+ if (
+ warmupResult !== null &&
+ typeof warmupResult === 'object' &&
+ 'then' in warmupResult
+ ) {
+ await warmupResult;
+ }
+ } catch {
+ // Expected: fake file path causes module resolution errors, but
+ // Babel's JIT compilation is already triggered — that's all we need.
+ }
+
+ const warmupMs = performance.now() - warmupStart;
+ const warmupWarning = warmupMs > warmupThresholdMs ? ' ⚠️ slow' : '';
+ console.log(
+ `[linaria/wyw] Pre-warm: ${warmupMs.toFixed(0)}ms${warmupWarning}`,
+ );
+ },
transform(code: string, id: string, ...rest: unknown[]) {
if (!LINARIA_IMPORT_RE.test(code)) {
skippedCount++;
@@ -47,14 +89,11 @@ export const createWywProfilingPlugin = (
const handleTiming = (elapsed: number) => {
totalMs += elapsed;
fileCount++;
+ allTransforms.push({ id, ms: elapsed });
- if (elapsed > slowThresholdMs) {
- slowFiles.push({ id, ms: elapsed });
- }
-
- if (fileCount % progressIntervalFiles === 0) {
+ if (isDevMode && elapsed > devSlowThresholdMs) {
console.log(
- `[linaria/wyw] CSS pre-build progress: ${fileCount} transformed, ${skippedCount} skipped, ${totalMs.toFixed(0)}ms total`,
+ `[linaria/wyw] slow: ${id.replace(process.cwd(), '')} ${elapsed.toFixed(0)}ms`,
);
}
};
@@ -69,18 +108,21 @@ export const createWywProfilingPlugin = (
handleTiming(performance.now() - start);
return result;
},
- buildEnd() {
- console.log('\n[linaria/wyw] ===== CSS PRE-BUILD TIMING SUMMARY =====');
+ closeBundle: () => {
+ const avg = fileCount > 0 ? totalMs / fileCount : 0;
+ const dynamicThreshold = Math.round(10 * avg);
+ const slowFiles = allTransforms.filter((f) => f.ms > dynamicThreshold);
+
+ console.log('\n[linaria/wyw] ===== CSS PRE-BUILD SUMMARY =====');
console.log(`[linaria/wyw] Files transformed: ${fileCount}`);
console.log(`[linaria/wyw] Files skipped (no @linaria): ${skippedCount}`);
console.log(`[linaria/wyw] Transform time: ${totalMs.toFixed(0)}ms`);
console.log(
- `[linaria/wyw] Avg per transformed file: ${fileCount > 0 ? (totalMs / fileCount).toFixed(1) : 0}ms`,
+ `[linaria/wyw] Avg per transformed file: ${avg.toFixed(1)}ms`,
);
-
if (slowFiles.length > 0) {
console.log(
- `[linaria/wyw] Slow CSS pre-build files (>${slowThresholdMs}ms):`,
+ `[linaria/wyw] Slow files (>10x avg = ${dynamicThreshold}ms):`,
);
slowFiles
.sort((a, b) => b.ms - a.ms)
@@ -91,7 +133,6 @@ export const createWywProfilingPlugin = (
),
);
}
-
console.log('[linaria/wyw] ==========================================\n');
},
};
diff --git a/packages/twenty-ui/scripts/generateThemeConstants.ts b/packages/twenty-ui/scripts/generateThemeConstants.ts
index 3e34080d45..fce2256e3b 100644
--- a/packages/twenty-ui/scripts/generateThemeConstants.ts
+++ b/packages/twenty-ui/scripts/generateThemeConstants.ts
@@ -20,6 +20,7 @@ const {
MOBILE_VIEWPORT,
THEME_LIGHT,
THEME_DARK,
+ ICON,
prepareThemeForRootCssVariableInjection,
} = require('../dist/theme.cjs');
@@ -106,6 +107,11 @@ writeFileSync(
// must be a static number rather than a var(--...) reference.
export const MOBILE_VIEWPORT = ${MOBILE_VIEWPORT};
+// Numeric icon size/stroke constants for components that require pixel values
+// (e.g. icon size props) rather than CSS variable strings.
+export const ICON_SIZES = ${serializeObject(ICON.size)} as const;
+export const ICON_STROKES = ${serializeObject(ICON.stroke)} as const;
+
export const THEME_LIGHT_CSS_VARIABLE_ENTRIES: [string, string][] = ${serializeTupleArray(lightEntries)};
`,
'utf-8',
diff --git a/packages/twenty-ui/src/accessibility/components/VisibilityHidden.tsx b/packages/twenty-ui/src/accessibility/components/VisibilityHidden.tsx
index 0aae6f4a3f..50b576f86e 100644
--- a/packages/twenty-ui/src/accessibility/components/VisibilityHidden.tsx
+++ b/packages/twenty-ui/src/accessibility/components/VisibilityHidden.tsx
@@ -1,8 +1,15 @@
import { styled } from '@linaria/react';
-import { VISIBILITY_HIDDEN } from '@ui/accessibility/utils/visibility-hidden';
const StyledSpan = styled.span`
- ${VISIBILITY_HIDDEN}
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0;
`;
export const VisibilityHidden = ({
diff --git a/packages/twenty-ui/src/components/chip/LinkChip.tsx b/packages/twenty-ui/src/components/chip/LinkChip.tsx
index e39b344619..3b9b232388 100644
--- a/packages/twenty-ui/src/components/chip/LinkChip.tsx
+++ b/packages/twenty-ui/src/components/chip/LinkChip.tsx
@@ -22,11 +22,14 @@ export type LinkChipProps = Omit<
target?: '_blank' | '_self';
};
-const StyledLink = styled(Link)`
+const StyledLinkContainer = styled.span`
display: inline-flex;
- text-decoration: none;
min-width: 0;
vertical-align: middle;
+
+ & > a {
+ text-decoration: none;
+ }
`;
export const LinkChip = ({
@@ -55,32 +58,34 @@ export const LinkChip = ({
});
return (
- {
- event.stopPropagation();
- onClickHandler(event);
- }}
- onMouseDown={onMouseDownHandler}
- data-click-outside-id={LINK_CHIP_CLICK_OUTSIDE_ID}
- target={target}
- rel={target === '_blank' ? 'noopener noreferrer' : undefined}
- >
-
-
+
+ {
+ event.stopPropagation();
+ onClickHandler(event);
+ }}
+ onMouseDown={onMouseDownHandler}
+ data-click-outside-id={LINK_CHIP_CLICK_OUTSIDE_ID}
+ target={target}
+ rel={target === '_blank' ? 'noopener noreferrer' : undefined}
+ >
+
+
+
);
};
diff --git a/packages/twenty-ui/src/display/info/components/Info.tsx b/packages/twenty-ui/src/display/info/components/Info.tsx
index 60a7e43c61..f2a28215ea 100644
--- a/packages/twenty-ui/src/display/info/components/Info.tsx
+++ b/packages/twenty-ui/src/display/info/components/Info.tsx
@@ -1,10 +1,9 @@
import { styled } from '@linaria/react';
import { IconInfoCircle } from '@ui/display/icon/components/TablerIcons';
-import { ThemeContext } from '@ui/theme';
-import { themeCssVariables } from '@ui/theme-constants';
+import { ICON_SIZES, themeCssVariables } from '@ui/theme-constants';
import { Button } from '@ui/input/button/components/Button/Button';
-import React, { useContext } from 'react';
+import React from 'react';
import { Link } from 'react-router-dom';
export type InfoAccent = 'blue' | 'danger';
@@ -20,10 +19,10 @@ const StyledTextContainer = styled.div`
align-items: center;
display: flex;
gap: ${themeCssVariables.spacing[2]};
-`;
-const StyledIconInfoCircle = styled(IconInfoCircle)`
- flex-shrink: 0;
+ & > svg {
+ flex-shrink: 0;
+ }
`;
const StyledInfo = styled.div>`
@@ -57,8 +56,10 @@ const StyledInfo = styled.div>`
}};
`;
-const StyledLink = styled(Link)`
- text-decoration: none;
+const StyledLinkContainer = styled.span`
+ & > a {
+ text-decoration: none;
+ }
`;
export const Info = ({
@@ -68,22 +69,23 @@ export const Info = ({
onClick,
to,
}: InfoProps) => {
- const { theme } = useContext(ThemeContext);
return (
-
+
{text}
{buttonTitle && to && (
-
-
-
+
+
+
+
+
)}
{buttonTitle && onClick && !to && (