Only fetch steps and trigger for the current workflow version (#15003)

Avoid fetching full steps and trigger for versions that are not the
current version. Because those won't be used anyway. Better for
performances.

Only difficulty was for the `createDraft` mutation. I needed to return
the full created version so I can store it in cache and use it as new
`currentVersion`. Otherwise the current version is considered as
incomplete for a short time, since workflow is fetched separately from
the current version.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Thomas Trompette
2025-10-12 18:06:12 +02:00
committed by GitHub
parent 0fb2d66808
commit 7b84db4708
54 changed files with 485 additions and 259 deletions
@@ -2,6 +2,8 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { deleteRecordFromCache } from '@/object-record/cache/utils/deleteRecordFromCache';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
export const useDeleteRecordFromCache = ({
@@ -10,11 +12,12 @@ export const useDeleteRecordFromCache = ({
objectNameSingular: string;
}) => {
const apolloCoreClient = useApolloCoreClient();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular,
});
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { objectMetadataItems } = useObjectMetadataItems();
return (recordToDestroy: ObjectRecord) => {
@@ -23,6 +26,8 @@ export const useDeleteRecordFromCache = ({
objectMetadataItems,
recordToDestroy,
cache: apolloCoreClient.cache,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
};
};
@@ -4,17 +4,25 @@ import { triggerDestroyRecordsOptimisticEffect } from '@/apollo/optimistic-effec
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { type ObjectPermissions } from 'twenty-shared/types';
export const deleteRecordFromCache = ({
objectMetadataItem,
objectMetadataItems,
recordToDestroy,
cache,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
}: {
objectMetadataItem: ObjectMetadataItem;
objectMetadataItems: ObjectMetadataItem[];
recordToDestroy: ObjectRecord;
cache: ApolloCache<object>;
objectPermissionsByObjectMetadataId: Record<
string,
ObjectPermissions & { objectMetadataId: string }
>;
upsertRecordsInStore: (records: ObjectRecord[]) => void;
}) => {
triggerDestroyRecordsOptimisticEffect({
cache,
@@ -26,5 +34,7 @@ export const deleteRecordFromCache = ({
__typename: getObjectTypename(objectMetadataItem.nameSingular),
},
],
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
};
@@ -12,10 +12,13 @@ import { isEmptyObject } from '~/utils/isEmptyObject';
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
export type GetRecordFromCacheArgs = {
cache: ApolloCache<object>;
cache: ApolloCache<unknown>;
recordId: string;
objectMetadataItems: ObjectMetadataItem[];
objectMetadataItem: ObjectMetadataItem;
objectMetadataItem: Pick<
ObjectMetadataItem,
'fields' | 'nameSingular' | 'id' | 'readableFields'
>;
recordGqlFields?: RecordGqlFields;
objectPermissionsByObjectMetadataId: Record<
string,
@@ -3,7 +3,7 @@ import { generateDepthRecordGqlFieldsFromFields } from '@/object-record/graphql/
export type GenerateDepthRecordGqlFields = {
objectMetadataItems: ObjectMetadataItem[];
objectMetadataItem: ObjectMetadataItem;
objectMetadataItem: Pick<ObjectMetadataItem, 'fields'>;
depth: 0 | 1;
shouldOnlyLoadRelationIdentifiers?: boolean;
};
@@ -18,6 +18,7 @@ import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { type FieldActorForInputValue } from '@/object-record/record-field/ui/types/FieldMetadata';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
import { getCreateManyRecordsMutationResponseField } from '@/object-record/utils/getCreateManyRecordsMutationResponseField';
@@ -51,6 +52,7 @@ export const useCreateManyRecords = <
shouldRefetchAggregateQueries = true,
}: useCreateManyRecordsProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apolloCoreClient = useApolloCoreClient();
@@ -171,6 +173,7 @@ export const useCreateManyRecords = <
objectMetadataItems,
shouldMatchRootQueryFilter,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -208,6 +211,7 @@ export const useCreateManyRecords = <
shouldMatchRootQueryFilter,
checkForRecordInCache: true,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
},
})
@@ -218,6 +222,8 @@ export const useCreateManyRecords = <
objectMetadataItem,
cache: apolloCoreClient.cache,
recordToDestroy,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
});
@@ -226,6 +232,8 @@ export const useCreateManyRecords = <
objectMetadataItem,
recordsToDestroy: recordsCreatedInCache,
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
throw error;
@@ -17,6 +17,7 @@ import { useCreateOneRecordMutation } from '@/object-record/hooks/useCreateOneRe
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { computeOptimisticCreateRecordBaseRecordInput } from '@/object-record/utils/computeOptimisticCreateRecordBaseRecordInput';
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
@@ -39,6 +40,7 @@ export const useCreateOneRecord = <
skipPostOptimisticEffect = false,
shouldMatchRootQueryFilter,
}: useCreateOneRecordProps) => {
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { registerObjectOperation } = useRegisterObjectOperation();
const apolloCoreClient = useApolloCoreClient();
const [loading, setLoading] = useState(false);
@@ -123,6 +125,7 @@ export const useCreateOneRecord = <
objectMetadataItems,
shouldMatchRootQueryFilter,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
}
@@ -147,6 +150,7 @@ export const useCreateOneRecord = <
shouldMatchRootQueryFilter,
checkForRecordInCache: true,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -163,6 +167,8 @@ export const useCreateOneRecord = <
objectMetadataItem,
cache: apolloCoreClient.cache,
recordToDestroy: recordCreatedInCache,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
triggerDestroyRecordsOptimisticEffect({
@@ -170,6 +176,8 @@ export const useCreateOneRecord = <
objectMetadataItem,
recordsToDestroy: [recordCreatedInCache],
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
throw error;
@@ -13,6 +13,7 @@ import { useDeleteManyRecordsMutation } from '@/object-record/hooks/useDeleteMan
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getDeleteManyRecordsMutationResponseField } from '@/object-record/utils/getDeleteManyRecordsMutationResponseField';
import { useRecoilValue } from 'recoil';
@@ -34,6 +35,7 @@ export const useDeleteManyRecords = ({
objectNameSingular,
}: useDeleteManyRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apiConfig = useRecoilValue(apiConfigState);
const mutationPageSize =
@@ -133,6 +135,8 @@ export const useDeleteManyRecords = ({
currentRecords: cachedRecordsNode,
updatedRecords: computedOptimisticRecordsNode,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -203,6 +207,8 @@ export const useDeleteManyRecords = ({
currentRecords: computedOptimisticRecordsNode,
updatedRecords: cachedRecordsNode,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
throw error;
@@ -13,6 +13,7 @@ import { useDeleteOneRecordMutation } from '@/object-record/hooks/useDeleteOneRe
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getDeleteOneRecordMutationResponseField } from '@/object-record/utils/getDeleteOneRecordMutationResponseField';
import { isNull } from '@sniptt/guards';
@@ -26,6 +27,7 @@ export const useDeleteOneRecord = ({
objectNameSingular,
}: useDeleteOneRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apolloCoreClient = useApolloCoreClient();
const { objectMetadataItem } = useObjectMetadataItem({
@@ -100,6 +102,8 @@ export const useDeleteOneRecord = ({
currentRecord: cachedRecordNode,
updatedRecord: optimisticRecordNode,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -121,6 +125,8 @@ export const useDeleteOneRecord = ({
currentRecord: optimisticRecordNode,
updatedRecord: record,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
},
})
@@ -150,6 +156,8 @@ export const useDeleteOneRecord = ({
currentRecord: optimisticRecordNode,
updatedRecord: cachedRecordNode,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
throw error;
@@ -164,16 +172,17 @@ export const useDeleteOneRecord = ({
return deletedRecord.data?.[mutationResponseField] ?? null;
},
[
apolloCoreClient,
deleteOneRecordMutation,
getRecordFromCache,
mutationResponseField,
apolloCoreClient,
objectMetadataItem,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
deleteOneRecordMutation,
refetchAggregateQueries,
objectNameSingular,
registerObjectOperation,
objectNameSingular,
mutationResponseField,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
],
);
@@ -10,6 +10,7 @@ import { useDestroyManyRecordsMutation } from '@/object-record/hooks/useDestroyM
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getDestroyManyRecordsMutationResponseField } from '@/object-record/utils/getDestroyManyRecordsMutationResponseField';
import { useRecoilValue } from 'recoil';
@@ -31,6 +32,7 @@ export const useDestroyManyRecords = ({
objectNameSingular,
}: useDestroyManyRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apiConfig = useRecoilValue(apiConfigState);
const mutationPageSize =
@@ -112,6 +114,8 @@ export const useDestroyManyRecords = ({
objectMetadataItem,
recordsToDestroy: cachedRecords,
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
},
})
@@ -123,6 +127,7 @@ export const useDestroyManyRecords = ({
recordsToCreate: cachedRecords,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
throw error;
@@ -9,6 +9,7 @@ import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordF
import { useDestroyOneRecordMutation } from '@/object-record/hooks/useDestroyOneRecordMutation';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { getDestroyOneRecordMutationResponseField } from '@/object-record/utils/getDestroyOneRecordMutationResponseField';
import { capitalize, isDefined } from 'twenty-shared/utils';
@@ -21,6 +22,7 @@ export const useDestroyOneRecord = ({
objectNameSingular,
}: useDestroyOneRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apolloCoreClient = useApolloCoreClient();
@@ -67,6 +69,8 @@ export const useDestroyOneRecord = ({
objectMetadataItem,
recordsToDestroy: [cachedRecord],
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
},
})
@@ -78,6 +82,7 @@ export const useDestroyOneRecord = ({
recordsToCreate: [originalRecord],
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -91,15 +96,16 @@ export const useDestroyOneRecord = ({
return deletedRecord.data?.[mutationResponseField] ?? null;
},
[
getRecordFromCache,
apolloCoreClient,
destroyOneRecordMutation,
getRecordFromCache,
mutationResponseField,
objectMetadataItem,
objectNameSingular,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
registerObjectOperation,
objectMetadataItem,
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
],
);
@@ -17,7 +17,7 @@ export const useLoadSelectedRecordsInContextStore = ({
objectRecordIds,
objectMetadataItemId,
}: UseLoadSelectedRecordsInContextStoreProps) => {
const { upsertRecords } = useUpsertRecordsInStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { findManyRecordsLazy } = useLazyFindManyRecords({
objectNameSingular,
@@ -57,10 +57,15 @@ export const useLoadSelectedRecordsInContextStore = ({
const { records } = await findManyRecordsLazy();
upsertRecords(records ?? []);
upsertRecordsInStore(records ?? []);
};
},
[objectRecordIds, objectMetadataItemId, findManyRecordsLazy, upsertRecords],
[
objectRecordIds,
objectMetadataItemId,
findManyRecordsLazy,
upsertRecordsInStore,
],
);
return {
@@ -116,14 +116,14 @@ export const useMergeManyRecords = <
}
},
[
apolloCoreClient,
findDuplicateRecordsQuery,
findOneRecordQuery,
mergeManyRecordsMutation,
objectMetadataItem.namePlural,
refetchAggregateQueries,
apolloCoreClient,
mergeManyRecordsMutation,
findOneRecordQuery,
findDuplicateRecordsQuery,
registerObjectOperation,
objectNameSingular,
refetchAggregateQueries,
],
);
@@ -11,6 +11,7 @@ import { DEFAULT_MUTATION_BATCH_SIZE } from '@/object-record/constants/DefaultMu
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useRestoreManyRecordsMutation } from '@/object-record/hooks/useRestoreManyRecordsMutation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { getRestoreManyRecordsMutationResponseField } from '@/object-record/utils/getRestoreManyRecordsMutationResponseField';
import { useRecoilValue } from 'recoil';
@@ -32,6 +33,7 @@ export const useRestoreManyRecords = ({
objectNameSingular,
}: useRestoreManyRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apiConfig = useRecoilValue(apiConfigState);
@@ -122,6 +124,8 @@ export const useRestoreManyRecords = ({
currentRecord: cachedRecordWithConnection,
updatedRecord: optimisticRecordWithConnection,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
});
@@ -182,6 +186,8 @@ export const useRestoreManyRecords = ({
currentRecord: optimisticRecordWithConnection,
updatedRecord: cachedRecordWithConnection,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
});
@@ -13,6 +13,7 @@ import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions
import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpdateOneRecordMutation } from '@/object-record/hooks/useUpdateOneRecordMutation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField';
@@ -38,6 +39,7 @@ export const useUpdateOneRecord = <
recordGqlFields,
}: useUpdateOneRecordProps) => {
const { registerObjectOperation } = useRegisterObjectOperation();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const apolloCoreClient = useApolloCoreClient();
const { objectMetadataItem } = useObjectMetadataItem({
@@ -138,6 +140,8 @@ export const useUpdateOneRecord = <
currentRecord: cachedRecordWithConnection,
updatedRecord: optimisticRecordWithConnection,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -167,6 +171,8 @@ export const useUpdateOneRecord = <
currentRecord: computedOptimisticRecord,
updatedRecord: record,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
},
})
@@ -213,6 +219,8 @@ export const useUpdateOneRecord = <
currentRecord: optimisticRecordWithConnection,
updatedRecord: cachedRecordWithConnection,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
throw error;
@@ -11,6 +11,8 @@ import { type RecordGqlFields } from '@/object-record/graphql/record-gql-fields/
import { generateDepthRecordGqlFieldsFromObject } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromObject';
import { generateDepthRecordGqlFieldsFromRecord } from '@/object-record/graphql/record-gql-fields/utils/generateDepthRecordGqlFieldsFromRecord';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useRegisterObjectOperation } from '@/object-record/hooks/useRegisterObjectOperation';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput';
import { getUpdateOneRecordMutationResponseField } from '@/object-record/utils/getUpdateOneRecordMutationResponseField';
@@ -29,6 +31,8 @@ type UpdateOneRecordArgs<UpdatedObjectRecord> = {
};
export const useUpdateOneRecordV2 = () => {
const apolloCoreClient = useApolloCoreClient();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { registerObjectOperation } = useRegisterObjectOperation();
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
@@ -133,6 +137,8 @@ export const useUpdateOneRecordV2 = () => {
currentRecord: cachedRecordWithConnection,
updatedRecord: optimisticRecordWithConnection,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
}
@@ -171,6 +177,8 @@ export const useUpdateOneRecordV2 = () => {
currentRecord: computedOptimisticRecord,
updatedRecord: record,
objectMetadataItems,
objectPermissionsByObjectMetadataId,
upsertRecordsInStore,
});
},
})
@@ -217,11 +225,17 @@ export const useUpdateOneRecordV2 = () => {
currentRecord: optimisticRecordWithConnection,
updatedRecord: cachedRecordWithConnection,
objectMetadataItems,
upsertRecordsInStore,
objectPermissionsByObjectMetadataId,
});
throw error;
});
registerObjectOperation(objectMetadataItem.nameSingular, {
type: 'update-one',
result: { updatedRecord, updateInput: updateOneRecordInput },
});
return updatedRecord?.data?.[mutationResponseField] ?? null;
};
@@ -26,7 +26,7 @@ export const RecordIndexCalendarDataLoaderEffect = () => {
const { objectMetadataItem } = useRecordCalendarContextOrThrow();
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const setRecordIndexAllRecordIdsSelector = useSetRecoilComponentState(
recordIndexAllRecordIdsComponentSelector,
@@ -24,13 +24,13 @@ export const RecordDetailRelationRecordsListItemEffect = ({
objectRecordId: relationRecordId,
});
const { upsertRecords } = useUpsertRecordsInStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
useEffect(() => {
if (isDefined(record)) {
upsertRecords([record]);
upsertRecordsInStore([record]);
}
}, [record, upsertRecords]);
}, [record, upsertRecordsInStore]);
return null;
};
@@ -30,6 +30,7 @@ import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { getRecordFromCache } from '@/object-record/cache/utils/getRecordFromCache';
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { isFieldArray } from '@/object-record/record-field/ui/types/guards/isFieldArray';
@@ -42,6 +43,7 @@ import { isFieldRichText } from '@/object-record/record-field/ui/types/guards/is
import { isFieldRichTextV2 } from '@/object-record/record-field/ui/types/guards/isFieldRichTextV2';
import { isFieldRichTextValue } from '@/object-record/record-field/ui/types/guards/isFieldRichTextValue';
import { isFieldRichTextV2Value } from '@/object-record/record-field/ui/types/guards/isFieldRichTextValueV2';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { getForeignKeyNameFromRelationFieldName } from '@/object-record/utils/getForeignKeyNameFromRelationFieldName';
import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
@@ -72,11 +74,13 @@ export const usePersistField = ({
const { updateOneRecord } = useUpdateOneRecord({
objectNameSingular: objectMetadataItem?.nameSingular ?? '',
});
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
const persistField = useRecoilCallback(
({ set, snapshot }) =>
({
async ({
recordId,
fieldDefinition,
valueToPersist,
@@ -202,7 +206,7 @@ export const usePersistField = ({
return;
}
updateOneRecord?.({
const newRecord = await updateOneRecord?.({
idToUpdate: recordId,
updateOneRecordInput: {
[getForeignKeyNameFromRelationFieldName(fieldName)]:
@@ -210,10 +214,11 @@ export const usePersistField = ({
},
});
set(
recordStoreFamilySelector({ recordId, fieldName }),
valueToPersist,
);
upsertRecordsInStore([
getRecordFromRecordNode({
recordNode: newRecord,
}),
]);
return;
}
@@ -263,19 +268,17 @@ export const usePersistField = ({
candidateObjectMetadataItem.namePlural,
});
updateOneRecord?.({
const newRecord = await updateOneRecord?.({
idToUpdate: recordId,
updateOneRecordInput: {
[`${computedFieldName}Id`]: valueToPersist.id,
},
});
set(
recordStoreFamilySelector({
recordId,
fieldName: computedFieldName,
upsertRecordsInStore([
getRecordFromRecordNode({
recordNode: newRecord,
}),
valueToPersist,
);
]);
return;
}
}
@@ -310,6 +313,7 @@ export const usePersistField = ({
objectMetadataItems,
objectPermissionsByObjectMetadataId,
updateOneRecord,
upsertRecordsInStore,
],
);
@@ -42,7 +42,7 @@ export const useLoadRecordIndexBoardColumn = ({
objectNameSingular,
});
const { setRecordIdsForColumn } = useSetRecordIdsForColumn(recordBoardId);
const { upsertRecords: upsertRecordsInStore } = useUpsertRecordsInStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const recordGroupDefinition = useRecoilValue(
recordGroupDefinitionFamilyState(columnId),
@@ -31,7 +31,7 @@ export const useMergePreview = ({
const { mergeManyRecords } = useMergeManyRecords({
objectNameSingular,
});
const { upsertRecords } = useUpsertRecordsInStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { isLoading: isLoadingRelationships } = useMergeRecordRelationships({
objectNameSingular,
@@ -56,7 +56,7 @@ export const useMergePreview = ({
}
setMergePreviewRecord(previewRecord);
upsertRecords([previewRecord]);
upsertRecordsInStore([previewRecord]);
} catch {
setMergePreviewRecord(null);
} finally {
@@ -2,9 +2,10 @@ import { useRecoilCallback } from 'recoil';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useUpsertRecordsInStore = () => {
const upsertRecords = useRecoilCallback(
const upsertRecordsInStore = useRecoilCallback(
({ set, snapshot }) =>
(records: ObjectRecord[]) => {
for (const record of records) {
@@ -12,7 +13,7 @@ export const useUpsertRecordsInStore = () => {
.getLoadable(recordStoreFamilyState(record.id))
.getValue();
if (JSON.stringify(currentRecord) !== JSON.stringify(record)) {
if (!isDeeplyEqual(currentRecord, record)) {
set(recordStoreFamilyState(record.id), {
...currentRecord,
...record,
@@ -24,6 +25,6 @@ export const useUpsertRecordsInStore = () => {
);
return {
upsertRecords,
upsertRecordsInStore,
};
};
@@ -1,9 +1,9 @@
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { hasAnySoftDeleteFilterOnViewComponentSelector } from '@/object-record/record-filter/states/hasAnySoftDeleteFilterOnView';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
import { RecordTableActionRow } from '@/object-record/record-table/record-table-row/components/RecordTableActionRow';
import { useAssignRecordsToStore } from '@/object-record/record-table/virtualization/hooks/useAssignRecordsToStore';
import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows';
import { totalNumberOfRecordsToVirtualizeComponentState } from '@/object-record/record-table/virtualization/states/totalNumberOfRecordsToVirtualizeComponentState';
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
@@ -34,7 +34,7 @@ export const RecordTableNoRecordGroupAddNew = () => {
);
const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows();
const { assignRecordsToStore } = useAssignRecordsToStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const handleButtonClick = useRecoilCallback(
() => async () => {
@@ -42,7 +42,7 @@ export const RecordTableNoRecordGroupAddNew = () => {
position: 'last',
});
assignRecordsToStore({ records: [createdRecord] });
upsertRecordsInStore([createdRecord]);
if (isDefined(totalNumberOfRecordsToVirtualize)) {
loadRecordsToVirtualRows({
@@ -53,7 +53,7 @@ export const RecordTableNoRecordGroupAddNew = () => {
},
[
createNewIndexRecord,
assignRecordsToStore,
upsertRecordsInStore,
loadRecordsToVirtualRows,
totalNumberOfRecordsToVirtualize,
],
@@ -1,32 +0,0 @@
import { useRecoilCallback } from 'recoil';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
export const useAssignRecordsToStore = () => {
const assignRecordsToStore = useRecoilCallback(
({ set, snapshot }) =>
<T extends ObjectRecord>({ records }: { records: T[] }) => {
for (const record of records) {
const currentRecord = snapshot
.getLoadable(recordStoreFamilyState(record.id))
.getValue();
if (!isDeeplyEqual(currentRecord, record)) {
const newRecord = {
...currentRecord,
...record,
};
set(recordStoreFamilyState(record.id), newRecord);
}
}
},
[],
);
return {
assignRecordsToStore,
};
};
@@ -1,7 +1,7 @@
import { useLazyFindManyRecordsWithOffset } from '@/object-record/hooks/useLazyFindManyRecordsWithOffset';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { RECORD_TABLE_ROW_HEIGHT } from '@/object-record/record-table/constants/RecordTableRowHeight';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
import { useAssignRecordsToStore } from '@/object-record/record-table/virtualization/hooks/useAssignRecordsToStore';
import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows';
import { dataPagesLoadedComponentState } from '@/object-record/record-table/virtualization/states/dataPagesLoadedComponentState';
@@ -30,7 +30,7 @@ export const useTriggerFetchPages = () => {
const { objectNameSingular } = useRecordTableContextOrThrow();
const { scrollWrapperHTMLElement } = useScrollWrapperHTMLElement();
const { assignRecordsToStore } = useAssignRecordsToStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows();
@@ -193,7 +193,7 @@ export const useTriggerFetchPages = () => {
startingRealIndex: startingRealIndexInThisUIPage,
});
assignRecordsToStore({ records: recordsSlice });
upsertRecordsInStore(recordsSlice);
}
}
@@ -210,7 +210,7 @@ export const useTriggerFetchPages = () => {
findManyRecordsLazyWithOffset,
totalNumberOfRecordsToVirtualizeCallbackState,
loadRecordsToVirtualRows,
assignRecordsToStore,
upsertRecordsInStore,
lastScrollPositionCallbackState,
scrollWrapperHTMLElement,
lowDetailsActivatedCallbackState,
@@ -1,5 +1,6 @@
import { useRecordIndexTableFetchMore } from '@/object-record/record-index/hooks/useRecordIndexTableFetchMore';
import { recordIndexAllRecordIdsComponentSelector } from '@/object-record/record-index/states/selectors/recordIndexAllRecordIdsComponentSelector';
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { RECORD_TABLE_HORIZONTAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableHorizontalScrollShadowVisibilityCssVariableName';
import { RECORD_TABLE_VERTICAL_SCROLL_SHADOW_VISIBILITY_CSS_VARIABLE_NAME } from '@/object-record/record-table/constants/RecordTableVerticalScrollShadowVisibilityCssVariableName';
import { useRecordTableContextOrThrow } from '@/object-record/record-table/contexts/RecordTableContext';
@@ -8,7 +9,6 @@ import { isRecordTableInitialLoadingComponentState } from '@/object-record/recor
import { isRecordTableScrolledHorizontallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledHorizontallyComponentState';
import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState';
import { updateRecordTableCSSVariable } from '@/object-record/record-table/utils/updateRecordTableCSSVariable';
import { useAssignRecordsToStore } from '@/object-record/record-table/virtualization/hooks/useAssignRecordsToStore';
import { useLoadRecordsToVirtualRows } from '@/object-record/record-table/virtualization/hooks/useLoadRecordsToVirtualRows';
import { useReapplyRowSelection } from '@/object-record/record-table/virtualization/hooks/useReapplyRowSelection';
import { useResetNumberOfRecordsToVirtualize } from '@/object-record/record-table/virtualization/hooks/useResetNumberOfRecordsToVirtualize';
@@ -92,7 +92,7 @@ export const useTriggerInitialRecordTableDataLoad = () => {
useResetNumberOfRecordsToVirtualize();
const { resetTableFocuses } = useResetTableFocuses(recordTableId);
const { assignRecordsToStore } = useAssignRecordsToStore();
const { upsertRecordsInStore } = useUpsertRecordsInStore();
const { loadRecordsToVirtualRows } = useLoadRecordsToVirtualRows();
@@ -165,7 +165,7 @@ export const useTriggerInitialRecordTableDataLoad = () => {
totalCount,
});
assignRecordsToStore({ records });
upsertRecordsInStore(records);
loadRecordsToVirtualRows({
records,
@@ -210,7 +210,7 @@ export const useTriggerInitialRecordTableDataLoad = () => {
dataLoadingStatusByRealIndexCallbackState,
recordIdByRealIndexCallbackState,
resetNumberOfRecordsToVirtualize,
assignRecordsToStore,
upsertRecordsInStore,
loadRecordsToVirtualRows,
reapplyRowSelection,
],
@@ -157,19 +157,6 @@ export const computeOptimisticRecordFromInput = ({
continue;
}
const relationIdFieldMetadataItem = objectMetadataItem.fields.find(
(field) => field.name === relationFieldIdName,
);
if (
!isDefined(relationIdFieldMetadataItem) &&
!isDefined(fieldMetadataItem.settings?.joinColumnName)
) {
throw new Error(
'Should never occur, encountered unknown relationId within relations definitions',
);
}
if (isNull(recordInputFieldIdValue)) {
optimisticRecord[relationFieldIdName] = null;
optimisticRecord[fieldMetadataItem.name] = null;