diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts index 570335e1e..bce83e45a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts @@ -3,8 +3,8 @@ import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryP import { UseFindManyRecordsParams } from '@/object-record/hooks/useFetchMoreRecordsWithPagination'; import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; import { useCallback, useState } from 'react'; -import { sleep } from '~/utils/sleep'; import { isDefined } from 'twenty-shared/utils'; +import { sleep } from '~/utils/sleep'; type UseLazyFetchAllRecordIdsParams = Omit< UseFindManyRecordsParams, diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldContextProvider.tsx index f9037f09f..37971e161 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldContextProvider.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldContextProvider.tsx @@ -14,7 +14,6 @@ export const FieldContextProvider = ({ fieldMetadataName, fieldPosition, isLabelIdentifier = false, - isLabelHidden, objectNameSingular, objectRecordId, customUseUpdateOneObjectHook, @@ -25,7 +24,6 @@ export const FieldContextProvider = ({ fieldMetadataName: string; fieldPosition: number; isLabelIdentifier?: boolean; - isLabelHidden?: boolean; objectNameSingular: string; objectRecordId: string; customUseUpdateOneObjectHook?: RecordUpdateHook; @@ -65,7 +63,6 @@ export const FieldContextProvider = ({ value={{ recordId: objectRecordId, isLabelIdentifier, - isLabelHidden, fieldDefinition: formatFieldMetadataItemAsColumnDefinition({ field: fieldMetadataItem, showLabel: true, diff --git a/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts b/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts index cb62086c1..61bfb1cc9 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/contexts/FieldContext.ts @@ -35,7 +35,6 @@ export type GenericFieldContextType = { isReadOnly: boolean; onOpenEditMode?: () => void; onCloseEditMode?: () => void; - isLabelHidden?: boolean; }; export const FieldContext = createContext( diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx index 984568f91..9f555d88c 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/ChipFieldDisplay.perf.stories.tsx @@ -4,12 +4,13 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ChipFieldDisplay } from '@/object-record/record-field/meta-types/display/components/ChipFieldDisplay'; import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; +import { ComponentDecorator } from 'twenty-ui/testing'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; -import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; +import { getFieldDecorator } from '~/testing/decorators/getFieldDecorator'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; -import { ComponentDecorator } from 'twenty-ui/testing'; const meta: Meta = { title: 'UI/Data/Field/Display/ChipFieldDisplay', @@ -22,18 +23,25 @@ const meta: Meta = { )!; return ( - '', - onIndexRecordsLoaded: () => {}, - objectNamePlural: CoreObjectNamePlural.Company, - objectNameSingular: CoreObjectNameSingular.Company, - objectMetadataItem: companyObjectMetadataItem, - recordIndexId: instanceId, + instanceId, + onColumnsChange: () => {}, }} > - - + '', + onIndexRecordsLoaded: () => {}, + objectNamePlural: CoreObjectNamePlural.Company, + objectNameSingular: CoreObjectNameSingular.Company, + objectMetadataItem: companyObjectMetadataItem, + recordIndexId: instanceId, + }} + > + + + ); }, MemoryRouterDecorator, diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts index 0d4ce17ba..fc6eede7b 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useChipFieldDisplay.ts @@ -8,17 +8,23 @@ import { isFieldText } from '@/object-record/record-field/types/guards/isFieldTe import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { isFieldActor } from '@/object-record/record-field/types/guards/isFieldActor'; -import { FieldContext } from '../../contexts/FieldContext'; +import { isRecordTableScrolledLeftComponentState } from '@/object-record/record-table/states/isRecordTableScrolledLeftComponentState'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; +import { useIsMobile } from 'twenty-ui/utilities'; +import { FieldContext } from '../../contexts/FieldContext'; export const useChipFieldDisplay = () => { - const { - recordId, - fieldDefinition, - isLabelIdentifier, - labelIdentifierLink, - isLabelHidden, - } = useContext(FieldContext); + const { recordId, fieldDefinition, isLabelIdentifier, labelIdentifierLink } = + useContext(FieldContext); + + const isMobile = useIsMobile(); + const isRecordTableScrolledLeftComponent = useRecoilComponentValueV2( + isRecordTableScrolledLeftComponentState, + ); + + const isLabelHidden = + isMobile && isLabelIdentifier && !isRecordTableScrolledLeftComponent; const { chipGeneratorPerObjectPerField } = useContext( PreComputedChipGeneratorsContext, diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx index 744846f51..55efaec68 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRecordGroupRows.tsx @@ -52,7 +52,6 @@ export const RecordTableRecordGroupRows = () => { recordId={recordId} rowIndexForFocus={rowIndex} rowIndexForDrag={rowIndexInGroup} - isPendingRow={!isRecordGroupTableSectionToggled} /> ); })} diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx index ff83c6a21..0facf47b9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableWithWrappers.tsx @@ -24,6 +24,7 @@ const StyledTableContainer = styled.div` display: flex; flex-direction: column; position: relative; + width: 100%; `; type RecordTableWithWrappersProps = { diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx index 0ad261a81..eebeabe3d 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/__stories__/perf/RecordTableCell.perf.stories.tsx @@ -23,9 +23,9 @@ import { RecordTableContextProvider } from '@/object-record/record-table/context import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper'; +import { ComponentDecorator } from 'twenty-ui/testing'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { mockPerformance } from './mock'; -import { ComponentDecorator } from 'twenty-ui/testing'; const RelationFieldValueSetterEffect = () => { const setEntity = useSetRecoilState( @@ -110,7 +110,6 @@ const meta: Meta = { mockPerformance.entityValue.__typename.toLocaleLowerCase(), }) + mockPerformance.recordId, isSelected: false, - isPendingRow: false, inView: true, }} > diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts index ee9706133..7eca8385e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts @@ -7,7 +7,6 @@ export type RecordTableRowContextValue = { rowIndex: number; isSelected: boolean; inView: boolean; - isPendingRow?: boolean; isReadOnly?: boolean; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx index 6f4ca947d..bb684e88f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyLoading.tsx @@ -33,6 +33,8 @@ export const RecordTableBodyLoading = () => { }} > { const { hasSoftFocus, isInEditMode } = useContext(RecordTableCellContext); - const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState); - return ( {isInEditMode ? ( {editModeContent} ) : hasSoftFocus ? ( <> - {currentHotkeyScope.scope === TableHotkeyScope.TableSoftFocus && ( - - )} + , @@ -93,7 +80,6 @@ export const RecordTableCellFieldContext = ({ objectMetadataItem, }), displayedMaxRows: 1, - isLabelHidden, isReadOnly: isFieldReadOnly, }} > diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx index 198e581fb..8578c7407 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellGrip.tsx @@ -1,27 +1,21 @@ import styled from '@emotion/styled'; -import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; -import { css } from '@emotion/react'; import { IconListViewGrip } from 'twenty-ui/input'; export const TABLE_CELL_GRIP_WIDTH = '16px'; -const StyledContainer = styled.div<{ isPendingRow?: boolean }>` +const StyledContainer = styled.div` height: 32px; width: ${TABLE_CELL_GRIP_WIDTH}; border-color: transparent; cursor: grab; display: flex; - ${({ isPendingRow }) => - !isPendingRow - ? css` - &:hover .icon { - opacity: 1; - } - ` - : ''}; + + &:hover .icon { + opacity: 1; + } z-index: 200; `; @@ -32,8 +26,6 @@ const StyledIconWrapper = styled.div<{ isDragging: boolean }>` `; export const RecordTableCellGrip = () => { - const { isPendingRow } = useRecordTableRowContextOrThrow(); - const { dragHandleProps, isDragging } = useRecordTableRowDraggableContextOrThrow(); @@ -45,7 +37,7 @@ export const RecordTableCellGrip = () => { hasRightBorder={false} hasBottomBorder={false} > - + diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect.tsx index 323521a8d..7503a8e1c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellSoftFocusModeHotkeysSetterEffect.tsx @@ -12,9 +12,12 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; +import { currentHotkeyScopeState } from '@/ui/utilities/hotkey/states/internal/currentHotkeyScopeState'; import { TableHotkeyScope } from '../../types/TableHotkeyScope'; export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => { + const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState); + const { openTableCell } = useOpenRecordTableCellFromCell(); const { isReadOnly } = useContext(FieldContext); @@ -29,10 +32,14 @@ export const RecordTableCellSoftFocusModeHotkeysSetterEffect = () => { const clearField = useClearField(); useEffect(() => { + if (currentHotkeyScope.scope !== TableHotkeyScope.TableSoftFocus) { + return; + } + if (!isSoftFocusUsingMouse) { scrollRef.current?.scrollIntoView({ block: 'nearest' }); } - }, [isSoftFocusUsingMouse]); + }, [currentHotkeyScope.scope, isSoftFocusUsingMouse]); useScopedHotkeys( [Key.Backspace, Key.Delete], diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts index 408c40ca7..5c2da2040 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__mocks__/cell.ts @@ -9,7 +9,6 @@ export const recordTableRowContextValue: RecordTableRowContextValue = { recordId: 'recordId', pathToShowPage: '/', objectNameSingular: 'objectNameSingular', - isPendingRow: false, inView: true, }; 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 34827de05..d5bafb2a3 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 @@ -65,8 +65,9 @@ export const RecordTableActionRow = ({ return ( diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTr.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTr.tsx index e46e57d8c..a128ecf55 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTr.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTr.tsx @@ -1,55 +1,44 @@ import { useTheme } from '@emotion/react'; -import { Draggable, DraggableId } from '@hello-pangea/dnd'; -import { ReactNode, forwardRef } from 'react'; +import { Draggable } from '@hello-pangea/dnd'; +import { ReactNode } from 'react'; import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr'; -import styled from '@emotion/styled'; +import { RecordTableTrEffect } from '@/object-record/record-table/record-table-row/components/RecordTableTrEffect'; type RecordTableDraggableTrProps = { className?: string; - draggableId: DraggableId; + recordId: string; draggableIndex: number; + focusIndex: number; isDragDisabled?: boolean; onClick?: (event: React.MouseEvent) => void; children: ReactNode; }; -const StyledAbsoluteInViewContainer = styled.td` - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - pointer-events: none; - z-index: -1; -`; +export const RecordTableDraggableTr = ({ + className, + recordId, + draggableIndex, + focusIndex, + isDragDisabled, + onClick, + children, +}: RecordTableDraggableTrProps) => { + const theme = useTheme(); -export const RecordTableDraggableTr = forwardRef< - HTMLTableCellElement, - RecordTableDraggableTrProps ->( - ( - { - className, - draggableId, - draggableIndex, - isDragDisabled, - onClick, - children, - }, - ref, - ) => { - const theme = useTheme(); - - return ( - - {(draggableProvided, draggableSnapshot) => ( + return ( + + {(draggableProvided, draggableSnapshot) => ( + <> + {children} - - )} - - ); - }, -); + + )} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx index 2b3699c89..849d4af58 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRow.tsx @@ -3,33 +3,30 @@ import { RecordTableCellCheckbox } from '@/object-record/record-table/record-tab import { RecordTableCellGrip } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip'; import { RecordTableLastEmptyCell } from '@/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell'; import { RecordTableCells } from '@/object-record/record-table/record-table-row/components/RecordTableCells'; -import { RecordTableRowWrapper } from '@/object-record/record-table/record-table-row/components/RecordTableRowWrapper'; +import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr'; type RecordTableRowProps = { recordId: string; rowIndexForFocus: number; rowIndexForDrag: number; - isPendingRow?: boolean; }; export const RecordTableRow = ({ recordId, rowIndexForFocus, rowIndexForDrag, - isPendingRow, }: RecordTableRowProps) => { return ( - - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx deleted file mode 100644 index 76e79a40d..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableRowWrapper.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { ReactNode, useEffect } from 'react'; - -import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; -import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; -import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr'; -import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; -import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; -import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; -import { useInView } from 'react-intersection-observer'; - -type RecordTableRowWrapperProps = { - recordId: string; - rowIndexForFocus: number; - rowIndexForDrag: number; - isPendingRow?: boolean; - children: ReactNode; -}; - -export const RecordTableRowWrapper = ({ - recordId, - rowIndexForFocus, - rowIndexForDrag, - isPendingRow, - children, -}: RecordTableRowWrapperProps) => { - const { objectMetadataItem } = useRecordTableContextOrThrow(); - - const currentRowSelected = useRecoilComponentFamilyValueV2( - isRowSelectedComponentFamilyState, - recordId, - ); - - const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow(); - - const { scrollWrapperHTMLElement } = useScrollWrapperElement(); - - const { ref: elementRef, inView } = useInView({ - root: scrollWrapperHTMLElement, - rootMargin: '1000px', - }); - - // TODO: find a better way to emit this event - useEffect(() => { - if (inView) { - onIndexRecordsLoaded?.(); - } - }, [inView, onIndexRecordsLoaded]); - - return ( - - - {children} - - - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx index 3c155883b..a7aa53d9b 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTr.tsx @@ -1,4 +1,11 @@ +import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; +import { isRowVisibleComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState'; +import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; import styled from '@emotion/styled'; +import { ReactNode, forwardRef } from 'react'; const StyledTr = styled.tr<{ isDragging: boolean }>` position: relative; @@ -9,4 +16,51 @@ const StyledTr = styled.tr<{ isDragging: boolean }>` transition: border-left-color 0.2s ease-in-out; `; -export const RecordTableTr = StyledTr; +type RecordTableTrProps = { + children: ReactNode; + recordId: string; + focusIndex: number; + isDragging?: boolean; +} & React.ComponentProps; + +export const RecordTableTr = forwardRef< + HTMLTableRowElement, + RecordTableTrProps +>(({ children, recordId, focusIndex, isDragging = false, ...props }, ref) => { + const { objectMetadataItem } = useRecordTableContextOrThrow(); + const currentRowSelected = useRecoilComponentFamilyValueV2( + isRowSelectedComponentFamilyState, + recordId, + ); + + const isRowVisible = useRecoilComponentFamilyValueV2( + isRowVisibleComponentFamilyState, + recordId, + ); + + return ( + + + {children} + + + ); +}); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx new file mode 100644 index 000000000..3fbe22e7b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableTrEffect.tsx @@ -0,0 +1,61 @@ +import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { isRowVisibleComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState'; +import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; +import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; +import { useEffect } from 'react'; + +type RecordTableTrEffectProps = { + recordId: string; +}; + +export const RecordTableTrEffect = ({ recordId }: RecordTableTrEffectProps) => { + const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow(); + const { scrollWrapperHTMLElement } = useScrollWrapperElement(); + + const setIsRowVisible = useSetRecoilComponentFamilyStateV2( + isRowVisibleComponentFamilyState, + recordId, + ); + + useEffect(() => { + const options = { + root: scrollWrapperHTMLElement, + rootMargin: '1000px', + threshold: 0.1, + }; + + const callback = (entries: IntersectionObserverEntry[]) => { + entries.forEach((entry) => { + const isIntersecting = entry.isIntersecting; + + if (isIntersecting) { + onIndexRecordsLoaded?.(); + setIsRowVisible(true); + } + + if (!isIntersecting) { + setIsRowVisible(false); + } + }); + }; + + const observer = new IntersectionObserver(callback, options); + + observer.observe( + document.querySelector( + `[data-virtualized-id="${recordId}"]`, + ) as HTMLElement, + ); + + return () => { + observer.disconnect(); + }; + }, [ + onIndexRecordsLoaded, + recordId, + scrollWrapperHTMLElement, + setIsRowVisible, + ]); + + return <>; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState.ts new file mode 100644 index 000000000..ff0e80074 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/states/isRowVisibleComponentFamilyState.ts @@ -0,0 +1,11 @@ +import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; +import { createComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentFamilyStateV2'; + +export const isRowVisibleComponentFamilyState = createComponentFamilyStateV2< + boolean, + string +>({ + key: 'isRowVisibleComponentFamilyState', + defaultValue: true, + componentInstanceContext: RecordTableComponentInstanceContext, +}); diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx index a7a4bf7f0..4b838c8f7 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/Dropdown.tsx @@ -20,7 +20,6 @@ import { flushSync } from 'react-dom'; import { Keys } from 'react-hotkeys-hook'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; -import { sleep } from '~/utils/sleep'; import { useDropdown } from '../hooks/useDropdown'; const StyledDropdownFallbackAnchor = styled.div` @@ -115,8 +114,6 @@ export const Dropdown = ({ dropdownHotkeyScope, ); - await sleep(100); - toggleDropdown(); onClickOutside?.(); }, diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx index eb45d905e..dde93fe79 100644 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/components/ScrollWrapper.tsx @@ -14,6 +14,8 @@ const StyledScrollWrapper = styled.div` &.scroll-wrapper-y-enabled { overflow-y: scroll; } + overflow-x: hidden; + overflow-y: hidden; display: flex; width: 100%; height: 100%;