From c878f09d72660e7c6e605a1959b637f943ed9791 Mon Sep 17 00:00:00 2001 From: eliasylonen Date: Fri, 29 Nov 2024 10:59:19 +0100 Subject: [PATCH] Fix token expiration error loop (#6731) (#8802) Fixes issue https://github.com/twentyhq/twenty/issues/6731 **Problem:** After access token token expires, scrolling down the `RecordTable` component will put it to an infinite loop of trying to fetch records and printing errors on every iteration. **Solution:** Disable fetching until component remount if a `FORBIDDEN` error is encountered. --------- Co-authored-by: ad-elias --- .../useFetchMoreRecordsWithPagination.ts | 1 + .../RecordTableNoRecordGroupBodyEffect.tsx | 27 ++++++++++++++++--- ...unteredUnrecoverableErrorComponentState.ts | 9 +++++++ 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts 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 8eb10ecc4..5f19c4edc 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useFetchMoreRecordsWithPagination.ts @@ -188,6 +188,7 @@ export const useFetchMoreRecordsWithPagination = < }; } catch (error) { handleFindManyRecordsError(error as ApolloError); + return { error: error as ApolloError }; } finally { setIsFetchingMoreObjects(false); } 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 76a29fcca..89fc0e8f3 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 @@ -13,6 +13,8 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; import { isNonEmptyString } from '@sniptt/guards'; import { useScrollToPosition } from '~/hooks/useScrollToPosition'; +import { tableEncounteredUnrecoverableErrorComponentState } from '@/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; export const RecordTableNoRecordGroupBodyEffect = () => { const { objectNameSingular } = useContext(RecordTableContext); @@ -37,6 +39,9 @@ export const RecordTableNoRecordGroupBodyEffect = () => { tableLastRowVisibleComponentState, ); + const [encounteredUnrecoverableError, setEncounteredUnrecoverableError] = + useRecoilComponentStateV2(tableEncounteredUnrecoverableErrorComponentState); + const setHasRecordTableFetchedAllRecordsComponents = useSetRecoilComponentStateV2( hasRecordTableFetchedAllRecordsComponentStateV2, @@ -86,7 +91,7 @@ export const RecordTableNoRecordGroupBodyEffect = () => { const fetchMoreDebouncedIfRequested = useDebouncedCallback(async () => { // We are debouncing here to give the user some room to scroll if they want to within this throttle window - await fetchMoreRecords(); + return await fetchMoreRecords(); }, 100); useEffect(() => { @@ -97,8 +102,22 @@ export const RecordTableNoRecordGroupBodyEffect = () => { useEffect(() => { (async () => { - if (!isFetchingMoreObjects && tableLastRowVisible && hasNextPage) { - await fetchMoreDebouncedIfRequested(); + 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); + } } })(); }, [ @@ -109,6 +128,8 @@ export const RecordTableNoRecordGroupBodyEffect = () => { fetchMoreDebouncedIfRequested, isFetchingMoreObjects, tableLastRowVisible, + encounteredUnrecoverableError, + setEncounteredUnrecoverableError, ]); return <>; 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 new file mode 100644 index 000000000..58781b87b --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-table/states/tableEncounteredUnrecoverableErrorComponentState.ts @@ -0,0 +1,9 @@ +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, + });