From f3a8b849aa0009c74ab46b813e5ef765d0011023 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Tue, 17 Jun 2025 15:01:28 +0200 Subject: [PATCH] Fix table loading (#12653) As per title --- ....tsx => useRecordIndexTableQuery.test.tsx} | 23 +-- .../useFetchMoreRecordsWithPagination.ts | 2 +- .../object-record/hooks/useFindManyRecords.ts | 2 +- .../useHandleFindManyRecordsCompleted.ts | 46 +++-- .../hooks/useHandleFindManyRecordsError.ts | 24 ++- .../hooks/useLazyFetchAllRecords.ts | 19 +- .../useLazyFetchMoreRecordsWithPagination.ts | 194 ++++++++++++++++++ .../hooks/useLazyFindManyRecords.ts | 79 +++---- .../RecordBoardColumnFetchMoreLoader.tsx | 16 +- .../hooks/useLazyLoadRecordIndexTable.ts | 52 ----- .../hooks/useLoadRecordIndexBoardColumn.ts | 23 +-- .../hooks/useRecordIndexTableFetchMore.ts | 24 +++ .../hooks/useRecordIndexTableQuery.ts | 35 ++++ ...RecordIndexLoadMoreLockedComponentState.ts | 9 - .../RecordTableComponentInstanceEffect.tsx | 1 - .../hooks/internal/useSetRecordTableData.ts | 15 +- .../record-table/hooks/useRecordTable.ts | 39 ---- .../RecordTableBodyFetchMoreLoader.tsx | 43 ++-- .../RecordTableNoRecordGroupBodyEffect.tsx | 147 ++++--------- .../RecordTableRecordGroupBodyEffect.tsx | 88 ++++---- .../RecordTableRecordGroupSectionLoadMore.tsx | 14 +- .../onEntityCountChangeComponentState.ts | 10 - ...unteredUnrecoverableErrorComponentState.ts | 9 - .../tableLastRowVisibleComponentState.ts | 9 - .../scroll/hooks/useScrollToPosition.ts | 10 +- ...useRecoilComponentFamilyCallbackStateV2.ts | 97 +++++++++ .../hooks/useCreateViewFromCurrentView.ts | 8 +- .../modules/views/hooks/useRefreshViews.ts | 2 +- .../decorators/RecordTableDecorator.tsx | 19 +- 29 files changed, 592 insertions(+), 467 deletions(-) rename packages/twenty-front/src/modules/object-record/hooks/__tests__/{useLazyLoadRecordIndexTable.test.tsx => useRecordIndexTableQuery.test.tsx} (97%) create mode 100644 packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-index/hooks/useLazyLoadRecordIndexTable.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableFetchMore.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableQuery.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/onEntityCountChangeComponentState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts delete mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/tableLastRowVisibleComponentState.ts create mode 100644 packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2.ts diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx similarity index 97% rename from packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx rename to packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx index e5eb76d58..df48c5514 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useRecordIndexTableQuery.test.tsx @@ -1,9 +1,8 @@ -import { expect } from '@storybook/test'; -import { renderHook } from '@testing-library/react'; -import { ReactNode, act } from 'react'; +import { renderHook, waitFor } from '@testing-library/react'; +import { ReactNode } from 'react'; import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; -import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable'; +import { useRecordIndexTableQuery } from '@/object-record/record-index/hooks/useRecordIndexTableQuery'; import { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { MockedResponse } from '@apollo/client/testing'; @@ -679,16 +678,14 @@ const Wrapper = ({ children }: { children: ReactNode }) => { ); }; -describe('useLazyLoadRecordIndexTable', () => { +describe('useRecordIndexTableQuery', () => { it('should fetch', async () => { const { result } = renderHook( () => { - const { findManyRecords, ...result } = - useLazyLoadRecordIndexTable(objectNameSingular); + const { records } = useRecordIndexTableQuery(objectNameSingular); return { - findManyRecords, - ...result, + records, }; }, { @@ -696,12 +693,8 @@ describe('useLazyLoadRecordIndexTable', () => { }, ); - expect(result.current.loading).toBe(false); - - await act(async () => { - await result.current.findManyRecords(); + await waitFor(() => { + expect(result.current.records).toHaveLength(16); }); - - expect(result.current.records).toHaveLength(16); }); }); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts index 6ba675b68..802afe9eb 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts @@ -24,10 +24,10 @@ import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyReco import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; +import { capitalize, isDefined } from 'twenty-shared/utils'; import { cursorFamilyState } from '../states/cursorFamilyState'; import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState'; -import { capitalize, isDefined } from 'twenty-shared/utils'; export type UseFindManyRecordsParams = ObjectMetadataItemIdentifier & RecordGqlOperationVariables & { diff --git a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts index dd769b00e..fd644dae0 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFindManyRecords.ts @@ -119,7 +119,7 @@ export const useFindManyRecords = ({ loading, error, fetchMoreRecords, - queryStateIdentifier: queryIdentifier, + queryIdentifier, hasNextPage, pageInfo, }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts index 965f82f1c..0878b6d2a 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsCompleted.ts @@ -1,4 +1,4 @@ -import { useRecoilState } from 'recoil'; +import { useSetRecoilState } from 'recoil'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; @@ -6,6 +6,7 @@ import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/ import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; +import { useCallback } from 'react'; import { isDefined } from 'twenty-shared/utils'; export const useHandleFindManyRecordsCompleted = ({ @@ -17,35 +18,36 @@ export const useHandleFindManyRecordsCompleted = ({ objectMetadataItem: ObjectMetadataItem; onCompleted?: OnFindManyRecordsCompleted; }) => { - const [, setLastCursor] = useRecoilState(cursorFamilyState(queryIdentifier)); + const setLastCursor = useSetRecoilState(cursorFamilyState(queryIdentifier)); - const [, setHasNextPage] = useRecoilState( + const setHasNextPage = useSetRecoilState( hasNextPageFamilyState(queryIdentifier), ); - const handleFindManyRecordsCompleted = ( - data: RecordGqlOperationFindManyResult, - ) => { - if (!isDefined(data)) { - onCompleted?.([]); - } + const handleFindManyRecordsCompleted = useCallback( + (data: RecordGqlOperationFindManyResult) => { + if (!isDefined(data)) { + onCompleted?.([]); + } - const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; + const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo; - const records = getRecordsFromRecordConnection({ - recordConnection: data?.[objectMetadataItem.namePlural], - }) as T[]; + const records = getRecordsFromRecordConnection({ + recordConnection: data?.[objectMetadataItem.namePlural], + }) as T[]; - onCompleted?.(records, { - pageInfo, - totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, - }); + onCompleted?.(records, { + pageInfo, + totalCount: data?.[objectMetadataItem.namePlural]?.totalCount, + }); - if (isDefined(data?.[objectMetadataItem.namePlural])) { - setLastCursor(pageInfo.endCursor ?? ''); - setHasNextPage(pageInfo.hasNextPage ?? false); - } - }; + if (isDefined(data?.[objectMetadataItem.namePlural])) { + setLastCursor(pageInfo.endCursor ?? ''); + setHasNextPage(pageInfo.hasNextPage ?? false); + } + }, + [onCompleted, objectMetadataItem.namePlural, setLastCursor, setHasNextPage], + ); return { handleFindManyRecordsCompleted, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts index 1517c92e7..b5a89b7eb 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useHandleFindManyRecordsError.ts @@ -4,6 +4,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { logError } from '~/utils/logError'; +import { useCallback } from 'react'; export const useHandleFindManyRecordsError = ({ handleError, @@ -14,16 +15,19 @@ export const useHandleFindManyRecordsError = ({ }) => { const { enqueueSnackBar } = useSnackBar(); - const handleFindManyRecordsError = (error: ApolloError) => { - logError( - `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + - error, - ); - enqueueSnackBar(`${error.message}`, { - variant: SnackBarVariant.Error, - }); - handleError?.(error); - }; + const handleFindManyRecordsError = useCallback( + (error: ApolloError) => { + logError( + `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + + error, + ); + enqueueSnackBar(`${error.message}`, { + variant: SnackBarVariant.Error, + }); + handleError?.(error); + }, + [enqueueSnackBar, handleError, objectMetadataItem.namePlural], + ); return { handleFindManyRecordsError, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts index bce83e45a..c8dfbbe49 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts @@ -34,7 +34,7 @@ export const useLazyFetchAllRecords = ({ const [progress, setProgress] = useState({ displayType: 'number', }); - const { fetchMore, findManyRecords } = useLazyFindManyRecords({ + const { fetchMoreRecordsLazy, findManyRecordsLazy } = useLazyFindManyRecords({ objectNameSingular, filter, orderBy, @@ -47,12 +47,12 @@ export const useLazyFetchAllRecords = ({ }); const fetchAllRecords = useCallback(async () => { - if (!isDefined(findManyRecords)) { + if (!isDefined(findManyRecordsLazy)) { return []; } setIsDownloading(true); - const findManyRecordsDataResult = await findManyRecords(); + const findManyRecordsDataResult = await findManyRecordsLazy(); const firstQueryResult = findManyRecordsDataResult?.data?.[objectMetadataItem.namePlural]; @@ -84,7 +84,7 @@ export const useLazyFetchAllRecords = ({ break; } - if (!isDefined(fetchMore)) { + if (!isDefined(fetchMoreRecordsLazy)) { break; } @@ -92,12 +92,7 @@ export const useLazyFetchAllRecords = ({ await sleep(delayMs); } - const rawResult = await fetchMore({ - variables: { - lastCursor: lastCursor, - limit, - }, - }); + const rawResult = await fetchMoreRecordsLazy(); const fetchMoreResult = rawResult?.data?.[objectMetadataItem.namePlural]; @@ -126,8 +121,8 @@ export const useLazyFetchAllRecords = ({ return records; }, [ delayMs, - fetchMore, - findManyRecords, + fetchMoreRecordsLazy, + findManyRecordsLazy, objectMetadataItem.namePlural, limit, maximumRequests, diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts new file mode 100644 index 000000000..cbe606b77 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFetchMoreRecordsWithPagination.ts @@ -0,0 +1,194 @@ +import { + ApolloError, + ApolloQueryResult, + FetchMoreQueryOptions, + OperationVariables, + WatchQueryFetchPolicy, +} from '@apollo/client'; +import { isNonEmptyArray } from '@apollo/client/utilities'; +import { isNonEmptyString } from '@sniptt/guards'; +import { useRecoilCallback } from 'recoil'; + +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier'; +import { isAggregationEnabled } from '@/object-metadata/utils/isAggregationEnabled'; +import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; +import { RecordGqlEdge } from '@/object-record/graphql/types/RecordGqlEdge'; +import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; +import { RecordGqlOperationGqlRecordFields } from '@/object-record/graphql/types/RecordGqlOperationGqlRecordFields'; +import { RecordGqlOperationVariables } from '@/object-record/graphql/types/RecordGqlOperationVariables'; +import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; +import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; +import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; + +import { capitalize, isDefined } from 'twenty-shared/utils'; +import { cursorFamilyState } from '../states/cursorFamilyState'; +import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; + +export type UseFindManyRecordsParams = ObjectMetadataItemIdentifier & + RecordGqlOperationVariables & { + onCompleted?: OnFindManyRecordsCompleted; + skip?: boolean; + recordGqlFields?: RecordGqlOperationGqlRecordFields; + fetchPolicy?: WatchQueryFetchPolicy; + }; + +type UseFindManyRecordsStateParams< + T, + TData = RecordGqlOperationFindManyResult, +> = Omit< + UseFindManyRecordsParams, + 'skip' | 'recordGqlFields' | 'fetchPolicy' | 'onCompleted' +> & { + data: RecordGqlOperationFindManyResult | undefined; + error: ApolloError | undefined; + fetchMore< + TFetchData = TData, + TFetchVars extends OperationVariables = OperationVariables, + >( + fetchMoreOptions: FetchMoreQueryOptions & { + updateQuery?: ( + previousQueryResult: TData, + options: { + fetchMoreResult: TFetchData; + variables: TFetchVars; + }, + ) => TData; + }, + ): Promise>; + objectMetadataItem: ObjectMetadataItem; +}; + +export const useLazyFetchMoreRecordsWithPagination = < + T extends ObjectRecord = ObjectRecord, +>({ + objectNameSingular, + filter, + orderBy, + limit, + error, + fetchMore, + objectMetadataItem, +}: UseFindManyRecordsStateParams) => { + const queryIdentifier = getQueryIdentifier({ + objectNameSingular, + filter, + limit, + orderBy, + }); + + const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ + objectMetadataItem, + }); + + // TODO: put this into a util inspired from https://github.com/apollographql/apollo-client/blob/master/src/utilities/policies/pagination.ts + // This function is equivalent to merge function + read function in field policy + const fetchMoreRecordsLazy = useRecoilCallback( + ({ snapshot, set }) => + async () => { + const hasNextPageLocal = snapshot + .getLoadable(hasNextPageFamilyState(queryIdentifier)) + .getValue(); + + const lastCursorLocal = snapshot + .getLoadable(cursorFamilyState(queryIdentifier)) + .getValue(); + + // Remote objects does not support hasNextPage. We cannot rely on it to fetch more records. + if ( + hasNextPageLocal || + (!isAggregationEnabled(objectMetadataItem) && !error) + ) { + try { + const { data: fetchMoreDataResult } = await fetchMore({ + variables: { + filter, + orderBy, + lastCursor: isNonEmptyString(lastCursorLocal) + ? lastCursorLocal + : undefined, + }, + updateQuery: (prev, { fetchMoreResult }) => { + const previousEdges = + prev?.[objectMetadataItem.namePlural]?.edges; + const nextEdges = + fetchMoreResult?.[objectMetadataItem.namePlural]?.edges; + + let newEdges: RecordGqlEdge[] = previousEdges ?? []; + + if (isNonEmptyArray(nextEdges)) { + newEdges = filterUniqueRecordEdgesByCursor([ + ...newEdges, + ...(fetchMoreResult?.[objectMetadataItem.namePlural] + ?.edges ?? []), + ]); + } + + const pageInfo = + fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; + + if (isDefined(pageInfo)) { + set( + cursorFamilyState(queryIdentifier), + pageInfo.endCursor ?? '', + ); + set( + hasNextPageFamilyState(queryIdentifier), + pageInfo.hasNextPage ?? false, + ); + } + + return Object.assign({}, prev, { + [objectMetadataItem.namePlural]: { + __typename: `${capitalize( + objectMetadataItem.nameSingular, + )}Connection`, + edges: newEdges, + pageInfo: + fetchMoreResult?.[objectMetadataItem.namePlural].pageInfo, + totalCount: + fetchMoreResult?.[objectMetadataItem.namePlural] + .totalCount, + }, + } as RecordGqlOperationFindManyResult); + }, + }); + + return { + data: fetchMoreDataResult?.[objectMetadataItem.namePlural], + totalCount: + fetchMoreDataResult?.[objectMetadataItem.namePlural] + ?.totalCount, + records: getRecordsFromRecordConnection({ + recordConnection: { + edges: + fetchMoreDataResult?.[objectMetadataItem.namePlural]?.edges, + pageInfo: + fetchMoreDataResult?.[objectMetadataItem.namePlural] + ?.pageInfo, + }, + }) as T[], + }; + } catch (error) { + handleFindManyRecordsError(error as ApolloError); + return { error: error as ApolloError }; + } + } + }, + [ + queryIdentifier, + objectMetadataItem, + error, + fetchMore, + filter, + orderBy, + handleFindManyRecordsError, + ], + ); + + return { + fetchMoreRecordsLazy, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts index 202792e8b..78b8bfec9 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useLazyFindManyRecords.ts @@ -2,12 +2,13 @@ import { useLazyQuery } from '@apollo/client'; import { useRecoilCallback } from 'recoil'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; -import { useFetchMoreRecordsWithPagination } from '@/object-record/hooks/useFetchMoreRecordsWithPagination'; import { UseFindManyRecordsParams } from '@/object-record/hooks/useFindManyRecords'; import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted'; import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; +import { useLazyFetchMoreRecordsWithPagination } from '@/object-record/hooks/useLazyFetchMoreRecordsWithPagination'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; @@ -16,7 +17,7 @@ import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; type UseLazyFindManyRecordsParams = Omit< UseFindManyRecordsParams, - 'skip' + 'skip' | 'onCompleted' | 'onError' >; export const useLazyFindManyRecords = ({ @@ -25,9 +26,6 @@ export const useLazyFindManyRecords = ({ orderBy, limit, recordGqlFields, - fetchPolicy, - onCompleted, - onError, }: UseLazyFindManyRecordsParams) => { const { objectMetadataItem } = useObjectMetadataItem({ objectNameSingular, @@ -40,7 +38,6 @@ export const useLazyFindManyRecords = ({ const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ objectMetadataItem, - handleError: onError, }); const queryIdentifier = getQueryIdentifier({ @@ -53,7 +50,6 @@ export const useLazyFindManyRecords = ({ const { handleFindManyRecordsCompleted } = useHandleFindManyRecordsCompleted({ objectMetadataItem, queryIdentifier, - onCompleted, }); const objectPermissions = useObjectPermissionsForObject( @@ -62,30 +58,28 @@ export const useLazyFindManyRecords = ({ const hasReadPermission = objectPermissions.canReadObjectRecords; - const [findManyRecords, { data, loading, error, fetchMore }] = + const [findManyRecords, { data, error, fetchMore }] = useLazyQuery(findManyRecordsQuery, { variables: { filter, limit, orderBy, }, - fetchPolicy: fetchPolicy, + fetchPolicy: 'network-only', onCompleted: handleFindManyRecordsCompleted, onError: handleFindManyRecordsError, }); - const { fetchMoreRecords, totalCount, records, hasNextPage } = - useFetchMoreRecordsWithPagination({ - objectNameSingular, - filter, - orderBy, - limit, - onCompleted, - fetchMore, - data, - error, - objectMetadataItem, - }); + const { fetchMoreRecordsLazy } = useLazyFetchMoreRecordsWithPagination({ + objectNameSingular, + filter, + orderBy, + limit, + fetchMore, + data, + error, + objectMetadataItem, + }); const findManyRecordsLazy = useRecoilCallback( ({ set }) => @@ -96,9 +90,10 @@ export const useLazyFindManyRecords = ({ return { data: null, - loading: false, + records: [], + totalCount: 0, + hasNextPage: false, error: undefined, - called: true, }; } @@ -115,7 +110,29 @@ export const useLazyFindManyRecords = ({ set(hasNextPageFamilyState(queryIdentifier), hasNextPage); set(cursorFamilyState(queryIdentifier), lastCursor); - return result; + const records = getRecordsFromRecordConnection({ + recordConnection: { + edges: result?.data?.[objectMetadataItem.namePlural]?.edges ?? [], + pageInfo: result?.data?.[objectMetadataItem.namePlural] + ?.pageInfo ?? { + hasNextPage: false, + hasPreviousPage: false, + startCursor: '', + endCursor: '', + }, + }, + }); + + const totalCount = + result?.data?.[objectMetadataItem.namePlural]?.totalCount ?? 0; + + return { + data: result?.data, + records, + totalCount, + hasNextPage, + error: result?.error, + }; }, [ hasReadPermission, @@ -126,16 +143,8 @@ export const useLazyFindManyRecords = ({ ); return { - objectMetadataItem, - records, - totalCount, - loading: hasReadPermission ? loading : false, - error: hasReadPermission ? error : undefined, - fetchMore, - fetchMoreRecords, - queryStateIdentifier: queryIdentifier, - findManyRecords: findManyRecordsLazy, - hasNextPage, - hasReadPermission, + findManyRecordsLazy, + fetchMoreRecordsLazy, + queryIdentifier, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader.tsx index eda0fc17e..c6524bae5 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnFetchMoreLoader.tsx @@ -6,8 +6,6 @@ import { useRecoilValue } from 'recoil'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState'; import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState'; -import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; import { GRAY_SCALE } from 'twenty-ui/theme'; @@ -33,23 +31,11 @@ export const RecordBoardColumnFetchMoreLoader = () => { columnDefinition.id, ); - const isLoadMoreLocked = useRecoilComponentValueV2( - isRecordIndexLoadMoreLockedComponentState, - ); - const { ref, inView } = useInView(); useEffect(() => { - if (isLoadMoreLocked) { - return; - } - setShouldFetchMore(inView); - }, [setShouldFetchMore, inView, isLoadMoreLocked]); - - if (isLoadMoreLocked) { - return null; - } + }, [setShouldFetchMore, inView]); return (
diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLazyLoadRecordIndexTable.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLazyLoadRecordIndexTable.ts deleted file mode 100644 index 115cadee8..000000000 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLazyLoadRecordIndexTable.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; -import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams'; -import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields'; -import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; -import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies'; -import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; - -export const useLazyLoadRecordIndexTable = (objectNameSingular: string) => { - const showAuthModal = useShowAuthModal(); - - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular, - }); - - const { setRecordTableData, setIsRecordTableInitialLoading } = - useRecordTable(); - - const params = useFindManyRecordIndexTableParams(objectNameSingular); - - const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem }); - - const { - findManyRecords, - records, - loading, - totalCount, - fetchMoreRecords, - queryStateIdentifier, - hasNextPage, - } = useLazyFindManyRecords({ - ...params, - recordGqlFields, - onCompleted: () => { - setIsRecordTableInitialLoading(false); - }, - onError: () => { - setIsRecordTableInitialLoading(false); - }, - }); - - return { - findManyRecords, - records: !showAuthModal ? records : SIGN_IN_BACKGROUND_MOCK_COMPANIES, - totalCount: totalCount, - loading, - fetchMoreRecords, - queryStateIdentifier, - setRecordTableData, - hasNextPage, - }; -}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts index 61a400240..4d7d48ae2 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useLoadRecordIndexBoardColumn.ts @@ -84,19 +84,14 @@ export const useLoadRecordIndexBoardColumn = ({ }, ]); - const { - records, - loading, - fetchMoreRecords, - queryStateIdentifier, - hasNextPage, - } = useFindManyRecords({ - objectNameSingular, - filter: combinedFilters, - orderBy, - recordGqlFields, - limit: 10, - }); + const { records, loading, fetchMoreRecords, queryIdentifier, hasNextPage } = + useFindManyRecords({ + objectNameSingular, + filter: combinedFilters, + orderBy, + recordGqlFields, + limit: 10, + }); useEffect(() => { setRecordIdsForColumn(columnId, records); @@ -110,7 +105,7 @@ export const useLoadRecordIndexBoardColumn = ({ records, loading, fetchMoreRecords, - queryStateIdentifier, + queryIdentifier, hasNextPage, }; }; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableFetchMore.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableFetchMore.ts new file mode 100644 index 000000000..1aa8d1533 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableFetchMore.ts @@ -0,0 +1,24 @@ +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords'; +import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams'; +import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields'; + +export const useRecordIndexTableFetchMore = (objectNameSingular: string) => { + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const params = useFindManyRecordIndexTableParams(objectNameSingular); + + const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem }); + + const { fetchMoreRecordsLazy, queryIdentifier } = useLazyFindManyRecords({ + ...params, + recordGqlFields, + }); + + return { + fetchMoreRecordsLazy, + queryIdentifier, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableQuery.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableQuery.ts new file mode 100644 index 000000000..1c71f92bb --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableQuery.ts @@ -0,0 +1,35 @@ +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { useFindManyRecordIndexTableParams } from '@/object-record/record-index/hooks/useFindManyRecordIndexTableParams'; +import { useRecordTableRecordGqlFields } from '@/object-record/record-index/hooks/useRecordTableRecordGqlFields'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; +import { SIGN_IN_BACKGROUND_MOCK_COMPANIES } from '@/sign-in-background-mock/constants/SignInBackgroundMockCompanies'; +import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; + +export const useRecordIndexTableQuery = (objectNameSingular: string) => { + const { recordTableId } = useRecordTableContextOrThrow(); + const { objectMetadataItem } = useObjectMetadataItem({ + objectNameSingular, + }); + + const showAuthModal = useShowAuthModal(); + + const params = useFindManyRecordIndexTableParams(objectNameSingular); + + const recordGqlFields = useRecordTableRecordGqlFields({ objectMetadataItem }); + + const { records, hasNextPage, queryIdentifier, loading } = useFindManyRecords( + { + ...params, + recordGqlFields, + skip: showAuthModal, + }, + ); + + return { + records: showAuthModal ? SIGN_IN_BACKGROUND_MOCK_COMPANIES : records, + loading: showAuthModal ? false : loading, + hasNextPage, + queryIdentifier, + }; +}; diff --git a/packages/twenty-front/src/modules/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState.ts b/packages/twenty-front/src/modules/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState.ts deleted file mode 100644 index dbdb3a0f3..000000000 --- a/packages/twenty-front/src/modules/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; -import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; - -export const isRecordIndexLoadMoreLockedComponentState = - createComponentStateV2({ - key: 'isRecordIndexLoadMoreLockedComponentState', - componentInstanceContext: ViewComponentInstanceContext, - defaultValue: false, - }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableComponentInstanceEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableComponentInstanceEffect.tsx index 25c88181f..ce43c2e88 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableComponentInstanceEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTableComponentInstanceEffect.tsx @@ -6,7 +6,6 @@ import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefin type RecordTableComponentInstanceEffectProps = { onColumnsChange: (columns: ColumnDefinition[]) => void; - onEntityCountChange?: (count: number) => void | Promise; }; export const RecordTableComponentInstanceEffect = ({ diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts index bf969533d..b01d4ba82 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/internal/useSetRecordTableData.ts @@ -11,24 +11,20 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; +import { useRecoilComponentFamilyCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { isDefined } from 'twenty-shared/utils'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; type useSetRecordTableDataProps = { recordTableId?: string; - onEntityCountChange: ( - entityCount?: number, - currentRecordGroupId?: string, - ) => void; }; export const useSetRecordTableData = ({ recordTableId, - onEntityCountChange, }: useSetRecordTableDataProps) => { const recordIndexRecordIdsByGroupFamilyState = - useRecoilComponentCallbackStateV2( + useRecoilComponentFamilyCallbackStateV2( recordIndexRecordIdsByGroupComponentFamilyState, recordTableId, ); @@ -38,7 +34,7 @@ export const useSetRecordTableData = ({ recordTableId, ); - const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2( + const isRowSelectedFamilyState = useRecoilComponentFamilyCallbackStateV2( isRowSelectedComponentFamilyState, recordTableId, ); @@ -61,11 +57,9 @@ export const useSetRecordTableData = ({ ({ records, currentRecordGroupId, - totalCount, }: { records: T[]; currentRecordGroupId?: string; - totalCount?: number; }) => { for (const record of records) { // TODO: refactor with scoped state later @@ -115,8 +109,6 @@ export const useSetRecordTableData = ({ } else { set(recordIndexAllRecordIdsSelector, recordIds); } - - onEntityCountChange(totalCount, currentRecordGroupId); } }, [ @@ -125,7 +117,6 @@ export const useSetRecordTableData = ({ hasUserSelectedAllRowsState, setIsFocusActiveForCurrentPosition, setRecordTableHoverPosition, - onEntityCountChange, isRowSelectedFamilyState, ], ); diff --git a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts index 3295b0bb2..739c8e8dd 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/hooks/useRecordTable.ts @@ -11,18 +11,15 @@ import { availableTableColumnsComponentState } from '@/object-record/record-tabl import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { onColumnsChangeComponentState } from '@/object-record/record-table/states/onColumnsChangeComponentState'; -import { onEntityCountChangeComponentState } from '@/object-record/record-table/states/onEntityCountChangeComponentState'; import { useRecordTableMove } from '@/object-record/record-table/hooks/useRecordTableMove'; import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState'; -import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useLeaveTableFocus } from './internal/useLeaveTableFocus'; import { useResetTableRowSelection } from './internal/useResetTableRowSelection'; import { useSelectAllRows } from './internal/useSelectAllRows'; -import { useSetRecordTableData } from './internal/useSetRecordTableData'; import { useSetRecordTableFocusPosition } from './internal/useSetRecordTableFocusPosition'; import { useSetRowSelectedState } from './internal/useSetRowSelectedState'; type useRecordTableProps = { @@ -56,11 +53,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { [availableTableColumnsState], ); - const setOnEntityCountChange = useSetRecoilComponentStateV2( - onEntityCountChangeComponentState, - recordTableId, - ); - const setOnColumnsChange = useSetRecoilComponentStateV2( onColumnsChangeComponentState, recordTableId, @@ -76,11 +68,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { recordTableId, ); - const setRecordTableLastRowVisible = useSetRecoilComponentStateV2( - tableLastRowVisibleComponentState, - recordTableId, - ); - const onColumnsChangeState = useRecoilComponentCallbackStateV2( onColumnsChangeComponentState, recordTableId, @@ -99,29 +86,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { [onColumnsChangeState], ); - const onEntityCountChangeState = useRecoilComponentCallbackStateV2( - onEntityCountChangeComponentState, - recordTableId, - ); - - const onEntityCountChange = useRecoilCallback( - ({ snapshot }) => - (count?: number, currentRecordGroupId?: string) => { - const onEntityCountChange = getSnapshotValue( - snapshot, - onEntityCountChangeState, - ); - - onEntityCountChange?.(count, currentRecordGroupId); - }, - [onEntityCountChangeState], - ); - - const setRecordTableData = useSetRecordTableData({ - recordTableId, - onEntityCountChange, - }); - const leaveTableFocus = useLeaveTableFocus(recordTableId); const setRowSelected = useSetRowSelectedState(recordTableId); @@ -139,8 +103,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { return { onColumnsChange, setAvailableTableColumns, - setOnEntityCountChange, - setRecordTableData, leaveTableFocus, setRowSelected, resetTableRowSelection, @@ -148,7 +110,6 @@ export const useRecordTable = (props?: useRecordTableProps) => { selectAllRows, setOnColumnsChange, setIsRecordTableInitialLoading, - setRecordTableLastRowVisible, setFocusPosition, setHasUserSelectedAllRows, setOnToggleColumnSort, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx index 68efaf749..c84a7eccb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableBodyFetchMoreLoader.tsx @@ -1,13 +1,15 @@ import styled from '@emotion/styled'; import { useInView } from 'react-intersection-observer'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilState } from 'recoil'; -import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState'; -import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore'; +import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2'; +import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { GRAY_SCALE } from 'twenty-ui/theme'; +import { useDebouncedCallback } from 'use-debounce'; const StyledText = styled.div` align-items: center; @@ -20,21 +22,13 @@ const StyledText = styled.div` `; export const RecordTableBodyFetchMoreLoader = () => { - const { setRecordTableLastRowVisible } = useRecordTable(); + const { recordTableId, objectNameSingular } = useRecordTableContextOrThrow(); - const isRecordTableLoadMoreLocked = useRecoilComponentValueV2( - isRecordIndexLoadMoreLockedComponentState, - ); + const { fetchMoreRecordsLazy } = + useRecordIndexTableFetchMore(objectNameSingular); - const onLastRowVisible = useRecoilCallback( - () => async (inView: boolean) => { - if (isRecordTableLoadMoreLocked) { - return; - } - - setRecordTableLastRowVisible(inView); - }, - [setRecordTableLastRowVisible, isRecordTableLoadMoreLocked], + const [isFetchingMoreRecords, setIsFetchingMoreRecords] = useRecoilState( + isFetchingMoreRecordsFamilyState(recordTableId), ); const { scrollWrapperHTMLElement } = useScrollWrapperElement(); @@ -43,11 +37,22 @@ export const RecordTableBodyFetchMoreLoader = () => { hasRecordTableFetchedAllRecordsComponentStateV2, ); - const showLoadingMoreRow = - !hasRecordTableFetchedAllRecordsComponents && !isRecordTableLoadMoreLocked; + const showLoadingMoreRow = !hasRecordTableFetchedAllRecordsComponents; + const debouncedFetchMoreRecordsLazy = useDebouncedCallback( + fetchMoreRecordsLazy, + 100, + ); const { ref: tbodyRef } = useInView({ - onChange: onLastRowVisible, + onChange: async (inView) => { + if (isFetchingMoreRecords || !inView) { + return; + } + + setIsFetchingMoreRecords(true); + await debouncedFetchMoreRecordsLazy(); + setIsFetchingMoreRecords(false); + }, delay: 1000, rootMargin: '1000px', root: scrollWrapperHTMLElement, diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect.tsx index 97a2eb1a2..9c08e4966 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableNoRecordGroupBodyEffect.tsx @@ -1,67 +1,73 @@ import { useEffect, useState } from 'react'; import { useRecoilState, useRecoilValue } from 'recoil'; -import { useDebouncedCallback } from 'use-debounce'; import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; -import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable'; +import { useRecordIndexTableQuery } from '@/object-record/record-index/hooks/useRecordIndexTableQuery'; import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { useSetRecordTableData } from '@/object-record/record-table/hooks/internal/useSetRecordTableData'; import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2'; -import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState'; -import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState'; +import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition'; -import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { isNonEmptyString } from '@sniptt/guards'; export const RecordTableNoRecordGroupBodyEffect = () => { - const { objectNameSingular } = useRecordTableContextOrThrow(); + const { objectNameSingular, recordTableId } = useRecordTableContextOrThrow(); - const { setIsRecordTableInitialLoading } = useRecordTable(); + const { records, loading, hasNextPage } = + useRecordIndexTableQuery(objectNameSingular); + + const setRecordTableData = useSetRecordTableData({ + recordTableId, + }); const showAuthModal = useShowAuthModal(); const [hasInitializedScroll, setHasInitializedScroll] = useState(false); - const { - findManyRecords, - fetchMoreRecords, - records, - totalCount, - setRecordTableData, - loading, - queryStateIdentifier, - hasNextPage, - } = useLazyLoadRecordIndexTable(objectNameSingular); - - const isFetchingMoreObjects = useRecoilValue( - isFetchingMoreRecordsFamilyState(queryStateIdentifier), - ); - - const tableLastRowVisible = useRecoilComponentValueV2( - tableLastRowVisibleComponentState, - ); - - const [encounteredUnrecoverableError, setEncounteredUnrecoverableError] = - useRecoilComponentStateV2(tableEncounteredUnrecoverableErrorComponentState); - const setHasRecordTableFetchedAllRecordsComponents = useSetRecoilComponentStateV2( hasRecordTableFetchedAllRecordsComponentStateV2, ); - - const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilState( - lastShowPageRecordIdState, + const setIsRecordTableInitialLoading = useSetRecoilComponentStateV2( + isRecordTableInitialLoadingComponentState, ); + const isFetchingMoreRecords = useRecoilValue( + isFetchingMoreRecordsFamilyState(recordTableId), + ); + + const [lastShowPageRecordId] = useRecoilState(lastShowPageRecordIdState); const { scrollToPosition } = useScrollToPosition(); useEffect(() => { - if (isNonEmptyString(lastShowPageRecordId) && !hasInitializedScroll) { + if (!loading && !isFetchingMoreRecords) { + setRecordTableData({ + records, + }); + setHasRecordTableFetchedAllRecordsComponents(!hasNextPage); + setIsRecordTableInitialLoading(false); + } + }, [ + hasNextPage, + isFetchingMoreRecords, + loading, + records, + setHasRecordTableFetchedAllRecordsComponents, + setIsRecordTableInitialLoading, + setRecordTableData, + showAuthModal, + ]); + + useEffect(() => { + if (hasInitializedScroll) { + return; + } + + if (isNonEmptyString(lastShowPageRecordId)) { const isRecordAlreadyFetched = records.some( (record) => record.id === lastShowPageRecordId, ); @@ -78,76 +84,7 @@ export const RecordTableNoRecordGroupBodyEffect = () => { setHasInitializedScroll(true); } } - }, [ - loading, - lastShowPageRecordId, - records, - scrollToPosition, - hasInitializedScroll, - setLastShowPageRecordId, - ]); - - useEffect(() => { - if (!loading) { - setRecordTableData({ - records, - totalCount, - }); - } - }, [records, totalCount, setRecordTableData, loading]); - - const fetchMoreDebouncedIfRequested = useDebouncedCallback(async () => { - // We are debouncing here to give the user some room to scroll if they want to within this throttle window - return await fetchMoreRecords(); - }, 100); - - useEffect(() => { - const allRecordsHaveBeenFetched = !hasNextPage; - - setHasRecordTableFetchedAllRecordsComponents(allRecordsHaveBeenFetched); - }, [hasNextPage, setHasRecordTableFetchedAllRecordsComponents]); - - useEffect(() => { - (async () => { - if ( - !isFetchingMoreObjects && - tableLastRowVisible && - hasNextPage && - !encounteredUnrecoverableError - ) { - const result = await fetchMoreDebouncedIfRequested(); - - const isForbidden = - result?.error?.graphQLErrors.some( - (e) => e.extensions?.code === 'FORBIDDEN', - ) ?? false; - - if (isForbidden) { - setEncounteredUnrecoverableError(true); - } - } - })(); - }, [ - hasNextPage, - records, - lastShowPageRecordId, - scrollToPosition, - fetchMoreDebouncedIfRequested, - isFetchingMoreObjects, - tableLastRowVisible, - encounteredUnrecoverableError, - setEncounteredUnrecoverableError, - ]); - - useEffect(() => { - setIsRecordTableInitialLoading(false); - - if (showAuthModal) { - return; - } - - findManyRecords(); - }, [findManyRecords, setIsRecordTableInitialLoading, showAuthModal]); + }, [hasInitializedScroll, lastShowPageRecordId, records, scrollToPosition]); return <>; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx index 360bf5d79..d7fa16d65 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-body/components/RecordTableRecordGroupBodyEffect.tsx @@ -1,37 +1,35 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useRecoilState } from 'recoil'; import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; -import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable'; +import { useRecordIndexTableQuery } from '@/object-record/record-index/hooks/useRecordIndexTableQuery'; import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState'; import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus'; +import { useSetRecordTableData } from '@/object-record/record-table/hooks/internal/useSetRecordTableData'; +import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition'; import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { isNonEmptyString } from '@sniptt/guards'; -import { OnboardingStatus } from '~/generated-metadata/graphql'; export const RecordTableRecordGroupBodyEffect = () => { const { objectNameSingular } = useRecordTableContextOrThrow(); + const { recordTableId } = useRecordTableContextOrThrow(); - const [hasInitialized, setHasInitialized] = useState(false); + const setRecordTableData = useSetRecordTableData({ + recordTableId, + }); - const onboardingStatus = useOnboardingStatus(); + const setIsRecordTableInitialLoading = useSetRecoilComponentStateV2( + isRecordTableInitialLoadingComponentState, + ); const recordGroupId = useCurrentRecordGroupId(); - const [hasInitializedScroll, setHasInitializedScroll] = useState(false); - - const { - findManyRecords, - records, - totalCount, - setRecordTableData, - loading, - hasNextPage, - } = useLazyLoadRecordIndexTable(objectNameSingular); + const { records, loading, hasNextPage } = + useRecordIndexTableQuery(objectNameSingular); const setHasRecordFetchedAllRecordsComponents = useSetRecoilComponentFamilyStateV2( @@ -44,7 +42,26 @@ export const RecordTableRecordGroupBodyEffect = () => { const { scrollToPosition } = useScrollToPosition(); useEffect(() => { - if (isNonEmptyString(lastShowPageRecordId) && !hasInitializedScroll) { + if (!loading) { + setRecordTableData({ + records, + currentRecordGroupId: recordGroupId, + }); + setIsRecordTableInitialLoading(false); + setHasRecordFetchedAllRecordsComponents(!hasNextPage); + } + }, [ + hasNextPage, + loading, + records, + recordGroupId, + setHasRecordFetchedAllRecordsComponents, + setIsRecordTableInitialLoading, + setRecordTableData, + ]); + + useEffect(() => { + if (isNonEmptyString(lastShowPageRecordId)) { const recordPosition = records.findIndex( (record) => record.id === lastShowPageRecordId, ); @@ -53,44 +70,9 @@ export const RecordTableRecordGroupBodyEffect = () => { const positionInPx = recordPosition * ROW_HEIGHT; scrollToPosition(positionInPx); - - setHasInitializedScroll(true); } } - }, [ - loading, - lastShowPageRecordId, - records, - scrollToPosition, - hasInitializedScroll, - ]); - - useEffect(() => { - if (!loading) { - setRecordTableData({ - records, - currentRecordGroupId: recordGroupId, - totalCount, - }); - } - }, [records, totalCount, setRecordTableData, loading, recordGroupId]); - - useEffect(() => { - const allRecordsHaveBeenFetched = !hasNextPage; - - setHasRecordFetchedAllRecordsComponents(allRecordsHaveBeenFetched); - }, [hasNextPage, setHasRecordFetchedAllRecordsComponents]); - - useEffect(() => { - if (onboardingStatus !== OnboardingStatus.COMPLETED) { - return; - } - - if (!hasInitialized) { - findManyRecords(); - setHasInitialized(true); - } - }, [onboardingStatus, findManyRecords, hasInitialized]); + }, [lastShowPageRecordId, records, scrollToPosition]); return <>; }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx index 0f59433a7..b441d0154 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-section/components/RecordTableRecordGroupSectionLoadMore.tsx @@ -1,6 +1,5 @@ import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; -import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable'; -import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState'; +import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore'; import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; @@ -14,26 +13,23 @@ export const RecordTableRecordGroupSectionLoadMore = () => { const currentRecordGroupId = useCurrentRecordGroupId(); - const { fetchMoreRecords } = useLazyLoadRecordIndexTable(objectNameSingular); + const { fetchMoreRecordsLazy } = + useRecordIndexTableFetchMore(objectNameSingular); const hasFetchedAllRecords = useRecoilComponentFamilyValueV2( recordIndexHasFetchedAllRecordsByGroupComponentState, currentRecordGroupId, ); - const isLoadMoreLocked = useRecoilComponentValueV2( - isRecordIndexLoadMoreLockedComponentState, - ); - const recordIds = useRecoilComponentValueV2( recordIndexAllRecordIdsComponentSelector, ); const handleLoadMore = () => { - fetchMoreRecords(); + fetchMoreRecordsLazy(); }; - if (hasFetchedAllRecords || isLoadMoreLocked) { + if (hasFetchedAllRecords) { return null; } diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/onEntityCountChangeComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/onEntityCountChangeComponentState.ts deleted file mode 100644 index ecdd0d022..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/states/onEntityCountChangeComponentState.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; - -export const onEntityCountChangeComponentState = createComponentStateV2< - ((entityCount?: number, currentRecordGroupId?: string) => void) | undefined ->({ - key: 'onEntityCountChangeComponentState', - defaultValue: undefined, - componentInstanceContext: RecordTableComponentInstanceContext, -}); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts deleted file mode 100644 index 58781b87b..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; - -export const tableEncounteredUnrecoverableErrorComponentState = - createComponentStateV2({ - key: 'tableEncounteredUnrecoverableErrorComponentState', - defaultValue: false, - componentInstanceContext: RecordTableComponentInstanceContext, - }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/states/tableLastRowVisibleComponentState.ts b/packages/twenty-front/src/modules/object-record/record-table/states/tableLastRowVisibleComponentState.ts deleted file mode 100644 index 83495913e..000000000 --- a/packages/twenty-front/src/modules/object-record/record-table/states/tableLastRowVisibleComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; -import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; - -export const tableLastRowVisibleComponentState = - createComponentStateV2({ - key: 'tableLastRowVisibleComponentState', - defaultValue: false, - componentInstanceContext: RecordTableComponentInstanceContext, - }); diff --git a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollToPosition.ts b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollToPosition.ts index 46bcb5c13..ea035fd8d 100644 --- a/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollToPosition.ts +++ b/packages/twenty-front/src/modules/ui/utilities/scroll/hooks/useScrollToPosition.ts @@ -1,11 +1,15 @@ import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; +import { useCallback } from 'react'; export const useScrollToPosition = () => { const { scrollWrapperHTMLElement } = useScrollWrapperElement(); - const scrollToPosition = (scrollPositionInPx: number) => { - scrollWrapperHTMLElement?.scrollTo({ top: scrollPositionInPx }); - }; + const scrollToPosition = useCallback( + (scrollPositionInPx: number) => { + scrollWrapperHTMLElement?.scrollTo({ top: scrollPositionInPx }); + }, + [scrollWrapperHTMLElement], + ); return { scrollToPosition }; }; diff --git a/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2.ts b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2.ts new file mode 100644 index 000000000..7a2002720 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyCallbackStateV2.ts @@ -0,0 +1,97 @@ +/* eslint-disable prefer-arrow/prefer-arrow-functions */ +import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; +import { ComponentFamilyReadOnlySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyReadOnlySelectorV2'; +import { ComponentFamilySelectorV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilySelectorV2'; +import { ComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/types/ComponentFamilyStateV2'; +import { globalComponentInstanceContextMap } from '@/ui/utilities/state/component-state/utils/globalComponentInstanceContextMap'; +import { useCallback } from 'react'; +import { RecoilState, RecoilValueReadOnly, SerializableParam } from 'recoil'; + +export function useRecoilComponentFamilyCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyState: ComponentFamilyStateV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentFamilyCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilySelector: ComponentFamilySelectorV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentFamilyCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyReadOnlySelector: ComponentFamilyReadOnlySelectorV2< + ValueType, + FamilyKey + >, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilValueReadOnly; +export function useRecoilComponentFamilyCallbackStateV2< + ValueType, + FamilyKey extends SerializableParam, +>( + componentFamilyState: ComponentFamilyStateV2, + instanceIdFromProps?: string, +): (familyKey: FamilyKey) => RecoilState; +export function useRecoilComponentFamilyCallbackStateV2< + ComponentState extends + | ComponentFamilyStateV2 + | ComponentFamilySelectorV2 + | ComponentFamilyReadOnlySelectorV2, + ValueType, + FamilyKey extends SerializableParam = never, +>( + componentState: ComponentState, + instanceIdFromProps?: string, +): + | RecoilState + | RecoilValueReadOnly + | ((familyKey: FamilyKey) => RecoilState) + | ((familyKey: FamilyKey) => RecoilValueReadOnly) { + const componentStateKey = componentState.key; + + const componentInstanceContext = + globalComponentInstanceContextMap.get(componentStateKey); + + if (!componentInstanceContext) { + throw new Error( + `Instance context for key "${componentStateKey}" is not defined, check the component state declaration.`, + ); + } + + const instanceId = useAvailableComponentInstanceIdOrThrow( + componentInstanceContext, + instanceIdFromProps, + ); + + return useCallback( + (familyKey: FamilyKey) => { + switch (componentState.type) { + case 'ComponentFamilyState': { + return componentState.atomFamily({ + instanceId, + familyKey, + }); + } + case 'ComponentFamilySelector': { + return componentState.selectorFamily({ + instanceId, + familyKey, + }); + } + case 'ComponentFamilyReadOnlySelector': { + return componentState.selectorFamily({ + instanceId, + familyKey, + }); + } + } + }, + [componentState, instanceId], + ); +} diff --git a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts index d7118e2af..08f9a676b 100644 --- a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts @@ -26,9 +26,9 @@ import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFi import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter'; import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; -import { isDefined } from 'twenty-shared/utils'; export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const currentViewIdCallbackState = useRecoilComponentCallbackStateV2( @@ -52,7 +52,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const { findManyRecords } = useLazyFindManyRecords({ + const { findManyRecordsLazy } = useLazyFindManyRecords({ objectNameSingular: CoreObjectNameSingular.View, fetchPolicy: 'network-only', }); @@ -204,14 +204,14 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { await createViewSortRecords(viewSortsToCreate, newView); } - await findManyRecords(); + await findManyRecordsLazy(); set(isPersistingViewFieldsState, false); }, [ currentViewIdCallbackState, createOneRecord, createViewFieldRecords, - findManyRecords, + findManyRecordsLazy, objectMetadataItem.fields, createViewGroupRecords, createViewSortRecords, diff --git a/packages/twenty-front/src/modules/views/hooks/useRefreshViews.ts b/packages/twenty-front/src/modules/views/hooks/useRefreshViews.ts index 0f2b04750..9249eff7e 100644 --- a/packages/twenty-front/src/modules/views/hooks/useRefreshViews.ts +++ b/packages/twenty-front/src/modules/views/hooks/useRefreshViews.ts @@ -12,7 +12,7 @@ export const useRefreshCachedViews = () => { ), }); - const { findManyRecords: refreshCachedViews } = useLazyFindManyRecords({ + const { findManyRecordsLazy: refreshCachedViews } = useLazyFindManyRecords({ objectNameSingular: CoreObjectNameSingular.View, filter: findAllViewsOperationSignature.variables.filter, recordGqlFields: findAllViewsOperationSignature.fields, diff --git a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx index 2225e1476..052102e5e 100644 --- a/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/RecordTableDecorator.tsx @@ -12,8 +12,11 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; -import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext'; -import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; +import { + RecordTableContextProvider, + useRecordTableContextOrThrow, +} from '@/object-record/record-table/contexts/RecordTableContext'; +import { useSetRecordTableData } from '@/object-record/record-table/hooks/internal/useSetRecordTableData'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; @@ -31,9 +34,12 @@ const InternalTableStateLoaderEffect = ({ }: { objectMetadataItem: ObjectMetadataItem; }) => { + const { recordTableId } = useRecordTableContextOrThrow(); const { loadRecordIndexStates } = useLoadRecordIndexStates(); - const { setRecordTableData } = useRecordTable(); + const setRecordTableData = useSetRecordTableData({ + recordTableId, + }); const view = useMemo(() => { return { @@ -48,7 +54,6 @@ const InternalTableStateLoaderEffect = ({ loadRecordIndexStates(view, objectMetadataItem); setRecordTableData({ records: getCompaniesMock(), - totalCount: getCompaniesMock().length, }); }, [loadRecordIndexStates, objectMetadataItem, setRecordTableData, view]); @@ -149,12 +154,12 @@ export const RecordTableDecorator: Decorator = (Story, context) => { instanceId: getActionMenuIdFromRecordIndexId(recordIndexId), }} > - +