From d6e4bcb53373df8884dcd3099e49a09da9971db4 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Mon, 22 Sep 2025 10:18:12 +0200 Subject: [PATCH] Fix table column width on mobile (#14623) This PR fixes some minor issues to have all width computation working properly and table displaying nicely on mobile. --- .../components/RecordTableEmpty.tsx | 18 ++++++----- .../useRecordTableLastColumnWidthToFill.ts | 4 +++ .../components/RecordTableActionRow.tsx | 18 ++++++++--- .../RecordTableRecordGroupSection.tsx | 22 ++++++++----- .../computeLastRecordTableColumnWidth.ts | 11 +++++-- .../computeVisibleRecordFieldsWidthOnTable.ts | 31 +++++++++++++++++++ 6 files changed, 82 insertions(+), 22 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx index 70d9742051..16261df65b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableEmpty.tsx @@ -13,9 +13,11 @@ import { RecordTableHeader } from '@/object-record/record-table/record-table-hea import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { resizedFieldMetadataIdComponentState } from '@/object-record/record-table/states/resizedFieldMetadataIdComponentState'; import { resizeFieldOffsetComponentState } from '@/object-record/record-table/states/resizeFieldOffsetComponentState'; +import { computeVisibleRecordFieldsWidthOnTable } from '@/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import styled from '@emotion/styled'; -import { isDefined, sumByProperty } from 'twenty-shared/utils'; +import { isDefined } from 'twenty-shared/utils'; +import { useIsMobile } from 'twenty-ui/utilities'; const StyledEmptyStateContainer = styled.div<{ width: number }>` height: 100%; @@ -44,23 +46,25 @@ export const RecordTableEmpty = ({ tableBodyRef }: RecordTableEmptyProps) => { const isResizing = isDefined(resizedFieldMetadataId); + const isMobile = useIsMobile(); + const resizeOffsetToAddOnlyIfItMakesTableContainerGrow = isResizing ? resizeFieldOffset > 0 ? resizeFieldOffset : 0 : 0; - const totalWidthOfRecordFieldColumns = visibleRecordFields.reduce( - sumByProperty('size'), - 0, - ); - const totalColumnsBorderWidth = visibleRecordFields.length; + const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable({ + isMobile, + visibleRecordFields, + }); + const { lastColumnWidth } = useRecordTableLastColumnWidthToFill(); const emptyTableContainerComputedWidth = - totalWidthOfRecordFieldColumns + + visibleRecordFieldsWidth + RECORD_TABLE_COLUMN_CHECKBOX_WIDTH + RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH + RECORD_TABLE_COLUMN_ADD_COLUMN_BUTTON_WIDTH + diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts index 11cb40912f..40262ef2dc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableLastColumnWidthToFill.ts @@ -2,6 +2,7 @@ import { useRecordTableContextOrThrow } from '@/object-record/record-table/conte import { recordTableWidthComponentState } from '@/object-record/record-table/states/recordTableWidthComponentState'; import { computeLastRecordTableColumnWidth } from '@/object-record/record-table/utils/computeLastRecordTableColumnWidth'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; +import { useIsMobile } from 'twenty-ui/utilities'; export const useRecordTableLastColumnWidthToFill = () => { const { visibleRecordFields } = useRecordTableContextOrThrow(); @@ -10,9 +11,12 @@ export const useRecordTableLastColumnWidthToFill = () => { recordTableWidthComponentState, ); + const isMobile = useIsMobile(); + const { lastColumnWidth } = computeLastRecordTableColumnWidth({ recordFields: visibleRecordFields, tableWidth: recordTableWidth, + isMobile, }); return { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableActionRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableActionRow.tsx index d59eacb2e5..5855f53edc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableActionRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableActionRow.tsx @@ -3,6 +3,8 @@ import styled from '@emotion/styled'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { RECORD_TABLE_COLUMN_CHECKBOX_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnCheckboxWidth'; import { RECORD_TABLE_COLUMN_DRAG_AND_DROP_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnDragAndDropWidth'; +import { RECORD_TABLE_COLUMN_MIN_WIDTH } from '@/object-record/record-table/constants/RecordTableColumnMinWidth'; +import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-record/record-table/constants/RecordTableLabelIdentifierColumnWidthOnMobile'; import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableDragAndDropPlaceholderCell } from '@/object-record/record-table/record-table-cell/components/RecordTableDragAndDropPlaceholderCell'; @@ -15,6 +17,7 @@ import { sumByProperty, } from 'twenty-shared/utils'; import { type IconComponent } from 'twenty-ui/display'; +import { useIsMobile } from 'twenty-ui/utilities'; const StyledDragDropPlaceholderCell = styled( RecordTableDragAndDropPlaceholderCell, @@ -85,8 +88,11 @@ const StyledText = styled.span` color: ${({ theme }) => theme.font.color.tertiary}; margin-left: ${({ theme }) => theme.spacing(2)}; font-size: ${({ theme }) => theme.font.size.md}; - text-align: center; + text-align: left; vertical-align: middle; + + position: absolute; + width: 100px; `; type RecordTableActionRowProps = { @@ -112,10 +118,16 @@ export const RecordTableActionRow = ({ ), ); + const isMobile = useIsMobile(); + const labelIdentifierRecordField = visibleRecordFields.find( findByProperty('fieldMetadataItemId', labelIdentifierFieldMetadataItem?.id), ); + const firstColumnWidth = isMobile + ? RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE + : (labelIdentifierRecordField?.size ?? RECORD_TABLE_COLUMN_MIN_WIDTH); + const sumOfWidthOfVisibleRecordFieldsAfterLabelIdentifierField = visibleRecordFieldsWithoutLabelIdentifier.reduce(sumByProperty('size'), 0); @@ -132,9 +144,7 @@ export const RecordTableActionRow = ({ color={theme.font.color.tertiary} /> - + {text} ` cursor: pointer; @@ -135,13 +138,16 @@ export const RecordTableRecordGroupSection = () => { visibleRecordFieldsComponentSelector, ); - const widthOfLabelIdentifierRecordField = - visibleRecordFields.find( - findByProperty( - 'fieldMetadataItemId', - labelIdentifierFieldMetadataItem?.id ?? '', - ), - )?.size ?? null; + const isMobile = useIsMobile(); + + const widthOfLabelIdentifierRecordField = isMobile + ? RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE + : (visibleRecordFields.find( + findByProperty( + 'fieldMetadataItemId', + labelIdentifierFieldMetadataItem?.id ?? '', + ), + )?.size ?? RECORD_TABLE_COLUMN_MIN_WIDTH); const [ isRecordGroupTableSectionToggled, @@ -226,7 +232,7 @@ export const RecordTableRecordGroupSection = () => { []; tableWidth: number; + isMobile: boolean; }) => { - const totalColumnsWidth = recordFields.reduce(sumByProperty('size'), 0); + const { visibleRecordFieldsWidth } = computeVisibleRecordFieldsWidthOnTable({ + isMobile, + visibleRecordFields: recordFields, + }); const widthOfBorders = recordFields.length; @@ -23,7 +28,7 @@ export const computeLastRecordTableColumnWidth = ({ const remainingWidthToFill = Math.max( 0, - tableWidth - fixedColumnsWidth - totalColumnsWidth, + tableWidth - fixedColumnsWidth - visibleRecordFieldsWidth, ); const lastColumnWidth = remainingWidthToFill; diff --git a/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts b/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts new file mode 100644 index 0000000000..935917bb76 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/utils/computeVisibleRecordFieldsWidthOnTable.ts @@ -0,0 +1,31 @@ +import { type RecordField } from '@/object-record/record-field/types/RecordField'; +import { RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE } from '@/object-record/record-table/constants/RecordTableLabelIdentifierColumnWidthOnMobile'; +import { sumByProperty } from 'twenty-shared/utils'; + +export const computeVisibleRecordFieldsWidthOnTable = ({ + isMobile, + visibleRecordFields, +}: { + isMobile: boolean; + visibleRecordFields: Pick[]; +}) => { + const visibleRecordFieldsWithoutFirst = visibleRecordFields.slice(1); + + const sumWithoutFirstField = visibleRecordFieldsWithoutFirst.reduce( + sumByProperty('size'), + 0, + ); + + const sumWithAllFields = visibleRecordFields.reduce(sumByProperty('size'), 0); + + const sumForMobile = + RECORD_TABLE_LABEL_IDENTIFIER_COLUMN_WIDTH_ON_MOBILE + sumWithoutFirstField; + + const sumForNonMobile = sumWithAllFields; + + const visibleRecordFieldsWidth = isMobile ? sumForMobile : sumForNonMobile; + + return { + visibleRecordFieldsWidth, + }; +};