diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/contexts/FieldFocusContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-field/ui/contexts/FieldFocusContextProvider.tsx
index 6b0a8a6fd0..1c61a5665c 100644
--- a/packages/twenty-front/src/modules/object-record/record-field/ui/contexts/FieldFocusContextProvider.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-field/ui/contexts/FieldFocusContextProvider.tsx
@@ -2,6 +2,16 @@ import { useState } from 'react';
import { FieldFocusContext } from '@/object-record/record-field/ui/contexts/FieldFocusContext';
+const STATIC_UNFOCUSED_VALUE = {
+ isFocused: false,
+ setIsFocused: () => {},
+};
+
+const STATIC_FOCUSED_VALUE = {
+ isFocused: true,
+ setIsFocused: () => {},
+};
+
export const FieldFocusContextProvider = ({ children }: any) => {
const [isFocused, setIsFocused] = useState(false);
@@ -16,3 +26,23 @@ export const FieldFocusContextProvider = ({ children }: any) => {
);
};
+
+export const FieldFocusStaticUnfocusedProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+}) => (
+
+ {children}
+
+);
+
+export const FieldFocusStaticFocusedProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+}) => (
+
+ {children}
+
+);
diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx
index cd41665547..b31a4b78fe 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContent.tsx
@@ -12,9 +12,9 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t
import { isSomeCellInEditModeComponentSelector } from '@/object-record/record-table/states/selectors/isSomeCellInEditModeComponentSelector';
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
import { RECORD_INDEX_DRAG_SELECT_BOUNDARY_CLASS } from '@/ui/utilities/drag-select/constants/RecordIndecDragSelectBoundaryClass';
+import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
import { useAtomComponentSelectorCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentSelectorCallbackState';
import { useAtomComponentFamilyStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateCallbackState';
-import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
import styled from '@emotion/styled';
import { useCallback, useRef, useState } from 'react';
import { useStore } from 'jotai';
@@ -73,10 +73,11 @@ export const RecordTableContent = ({
const { visibleRecordFields } = useRecordTableContextOrThrow();
- const setRecordTableHoverPosition = useSetAtomComponentState(
- recordTableHoverPositionComponentState,
- recordTableId,
- );
+ const recordTableHoverPositionCallbackState =
+ useAtomComponentStateCallbackState(
+ recordTableHoverPositionComponentState,
+ recordTableId,
+ );
const isSomeCellInEditMode = useAtomComponentSelectorCallbackState(
isSomeCellInEditModeComponentSelector,
@@ -87,9 +88,42 @@ export const RecordTableContent = ({
const cellInEditMode = store.get(isSomeCellInEditMode);
if (!cellInEditMode) {
- setRecordTableHoverPosition(null);
+ store.set(recordTableHoverPositionCallbackState, null);
}
- }, [store, isSomeCellInEditMode, setRecordTableHoverPosition]);
+ }, [store, isSomeCellInEditMode, recordTableHoverPositionCallbackState]);
+
+ const handleDelegatedMouseMove = useCallback(
+ (event: React.MouseEvent) => {
+ if (store.get(isSomeCellInEditMode)) {
+ return;
+ }
+
+ const target = event.target as HTMLElement;
+ const cellElement = target.closest(
+ '[data-record-table-col]',
+ );
+
+ if (!cellElement) {
+ return;
+ }
+
+ const column = Number(cellElement.dataset.recordTableCol);
+ const row = Number(cellElement.dataset.recordTableRow);
+
+ if (isNaN(column) || isNaN(row)) {
+ return;
+ }
+
+ const lastPosition = store.get(recordTableHoverPositionCallbackState);
+
+ if (lastPosition?.column === column && lastPosition?.row === row) {
+ return;
+ }
+
+ store.set(recordTableHoverPositionCallbackState, { column, row });
+ },
+ [store, isSomeCellInEditMode, recordTableHoverPositionCallbackState],
+ );
return (
@@ -98,6 +132,7 @@ export const RecordTableContent = ({
isDragging={isDragging}
visibleRecordFields={visibleRecordFields}
id={RECORD_TABLE_HTML_ID}
+ onMouseMove={handleDelegatedMouseMove}
onMouseLeave={handleMouseLeave}
hasRecordGroups={hasRecordGroups}
>
diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx
index 31e15b3063..46f00d3e60 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableContextProvider.tsx
@@ -1,6 +1,7 @@
import { type ReactNode } from 'react';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
+import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { RecordTableContextProvider as RecordTableContextInternalProvider } from '@/object-record/record-table/contexts/RecordTableContext';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
@@ -32,6 +33,8 @@ export const RecordTableContextProvider = ({
objectNameSingular,
});
+ const { objectMetadataItems } = useObjectMetadataItems();
+
const objectPermissions = useObjectPermissionsForObject(
objectMetadataItem.id,
);
@@ -57,6 +60,7 @@ export const RecordTableContextProvider = ({
value={{
viewBarId,
objectMetadataItem,
+ objectMetadataItems,
recordTableId,
objectNameSingular,
objectPermissions,
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 7f965b6e35..3a3bce3d4f 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
@@ -163,6 +163,7 @@ const meta: Meta = {
viewBarId: mockPerformance.recordId,
// TODO: update performance mocks with new data, and merge with common mocks if possible
objectMetadataItem: mockPerformance.objectMetadataItem as any,
+ objectMetadataItems: [],
objectNameSingular:
mockPerformance.objectMetadataItem.nameSingular,
objectPermissions: {
diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts
index e8e74540bc..8af4ceb5a2 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts
+++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts
@@ -8,6 +8,7 @@ type RecordTableContextValue = {
viewBarId: string;
objectNameSingular: string;
objectMetadataItem: ObjectMetadataItem;
+ objectMetadataItems: ObjectMetadataItem[];
objectPermissions: ObjectPermission;
visibleRecordFields: RecordField[];
onRecordIdentifierClick?: (rowIndex: number, recordId: string) => void;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx
index f1c71eaf13..adf975aab7 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCell.tsx
@@ -1,11 +1,11 @@
import { FieldDisplay } from '@/object-record/record-field/ui/components/FieldDisplay';
-import { FieldFocusContextProvider } from '@/object-record/record-field/ui/contexts/FieldFocusContextProvider';
+import { FieldFocusStaticUnfocusedProvider } from '@/object-record/record-field/ui/contexts/FieldFocusContextProvider';
import { RecordTableCellContainer } from '@/object-record/record-table/record-table-cell/components/RecordTableCellContainer';
export const RecordTableCell = () => {
return (
-
+
} />
-
+
);
};
diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx
index 866f97c434..0ab91883da 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellBaseContainer.tsx
@@ -2,11 +2,9 @@ import { styled } from '@linaria/react';
import { useContext, type ReactNode } from 'react';
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
-import { useFieldFocus } from '@/object-record/record-field/ui/hooks/useFieldFocus';
import { isFieldIdentifierDisplay } from '@/object-record/record-field/ui/meta-types/display/utils/isFieldIdentifierDisplay';
import { RECORD_CHIP_CLICK_OUTSIDE_ID } from '@/object-record/record-table/constants/RecordChipClickOutsideId';
import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight';
-import { useRecordTableBodyContextOrThrow } from '@/object-record/record-table/contexts/RecordTableBodyContext';
import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext';
import { useOpenRecordTableCellFromCell } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell';
import { ThemeContext } from 'twenty-ui/theme';
@@ -60,7 +58,6 @@ export const RecordTableCellBaseContainer = ({
fieldDefinition,
isLabelIdentifier,
} = useContext(FieldContext);
- const { setIsFocused } = useFieldFocus();
const { openTableCell } = useOpenRecordTableCellFromCell();
const { theme } = useContext(ThemeContext);
@@ -70,26 +67,13 @@ export const RecordTableCellBaseContainer = ({
fieldDefinition,
isLabelIdentifier,
);
- const { onMoveHoverToCurrentCell } = useRecordTableBodyContextOrThrow();
-
- const handleContainerMouseMove = () => {
- setIsFocused(true);
- onMoveHoverToCurrentCell(cellPosition);
- };
-
- const handleContainerMouseLeave = () => {
- setIsFocused(false);
- };
const handleContainerClick = () => {
- onMoveHoverToCurrentCell(cellPosition);
openTableCell();
};
return (
{
const { recordId, isRecordReadOnly } = useRecordTableRowContextOrThrow();
- const { objectMetadataItem, objectPermissions } =
+ const { objectMetadataItem, objectMetadataItems, objectPermissions } =
useRecordTableContextOrThrow();
const {
@@ -35,8 +33,6 @@ export const RecordTableCellFieldContextGeneric = ({
fieldDefinitionByFieldMetadataItemId,
} = useRecordIndexContextOrThrow();
- const { objectMetadataItems } = useObjectMetadataItems();
-
const fieldDefinition =
fieldDefinitionByFieldMetadataItemId[recordField.fieldMetadataItemId];
diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx
index 2e18b316e2..8f4c0ae299 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellHoveredPortalContent.tsx
@@ -1,5 +1,6 @@
import { FieldDisplay } from '@/object-record/record-field/ui/components/FieldDisplay';
import { FieldContext } from '@/object-record/record-field/ui/contexts/FieldContext';
+import { FieldFocusStaticFocusedProvider } from '@/object-record/record-field/ui/contexts/FieldFocusContextProvider';
import { useIsFieldInputOnly } from '@/object-record/record-field/ui/hooks/useIsFieldInputOnly';
import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight';
import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext';
@@ -78,15 +79,17 @@ export const RecordTableCellHoveredPortalContent = () => {
showInteractiveStyle={showInteractiveStyle}
isRecordTableRowActive={isRecordTableRowActive}
>
- {isFieldInputOnly ? (
-
-
-
- ) : (
-
-
-
- )}
+
+ {isFieldInputOnly ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
{showButton && }
);
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 a2cfdf4e20..3ed5ba3f25 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
@@ -15,7 +15,6 @@ import { useAtomComponentFamilySelectorValue } from '@/ui/utilities/state/jotai/
import { useAtomComponentFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilyStateValue';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { forwardRef, type ReactNode } from 'react';
-
type RecordTableTrProps = {
children: ReactNode;
recordId: string;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx
index 3470f75b7d..b7a2fd089f 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx
+++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/components/RecordTableVirtualizedRowTreadmillEffect.tsx
@@ -13,8 +13,8 @@ import { useScrollWrapperHTMLElement } from '@/ui/utilities/scroll/hooks/useScro
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
import { useDebouncedCallback } from 'use-debounce';
-export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_ACTIVATE_LOW_DETAILS = 120;
-export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_DEACTIVATE_LOW_DETAILS = 30;
+export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_ACTIVATE_LOW_DETAILS = 200;
+export const SCROLL_SPEED_THRESHOLD_IN_ROWS_PER_SECOND_TO_DEACTIVATE_LOW_DETAILS = 50;
export const TIME_BEFORE_DEACTIVATING_LOW_DETAILS = 20;
export const NUMBER_OF_EVENTS_TO_COMPUTE_AVERAGE = 10;
diff --git a/packages/twenty-front/src/modules/object-record/record-table/virtualization/constants/TableVirtualizationNumberOfOverscanPages.ts b/packages/twenty-front/src/modules/object-record/record-table/virtualization/constants/TableVirtualizationNumberOfOverscanPages.ts
index 43bf957c9d..fb2cbc0f48 100644
--- a/packages/twenty-front/src/modules/object-record/record-table/virtualization/constants/TableVirtualizationNumberOfOverscanPages.ts
+++ b/packages/twenty-front/src/modules/object-record/record-table/virtualization/constants/TableVirtualizationNumberOfOverscanPages.ts
@@ -1 +1 @@
-export const TABLE_VIRTUALIZATION_NUMBER_OF_OVERSCAN_PAGES = 3;
+export const TABLE_VIRTUALIZATION_NUMBER_OF_OVERSCAN_PAGES = 5;
diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx
index fc204f04a8..dc309c840a 100644
--- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx
+++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx
@@ -104,6 +104,7 @@ const InternalTableContextProviders = ({
children: React.ReactNode;
objectMetadataItem: ObjectMetadataItem;
}) => {
+ const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const currentRecordFields = useAtomComponentStateValue(
@@ -174,6 +175,7 @@ const InternalTableContextProviders = ({
value={{
objectNameSingular: objectMetadataItem.nameSingular,
objectMetadataItem: objectMetadataItem,
+ objectMetadataItems: objectMetadataItems,
recordTableId: objectMetadataItem.namePlural,
viewBarId: 'view-bar',
objectPermissions: getObjectPermissionsFromMapByObjectMetadataId({