diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewIndexRecordNoSelectionRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewIndexRecordNoSelectionRecordAction.tsx index 85f39bf554..2008016df3 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewIndexRecordNoSelectionRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/components/CreateNewIndexRecordNoSelectionRecordAction.tsx @@ -11,7 +11,7 @@ export const CreateNewIndexRecordNoSelectionRecordAction = () => { return ( createNewIndexRecord()} + onClick={() => createNewIndexRecord({ position: 'first' })} closeSidePanelOnCommandMenuListActionExecution={false} /> ); diff --git a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts index fbbc356a11..cac40d617d 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useCreateOneRecord.ts @@ -18,13 +18,18 @@ import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions import { useRefetchAggregateQueries } from '@/object-record/hooks/useRefetchAggregateQueries'; import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { + type ObjectRecord as ObjectRecordShared, + type RecordGqlOperationGqlRecordFields, +} from 'twenty-shared/types'; + +import { type BaseObjectRecord } from '@/object-record/types/BaseObjectRecord'; import { computeOptimisticCreateRecordBaseRecordInput } from '@/object-record/utils/computeOptimisticCreateRecordBaseRecordInput'; import { computeOptimisticRecordFromInput } from '@/object-record/utils/computeOptimisticRecordFromInput'; import { dispatchObjectRecordOperationBrowserEvent } from '@/object-record/utils/dispatchObjectRecordOperationBrowserEvent'; import { getCreateOneRecordMutationResponseField } from '@/object-record/utils/getCreateOneRecordMutationResponseField'; import { sanitizeRecordInput } from '@/object-record/utils/sanitizeRecordInput'; import { useRecoilValue } from 'recoil'; -import { type RecordGqlOperationGqlRecordFields } from 'twenty-shared/types'; import { CustomError, isDefined } from 'twenty-shared/utils'; type useCreateOneRecordProps = { @@ -135,7 +140,7 @@ export const useCreateOneRecord = < getCreateOneRecordMutationResponseField(objectNameSingular); const createdObject = await apolloCoreClient - .mutate({ + .mutate({ mutation: createOneRecordMutation, variables: { input: sanitizedInput, @@ -186,17 +191,31 @@ export const useCreateOneRecord = < await refetchAggregateQueries(); + const positionToUse = + recordInput.position === 'first' + ? 'first' + : recordInput.position === 'last' + ? 'last' + : null; + + const createdRecord = createdObject.data?.[ + mutationResponseField + ] as ObjectRecordShared & BaseObjectRecord; + dispatchObjectRecordOperationBrowserEvent({ objectMetadataItem, - operation: { type: 'create-one' }, + operation: { + type: 'create-one', + createdRecord: { ...createdRecord, position: positionToUse }, + }, }); - if (!isDefined(createdObject.data?.[mutationResponseField])) { + if (!isDefined(createdRecord)) { throw new CustomError('Failed to create record'); } return getRecordFromRecordNode({ - recordNode: createdObject.data?.[mutationResponseField], + recordNode: createdRecord, }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx index 95f133260b..62ddd85583 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardDataChangedEffect.tsx @@ -1,8 +1,16 @@ import { useListenToObjectRecordOperationBrowserEvent } from '@/object-record/hooks/useListenToObjectRecordOperationBrowserEvent'; import { useGetShouldInitializeRecordBoardForUpdateInputs } from '@/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs'; import { useTriggerRecordBoardInitialQuery } from '@/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery'; +import { recordGroupFromGroupValueComponentFamilySelector } from '@/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState'; +import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; +import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { type ObjectRecordOperationBrowserEventDetail } from '@/object-record/types/ObjectRecordOperationBrowserEventDetail'; +import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; +import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; export const RecordBoardDataChangedEffect = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -11,31 +19,126 @@ export const RecordBoardDataChangedEffect = () => { const { getShouldInitializeRecordBoardForUpdateInputs } = useGetShouldInitializeRecordBoardForUpdateInputs(); - const handleObjectRecordOperation = ( - objectRecordOperationEventDetail: ObjectRecordOperationBrowserEventDetail, - ) => { - const objectRecordOperation = objectRecordOperationEventDetail.operation; + const recordGroupFromGroupValueCallbackState = + useRecoilComponentCallbackState( + recordGroupFromGroupValueComponentFamilySelector, + ); + const recordIndexGroupFieldMetadataItemCallbackState = + useRecoilComponentCallbackState( + recordIndexGroupFieldMetadataItemComponentState, + ); + const recordIndexRecordIdsByGroupCallbackState = + useRecoilComponentCallbackState( + recordIndexRecordIdsByGroupComponentFamilyState, + ); - const isUpdateOperation = - objectRecordOperation.type === 'update-one' || - objectRecordOperation.type === 'update-many'; + const handleObjectRecordOperation = useRecoilCallback( + ({ snapshot }) => + ( + objectRecordOperationEventDetail: ObjectRecordOperationBrowserEventDetail, + ) => { + const objectRecordOperation = + objectRecordOperationEventDetail.operation; - if (isUpdateOperation) { - const updateInputs = - objectRecordOperation.type === 'update-one' - ? [objectRecordOperation.result.updateInput] - : objectRecordOperation.result.updateInputs; + switch (objectRecordOperation.type) { + case 'update-one': + case 'update-many': + { + const updateInputs = + objectRecordOperation.type === 'update-one' + ? [objectRecordOperation.result.updateInput] + : objectRecordOperation.result.updateInputs; - const shouldInitializeForUpdateOperation = - getShouldInitializeRecordBoardForUpdateInputs(updateInputs); + const shouldInitializeForUpdateOperation = + getShouldInitializeRecordBoardForUpdateInputs(updateInputs); - if (shouldInitializeForUpdateOperation) { - triggerRecordBoardInitialQuery(); - } - } else { - triggerRecordBoardInitialQuery(); - } - }; + if (shouldInitializeForUpdateOperation) { + triggerRecordBoardInitialQuery(); + } + } + break; + case 'create-one': { + if (objectRecordOperation.createdRecord.position === 'first') { + triggerRecordBoardInitialQuery(); + } else { + const createdRecordPosition = + objectRecordOperation.createdRecord.position; + + if (!isDefined(createdRecordPosition)) { + return; + } + + const recordIndexGroupFieldMetadataItem = getSnapshotValue( + snapshot, + recordIndexGroupFieldMetadataItemCallbackState, + ); + + if (!isDefined(recordIndexGroupFieldMetadataItem)) { + return; + } + + const recordGroupValue = + objectRecordOperation.createdRecord[ + recordIndexGroupFieldMetadataItem.name + ]; + + const recordGroupDefinitionFromGroupValue = getSnapshotValue( + snapshot, + recordGroupFromGroupValueCallbackState({ recordGroupValue }), + ); + + if (!isDefined(recordGroupDefinitionFromGroupValue)) { + return; + } + + const recordIdsForGroup = getSnapshotValue( + snapshot, + recordIndexRecordIdsByGroupCallbackState( + recordGroupDefinitionFromGroupValue.id, + ), + ); + + const recordIdsWithoutCreatedRecord = recordIdsForGroup.filter( + (recordId) => + recordId !== objectRecordOperation.createdRecord.id, + ); + + const groupIsEmpty = recordIdsWithoutCreatedRecord.length === 0; + + if (groupIsEmpty) { + triggerRecordBoardInitialQuery(); + return; + } + + const firstRecordIdInGroup = recordIdsWithoutCreatedRecord[0]; + const firstExistingRecordInGroup = getSnapshotValue( + snapshot, + recordStoreFamilyState(firstRecordIdInGroup), + ); + + if (!isDefined(firstExistingRecordInGroup)) { + return; + } + + if (createdRecordPosition < firstExistingRecordInGroup.position) { + triggerRecordBoardInitialQuery(); + } + } + break; + } + default: { + triggerRecordBoardInitialQuery(); + } + } + }, + [ + triggerRecordBoardInitialQuery, + getShouldInitializeRecordBoardForUpdateInputs, + recordIndexGroupFieldMetadataItemCallbackState, + recordGroupFromGroupValueCallbackState, + recordIndexRecordIdsByGroupCallbackState, + ], + ); useListenToObjectRecordOperationBrowserEvent({ onObjectRecordOperationBrowserEvent: handleObjectRecordOperation, diff --git a/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts b/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts index 00f80566c8..90c790193e 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/hooks/useGetShouldInitializeRecordBoardForUpdateInputs.ts @@ -84,7 +84,7 @@ export const useGetShouldInitializeRecordBoardForUpdateInputs = () => { } if (updatedFieldNames.has('position')) { - return true; + return false; } return ( diff --git a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx index 2d986eae4e..0e000e1d78 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/record-board-column/components/RecordBoardColumnCardsContainer.tsx @@ -9,10 +9,8 @@ import { RecordBoardColumnContext } from '@/object-record/record-board/record-bo import { RecordBoardColumnLoadingSkeletonCards } from '@/object-record/record-board/record-board-column/components/RecordBoardColumnLoadingSkeletonCards'; import { recordBoardShouldFetchMoreInColumnComponentFamilyState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState'; -import { recordIndexRecordGroupsAreInInitialLoadingComponentState } from '@/object-record/record-index/states/recordIndexRecordGroupsAreInInitialLoadingComponentState'; import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState'; import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue'; -import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; const StyledColumnCardsContainer = styled.div` display: flex; @@ -40,10 +38,6 @@ export const RecordBoardColumnCardsContainer = ({ recordBoardColumnId, ); - const recordIndexRecordGroupsAreInInitialLoading = useRecoilComponentValue( - recordIndexRecordGroupsAreInInitialLoadingComponentState, - ); - const recordBoardShouldFetchMoreInColumn = useRecoilComponentFamilyValue( recordBoardShouldFetchMoreInColumnComponentFamilyState, recordBoardColumnId, @@ -55,17 +49,13 @@ export const RecordBoardColumnCardsContainer = ({ // eslint-disable-next-line react/jsx-props-no-spreading {...droppableProvided?.droppableProps} > - {recordIndexRecordGroupsAreInInitialLoading ? ( - - ) : ( - recordIds.map((recordId, index) => ( - - )) - )} + {recordIds.map((recordId, index) => ( + + ))} {recordBoardShouldFetchMoreInColumn ? ( ) : null} diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts index f79c886be3..996618ef30 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts +++ b/packages/twenty-front/src/modules/object-record/record-board/states/recordBoardShouldFetchMoreInColumnComponentFamilyState.ts @@ -4,6 +4,6 @@ import { createComponentFamilyState } from '@/ui/utilities/state/component-state export const recordBoardShouldFetchMoreInColumnComponentFamilyState = createComponentFamilyState({ key: 'recordBoardShouldFetchMoreInColumnComponentFamilyState', - defaultValue: false, + defaultValue: true, componentInstanceContext: RecordBoardComponentInstanceContext, }); diff --git a/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts new file mode 100644 index 0000000000..f2c75e65e1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector.ts @@ -0,0 +1,44 @@ +import { recordGroupDefinitionFamilyState } from '@/object-record/record-group/states/recordGroupDefinitionFamilyState'; +import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; +import { type RecordGroupDefinition } from '@/object-record/record-group/types/RecordGroupDefinition'; +import { createComponentFamilySelector } from '@/ui/utilities/state/component-state/utils/createComponentFamilySelector'; + +import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; +import { type Nullable } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; + +export const recordGroupFromGroupValueComponentFamilySelector = + createComponentFamilySelector< + RecordGroupDefinition | undefined, + { recordGroupValue: Nullable } + >({ + key: 'recordGroupFromGroupValueComponentSelector', + componentInstanceContext: ViewComponentInstanceContext, + get: + ({ instanceId, familyKey }) => + ({ get }): RecordGroupDefinition | undefined => { + const recordGroupIds = get( + recordGroupIdsComponentState.atomFamily({ + instanceId, + }), + ); + + const recordGroupId = recordGroupIds.find((recordGroupId) => { + const recordGroupDefinition = get( + recordGroupDefinitionFamilyState(recordGroupId), + ); + + return recordGroupDefinition?.value === familyKey.recordGroupValue; + }); + + if (!isDefined(recordGroupId)) { + return undefined; + } + + const recordGroupDefinition = get( + recordGroupDefinitionFamilyState(recordGroupId), + ); + + return recordGroupDefinition; + }, + }); diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx index 991a661e52..5ae9473c98 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/components/RecordTableHeaderLabelIdentifierCellPlusButton.tsx @@ -23,7 +23,9 @@ export const RecordTableHeaderLabelIdentifierCellPlusButton = () => { }); const handlePlusButtonClick = () => { - createNewIndexRecord(); + createNewIndexRecord({ + position: 'first', + }); }; const isReadOnly = isObjectMetadataReadOnly({ diff --git a/packages/twenty-front/src/modules/object-record/types/ObjectRecordOperation.ts b/packages/twenty-front/src/modules/object-record/types/ObjectRecordOperation.ts index 232e157fcb..1677073374 100644 --- a/packages/twenty-front/src/modules/object-record/types/ObjectRecordOperation.ts +++ b/packages/twenty-front/src/modules/object-record/types/ObjectRecordOperation.ts @@ -1,4 +1,5 @@ import { type ObjectRecordOperationUpdateInput } from '@/object-record/types/ObjectRecordOperationUpdateInput'; +import { type ObjectRecord } from 'twenty-shared/types'; export type ObjectRecordOperation = | { @@ -13,9 +14,12 @@ export type ObjectRecordOperation = updateInputs: ObjectRecordOperationUpdateInput[]; }; } + | { + type: 'create-one'; + createdRecord: ObjectRecord; + } | { type: - | 'create-one' | 'create-many' | 'destroy-one' | 'destroy-many' diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseCreateEvents.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseCreateEvents.ts new file mode 100644 index 0000000000..2b5f6e260d --- /dev/null +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseCreateEvents.ts @@ -0,0 +1,76 @@ +import { triggerCreateRecordsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerCreateRecordsOptimisticEffect'; +import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; +import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { getObjectTypename } from '@/object-record/cache/utils/getObjectTypename'; +import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; +import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions'; +import { useRefetchAggregateQueriesForObjectMetadataItem } from '@/object-record/hooks/useRefetchAggregateQueriesForObjectMetadataItem'; +import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore'; +import { useCallback } from 'react'; +import { useDebouncedCallback } from 'use-debounce'; +import { + DatabaseEventAction, + type ObjectRecordEvent, +} from '~/generated/graphql'; + +export const useTriggerOptimisticEffectFromSseCreateEvents = () => { + const apolloCoreClient = useApolloCoreClient(); + const { objectMetadataItems } = useObjectMetadataItems(); + const { objectPermissionsByObjectMetadataId } = useObjectPermissions(); + const { refetchAggregateQueriesForObjectMetadataItem } = + useRefetchAggregateQueriesForObjectMetadataItem(); + const { upsertRecordsInStore } = useUpsertRecordsInStore(); + + const debouncedRefetchAggregateQueriesForObjectMetadataItem = + useDebouncedCallback(refetchAggregateQueriesForObjectMetadataItem, 100); + + const triggerOptimisticEffectFromSseCreateEvents = useCallback( + ({ + objectRecordEvents, + objectMetadataItem, + }: { + objectRecordEvents: ObjectRecordEvent[]; + objectMetadataItem: ObjectMetadataItem; + }) => { + const createEvents = objectRecordEvents.filter((objectRecordEvent) => { + return objectRecordEvent.action === DatabaseEventAction.CREATED; + }); + + const cache = apolloCoreClient.cache; + + const recordsToCreate = createEvents.map((createEvent) => { + return { + ...createEvent.properties.after, + __typename: getObjectTypename(objectMetadataItem.nameSingular), + } as RecordGqlNode; + }); + + triggerCreateRecordsOptimisticEffect({ + cache, + objectMetadataItem, + recordsToCreate: recordsToCreate, + objectMetadataItems, + shouldMatchRootQueryFilter: true, + checkForRecordInCache: true, + objectPermissionsByObjectMetadataId, + upsertRecordsInStore, + }); + + debouncedRefetchAggregateQueriesForObjectMetadataItem({ + objectMetadataItem, + }); + }, + [ + apolloCoreClient.cache, + objectMetadataItems, + objectPermissionsByObjectMetadataId, + upsertRecordsInStore, + debouncedRefetchAggregateQueriesForObjectMetadataItem, + ], + ); + + return { + triggerOptimisticEffectFromSseCreateEvents, + }; +}; diff --git a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseEvents.ts b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseEvents.ts index 6a62b899d0..e3ed19641b 100644 --- a/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseEvents.ts +++ b/packages/twenty-front/src/modules/sse-db-event/hooks/useTriggerOptimisticEffectFromSseEvents.ts @@ -1,4 +1,5 @@ import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems'; +import { useTriggerOptimisticEffectFromSseCreateEvents } from '@/sse-db-event/hooks/useTriggerOptimisticEffectFromSseCreateEvents'; import { useTriggerOptimisticEffectFromSseUpdateEvents } from '@/sse-db-event/hooks/useTriggerOptimisticEffectFromSseUpdateEvents'; import { groupObjectRecordSseEventsByEventType } from '@/sse-db-event/utils/groupObjectRecordSseEventsByEventType'; import { groupObjectRecordSseEventsByObjectMetadataItemNameSingular } from '@/sse-db-event/utils/groupObjectRecordSseEventsByObjectMetadataItemNameSingular'; @@ -15,6 +16,9 @@ export const useTriggerOptimisticEffectFromSseEvents = () => { const { triggerOptimisticEffectFromSseUpdateEvents } = useTriggerOptimisticEffectFromSseUpdateEvents(); + const { triggerOptimisticEffectFromSseCreateEvents } = + useTriggerOptimisticEffectFromSseCreateEvents(); + const triggerOptimisticEffectFromSseEvents = useCallback( ({ objectRecordEvents }: { objectRecordEvents: ObjectRecordEvent[] }) => { const objectRecordEventsByObjectMetadataItemNameSingular = @@ -58,11 +62,21 @@ export const useTriggerOptimisticEffectFromSseEvents = () => { objectMetadataItem, }); break; + case DatabaseEventAction.CREATED: + triggerOptimisticEffectFromSseCreateEvents({ + objectRecordEvents: objectRecordEventsForThisEventType, + objectMetadataItem, + }); + break; } } } }, - [objectMetadataItems, triggerOptimisticEffectFromSseUpdateEvents], + [ + objectMetadataItems, + triggerOptimisticEffectFromSseUpdateEvents, + triggerOptimisticEffectFromSseCreateEvents, + ], ); return { triggerOptimisticEffectFromSseEvents }; diff --git a/packages/twenty-front/src/modules/sse-db-event/utils/turnSseObjectRecordEventToObjectRecordOperationBrowserEvent.ts b/packages/twenty-front/src/modules/sse-db-event/utils/turnSseObjectRecordEventToObjectRecordOperationBrowserEvent.ts index 2c5cd0befa..3d62be835f 100644 --- a/packages/twenty-front/src/modules/sse-db-event/utils/turnSseObjectRecordEventToObjectRecordOperationBrowserEvent.ts +++ b/packages/twenty-front/src/modules/sse-db-event/utils/turnSseObjectRecordEventToObjectRecordOperationBrowserEvent.ts @@ -90,7 +90,11 @@ export const turnSseObjectRecordEventsToObjectRecordOperationBrowserEvents = ({ if (hasSingleEvent) { objectRecordOperationBrowserEvents.push({ objectMetadataItem, - operation: { type: 'create-one' }, + operation: { + type: 'create-one', + createdRecord: + objectRecordEventsForThisEventType[0].properties.after, + }, }); } else { objectRecordOperationBrowserEvents.push({ @@ -103,7 +107,11 @@ export const turnSseObjectRecordEventsToObjectRecordOperationBrowserEvents = ({ if (hasSingleEvent) { objectRecordOperationBrowserEvents.push({ objectMetadataItem, - operation: { type: 'create-one' }, + operation: { + type: 'create-one', + createdRecord: + objectRecordEventsForThisEventType[0].properties.after, + }, }); } else { objectRecordOperationBrowserEvents.push({