Fix infinite loading on field settings (#8938)

We were experiencing infinite loading on field settings pages (creation
of new field), due to the fact that the component was being rendered on
and on and on.
This was due to useGetCurrentUserQuery calls outside of the update
function, causing renders in cascade. We also had an issue with the
component being unmounted too often.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Marie 2024-12-06 18:46:06 +01:00 committed by GitHub
parent b2be2fb398
commit f36555bdc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 28 additions and 48 deletions

View File

@ -16,10 +16,12 @@ export const ObjectMetadataItemsLoadEffect = () => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const isLoggedIn = useIsLogged();
const { objectMetadataItems: newObjectMetadataItems } =
useFindManyObjectMetadataItems({
skip: !isLoggedIn,
});
const {
objectMetadataItems: newObjectMetadataItems,
loading: isObjectMetadataLoading,
} = useFindManyObjectMetadataItems({
skip: !isLoggedIn,
});
const updateObjectMetadataItems = useRecoilCallback(
({ set, snapshot }) =>
@ -32,6 +34,7 @@ export const ObjectMetadataItemsLoadEffect = () => {
: newObjectMetadataItems;
if (
!isObjectMetadataLoading &&
!isDeeplyEqual(
snapshot.getLoadable(objectMetadataItemsState).getValue(),
toSetObjectMetadataItems,
@ -40,7 +43,12 @@ export const ObjectMetadataItemsLoadEffect = () => {
set(objectMetadataItemsState, toSetObjectMetadataItems);
}
},
[currentUser, currentWorkspace?.activationStatus, newObjectMetadataItems],
[
currentUser,
currentWorkspace?.activationStatus,
isObjectMetadataLoading,
newObjectMetadataItems,
],
);
useEffect(() => {

View File

@ -12,9 +12,8 @@ import { FIND_MANY_OBJECT_METADATA_ITEMS } from '../graphql/queries';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-ui';
import { useGetCurrentUserQuery } from '~/generated/graphql';
import { useApolloMetadataClient } from './useApolloMetadataClient';
export const useUpdateOneFieldMetadataItem = () => {
@ -23,15 +22,7 @@ export const useUpdateOneFieldMetadataItem = () => {
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
const { refetch: refetchCurrentUser } = useGetCurrentUserQuery({
onCompleted: (data) => {
if (isDefined(data?.currentUser?.defaultWorkspace)) {
setCurrentWorkspace(data.currentUser.defaultWorkspace);
}
},
});
const { findManyRecordsQuery } = useFindManyRecordsQuery({
const { findManyRecordsQuery: findManyViewsQuery } = useFindManyRecordsQuery({
objectNameSingular: CoreObjectNameSingular.View,
recordGqlFields: {
id: true,
@ -80,10 +71,11 @@ export const useUpdateOneFieldMetadataItem = () => {
refetchQueries: [getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? ''],
});
await refetchCurrentUser();
const { data } = await apolloClient.query({ query: GET_CURRENT_USER });
setCurrentWorkspace(data?.currentUser?.defaultWorkspace);
await apolloClient.query({
query: findManyRecordsQuery,
query: findManyViewsQuery,
variables: {
filter: {
objectMetadataId: {

View File

@ -1,3 +1,4 @@
import { WORKSPACE_MEMBER_QUERY_FRAGMENT } from '@/workspace-member/graphql/fragments/workspaceMemberQueryFragment';
import { gql } from '@apollo/client';
export const USER_QUERY_FRAGMENT = gql`
@ -62,4 +63,6 @@ export const USER_QUERY_FRAGMENT = gql`
}
userVars
}
${WORKSPACE_MEMBER_QUERY_FRAGMENT}
`;

View File

@ -1,4 +1,5 @@
// This query cannot be put in the graphQL folder because it cannot be generated by the graphQL codegen.
import { USER_QUERY_FRAGMENT } from '@/users/graphql/fragments/userQueryFragment';
import { gql } from '@apollo/client';
export const GET_CURRENT_USER = gql`
@ -7,4 +8,6 @@ export const GET_CURRENT_USER = gql`
...UserQueryFragment
}
}
${USER_QUERY_FRAGMENT}
`;

View File

@ -1,6 +1,6 @@
import { gql } from '@apollo/client';
export const USER_QUERY_FRAGMENT = gql`
export const WORKSPACE_MEMBER_QUERY_FRAGMENT = gql`
fragment WorkspaceMemberQueryFragment on WorkspaceMember {
id
name {

View File

@ -1,8 +1,7 @@
import { useApolloClient } from '@apollo/client';
import { zodResolver } from '@hookform/resolvers/zod';
import omit from 'lodash.omit';
import pick from 'lodash.pick';
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate, useParams } from 'react-router-dom';
import {
@ -21,7 +20,6 @@ import { useUpdateOneFieldMetadataItem } from '@/object-metadata/hooks/useUpdate
import { formatFieldMetadataItemInput } from '@/object-metadata/utils/formatFieldMetadataItemInput';
import { getFieldSlug } from '@/object-metadata/utils/getFieldSlug';
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
@ -49,7 +47,6 @@ type SettingsDataModelFieldEditFormValues = z.infer<
export const SettingsObjectFieldEdit = () => {
const navigate = useNavigate();
const { enqueueSnackBar } = useSnackBar();
const [isPersisting, setIsPersisting] = useState(false);
const { objectSlug = '', fieldSlug = '' } = useParams();
const { findObjectMetadataItemBySlug } = useFilteredObjectMetadataItems();
@ -66,20 +63,6 @@ export const SettingsObjectFieldEdit = () => {
const getRelationMetadata = useGetRelationMetadata();
const { updateOneFieldMetadataItem } = useUpdateOneFieldMetadataItem();
const apolloClient = useApolloClient();
const { findManyRecordsQuery } = useFindManyRecordsQuery({
objectNameSingular: objectMetadataItem?.nameSingular || '',
});
const refetchRecords = async () => {
if (!objectMetadataItem) return;
await apolloClient.query({
query: findManyRecordsQuery,
fetchPolicy: 'network-only',
});
};
const formConfig = useForm<SettingsDataModelFieldEditFormValues>({
mode: 'onTouched',
resolver: zodResolver(settingsFieldFormSchema()),
@ -93,11 +76,10 @@ export const SettingsObjectFieldEdit = () => {
});
useEffect(() => {
if (isPersisting) return;
if (!objectMetadataItem || !fieldMetadataItem) {
navigate(AppPath.NotFound);
}
}, [navigate, objectMetadataItem, fieldMetadataItem, isPersisting]);
}, [navigate, objectMetadataItem, fieldMetadataItem]);
const { isDirty, isValid, isSubmitting } = formConfig.formState;
const canSave = isDirty && isValid && !isSubmitting;
@ -128,8 +110,6 @@ export const SettingsObjectFieldEdit = () => {
}) ?? {};
if (isDefined(relationFieldMetadataItem)) {
setIsPersisting(true);
await updateOneFieldMetadataItem({
objectMetadataId: objectMetadataItem.id,
fieldMetadataIdToUpdate: relationFieldMetadataItem.id,
@ -146,7 +126,7 @@ export const SettingsObjectFieldEdit = () => {
Object.keys(otherDirtyFields),
);
setIsPersisting(true);
navigate(`/settings/objects/${objectSlug}`);
await updateOneFieldMetadataItem({
objectMetadataId: objectMetadataItem.id,
@ -154,16 +134,10 @@ export const SettingsObjectFieldEdit = () => {
updatePayload: formattedInput,
});
}
navigate(`/settings/objects/${objectSlug}`);
refetchRecords();
} catch (error) {
enqueueSnackBar((error as Error).message, {
variant: SnackBarVariant.Error,
});
} finally {
setIsPersisting(false);
}
};