diff --git a/packages/twenty-front/src/hooks/useCombinedRefs.ts b/packages/twenty-front/src/hooks/useCombinedRefs.ts index 525f7a15fdea..1f88564f51ed 100644 --- a/packages/twenty-front/src/hooks/useCombinedRefs.ts +++ b/packages/twenty-front/src/hooks/useCombinedRefs.ts @@ -1,14 +1,6 @@ -import React, { Ref, RefCallback } from 'react'; -import { isFunction } from '@sniptt/guards'; +import { Ref, RefCallback } from 'react'; +import { combineRefs } from '~/utils/combineRefs'; -export const useCombinedRefs = - (...refs: (Ref | undefined)[]): RefCallback => - (node: T) => { - for (const ref of refs) { - if (isFunction(ref)) { - ref(node); - } else if (ref !== null && ref !== undefined) { - (ref as React.MutableRefObject).current = node; - } - } - }; +export const useCombinedRefs = ( + ...refs: (Ref | undefined)[] +): RefCallback => combineRefs(...refs); 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 f2f99633ed45..acbff482d08d 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 @@ -14,13 +14,14 @@ import { import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { ChipGeneratorsDecorator } from '~/testing/decorators/ChipGeneratorsDecorator'; import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorator'; import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext'; +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 { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; import { mockPerformance } from './mock'; @@ -87,7 +88,7 @@ const meta: Meta = { onCellMouseEnter: () => {}, }} > - - - - - - - - - - -
-
-
-
+ + + + + + + + +
+
+ + + diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts index 78eb5a8a55cb..527d990193b1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts @@ -4,7 +4,7 @@ import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata' import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -export type RecordTableCellContextProps = { +export type RecordTableCellContextValue = { columnDefinition: ColumnDefinition; columnIndex: number; isInEditMode: boolean; @@ -13,4 +13,4 @@ export type RecordTableCellContextProps = { }; export const RecordTableCellContext = - createContext({} as RecordTableCellContextProps); + createContext({} as RecordTableCellContextValue); 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 3ff64f7adc3a..2957ab8d132c 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 @@ -1,19 +1,14 @@ -import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; -import { createContext } from 'react'; +import { createRequiredContext } from '~/utils/createRequiredContext'; -export type RecordTableRowContextProps = { +export type RecordTableRowContextValue = { pathToShowPage: string; objectNameSingular: string; recordId: string; rowIndex: number; isSelected: boolean; + inView: boolean; isPendingRow?: boolean; - isDragging: boolean; - dragHandleProps: DraggableProvidedDragHandleProps | null; - inView?: boolean; - isDragDisabled?: boolean; }; -export const RecordTableRowContext = createContext( - {} as RecordTableRowContextProps, -); +export const [RecordTableRowContextProvider, useRecordTableRowContextOrThrow] = + createRequiredContext('RecordTableRowContext'); diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowDraggableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowDraggableContext.ts new file mode 100644 index 000000000000..415f22a687f4 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowDraggableContext.ts @@ -0,0 +1,14 @@ +import { DraggableProvidedDragHandleProps } from '@hello-pangea/dnd'; +import { createRequiredContext } from '~/utils/createRequiredContext'; + +export type RecordTableRowDraggableContextValue = { + isDragging: boolean; + dragHandleProps: DraggableProvidedDragHandleProps | null; +}; + +export const [ + RecordTableRowDraggableContextProvider, + useRecordTableRowDraggableContextOrThrow, +] = createRequiredContext( + 'RecordTableRowDraggableContext', +); 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 a0309ba000eb..6f4ca947d590 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 @@ -1,3 +1,5 @@ +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableCellCheckbox } from '@/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox'; import { RecordTableCellGrip } from '@/object-record/record-table/record-table-cell/components/RecordTableCellGrip'; import { RecordTableCellLoading } from '@/object-record/record-table/record-table-cell/components/RecordTableCellLoading'; @@ -13,18 +15,36 @@ export const RecordTableBodyLoading = () => { return ( {Array.from({ length: 8 }).map((_, rowIndex) => ( - - - - {visibleTableColumns.map((column) => ( - - ))} - + + + + + {visibleTableColumns.map((column) => ( + + ))} + + + ))} ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx index 4d1a5d544e4e..f81022598722 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupsBody.tsx @@ -35,9 +35,9 @@ export const RecordTableRecordGroupsBody = () => { key={recordGroupId} recordGroupId={recordGroupId} > - {index > 0 && } + {index > 0 && } diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx index cac73801a14f..a822c4bd3098 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellCheckbox.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; -import { useCallback, useContext } from 'react'; +import { useCallback } from 'react'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { Checkbox } from 'twenty-ui'; @@ -16,7 +16,7 @@ const StyledContainer = styled.div` `; export const RecordTableCellCheckbox = () => { - const { isSelected } = useContext(RecordTableRowContext); + const { isSelected } = useRecordTableRowContextOrThrow(); const { setCurrentRowSelected } = useSetCurrentRowSelected(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx index d04920b67014..9fad3b90d9ac 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper.tsx @@ -7,7 +7,7 @@ import { isFieldSelect } from '@/object-record/record-field/types/guards/isField import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { SelectFieldHotkeyScope } from '@/object-record/select/types/SelectFieldHotkeyScope'; @@ -22,7 +22,7 @@ export const RecordTableCellFieldContextWrapper = ({ const { columnDefinition } = useContext(RecordTableCellContext); - const { recordId, pathToShowPage } = useContext(RecordTableRowContext); + const { recordId, pathToShowPage } = useRecordTableRowContextOrThrow(); const updateRecord = useContext(RecordUpdateContext); 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 f590e5ccb5f1..29da512d41ce 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,7 +1,7 @@ import styled from '@emotion/styled'; -import { useContext } from 'react'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +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'; @@ -30,9 +30,10 @@ const StyledIconWrapper = styled.div<{ isDragging: boolean }>` `; export const RecordTableCellGrip = () => { - const { dragHandleProps, isDragging, isPendingRow } = useContext( - RecordTableRowContext, - ); + const { isPendingRow } = useRecordTableRowContextOrThrow(); + + const { dragHandleProps, isDragging } = + useRecordTableRowDraggableContextOrThrow(); return ( { - const { rowIndex } = useContext(RecordTableRowContext); + const { rowIndex } = useRecordTableRowContextOrThrow(); const currentTableCellPosition: TableCellPosition = useMemo( () => ({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx index 8dd8112a2583..2243a41e6dd3 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableLastEmptyCell.tsx @@ -1,10 +1,8 @@ -import { useContext } from 'react'; - -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; export const RecordTableLastEmptyCell = () => { - const { isSelected } = useContext(RecordTableRowContext); + const { isSelected } = useRecordTableRowContextOrThrow(); return ( <> 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 068a0ba42b92..02b952a84de1 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 @@ -1,20 +1,24 @@ -import { RecordTableCellContextProps } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContextProps } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { FieldMetadataType } from '~/generated-metadata/graphql'; +import { RecordTableCellContextValue } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableRowContextValue } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextValue } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; +import { FieldMetadataType } from '~/generated/graphql'; -export const recordTableRow: RecordTableRowContextProps = { +export const recordTableRowContextValue: RecordTableRowContextValue = { rowIndex: 2, isSelected: false, recordId: 'recordId', pathToShowPage: '/', objectNameSingular: 'objectNameSingular', + isPendingRow: false, + inView: true, +}; + +export const recordTableRowDraggableContextValue: RecordTableRowDraggableContextValue = { dragHandleProps: {} as any, isDragging: false, - inView: true, - isPendingRow: false, }; -export const recordTableCell: RecordTableCellContextProps = { +export const recordTableCellContextValue: RecordTableCellContextValue = { columnIndex: 3, columnDefinition: { size: 1, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useCurrentCellPosition.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useCurrentCellPosition.test.tsx index 36d87343fc49..d389a446ad2f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useCurrentCellPosition.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useCurrentCellPosition.test.tsx @@ -1,19 +1,28 @@ import { renderHook } from '@testing-library/react'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { recordTableCell, recordTableRow } from '../__mocks__/cell'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; +import { + recordTableCellContextValue, + recordTableRowContextValue, + recordTableRowDraggableContextValue, +} from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell'; import { useCurrentTableCellPosition } from '../useCurrentCellPosition'; describe('useCurrentTableCellPosition', () => { it('should return the current table cell position', () => { const wrapper = ({ children }: { children: React.ReactNode }) => ( - - - {children} - - + + + + {children} + + + ); const { result } = renderHook(() => useCurrentTableCellPosition(), { diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useIsSoftFocusOnCurrentTableCell.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useIsSoftFocusOnCurrentTableCell.test.tsx index f3d4a89c37f4..c89570918d80 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useIsSoftFocusOnCurrentTableCell.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useIsSoftFocusOnCurrentTableCell.test.tsx @@ -3,10 +3,12 @@ import { RecoilRoot } from 'recoil'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { - recordTableCell, - recordTableRow, + recordTableCellContextValue, + recordTableRowContextValue, + recordTableRowDraggableContextValue, } from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell'; import { useIsSoftFocusOnCurrentTableCell } from '@/object-record/record-table/record-table-cell/hooks/useIsSoftFocusOnCurrentTableCell'; @@ -16,11 +18,15 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => ( recordTableId="scopeId" onColumnsChange={jest.fn()} > - - - {children} - - + + + + {children} + + + ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveSoftFocusToCurrentCellOnHover.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveSoftFocusToCurrentCellOnHover.test.tsx index c5ad3732ca7c..177efefd9b95 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveSoftFocusToCurrentCellOnHover.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/__tests__/useMoveSoftFocusToCurrentCellOnHover.test.tsx @@ -3,10 +3,12 @@ import { CallbackInterface, RecoilRoot } from 'recoil'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { - recordTableCell, - recordTableRow, + recordTableCellContextValue, + recordTableRowContextValue, + recordTableRowDraggableContextValue, } from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell'; import { useMoveSoftFocusToCurrentCellOnHover } from '@/object-record/record-table/record-table-cell/hooks/useMoveSoftFocusToCurrentCellOnHover'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; @@ -80,11 +82,15 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => ( recordTableId="scopeId" onColumnsChange={jest.fn()} > - - - {children} - - + + + + {children} + + + ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx index 146ea602e22d..5b3da4b8fe7e 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellInGroup.test.tsx @@ -8,10 +8,12 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { - recordTableCell, - recordTableRow, + recordTableCellContextValue, + recordTableRowContextValue, + recordTableRowDraggableContextValue, } from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell'; import { useCloseRecordTableCellInGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellInGroup'; import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState'; @@ -55,13 +57,17 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => ( isLabelIdentifier: false, }} > - - + - {children} - - + + {children} + + + diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx index 37eda06f10ae..4a4181977822 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/internal/__tests__/useCloseRecordTableCellNoGroup.test.tsx @@ -8,10 +8,12 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { RecordTableContextProvider } from '@/object-record/record-table/components/RecordTableContextProvider'; import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowContextProvider } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { RecordTableRowDraggableContextProvider } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { - recordTableCell, - recordTableRow, + recordTableCellContextValue, + recordTableRowContextValue, + recordTableRowDraggableContextValue, } from '@/object-record/record-table/record-table-cell/hooks/__mocks__/cell'; import { useCloseRecordTableCellNoGroup } from '@/object-record/record-table/record-table-cell/hooks/internal/useCloseRecordTableCellNoGroup'; import { currentTableCellInEditModePositionComponentState } from '@/object-record/record-table/states/currentTableCellInEditModePositionComponentState'; @@ -54,13 +56,17 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => ( isLabelIdentifier: false, }} > - - + - {children} - - + + {children} + + + diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell.ts index 326947483055..1c193dd644aa 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellFromCell.ts @@ -5,7 +5,7 @@ import { useIsFieldValueReadOnly } from '@/object-record/record-field/hooks/useI import { FieldDefinition } from '@/object-record/record-field/types/FieldDefinition'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { CellHotkeyScopeContext } from '@/object-record/record-table/contexts/CellHotkeyScopeContext'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useCurrentTableCellPosition } from '@/object-record/record-table/record-table-cell/hooks/useCurrentCellPosition'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; @@ -30,9 +30,9 @@ export type OpenTableCellArgs = { export const useOpenRecordTableCellFromCell = () => { const customCellHotkeyScope = useContext(CellHotkeyScopeContext); const { recordId, fieldDefinition } = useContext(FieldContext); - const { pathToShowPage, objectNameSingular } = useContext( - RecordTableRowContext, - ); + + const { pathToShowPage, objectNameSingular } = + useRecordTableRowContextOrThrow(); const { onOpenTableCell } = useRecordTableBodyContextOrThrow(); 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 94975fe78fdf..a50a889c64bf 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 @@ -1,12 +1,12 @@ import styled from '@emotion/styled'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; -import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { RecordTableDraggableTr } from '@/object-record/record-table/record-table-row/components/RecordTableDraggableTr'; import { useTheme } from '@emotion/react'; import { IconComponent } from 'twenty-ui'; -const StyledTrContainer = styled.tr` +const StyledRecordTableDraggableTr = styled(RecordTableDraggableTr)` cursor: pointer; `; @@ -36,33 +36,40 @@ const StyledEmptyTd = styled.td` `; type RecordTableActionRowProps = { + draggableId: string; + draggableIndex: number; LeftIcon: IconComponent; text: string; onClick?: (event?: React.MouseEvent) => void; }; export const RecordTableActionRow = ({ + draggableId, + draggableIndex, LeftIcon, text, onClick, }: RecordTableActionRowProps) => { const theme = useTheme(); - const visibleColumns = useRecoilComponentValueV2( - visibleTableColumnsComponentSelector, - ); + const { visibleTableColumns } = useRecordTableContextOrThrow(); return ( - + - + {text} - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx index 25c557144d9f..60a282a67a91 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCells.tsx @@ -1,11 +1,12 @@ -import { useContext } from 'react'; - -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableCellsEmpty } from '@/object-record/record-table/record-table-row/components/RecordTableCellsEmpty'; import { RecordTableCellsVisible } from '@/object-record/record-table/record-table-row/components/RecordTableCellsVisible'; export const RecordTableCells = () => { - const { inView, isDragging } = useContext(RecordTableRowContext); + const { inView } = useRecordTableRowContextOrThrow(); + + const { isDragging } = useRecordTableRowDraggableContextOrThrow(); const areCellsVisible = inView || isDragging; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx index f20f1a5b9480..f9209f0fca4f 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsEmpty.tsx @@ -1,11 +1,10 @@ -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { useContext } from 'react'; export const RecordTableCellsEmpty = () => { - const { isSelected } = useContext(RecordTableRowContext); + const { isSelected } = useRecordTableRowContextOrThrow(); const visibleTableColumns = useRecoilComponentValueV2( visibleTableColumnsComponentSelector, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx index 1271a056e749..5a5ba00e2020 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableCellsVisible.tsx @@ -1,20 +1,15 @@ -import { useContext } from 'react'; - -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowDraggableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowDraggableContext'; import { RecordTableCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCell'; import { RecordTableCellWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellWrapper'; import { RecordTableTd } from '@/object-record/record-table/record-table-cell/components/RecordTableTd'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; -import { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState'; -import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; export const RecordTableCellsVisible = () => { - const { isSelected, isDragging } = useContext(RecordTableRowContext); + const { isSelected } = useRecordTableRowContextOrThrow(); - const [tableCellWidths] = useRecoilComponentStateV2( - tableCellWidthsComponentState, - ); + const { isDragging } = useRecordTableRowDraggableContextOrThrow(); const visibleTableColumns = useRecoilComponentValueV2( visibleTableColumnsComponentSelector, @@ -28,7 +23,7 @@ export const RecordTableCellsVisible = () => { @@ -42,7 +37,7 @@ export const RecordTableCellsVisible = () => { 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 new file mode 100644 index 000000000000..068bca83075c --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/components/RecordTableDraggableTr.tsx @@ -0,0 +1,63 @@ +import { useTheme } from '@emotion/react'; +import { Draggable, DraggableId } from '@hello-pangea/dnd'; +import { forwardRef, 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 { combineRefs } from '~/utils/combineRefs'; + +type RecordTableDraggableTrProps = { + draggableId: DraggableId; + draggableIndex: number; + isDragDisabled?: boolean; + onClick?: (event: React.MouseEvent) => void; + children: ReactNode; +}; + +export const RecordTableDraggableTr = forwardRef< + HTMLTableRowElement, + RecordTableDraggableTrProps +>(({ draggableId, draggableIndex, isDragDisabled, onClick, children }, ref) => { + const theme = useTheme(); + + return ( + + {(draggableProvided, draggableSnapshot) => ( + ( + ref, + draggableProvided.innerRef, + )} + // eslint-disable-next-line react/jsx-props-no-spreading + {...draggableProvided.draggableProps} + style={{ + ...draggableProvided.draggableProps.style, + background: draggableSnapshot.isDragging + ? theme.background.transparent.light + : 'none', + borderColor: draggableSnapshot.isDragging + ? `${theme.border.color.medium}` + : 'transparent', + }} + isDragging={draggableSnapshot.isDragging} + data-testid={`row-id-${draggableId}`} + data-selectable-id={draggableId} + onClick={onClick} + > + + {children} + + + )} + + ); +}); 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 index 6cacd8c0d240..9dbc46f6bb0d 100644 --- 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 @@ -1,18 +1,14 @@ -import { useTheme } from '@emotion/react'; -import { Draggable } from '@hello-pangea/dnd'; -import { ReactNode, useContext, useEffect, useRef } from 'react'; -import { useInView } from 'react-intersection-observer'; +import { ReactNode, useContext, 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 { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; -import { RecordTableTr } from '@/object-record/record-table/record-table-row/components/RecordTableTr'; +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 { tableCellWidthsComponentState } from '@/object-record/record-table/states/tableCellWidthsComponentState'; import { RecordTableWithWrappersScrollWrapperContext } from '@/ui/utilities/scroll/contexts/ScrollWrapperContexts'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; -import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; +import { useInView } from 'react-intersection-observer'; type RecordTableRowWrapperProps = { recordId: string; @@ -29,18 +25,15 @@ export const RecordTableRowWrapper = ({ isPendingRow, children, }: RecordTableRowWrapperProps) => { - const trRef = useRef(null); - const { objectMetadataItem } = useRecordTableContextOrThrow(); - const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow(); - - const theme = useTheme(); const currentRowSelected = useRecoilComponentFamilyValueV2( isRowSelectedComponentFamilyState, recordId, ); + const { onIndexRecordsLoaded } = useRecordIndexContextOrThrow(); + const scrollWrapperRef = useContext( RecordTableWithWrappersScrollWrapperContext, ); @@ -52,24 +45,6 @@ export const RecordTableRowWrapper = ({ rootMargin: '1000px', }); - const setTableCellWidths = useSetRecoilComponentStateV2( - tableCellWidthsComponentState, - ); - - useEffect(() => { - if (rowIndexForFocus === 0) { - const tdArray = Array.from( - trRef.current?.getElementsByTagName('td') ?? [], - ); - - const tdWidths = tdArray.map((td) => { - return td.getBoundingClientRect().width; - }); - - setTableCellWidths(tdWidths); - } - }, [trRef, rowIndexForFocus, setTableCellWidths]); - // TODO: find a better way to emit this event useEffect(() => { if (inView) { @@ -78,55 +53,29 @@ export const RecordTableRowWrapper = ({ }, [inView, onIndexRecordsLoaded]); return ( - - {(draggableProvided, draggableSnapshot) => ( - { - // @ts-expect-error - TS doesn't know that node.current is assignable - trRef.current = node; - elementRef(node); - draggableProvided.innerRef(node); - }} - // eslint-disable-next-line react/jsx-props-no-spreading - {...draggableProvided.draggableProps} - style={{ - ...draggableProvided.draggableProps.style, - background: draggableSnapshot.isDragging - ? theme.background.transparent.light - : 'none', - borderColor: draggableSnapshot.isDragging - ? `${theme.border.color.medium}` - : 'transparent', - }} - isDragging={draggableSnapshot.isDragging} - data-testid={`row-id-${recordId}`} - data-selectable-id={recordId} - > - - {children} - - - )} - + }) + recordId, + objectNameSingular: objectMetadataItem.nameSingular, + isSelected: currentRowSelected, + isPendingRow, + inView, + }} + > + {children} + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts index 76effd043211..c096d0b0d370 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts @@ -1,13 +1,12 @@ -import { useContext } from 'react'; import { useRecoilCallback } from 'recoil'; -import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableRowContextOrThrow } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { isRowSelectedComponentFamilyState } from '@/object-record/record-table/record-table-row/states/isRowSelectedComponentFamilyState'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; export const useSetCurrentRowSelected = () => { - const { recordId } = useContext(RecordTableRowContext); + const { recordId } = useRecordTableRowContextOrThrow(); const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2( isRowSelectedComponentFamilyState, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx index 7217f372658d..1d05147c0020 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionAddNew.tsx @@ -1,9 +1,11 @@ import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; +import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords'; import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow'; import { recordTablePendingRecordIdByGroupComponentFamilyState } from '@/object-record/record-table/states/recordTablePendingRecordIdByGroupComponentFamilyState'; import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { IconPlus } from 'twenty-ui'; import { isDefined } from '~/utils/isDefined'; @@ -17,6 +19,10 @@ export const RecordTableRecordGroupSectionAddNew = () => { currentRecordGroupId, ); + const recordIds = useRecoilComponentValueV2( + recordIndexAllRecordIdsComponentSelector, + ); + const { createNewTableRecordInGroup } = useCreateNewTableRecord(recordTableId); @@ -28,6 +34,8 @@ export const RecordTableRecordGroupSectionAddNew = () => { return ( { @@ -18,6 +20,10 @@ export const RecordTableRecordGroupSectionLoadMore = () => { currentRecordGroupId, ); + const recordIds = useRecoilComponentValueV2( + recordIndexAllRecordIdsComponentSelector, + ); + const handleLoadMore = () => { fetchMoreRecords(); }; @@ -28,6 +34,8 @@ export const RecordTableRecordGroupSectionLoadMore = () => { return ( (...refs: (Ref | undefined)[]) => { + return (node: T) => { + for (const ref of refs) { + if (isFunction(ref)) { + ref(node); + } else if (isDefined(ref) && 'current' in ref) { + (ref as MutableRefObject).current = node; + } + } + }; +};