Fix table loading (#12653)

As per title
This commit is contained in:
Charles Bochet
2025-06-17 15:01:28 +02:00
committed by GitHub
parent fb9d5066dc
commit f3a8b849aa
29 changed files with 592 additions and 467 deletions

View File

@ -1,9 +1,8 @@
import { expect } from '@storybook/test'; import { renderHook, waitFor } from '@testing-library/react';
import { renderHook } from '@testing-library/react'; import { ReactNode } from 'react';
import { ReactNode, act } from 'react';
import { RecordGroupContext } from '@/object-record/record-group/states/context/RecordGroupContext'; 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 { RecordTableComponentInstance } from '@/object-record/record-table/components/RecordTableComponentInstance';
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
import { MockedResponse } from '@apollo/client/testing'; import { MockedResponse } from '@apollo/client/testing';
@ -679,16 +678,14 @@ const Wrapper = ({ children }: { children: ReactNode }) => {
); );
}; };
describe('useLazyLoadRecordIndexTable', () => { describe('useRecordIndexTableQuery', () => {
it('should fetch', async () => { it('should fetch', async () => {
const { result } = renderHook( const { result } = renderHook(
() => { () => {
const { findManyRecords, ...result } = const { records } = useRecordIndexTableQuery(objectNameSingular);
useLazyLoadRecordIndexTable(objectNameSingular);
return { return {
findManyRecords, records,
...result,
}; };
}, },
{ {
@ -696,12 +693,8 @@ describe('useLazyLoadRecordIndexTable', () => {
}, },
); );
expect(result.current.loading).toBe(false); await waitFor(() => {
await act(async () => {
await result.current.findManyRecords();
});
expect(result.current.records).toHaveLength(16); expect(result.current.records).toHaveLength(16);
}); });
}); });
});

View File

@ -24,10 +24,10 @@ import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyReco
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier'; import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
import { capitalize, isDefined } from 'twenty-shared/utils';
import { cursorFamilyState } from '../states/cursorFamilyState'; import { cursorFamilyState } from '../states/cursorFamilyState';
import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState'; import { hasNextPageFamilyState } from '../states/hasNextPageFamilyState';
import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState'; import { isFetchingMoreRecordsFamilyState } from '../states/isFetchingMoreRecordsFamilyState';
import { capitalize, isDefined } from 'twenty-shared/utils';
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier & export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
RecordGqlOperationVariables & { RecordGqlOperationVariables & {

View File

@ -119,7 +119,7 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
loading, loading,
error, error,
fetchMoreRecords, fetchMoreRecords,
queryStateIdentifier: queryIdentifier, queryIdentifier,
hasNextPage, hasNextPage,
pageInfo, pageInfo,
}; };

View File

@ -1,4 +1,4 @@
import { useRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection'; 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 { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted'; import { OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
import { useCallback } from 'react';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
export const useHandleFindManyRecordsCompleted = <T>({ export const useHandleFindManyRecordsCompleted = <T>({
@ -17,15 +18,14 @@ export const useHandleFindManyRecordsCompleted = <T>({
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
onCompleted?: OnFindManyRecordsCompleted<T>; onCompleted?: OnFindManyRecordsCompleted<T>;
}) => { }) => {
const [, setLastCursor] = useRecoilState(cursorFamilyState(queryIdentifier)); const setLastCursor = useSetRecoilState(cursorFamilyState(queryIdentifier));
const [, setHasNextPage] = useRecoilState( const setHasNextPage = useSetRecoilState(
hasNextPageFamilyState(queryIdentifier), hasNextPageFamilyState(queryIdentifier),
); );
const handleFindManyRecordsCompleted = ( const handleFindManyRecordsCompleted = useCallback(
data: RecordGqlOperationFindManyResult, (data: RecordGqlOperationFindManyResult) => {
) => {
if (!isDefined(data)) { if (!isDefined(data)) {
onCompleted?.([]); onCompleted?.([]);
} }
@ -45,7 +45,9 @@ export const useHandleFindManyRecordsCompleted = <T>({
setLastCursor(pageInfo.endCursor ?? ''); setLastCursor(pageInfo.endCursor ?? '');
setHasNextPage(pageInfo.hasNextPage ?? false); setHasNextPage(pageInfo.hasNextPage ?? false);
} }
}; },
[onCompleted, objectMetadataItem.namePlural, setLastCursor, setHasNextPage],
);
return { return {
handleFindManyRecordsCompleted, handleFindManyRecordsCompleted,

View File

@ -4,6 +4,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { logError } from '~/utils/logError'; import { logError } from '~/utils/logError';
import { useCallback } from 'react';
export const useHandleFindManyRecordsError = ({ export const useHandleFindManyRecordsError = ({
handleError, handleError,
@ -14,7 +15,8 @@ export const useHandleFindManyRecordsError = ({
}) => { }) => {
const { enqueueSnackBar } = useSnackBar(); const { enqueueSnackBar } = useSnackBar();
const handleFindManyRecordsError = (error: ApolloError) => { const handleFindManyRecordsError = useCallback(
(error: ApolloError) => {
logError( logError(
`useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` + `useFindManyRecords for "${objectMetadataItem.namePlural}" error : ` +
error, error,
@ -23,7 +25,9 @@ export const useHandleFindManyRecordsError = ({
variant: SnackBarVariant.Error, variant: SnackBarVariant.Error,
}); });
handleError?.(error); handleError?.(error);
}; },
[enqueueSnackBar, handleError, objectMetadataItem.namePlural],
);
return { return {
handleFindManyRecordsError, handleFindManyRecordsError,

View File

@ -34,7 +34,7 @@ export const useLazyFetchAllRecords = <T>({
const [progress, setProgress] = useState<ExportProgress>({ const [progress, setProgress] = useState<ExportProgress>({
displayType: 'number', displayType: 'number',
}); });
const { fetchMore, findManyRecords } = useLazyFindManyRecords({ const { fetchMoreRecordsLazy, findManyRecordsLazy } = useLazyFindManyRecords({
objectNameSingular, objectNameSingular,
filter, filter,
orderBy, orderBy,
@ -47,12 +47,12 @@ export const useLazyFetchAllRecords = <T>({
}); });
const fetchAllRecords = useCallback(async () => { const fetchAllRecords = useCallback(async () => {
if (!isDefined(findManyRecords)) { if (!isDefined(findManyRecordsLazy)) {
return []; return [];
} }
setIsDownloading(true); setIsDownloading(true);
const findManyRecordsDataResult = await findManyRecords(); const findManyRecordsDataResult = await findManyRecordsLazy();
const firstQueryResult = const firstQueryResult =
findManyRecordsDataResult?.data?.[objectMetadataItem.namePlural]; findManyRecordsDataResult?.data?.[objectMetadataItem.namePlural];
@ -84,7 +84,7 @@ export const useLazyFetchAllRecords = <T>({
break; break;
} }
if (!isDefined(fetchMore)) { if (!isDefined(fetchMoreRecordsLazy)) {
break; break;
} }
@ -92,12 +92,7 @@ export const useLazyFetchAllRecords = <T>({
await sleep(delayMs); await sleep(delayMs);
} }
const rawResult = await fetchMore({ const rawResult = await fetchMoreRecordsLazy();
variables: {
lastCursor: lastCursor,
limit,
},
});
const fetchMoreResult = rawResult?.data?.[objectMetadataItem.namePlural]; const fetchMoreResult = rawResult?.data?.[objectMetadataItem.namePlural];
@ -126,8 +121,8 @@ export const useLazyFetchAllRecords = <T>({
return records; return records;
}, [ }, [
delayMs, delayMs,
fetchMore, fetchMoreRecordsLazy,
findManyRecords, findManyRecordsLazy,
objectMetadataItem.namePlural, objectMetadataItem.namePlural,
limit, limit,
maximumRequests, maximumRequests,

View File

@ -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<T> = ObjectMetadataItemIdentifier &
RecordGqlOperationVariables & {
onCompleted?: OnFindManyRecordsCompleted<T>;
skip?: boolean;
recordGqlFields?: RecordGqlOperationGqlRecordFields;
fetchPolicy?: WatchQueryFetchPolicy;
};
type UseFindManyRecordsStateParams<
T,
TData = RecordGqlOperationFindManyResult,
> = Omit<
UseFindManyRecordsParams<T>,
'skip' | 'recordGqlFields' | 'fetchPolicy' | 'onCompleted'
> & {
data: RecordGqlOperationFindManyResult | undefined;
error: ApolloError | undefined;
fetchMore<
TFetchData = TData,
TFetchVars extends OperationVariables = OperationVariables,
>(
fetchMoreOptions: FetchMoreQueryOptions<TFetchVars, TFetchData> & {
updateQuery?: (
previousQueryResult: TData,
options: {
fetchMoreResult: TFetchData;
variables: TFetchVars;
},
) => TData;
},
): Promise<ApolloQueryResult<TFetchData>>;
objectMetadataItem: ObjectMetadataItem;
};
export const useLazyFetchMoreRecordsWithPagination = <
T extends ObjectRecord = ObjectRecord,
>({
objectNameSingular,
filter,
orderBy,
limit,
error,
fetchMore,
objectMetadataItem,
}: UseFindManyRecordsStateParams<T>) => {
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,
};
};

View File

@ -2,12 +2,13 @@ import { useLazyQuery } from '@apollo/client';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { getRecordsFromRecordConnection } from '@/object-record/cache/utils/getRecordsFromRecordConnection';
import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult'; import { RecordGqlOperationFindManyResult } from '@/object-record/graphql/types/RecordGqlOperationFindManyResult';
import { useFetchMoreRecordsWithPagination } from '@/object-record/hooks/useFetchMoreRecordsWithPagination';
import { UseFindManyRecordsParams } from '@/object-record/hooks/useFindManyRecords'; import { UseFindManyRecordsParams } from '@/object-record/hooks/useFindManyRecords';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery'; import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted'; import { useHandleFindManyRecordsCompleted } from '@/object-record/hooks/useHandleFindManyRecordsCompleted';
import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError'; import { useHandleFindManyRecordsError } from '@/object-record/hooks/useHandleFindManyRecordsError';
import { useLazyFetchMoreRecordsWithPagination } from '@/object-record/hooks/useLazyFetchMoreRecordsWithPagination';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject'; import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState'; import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState'; import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
@ -16,7 +17,7 @@ import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
type UseLazyFindManyRecordsParams<T> = Omit< type UseLazyFindManyRecordsParams<T> = Omit<
UseFindManyRecordsParams<T>, UseFindManyRecordsParams<T>,
'skip' 'skip' | 'onCompleted' | 'onError'
>; >;
export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
@ -25,9 +26,6 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
orderBy, orderBy,
limit, limit,
recordGqlFields, recordGqlFields,
fetchPolicy,
onCompleted,
onError,
}: UseLazyFindManyRecordsParams<T>) => { }: UseLazyFindManyRecordsParams<T>) => {
const { objectMetadataItem } = useObjectMetadataItem({ const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular, objectNameSingular,
@ -40,7 +38,6 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
const { handleFindManyRecordsError } = useHandleFindManyRecordsError({ const { handleFindManyRecordsError } = useHandleFindManyRecordsError({
objectMetadataItem, objectMetadataItem,
handleError: onError,
}); });
const queryIdentifier = getQueryIdentifier({ const queryIdentifier = getQueryIdentifier({
@ -53,7 +50,6 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
const { handleFindManyRecordsCompleted } = useHandleFindManyRecordsCompleted({ const { handleFindManyRecordsCompleted } = useHandleFindManyRecordsCompleted({
objectMetadataItem, objectMetadataItem,
queryIdentifier, queryIdentifier,
onCompleted,
}); });
const objectPermissions = useObjectPermissionsForObject( const objectPermissions = useObjectPermissionsForObject(
@ -62,25 +58,23 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
const hasReadPermission = objectPermissions.canReadObjectRecords; const hasReadPermission = objectPermissions.canReadObjectRecords;
const [findManyRecords, { data, loading, error, fetchMore }] = const [findManyRecords, { data, error, fetchMore }] =
useLazyQuery<RecordGqlOperationFindManyResult>(findManyRecordsQuery, { useLazyQuery<RecordGqlOperationFindManyResult>(findManyRecordsQuery, {
variables: { variables: {
filter, filter,
limit, limit,
orderBy, orderBy,
}, },
fetchPolicy: fetchPolicy, fetchPolicy: 'network-only',
onCompleted: handleFindManyRecordsCompleted, onCompleted: handleFindManyRecordsCompleted,
onError: handleFindManyRecordsError, onError: handleFindManyRecordsError,
}); });
const { fetchMoreRecords, totalCount, records, hasNextPage } = const { fetchMoreRecordsLazy } = useLazyFetchMoreRecordsWithPagination<T>({
useFetchMoreRecordsWithPagination<T>({
objectNameSingular, objectNameSingular,
filter, filter,
orderBy, orderBy,
limit, limit,
onCompleted,
fetchMore, fetchMore,
data, data,
error, error,
@ -96,9 +90,10 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
return { return {
data: null, data: null,
loading: false, records: [],
totalCount: 0,
hasNextPage: false,
error: undefined, error: undefined,
called: true,
}; };
} }
@ -115,7 +110,29 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
set(hasNextPageFamilyState(queryIdentifier), hasNextPage); set(hasNextPageFamilyState(queryIdentifier), hasNextPage);
set(cursorFamilyState(queryIdentifier), lastCursor); 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, hasReadPermission,
@ -126,16 +143,8 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
); );
return { return {
objectMetadataItem, findManyRecordsLazy,
records, fetchMoreRecordsLazy,
totalCount, queryIdentifier,
loading: hasReadPermission ? loading : false,
error: hasReadPermission ? error : undefined,
fetchMore,
fetchMoreRecords,
queryStateIdentifier: queryIdentifier,
findManyRecords: findManyRecordsLazy,
hasNextPage,
hasReadPermission,
}; };
}; };

View File

@ -6,8 +6,6 @@ import { useRecoilValue } from 'recoil';
import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext'; import { RecordBoardColumnContext } from '@/object-record/record-board/record-board-column/contexts/RecordBoardColumnContext';
import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState'; import { isRecordBoardFetchingRecordsByColumnFamilyState } from '@/object-record/record-board/states/isRecordBoardFetchingRecordsByColumnFamilyState';
import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState'; 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 { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
import { GRAY_SCALE } from 'twenty-ui/theme'; import { GRAY_SCALE } from 'twenty-ui/theme';
@ -33,23 +31,11 @@ export const RecordBoardColumnFetchMoreLoader = () => {
columnDefinition.id, columnDefinition.id,
); );
const isLoadMoreLocked = useRecoilComponentValueV2(
isRecordIndexLoadMoreLockedComponentState,
);
const { ref, inView } = useInView(); const { ref, inView } = useInView();
useEffect(() => { useEffect(() => {
if (isLoadMoreLocked) {
return;
}
setShouldFetchMore(inView); setShouldFetchMore(inView);
}, [setShouldFetchMore, inView, isLoadMoreLocked]); }, [setShouldFetchMore, inView]);
if (isLoadMoreLocked) {
return null;
}
return ( return (
<div ref={ref}> <div ref={ref}>

View File

@ -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,
};
};

View File

@ -84,13 +84,8 @@ export const useLoadRecordIndexBoardColumn = ({
}, },
]); ]);
const { const { records, loading, fetchMoreRecords, queryIdentifier, hasNextPage } =
records, useFindManyRecords({
loading,
fetchMoreRecords,
queryStateIdentifier,
hasNextPage,
} = useFindManyRecords({
objectNameSingular, objectNameSingular,
filter: combinedFilters, filter: combinedFilters,
orderBy, orderBy,
@ -110,7 +105,7 @@ export const useLoadRecordIndexBoardColumn = ({
records, records,
loading, loading,
fetchMoreRecords, fetchMoreRecords,
queryStateIdentifier, queryIdentifier,
hasNextPage, hasNextPage,
}; };
}; };

View File

@ -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,
};
};

View File

@ -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,
};
};

View File

@ -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<boolean>({
key: 'isRecordIndexLoadMoreLockedComponentState',
componentInstanceContext: ViewComponentInstanceContext,
defaultValue: false,
});

View File

@ -6,7 +6,6 @@ import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefin
type RecordTableComponentInstanceEffectProps = { type RecordTableComponentInstanceEffectProps = {
onColumnsChange: (columns: ColumnDefinition<FieldMetadata>[]) => void; onColumnsChange: (columns: ColumnDefinition<FieldMetadata>[]) => void;
onEntityCountChange?: (count: number) => void | Promise<void>;
}; };
export const RecordTableComponentInstanceEffect = ({ export const RecordTableComponentInstanceEffect = ({

View File

@ -11,24 +11,20 @@ import { recordTableHoverPositionComponentState } from '@/object-record/record-t
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue'; import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; 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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
type useSetRecordTableDataProps = { type useSetRecordTableDataProps = {
recordTableId?: string; recordTableId?: string;
onEntityCountChange: (
entityCount?: number,
currentRecordGroupId?: string,
) => void;
}; };
export const useSetRecordTableData = ({ export const useSetRecordTableData = ({
recordTableId, recordTableId,
onEntityCountChange,
}: useSetRecordTableDataProps) => { }: useSetRecordTableDataProps) => {
const recordIndexRecordIdsByGroupFamilyState = const recordIndexRecordIdsByGroupFamilyState =
useRecoilComponentCallbackStateV2( useRecoilComponentFamilyCallbackStateV2(
recordIndexRecordIdsByGroupComponentFamilyState, recordIndexRecordIdsByGroupComponentFamilyState,
recordTableId, recordTableId,
); );
@ -38,7 +34,7 @@ export const useSetRecordTableData = ({
recordTableId, recordTableId,
); );
const isRowSelectedFamilyState = useRecoilComponentCallbackStateV2( const isRowSelectedFamilyState = useRecoilComponentFamilyCallbackStateV2(
isRowSelectedComponentFamilyState, isRowSelectedComponentFamilyState,
recordTableId, recordTableId,
); );
@ -61,11 +57,9 @@ export const useSetRecordTableData = ({
<T extends ObjectRecord>({ <T extends ObjectRecord>({
records, records,
currentRecordGroupId, currentRecordGroupId,
totalCount,
}: { }: {
records: T[]; records: T[];
currentRecordGroupId?: string; currentRecordGroupId?: string;
totalCount?: number;
}) => { }) => {
for (const record of records) { for (const record of records) {
// TODO: refactor with scoped state later // TODO: refactor with scoped state later
@ -115,8 +109,6 @@ export const useSetRecordTableData = ({
} else { } else {
set(recordIndexAllRecordIdsSelector, recordIds); set(recordIndexAllRecordIdsSelector, recordIds);
} }
onEntityCountChange(totalCount, currentRecordGroupId);
} }
}, },
[ [
@ -125,7 +117,6 @@ export const useSetRecordTableData = ({
hasUserSelectedAllRowsState, hasUserSelectedAllRowsState,
setIsFocusActiveForCurrentPosition, setIsFocusActiveForCurrentPosition,
setRecordTableHoverPosition, setRecordTableHoverPosition,
onEntityCountChange,
isRowSelectedFamilyState, isRowSelectedFamilyState,
], ],
); );

View File

@ -11,18 +11,15 @@ import { availableTableColumnsComponentState } from '@/object-record/record-tabl
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext'; import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { onColumnsChangeComponentState } from '@/object-record/record-table/states/onColumnsChangeComponentState'; 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 { useRecordTableMove } from '@/object-record/record-table/hooks/useRecordTableMove';
import { onToggleColumnSortComponentState } from '@/object-record/record-table/states/onToggleColumnSortComponentState'; 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 { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2'; import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { useLeaveTableFocus } from './internal/useLeaveTableFocus'; import { useLeaveTableFocus } from './internal/useLeaveTableFocus';
import { useResetTableRowSelection } from './internal/useResetTableRowSelection'; import { useResetTableRowSelection } from './internal/useResetTableRowSelection';
import { useSelectAllRows } from './internal/useSelectAllRows'; import { useSelectAllRows } from './internal/useSelectAllRows';
import { useSetRecordTableData } from './internal/useSetRecordTableData';
import { useSetRecordTableFocusPosition } from './internal/useSetRecordTableFocusPosition'; import { useSetRecordTableFocusPosition } from './internal/useSetRecordTableFocusPosition';
import { useSetRowSelectedState } from './internal/useSetRowSelectedState'; import { useSetRowSelectedState } from './internal/useSetRowSelectedState';
type useRecordTableProps = { type useRecordTableProps = {
@ -56,11 +53,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
[availableTableColumnsState], [availableTableColumnsState],
); );
const setOnEntityCountChange = useSetRecoilComponentStateV2(
onEntityCountChangeComponentState,
recordTableId,
);
const setOnColumnsChange = useSetRecoilComponentStateV2( const setOnColumnsChange = useSetRecoilComponentStateV2(
onColumnsChangeComponentState, onColumnsChangeComponentState,
recordTableId, recordTableId,
@ -76,11 +68,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
recordTableId, recordTableId,
); );
const setRecordTableLastRowVisible = useSetRecoilComponentStateV2(
tableLastRowVisibleComponentState,
recordTableId,
);
const onColumnsChangeState = useRecoilComponentCallbackStateV2( const onColumnsChangeState = useRecoilComponentCallbackStateV2(
onColumnsChangeComponentState, onColumnsChangeComponentState,
recordTableId, recordTableId,
@ -99,29 +86,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
[onColumnsChangeState], [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 leaveTableFocus = useLeaveTableFocus(recordTableId);
const setRowSelected = useSetRowSelectedState(recordTableId); const setRowSelected = useSetRowSelectedState(recordTableId);
@ -139,8 +103,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
return { return {
onColumnsChange, onColumnsChange,
setAvailableTableColumns, setAvailableTableColumns,
setOnEntityCountChange,
setRecordTableData,
leaveTableFocus, leaveTableFocus,
setRowSelected, setRowSelected,
resetTableRowSelection, resetTableRowSelection,
@ -148,7 +110,6 @@ export const useRecordTable = (props?: useRecordTableProps) => {
selectAllRows, selectAllRows,
setOnColumnsChange, setOnColumnsChange,
setIsRecordTableInitialLoading, setIsRecordTableInitialLoading,
setRecordTableLastRowVisible,
setFocusPosition, setFocusPosition,
setHasUserSelectedAllRows, setHasUserSelectedAllRows,
setOnToggleColumnSort, setOnToggleColumnSort,

View File

@ -1,13 +1,15 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useInView } from 'react-intersection-observer'; import { useInView } from 'react-intersection-observer';
import { useRecoilCallback } from 'recoil'; import { useRecoilState } from 'recoil';
import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState'; import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2'; 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 { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { GRAY_SCALE } from 'twenty-ui/theme'; import { GRAY_SCALE } from 'twenty-ui/theme';
import { useDebouncedCallback } from 'use-debounce';
const StyledText = styled.div` const StyledText = styled.div`
align-items: center; align-items: center;
@ -20,21 +22,13 @@ const StyledText = styled.div`
`; `;
export const RecordTableBodyFetchMoreLoader = () => { export const RecordTableBodyFetchMoreLoader = () => {
const { setRecordTableLastRowVisible } = useRecordTable(); const { recordTableId, objectNameSingular } = useRecordTableContextOrThrow();
const isRecordTableLoadMoreLocked = useRecoilComponentValueV2( const { fetchMoreRecordsLazy } =
isRecordIndexLoadMoreLockedComponentState, useRecordIndexTableFetchMore(objectNameSingular);
);
const onLastRowVisible = useRecoilCallback( const [isFetchingMoreRecords, setIsFetchingMoreRecords] = useRecoilState(
() => async (inView: boolean) => { isFetchingMoreRecordsFamilyState(recordTableId),
if (isRecordTableLoadMoreLocked) {
return;
}
setRecordTableLastRowVisible(inView);
},
[setRecordTableLastRowVisible, isRecordTableLoadMoreLocked],
); );
const { scrollWrapperHTMLElement } = useScrollWrapperElement(); const { scrollWrapperHTMLElement } = useScrollWrapperElement();
@ -43,11 +37,22 @@ export const RecordTableBodyFetchMoreLoader = () => {
hasRecordTableFetchedAllRecordsComponentStateV2, hasRecordTableFetchedAllRecordsComponentStateV2,
); );
const showLoadingMoreRow = const showLoadingMoreRow = !hasRecordTableFetchedAllRecordsComponents;
!hasRecordTableFetchedAllRecordsComponents && !isRecordTableLoadMoreLocked; const debouncedFetchMoreRecordsLazy = useDebouncedCallback(
fetchMoreRecordsLazy,
100,
);
const { ref: tbodyRef } = useInView({ const { ref: tbodyRef } = useInView({
onChange: onLastRowVisible, onChange: async (inView) => {
if (isFetchingMoreRecords || !inView) {
return;
}
setIsFetchingMoreRecords(true);
await debouncedFetchMoreRecordsLazy();
setIsFetchingMoreRecords(false);
},
delay: 1000, delay: 1000,
rootMargin: '1000px', rootMargin: '1000px',
root: scrollWrapperHTMLElement, root: scrollWrapperHTMLElement,

View File

@ -1,67 +1,73 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { useDebouncedCallback } from 'use-debounce';
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; 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 { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; 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 { hasRecordTableFetchedAllRecordsComponentStateV2 } from '@/object-record/record-table/states/hasRecordTableFetchedAllRecordsComponentStateV2';
import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState'; import { isRecordTableInitialLoadingComponentState } from '@/object-record/record-table/states/isRecordTableInitialLoadingComponentState';
import { tableLastRowVisibleComponentState } from '@/object-record/record-table/states/tableLastRowVisibleComponentState';
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState'; import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal'; import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
import { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition'; 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 { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
import { isNonEmptyString } from '@sniptt/guards'; import { isNonEmptyString } from '@sniptt/guards';
export const RecordTableNoRecordGroupBodyEffect = () => { 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 showAuthModal = useShowAuthModal();
const [hasInitializedScroll, setHasInitializedScroll] = useState(false); 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 = const setHasRecordTableFetchedAllRecordsComponents =
useSetRecoilComponentStateV2( useSetRecoilComponentStateV2(
hasRecordTableFetchedAllRecordsComponentStateV2, hasRecordTableFetchedAllRecordsComponentStateV2,
); );
const setIsRecordTableInitialLoading = useSetRecoilComponentStateV2(
const [lastShowPageRecordId, setLastShowPageRecordId] = useRecoilState( isRecordTableInitialLoadingComponentState,
lastShowPageRecordIdState,
); );
const isFetchingMoreRecords = useRecoilValue(
isFetchingMoreRecordsFamilyState(recordTableId),
);
const [lastShowPageRecordId] = useRecoilState(lastShowPageRecordIdState);
const { scrollToPosition } = useScrollToPosition(); const { scrollToPosition } = useScrollToPosition();
useEffect(() => { 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( const isRecordAlreadyFetched = records.some(
(record) => record.id === lastShowPageRecordId, (record) => record.id === lastShowPageRecordId,
); );
@ -78,76 +84,7 @@ export const RecordTableNoRecordGroupBodyEffect = () => {
setHasInitializedScroll(true); setHasInitializedScroll(true);
} }
} }
}, [ }, [hasInitializedScroll, lastShowPageRecordId, records, scrollToPosition]);
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]);
return <></>; return <></>;
}; };

View File

@ -1,37 +1,35 @@
import { useEffect, useState } from 'react'; import { useEffect } from 'react';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId'; import { lastShowPageRecordIdState } from '@/object-record/record-field/states/lastShowPageRecordId';
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; 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 { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight'; import { ROW_HEIGHT } from '@/object-record/record-table/constants/RowHeight';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; 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 { useScrollToPosition } from '@/ui/utilities/scroll/hooks/useScrollToPosition';
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2'; 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 { isNonEmptyString } from '@sniptt/guards';
import { OnboardingStatus } from '~/generated-metadata/graphql';
export const RecordTableRecordGroupBodyEffect = () => { export const RecordTableRecordGroupBodyEffect = () => {
const { objectNameSingular } = useRecordTableContextOrThrow(); 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 recordGroupId = useCurrentRecordGroupId();
const [hasInitializedScroll, setHasInitializedScroll] = useState(false); const { records, loading, hasNextPage } =
useRecordIndexTableQuery(objectNameSingular);
const {
findManyRecords,
records,
totalCount,
setRecordTableData,
loading,
hasNextPage,
} = useLazyLoadRecordIndexTable(objectNameSingular);
const setHasRecordFetchedAllRecordsComponents = const setHasRecordFetchedAllRecordsComponents =
useSetRecoilComponentFamilyStateV2( useSetRecoilComponentFamilyStateV2(
@ -44,7 +42,26 @@ export const RecordTableRecordGroupBodyEffect = () => {
const { scrollToPosition } = useScrollToPosition(); const { scrollToPosition } = useScrollToPosition();
useEffect(() => { 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( const recordPosition = records.findIndex(
(record) => record.id === lastShowPageRecordId, (record) => record.id === lastShowPageRecordId,
); );
@ -53,44 +70,9 @@ export const RecordTableRecordGroupBodyEffect = () => {
const positionInPx = recordPosition * ROW_HEIGHT; const positionInPx = recordPosition * ROW_HEIGHT;
scrollToPosition(positionInPx); scrollToPosition(positionInPx);
setHasInitializedScroll(true);
} }
} }
}, [ }, [lastShowPageRecordId, records, scrollToPosition]);
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]);
return <></>; return <></>;
}; };

View File

@ -1,6 +1,5 @@
import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId'; import { useCurrentRecordGroupId } from '@/object-record/record-group/hooks/useCurrentRecordGroupId';
import { useLazyLoadRecordIndexTable } from '@/object-record/record-index/hooks/useLazyLoadRecordIndexTable'; import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore';
import { isRecordIndexLoadMoreLockedComponentState } from '@/object-record/record-index/states/isRecordIndexLoadMoreLockedComponentState';
import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState'; import { recordIndexHasFetchedAllRecordsByGroupComponentState } from '@/object-record/record-index/states/recordIndexHasFetchedAllRecordsByGroupComponentState';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector'; import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext'; import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
@ -14,26 +13,23 @@ export const RecordTableRecordGroupSectionLoadMore = () => {
const currentRecordGroupId = useCurrentRecordGroupId(); const currentRecordGroupId = useCurrentRecordGroupId();
const { fetchMoreRecords } = useLazyLoadRecordIndexTable(objectNameSingular); const { fetchMoreRecordsLazy } =
useRecordIndexTableFetchMore(objectNameSingular);
const hasFetchedAllRecords = useRecoilComponentFamilyValueV2( const hasFetchedAllRecords = useRecoilComponentFamilyValueV2(
recordIndexHasFetchedAllRecordsByGroupComponentState, recordIndexHasFetchedAllRecordsByGroupComponentState,
currentRecordGroupId, currentRecordGroupId,
); );
const isLoadMoreLocked = useRecoilComponentValueV2(
isRecordIndexLoadMoreLockedComponentState,
);
const recordIds = useRecoilComponentValueV2( const recordIds = useRecoilComponentValueV2(
recordIndexAllRecordIdsComponentSelector, recordIndexAllRecordIdsComponentSelector,
); );
const handleLoadMore = () => { const handleLoadMore = () => {
fetchMoreRecords(); fetchMoreRecordsLazy();
}; };
if (hasFetchedAllRecords || isLoadMoreLocked) { if (hasFetchedAllRecords) {
return null; return null;
} }

View File

@ -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,
});

View File

@ -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<boolean>({
key: 'tableEncounteredUnrecoverableErrorComponentState',
defaultValue: false,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -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<boolean>({
key: 'tableLastRowVisibleComponentState',
defaultValue: false,
componentInstanceContext: RecordTableComponentInstanceContext,
});

View File

@ -1,11 +1,15 @@
import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement'; import { useScrollWrapperElement } from '@/ui/utilities/scroll/hooks/useScrollWrapperElement';
import { useCallback } from 'react';
export const useScrollToPosition = () => { export const useScrollToPosition = () => {
const { scrollWrapperHTMLElement } = useScrollWrapperElement(); const { scrollWrapperHTMLElement } = useScrollWrapperElement();
const scrollToPosition = (scrollPositionInPx: number) => { const scrollToPosition = useCallback(
(scrollPositionInPx: number) => {
scrollWrapperHTMLElement?.scrollTo({ top: scrollPositionInPx }); scrollWrapperHTMLElement?.scrollTo({ top: scrollPositionInPx });
}; },
[scrollWrapperHTMLElement],
);
return { scrollToPosition }; return { scrollToPosition };
}; };

View File

@ -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<ValueType, FamilyKey>,
instanceIdFromProps?: string,
): (familyKey: FamilyKey) => RecoilState<ValueType>;
export function useRecoilComponentFamilyCallbackStateV2<
ValueType,
FamilyKey extends SerializableParam,
>(
componentFamilySelector: ComponentFamilySelectorV2<ValueType, FamilyKey>,
instanceIdFromProps?: string,
): (familyKey: FamilyKey) => RecoilState<ValueType>;
export function useRecoilComponentFamilyCallbackStateV2<
ValueType,
FamilyKey extends SerializableParam,
>(
componentFamilyReadOnlySelector: ComponentFamilyReadOnlySelectorV2<
ValueType,
FamilyKey
>,
instanceIdFromProps?: string,
): (familyKey: FamilyKey) => RecoilValueReadOnly<ValueType>;
export function useRecoilComponentFamilyCallbackStateV2<
ValueType,
FamilyKey extends SerializableParam,
>(
componentFamilyState: ComponentFamilyStateV2<ValueType, FamilyKey>,
instanceIdFromProps?: string,
): (familyKey: FamilyKey) => RecoilState<ValueType>;
export function useRecoilComponentFamilyCallbackStateV2<
ComponentState extends
| ComponentFamilyStateV2<ValueType, FamilyKey>
| ComponentFamilySelectorV2<ValueType, FamilyKey>
| ComponentFamilyReadOnlySelectorV2<ValueType, FamilyKey>,
ValueType,
FamilyKey extends SerializableParam = never,
>(
componentState: ComponentState,
instanceIdFromProps?: string,
):
| RecoilState<ValueType>
| RecoilValueReadOnly<ValueType>
| ((familyKey: FamilyKey) => RecoilState<ValueType>)
| ((familyKey: FamilyKey) => RecoilValueReadOnly<ValueType>) {
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],
);
}

View File

@ -26,9 +26,9 @@ import { mapRecordFilterGroupToViewFilterGroup } from '@/views/utils/mapRecordFi
import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter'; import { mapRecordFilterToViewFilter } from '@/views/utils/mapRecordFilterToViewFilter';
import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort'; import { mapRecordSortToViewSort } from '@/views/utils/mapRecordSortToViewSort';
import { useRecoilCallback } from 'recoil'; import { useRecoilCallback } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
import { isDefined } from 'twenty-shared/utils';
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2( const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
@ -52,7 +52,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
const { objectMetadataItem } = useRecordIndexContextOrThrow(); const { objectMetadataItem } = useRecordIndexContextOrThrow();
const { findManyRecords } = useLazyFindManyRecords({ const { findManyRecordsLazy } = useLazyFindManyRecords({
objectNameSingular: CoreObjectNameSingular.View, objectNameSingular: CoreObjectNameSingular.View,
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
}); });
@ -204,14 +204,14 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
await createViewSortRecords(viewSortsToCreate, newView); await createViewSortRecords(viewSortsToCreate, newView);
} }
await findManyRecords(); await findManyRecordsLazy();
set(isPersistingViewFieldsState, false); set(isPersistingViewFieldsState, false);
}, },
[ [
currentViewIdCallbackState, currentViewIdCallbackState,
createOneRecord, createOneRecord,
createViewFieldRecords, createViewFieldRecords,
findManyRecords, findManyRecordsLazy,
objectMetadataItem.fields, objectMetadataItem.fields,
createViewGroupRecords, createViewGroupRecords,
createViewSortRecords, createViewSortRecords,

View File

@ -12,7 +12,7 @@ export const useRefreshCachedViews = () => {
), ),
}); });
const { findManyRecords: refreshCachedViews } = useLazyFindManyRecords({ const { findManyRecordsLazy: refreshCachedViews } = useLazyFindManyRecords({
objectNameSingular: CoreObjectNameSingular.View, objectNameSingular: CoreObjectNameSingular.View,
filter: findAllViewsOperationSignature.variables.filter, filter: findAllViewsOperationSignature.variables.filter,
recordGqlFields: findAllViewsOperationSignature.fields, recordGqlFields: findAllViewsOperationSignature.fields,

View File

@ -12,8 +12,11 @@ import { RecordIndexContextProvider } from '@/object-record/record-index/context
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext';
import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext'; import { RecordTableBodyContextProvider } from '@/object-record/record-table/contexts/RecordTableBodyContext';
import { RecordTableContextProvider } from '@/object-record/record-table/contexts/RecordTableContext'; import {
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; 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 { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
@ -31,9 +34,12 @@ const InternalTableStateLoaderEffect = ({
}: { }: {
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
}) => { }) => {
const { recordTableId } = useRecordTableContextOrThrow();
const { loadRecordIndexStates } = useLoadRecordIndexStates(); const { loadRecordIndexStates } = useLoadRecordIndexStates();
const { setRecordTableData } = useRecordTable(); const setRecordTableData = useSetRecordTableData({
recordTableId,
});
const view = useMemo(() => { const view = useMemo(() => {
return { return {
@ -48,7 +54,6 @@ const InternalTableStateLoaderEffect = ({
loadRecordIndexStates(view, objectMetadataItem); loadRecordIndexStates(view, objectMetadataItem);
setRecordTableData({ setRecordTableData({
records: getCompaniesMock(), records: getCompaniesMock(),
totalCount: getCompaniesMock().length,
}); });
}, [loadRecordIndexStates, objectMetadataItem, setRecordTableData, view]); }, [loadRecordIndexStates, objectMetadataItem, setRecordTableData, view]);
@ -149,12 +154,12 @@ export const RecordTableDecorator: Decorator = (Story, context) => {
instanceId: getActionMenuIdFromRecordIndexId(recordIndexId), instanceId: getActionMenuIdFromRecordIndexId(recordIndexId),
}} }}
> >
<InternalTableStateLoaderEffect
objectMetadataItem={objectMetadataItem}
/>
<InternalTableContextProviders <InternalTableContextProviders
objectMetadataItem={objectMetadataItem} objectMetadataItem={objectMetadataItem}
> >
<InternalTableStateLoaderEffect
objectMetadataItem={objectMetadataItem}
/>
<Story /> <Story />
</InternalTableContextProviders> </InternalTableContextProviders>
</ActionMenuComponentInstanceContext.Provider> </ActionMenuComponentInstanceContext.Provider>