From 419f8adde67426b0142ae2762c9202a381da7749 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Sun, 28 Jan 2024 20:32:28 +0100 Subject: [PATCH] Improve RecordTableCellperformances (#3659) * Improve RecordTableCellperformances * Fixes --- .../triggerDeleteRecordsOptimisticEffect.ts | 3 +- .../hooks/useObjectMetadataItemOnly.ts | 46 +++++ .../object-record/components/RecordChip.tsx | 9 +- .../__tests__/useObjectRecordTable.test.tsx | 6 +- .../components/RecordIndexTableContainer.tsx | 7 +- .../RecordIndexTableContainerEffect.tsx | 28 +-- .../hooks/useLoadRecordIndexTable.ts} | 19 +- .../record-table/components/CheckboxCell.tsx | 14 +- .../record-table/components/RecordTable.tsx | 39 ++-- .../components/RecordTableBody.tsx | 22 +-- .../components/RecordTableBodyEffect.tsx | 8 +- .../RecordTableBodyFetchMoreLoader.tsx | 8 +- .../components/RecordTableCellContainer.tsx | 87 ++++----- .../RecordTableFirstColumnScrollObserver.tsx | 4 +- .../components/RecordTableRefContext.tsx | 19 -- .../components/RecordTableRow.tsx | 92 +++++---- .../components/RecordTableWithWrappers.tsx | 96 ++++----- .../record-table/contexts/ColumnContext.ts | 8 - .../contexts/ColumnIndexContext.ts | 3 - .../contexts/RecordTableCellContext.ts | 13 ++ .../contexts/RecordTableContext.ts | 12 ++ .../contexts/RecordTableRefContext.ts | 7 - .../contexts/RecordTableRowContext.ts | 12 ++ .../record-table/contexts/RowIdContext.ts | 3 - .../record-table/contexts/RowIndexContext.ts | 3 - .../internal/useRecordTableScopedStates.ts | 31 --- .../hooks/internal/useRecordTableStates.ts | 6 +- .../record-table/hooks/useRecordTable.ts | 183 ++---------------- .../hooks/useRecordTableMoveFocus.ts | 183 ++++++++++++++++++ .../components/RecordTableCell.tsx | 14 +- .../components/RecordTableCellContainer.tsx | 33 ++-- .../components/RecordTableCellDisplayMode.tsx | 4 +- .../RecordTableCellSoftFocusMode.tsx | 4 +- ...ableCell.ts => useCloseRecordTableCell.ts} | 65 +------ .../hooks/useCurrentCellPosition.ts | 15 +- .../hooks/useOpenRecordTableCell.ts | 88 +++++++++ .../hooks/useSetSoftFocus.ts | 4 +- .../hooks/useCurrentRowSelected.ts | 41 ---- .../hooks/useSetCurrentRowSelected.ts | 31 +++ .../objectMetadataConfigStateScopeMap.ts | 8 - .../visibleTableColumnsSelectorScopeMap.ts | 2 +- .../types/ObjectMetadataConfig.ts | 4 - .../SignInBackgroundMockContainer.tsx | 3 +- .../SignInBackgroundMockContainerEffect.tsx | 10 - .../components/FetchMoreLoader.tsx | 5 +- .../pages/object-record/RecordIndexPage.tsx | 2 +- 46 files changed, 667 insertions(+), 637 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemOnly.ts rename packages/twenty-front/src/modules/object-record/{hooks/useObjectRecordTable.ts => record-index/hooks/useLoadRecordIndexTable.ts} (77%) delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRefContext.tsx delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/ColumnContext.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/ColumnIndexContext.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableCellContext.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRefContext.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableRowContext.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RowIdContext.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/contexts/RowIndexContext.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useRecordTableScopedStates.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTableMoveFocus.ts rename packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/{useTableCell.ts => useCloseRecordTableCell.ts} (52%) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCell.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useCurrentRowSelected.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/objectMetadataConfigStateScopeMap.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/types/ObjectMetadataConfig.ts diff --git a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts index 853b04310..d2d8e1af2 100644 --- a/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts +++ b/packages/twenty-front/src/modules/apollo/optimistic-effect/utils/triggerDeleteRecordsOptimisticEffect.ts @@ -28,8 +28,9 @@ export const triggerDeleteRecordsOptimisticEffect = ({ objectMetadataItem.nameSingular, cachedConnection, ) - ) + ) { return cachedConnection; + } const { variables } = parseApolloStoreFieldName( diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemOnly.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemOnly.ts new file mode 100644 index 000000000..4a32ee425 --- /dev/null +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItemOnly.ts @@ -0,0 +1,46 @@ +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError'; +import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; +import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; +import { isDefined } from '~/utils/isDefined'; + +import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier'; + +export const useObjectMetadataItemOnly = ({ + objectNameSingular, +}: ObjectMetadataItemIdentifier) => { + const currentWorkspace = useRecoilValue(currentWorkspaceState); + const mockObjectMetadataItems = getObjectMetadataItemsMock(); + + let objectMetadataItem = useRecoilValue( + objectMetadataItemFamilySelector({ + objectName: objectNameSingular, + objectNameType: 'singular', + }), + ); + + let objectMetadataItems = useRecoilValue(objectMetadataItemsState); + + if (!currentWorkspace) { + objectMetadataItem = + mockObjectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.nameSingular === objectNameSingular, + ) ?? null; + objectMetadataItems = mockObjectMetadataItems; + } + + if (!isDefined(objectMetadataItem)) { + throw new ObjectMetadataItemNotFoundError( + objectNameSingular, + objectMetadataItems, + ); + } + + return { + objectMetadataItem, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx index 30139bf99..8b09dc947 100644 --- a/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx +++ b/packages/twenty-front/src/modules/object-record/components/RecordChip.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useMapToObjectRecordIdentifier } from '@/object-metadata/hooks/useMapToObjectRecordIdentifier'; +import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { EntityChip } from '@/ui/display/chip/components/EntityChip'; @@ -15,10 +16,14 @@ export const RecordChip = ({ record, maxWidth, }: RecordChipProps) => { - const { mapToObjectRecordIdentifier } = useObjectMetadataItem({ + const { objectMetadataItem } = useObjectMetadataItemOnly({ objectNameSingular, }); + const mapToObjectRecordIdentifier = useMapToObjectRecordIdentifier({ + objectMetadataItem, + }); + const objectRecordIdentifier = mapToObjectRecordIdentifier(record); return ( diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx index e50f36d50..627991b7f 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useObjectRecordTable.test.tsx @@ -4,13 +4,13 @@ import { expect } from '@storybook/test'; import { renderHook } from '@testing-library/react'; import { RecoilRoot } from 'recoil'; -import { useObjectRecordTable } from '@/object-record/hooks/useObjectRecordTable'; +import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { getScopeIdFromComponentId } from '@/ui/utilities/recoil-scope/utils/getScopeIdFromComponentId'; const recordTableId = 'people'; -const objectNamePlural = 'people'; +const objectNameSingular = 'person'; const onColumnsChange = jest.fn(); const ObjectNamePluralSetter = ({ children }: { children: ReactNode }) => { @@ -37,7 +37,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => { describe('useObjectRecordTable', () => { it('should skip fetch if currentWorkspace is undefined', async () => { const { result } = renderHook( - () => useObjectRecordTable(objectNamePlural), + () => useLoadRecordIndexTable(objectNameSingular), { wrapper: Wrapper, }, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx index 6b6b0e18a..51a5caf58 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexTableContainer.tsx @@ -1,4 +1,3 @@ -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { RecordUpdateHookParams } from '@/object-record/record-field/contexts/FieldContext'; import { RecordTableActionBar } from '@/object-record/record-table/action-bar/components/RecordTableActionBar'; @@ -18,10 +17,6 @@ export const RecordIndexTableContainer = ({ objectNameSingular, createRecord, }: RecordIndexTableContainerProps) => { - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular, - }); - const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular, }); @@ -37,7 +32,7 @@ export const RecordIndexTableContainer = ({ <> { - const { - setAvailableTableColumns, - setOnEntityCountChange, - setObjectMetadataConfig, - } = useRecordTable({ recordTableId }); + const { setAvailableTableColumns, setOnEntityCountChange } = useRecordTable({ + recordTableId, + }); - const { - objectMetadataItem, - basePathToShowPage, - labelIdentifierFieldMetadata, - } = useObjectMetadataItem({ + const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, }); @@ -39,20 +33,6 @@ export const RecordIndexTableContainerEffect = ({ viewBarId, }); - useEffect(() => { - if (basePathToShowPage && labelIdentifierFieldMetadata) { - setObjectMetadataConfig?.({ - basePathToShowPage, - labelIdentifierFieldMetadataId: labelIdentifierFieldMetadata.id, - }); - } - }, [ - basePathToShowPage, - objectMetadataItem, - labelIdentifierFieldMetadata, - setObjectMetadataConfig, - ]); - useEffect(() => { const availableTableColumns = columnDefinitions.filter( filterAvailableTableColumns, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useObjectRecordTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts similarity index 77% rename from packages/twenty-front/src/modules/object-record/hooks/useObjectRecordTable.ts rename to packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts index 85b7eb132..cbbe33129 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useObjectRecordTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexTable.ts @@ -2,30 +2,23 @@ import { useRecoilValue, useSetRecoilState } from 'recoil'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { turnSortsIntoOrderBy } from '@/object-record/object-sort-dropdown/utils/turnSortsIntoOrderBy'; import { turnObjectDropdownFilterIntoQueryFilter } from '@/object-record/record-filter/utils/turnObjectDropdownFilterIntoQueryFilter'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { signInBackgroundMockCompanies } from '@/sign-in-background-mock/constants/signInBackgroundMockCompanies'; -import { useFindManyRecords } from './useFindManyRecords'; +import { useFindManyRecords } from '../../hooks/useFindManyRecords'; -export const useObjectRecordTable = (objectNamePlural: string) => { +export const useLoadRecordIndexTable = (objectNameSingular: string) => { const { setRecordTableData, setIsRecordTableInitialLoading } = useRecordTable(); const currentWorkspace = useRecoilValue(currentWorkspaceState); - const { objectNameSingular } = useObjectNameSingularFromPlural({ - objectNamePlural, + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, }); - const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( - { - objectNameSingular, - }, - ); - const { getTableFiltersState, getTableSortsState, @@ -38,12 +31,12 @@ export const useObjectRecordTable = (objectNamePlural: string) => { const requestFilters = turnObjectDropdownFilterIntoQueryFilter( tableFilters, - foundObjectMetadataItem?.fields ?? [], + objectMetadataItem?.fields ?? [], ); const orderBy = turnSortsIntoOrderBy( tableSorts, - foundObjectMetadataItem?.fields ?? [], + objectMetadataItem?.fields ?? [], ); const { records, loading, fetchMoreRecords, queryStateIdentifier } = diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx index 8d1c361a1..74af8f6ab 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/CheckboxCell.tsx @@ -1,12 +1,13 @@ -import { useCallback } from 'react'; +import { useCallback, useContext } from 'react'; import styled from '@emotion/styled'; -import { useSetRecoilState } from 'recoil'; +import { useRecoilValue, useSetRecoilState } from 'recoil'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; +import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; +import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { Checkbox } from '@/ui/input/components/Checkbox'; import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState'; -import { useCurrentRowSelected } from '../record-table-row/hooks/useCurrentRowSelected'; - const StyledContainer = styled.div` align-items: center; cursor: pointer; @@ -18,8 +19,11 @@ const StyledContainer = styled.div` `; export const CheckboxCell = () => { + const { recordId } = useContext(RecordTableRowContext); + const { isRowSelectedFamilyState } = useRecordTableStates(); const setActionBarOpenState = useSetRecoilState(actionBarOpenState); - const { currentRowSelected, setCurrentRowSelected } = useCurrentRowSelected(); + const { setCurrentRowSelected } = useSetCurrentRowSelected(); + const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId)); const handleClick = useCallback(() => { setCurrentRowSelected(!currentRowSelected); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 0ef044ed5..099ed23fe 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -1,10 +1,12 @@ -import { useContext } from 'react'; +import { useRef } from 'react'; import styled from '@emotion/styled'; +import { useObjectMetadataItemOnly } from '@/object-metadata/hooks/useObjectMetadataItemOnly'; import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody'; import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; +import { RecordTableFirstColumnScrollEffect } from '@/object-record/record-table/components/RecordTableFirstColumnScrollObserver'; import { RecordTableHeader } from '@/object-record/record-table/components/RecordTableHeader'; -import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; import { rgba } from '@/ui/theme/constants/colors'; @@ -48,8 +50,7 @@ const StyledTable = styled.table` } } - th, - td { + th { background-color: ${({ theme }) => theme.background.primary}; border-right: 1px solid ${({ theme }) => theme.border.color.light}; } @@ -98,31 +99,43 @@ const StyledTable = styled.table` type RecordTableProps = { recordTableId: string; - objectNamePlural: string; + objectNameSingular: string; onColumnsChange: (columns: any) => void; createRecord: () => void; }; export const RecordTable = ({ recordTableId, - objectNamePlural, + objectNameSingular, onColumnsChange, createRecord, }: RecordTableProps) => { - const recordTableRef = useContext(RecordTableRefContext); + const recordTableRef = useRef(null); const { scopeId } = useRecordTableStates(recordTableId); + const { objectMetadataItem } = useObjectMetadataItemOnly({ + objectNameSingular, + }); + return ( - {!!objectNamePlural && ( - - - - - + {!!objectNameSingular && ( + + + + + + + + )} ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx index ee7f98661..4ba288f22 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBody.tsx @@ -2,15 +2,15 @@ import { useRecoilValue } from 'recoil'; import { RecordTableBodyFetchMoreLoader } from '@/object-record/record-table/components/RecordTableBodyFetchMoreLoader'; import { RecordTableRow } from '@/object-record/record-table/components/RecordTableRow'; -import { RowIdContext } from '@/object-record/record-table/contexts/RowIdContext'; -import { RowIndexContext } from '@/object-record/record-table/contexts/RowIndexContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; type RecordTableBodyProps = { - objectNamePlural: string; + objectNameSingular: string; }; -export const RecordTableBody = ({ objectNamePlural }: RecordTableBodyProps) => { +export const RecordTableBody = ({ + objectNameSingular, +}: RecordTableBodyProps) => { const { getTableRowIdsState } = useRecordTableStates(); const tableRowIds = useRecoilValue(getTableRowIdsState()); @@ -18,15 +18,15 @@ export const RecordTableBody = ({ objectNamePlural }: RecordTableBodyProps) => { return ( <> - {tableRowIds.map((rowId, rowIndex) => ( - - - - - + {tableRowIds.map((recordId, rowIndex) => ( + ))} - + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx index d10fd977b..daa53951a 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyEffect.tsx @@ -1,16 +1,16 @@ import { useEffect } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { useObjectRecordTable } from '@/object-record/hooks/useObjectRecordTable'; +import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; type RecordTableBodyEffectProps = { - objectNamePlural: string; + objectNameSingular: string; }; export const RecordTableBodyEffect = ({ - objectNamePlural, + objectNameSingular, }: RecordTableBodyEffectProps) => { const { fetchMoreRecords: fetchMoreObjects, @@ -18,7 +18,7 @@ export const RecordTableBodyEffect = ({ setRecordTableData, queryStateIdentifier, loading, - } = useObjectRecordTable(objectNamePlural); + } = useLoadRecordIndexTable(objectNameSingular); const { getTableLastRowVisibleState } = useRecordTableStates(); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx index b020895ef..611dfc9fa 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableBodyFetchMoreLoader.tsx @@ -1,18 +1,18 @@ import { useRecoilCallback, useRecoilValue } from 'recoil'; -import { useObjectRecordTable } from '@/object-record/hooks/useObjectRecordTable'; +import { useLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLoadRecordIndexTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { FetchMoreLoader } from '@/ui/utilities/loading-state/components/FetchMoreLoader'; type RecordTableBodyFetchMoreLoaderProps = { - objectNamePlural: string; + objectNameSingular: string; }; export const RecordTableBodyFetchMoreLoader = ({ - objectNamePlural, + objectNameSingular, }: RecordTableBodyFetchMoreLoaderProps) => { - const { queryStateIdentifier } = useObjectRecordTable(objectNamePlural); + const { queryStateIdentifier } = useLoadRecordIndexTable(objectNameSingular); const { setRecordTableLastRowVisible } = useRecordTable(); const isFetchingMoreObjects = useRecoilValue( diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellContainer.tsx index 144afa7f4..85e8de1d1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableCellContainer.tsx @@ -1,32 +1,31 @@ import { useContext } from 'react'; +import styled from '@emotion/styled'; import { useSetRecoilState } from 'recoil'; -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; -import { ColumnContext } from '@/object-record/record-table/contexts/ColumnContext'; -import { ColumnIndexContext } from '@/object-record/record-table/contexts/ColumnIndexContext'; import { RecordUpdateContext } from '@/object-record/record-table/contexts/EntityUpdateMutationHookContext'; -import { RowIdContext } from '@/object-record/record-table/contexts/RowIdContext'; +import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { RecordTableCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCell'; -import { useCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useCurrentRowSelected'; +import { useSetCurrentRowSelected } from '@/object-record/record-table/record-table-row/hooks/useSetCurrentRowSelected'; import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState'; import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState'; -import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; -export const RecordTableCellContainer = ({ - cellIndex, -}: { - cellIndex: number; -}) => { +const StyledContainer = styled.td<{ isSelected: boolean }>` + background: ${({ isSelected, theme }) => + isSelected ? theme.accent.quaternary : theme.background.primary}; +`; + +export const RecordTableCellContainer = () => { const setContextMenuPosition = useSetRecoilState(contextMenuPositionState); const setContextMenuOpenState = useSetRecoilState(contextMenuIsOpenState); - const currentRowId = useContext(RowIdContext); - const { setCurrentRowSelected } = useCurrentRowSelected(); + const { setCurrentRowSelected } = useSetCurrentRowSelected(); const handleContextMenu = (event: React.MouseEvent) => { event.preventDefault(); @@ -38,16 +37,15 @@ export const RecordTableCellContainer = ({ setContextMenuOpenState(true); }; - const columnDefinition = useContext(ColumnContext); - - const { basePathToShowPage, objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: - columnDefinition?.metadata.objectMetadataNameSingular || '', - }); + const { objectMetadataItem } = useContext(RecordTableContext); + const { columnDefinition } = useContext(RecordTableCellContext); + const { recordId, pathToShowPage, isSelected } = useContext( + RecordTableRowContext, + ); const updateRecord = useContext(RecordUpdateContext); - if (!columnDefinition || !currentRowId) { + if (!columnDefinition) { return null; } @@ -56,30 +54,29 @@ export const RecordTableCellContainer = ({ : TableHotkeyScope.CellEditMode; return ( - - - handleContextMenu(event)}> - [updateRecord, {}], - hotkeyScope: customHotkeyScope, - basePathToShowPage, - isLabelIdentifier: isLabelIdentifierField({ - fieldMetadataItem: { - id: columnDefinition.fieldMetadataId, - name: columnDefinition.metadata.fieldName, - }, - objectMetadataItem, - }), - }} - > - - - - - + handleContextMenu(event)} + > + [updateRecord, {}], + hotkeyScope: customHotkeyScope, + basePathToShowPage: pathToShowPage, + isLabelIdentifier: isLabelIdentifierField({ + fieldMetadataItem: { + id: columnDefinition.fieldMetadataId, + name: columnDefinition.metadata.fieldName, + }, + objectMetadataItem, + }), + }} + > + + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableFirstColumnScrollObserver.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableFirstColumnScrollObserver.tsx index 6c64644bf..bd6a02946 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableFirstColumnScrollObserver.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableFirstColumnScrollObserver.tsx @@ -1,11 +1,11 @@ import { useContext, useEffect } from 'react'; import { useRecoilValue } from 'recoil'; -import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { scrollLeftState } from '@/ui/utilities/scroll/states/scrollLeftState'; export const RecordTableFirstColumnScrollEffect = () => { - const recordTableRef = useContext(RecordTableRefContext); + const { recordTableRef } = useContext(RecordTableContext); const scrollLeft = useRecoilValue(scrollLeftState); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRefContext.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRefContext.tsx deleted file mode 100644 index efe094607..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRefContext.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useRef } from 'react'; - -import { RecordTableRefContext } from '@/object-record/record-table/contexts/RecordTableRefContext'; - -export type RecordTableRefContextWrapperProps = { - children: React.ReactNode; -}; - -export const RecordTableRefContextWrapper = ({ - children, -}: RecordTableRefContextWrapperProps) => { - const tableRef = useRef(null); - - return ( - - {children} - - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx index 8bfe4873d..9fd2b1dc9 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableRow.tsx @@ -3,35 +3,33 @@ import { useInView } from 'react-intersection-observer'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; +import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage'; import { RecordTableCellContainer } from '@/object-record/record-table/components/RecordTableCellContainer'; +import { RecordTableCellContext } from '@/object-record/record-table/contexts/RecordTableCellContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; +import { RecordTableRowContext } from '@/object-record/record-table/contexts/RecordTableRowContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ScrollWrapperContext } from '@/ui/utilities/scroll/components/ScrollWrapper'; -import { ColumnContext } from '../contexts/ColumnContext'; -import { useCurrentRowSelected } from '../record-table-row/hooks/useCurrentRowSelected'; - import { CheckboxCell } from './CheckboxCell'; -export const StyledRow = styled.tr<{ selected: boolean }>` - background: ${(props) => - props.selected ? props.theme.accent.quaternary : 'none'}; -`; - type RecordTableRowProps = { - rowId: string; + recordId: string; + rowIndex: number; }; const StyledPlaceholder = styled.td` height: 30px; `; -export const RecordTableRow = ({ rowId }: RecordTableRowProps) => { - const { getVisibleTableColumnsSelector } = useRecordTableStates(); +export const RecordTableRow = ({ recordId, rowIndex }: RecordTableRowProps) => { + const { getVisibleTableColumnsSelector, isRowSelectedFamilyState } = + useRecordTableStates(); + const currentRowSelected = useRecoilValue(isRowSelectedFamilyState(recordId)); + const { objectMetadataItem } = useContext(RecordTableContext); const visibleTableColumns = useRecoilValue(getVisibleTableColumnsSelector()); - const { currentRowSelected } = useCurrentRowSelected(); - const scrollWrapperRef = useContext(ScrollWrapperContext); const { ref: elementRef, inView } = useInView({ @@ -40,34 +38,46 @@ export const RecordTableRow = ({ rowId }: RecordTableRowProps) => { }); return ( - - {inView ? ( - <> - - - - {[...visibleTableColumns] - .sort((columnA, columnB) => columnA.position - columnB.position) - .map((column, columnIndex) => { - return ( - - - - ); - })} - - - ) : ( - - )} - + + {inView ? ( + <> + + + + {[...visibleTableColumns] + .sort((columnA, columnB) => columnA.position - columnB.position) + .map((column, columnIndex) => { + return ( + + + + ); + })} + + + ) : ( + + )} + + ); }; 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 1db63087e..68d9ee804 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 @@ -3,11 +3,8 @@ import styled from '@emotion/styled'; import { useRecoilCallback, useRecoilValue } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { RecordTable } from '@/object-record/record-table/components/RecordTable'; -import { RecordTableFirstColumnScrollEffect } from '@/object-record/record-table/components/RecordTableFirstColumnScrollObserver'; -import { RecordTableRefContextWrapper } from '@/object-record/record-table/components/RecordTableRefContext'; import { EntityDeleteContext } from '@/object-record/record-table/contexts/EntityDeleteHookContext'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { IconPlus } from '@/ui/display/icon'; @@ -66,7 +63,7 @@ const StyledTableContainer = styled.div` `; type RecordTableWithWrappersProps = { - objectNamePlural: string; + objectNameSingular: string; recordTableId: string; viewBarId: string; updateRecordMutation: (params: any) => void; @@ -76,7 +73,7 @@ type RecordTableWithWrappersProps = { export const RecordTableWithWrappers = ({ updateRecordMutation, createRecord, - objectNamePlural, + objectNameSingular, recordTableId, viewBarId, }: RecordTableWithWrappersProps) => { @@ -95,10 +92,6 @@ export const RecordTableWithWrappers = ({ recordTableId, }); - const { objectNameSingular } = useObjectNameSingularFromPlural({ - objectNamePlural, - }); - const { objectMetadataItem: foundObjectMetadataItem } = useObjectMetadataItem( { objectNameSingular, @@ -112,52 +105,49 @@ export const RecordTableWithWrappers = ({ return ( - - - - - -
- (columns) => { - persistViewFields( - mapColumnDefinitionsToViewFields(columns), - ); - })} - createRecord={createRecord} - /> - -
- + + +
+ (columns) => { + persistViewFields( + mapColumnDefinitionsToViewFields(columns), + ); + })} + createRecord={createRecord} /> - {!isRecordTableInitialLoading && numberOfTableRows === 0 && ( - - - No {foundObjectMetadataItem?.namePlural} - - - Create one: - -
+ + {!isRecordTableInitialLoading && numberOfTableRows === 0 && ( + + + No {foundObjectMetadataItem?.namePlural} + + + Create one: + +