Update store on data model mutation (#18684)
- enrich SSE events with relations - remove queries from sse metadata events - on sse event, manage store - on object/field metadata changes, manage store TODO left: - fix other metadata items --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions <github-actions@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@@ -19,6 +19,71 @@ export const CREATE_ONE_OBJECT_METADATA_ITEM = gql`
|
||||
labelIdentifierFieldMetadataId
|
||||
imageIdentifierFieldMetadataId
|
||||
isLabelSyncedWithName
|
||||
fieldsList {
|
||||
id
|
||||
universalIdentifier
|
||||
type
|
||||
name
|
||||
label
|
||||
description
|
||||
icon
|
||||
isCustom
|
||||
isActive
|
||||
isSystem
|
||||
isUIReadOnly
|
||||
isNullable
|
||||
isUnique
|
||||
createdAt
|
||||
updatedAt
|
||||
defaultValue
|
||||
options
|
||||
settings
|
||||
isLabelSyncedWithName
|
||||
morphId
|
||||
applicationId
|
||||
relation {
|
||||
type
|
||||
sourceObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
targetObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
sourceFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
targetFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
morphRelations {
|
||||
type
|
||||
sourceObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
targetObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
sourceFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
targetFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -46,6 +111,48 @@ export const CREATE_ONE_FIELD_METADATA_ITEM = gql`
|
||||
object {
|
||||
id
|
||||
}
|
||||
relation {
|
||||
type
|
||||
sourceObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
targetObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
sourceFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
targetFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
morphRelations {
|
||||
type
|
||||
sourceObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
targetObjectMetadata {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
}
|
||||
sourceFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
targetFieldMetadata {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
+6
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
CreateOneObjectMetadataItemDocument,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
FindManyViewsDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
@@ -7,6 +8,9 @@ export const query = CreateOneObjectMetadataItemDocument;
|
||||
|
||||
export const findManyViewsQuery = FindManyViewsDocument;
|
||||
|
||||
export const findManyNavigationMenuItemsQuery =
|
||||
FindManyNavigationMenuItemsDocument;
|
||||
|
||||
export const variables = {
|
||||
input: {
|
||||
object: {
|
||||
@@ -35,4 +39,6 @@ export const responseData = {
|
||||
updatedAt: '',
|
||||
labelIdentifierFieldMetadataId: '20202020-72ba-4e11-a36d-e17b544541e1',
|
||||
imageIdentifierFieldMetadataId: '',
|
||||
isLabelSyncedWithName: false,
|
||||
fieldsList: [],
|
||||
};
|
||||
|
||||
+12
@@ -4,6 +4,7 @@ import { useCreateOneObjectMetadataItem } from '@/object-metadata/hooks/useCreat
|
||||
|
||||
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
|
||||
import {
|
||||
findManyNavigationMenuItemsQuery,
|
||||
findManyViewsQuery,
|
||||
query,
|
||||
responseData,
|
||||
@@ -63,6 +64,17 @@ const mocks = [
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: findManyNavigationMenuItemsQuery,
|
||||
variables: {},
|
||||
},
|
||||
result: jest.fn(() => ({
|
||||
data: {
|
||||
navigationMenuItems: [],
|
||||
},
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
const Wrapper = getJestMetadataAndApolloMocksWrapper({
|
||||
|
||||
+21
@@ -5,10 +5,13 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type FlatFieldMetadataItem } from '@/metadata-store/types/FlatFieldMetadataItem';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
|
||||
export const useCreateOneFieldMetadataItem = () => {
|
||||
@@ -18,6 +21,7 @@ export const useCreateOneFieldMetadataItem = () => {
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { addToDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const createOneFieldMetadataItem = async (
|
||||
input: CreateFieldInput,
|
||||
@@ -35,6 +39,23 @@ export const useCreateOneFieldMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const createdField = response.data?.createOneField;
|
||||
|
||||
if (isDefined(createdField)) {
|
||||
const { __typename, object, ...fieldData } = createdField;
|
||||
|
||||
addToDraft({
|
||||
key: 'fieldMetadataItems',
|
||||
items: [
|
||||
{
|
||||
...fieldData,
|
||||
objectMetadataId: object?.id ?? input.objectMetadataId,
|
||||
} as FlatFieldMetadataItem,
|
||||
],
|
||||
});
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
+78
-1
@@ -1,22 +1,32 @@
|
||||
import { useMutation } from '@apollo/client/react';
|
||||
import { useApolloClient, useMutation } from '@apollo/client/react';
|
||||
import {
|
||||
type CreateObjectInput,
|
||||
CreateOneObjectMetadataItemDocument,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
FindManyViewsDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type FlatFieldMetadataItem } from '@/metadata-store/types/FlatFieldMetadataItem';
|
||||
import { type FlatObjectMetadataItem } from '@/metadata-store/types/FlatObjectMetadataItem';
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCreateOneObjectMetadataItem = () => {
|
||||
const [createOneObjectMetadataItemMutation] = useMutation(
|
||||
CreateOneObjectMetadataItemDocument,
|
||||
);
|
||||
|
||||
const client = useApolloClient();
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { addToDraft, replaceDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const createOneObjectMetadataItem = async (
|
||||
input: CreateObjectInput,
|
||||
@@ -32,6 +42,73 @@ export const useCreateOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const createdObject = createdObjectMetadata.data?.createOneObject;
|
||||
|
||||
if (isDefined(createdObject)) {
|
||||
const {
|
||||
__typename: _objectTypename,
|
||||
fieldsList,
|
||||
...objectData
|
||||
} = createdObject;
|
||||
|
||||
addToDraft({
|
||||
key: 'objectMetadataItems',
|
||||
items: [objectData as FlatObjectMetadataItem],
|
||||
});
|
||||
|
||||
const flatFields = fieldsList.map((field) => {
|
||||
const { __typename: _fieldTypename, ...fieldData } = field;
|
||||
|
||||
return {
|
||||
...fieldData,
|
||||
objectMetadataId: createdObject.id,
|
||||
} as FlatFieldMetadataItem;
|
||||
});
|
||||
|
||||
addToDraft({ key: 'fieldMetadataItems', items: flatFields });
|
||||
|
||||
applyChanges();
|
||||
|
||||
const [viewsResult, navItemsResult] = await Promise.all([
|
||||
client.query({
|
||||
query: FindManyViewsDocument,
|
||||
variables: { objectMetadataId: createdObject.id },
|
||||
fetchPolicy: 'network-only',
|
||||
}),
|
||||
client.query({
|
||||
query: FindManyNavigationMenuItemsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
}),
|
||||
]);
|
||||
|
||||
const fetchedViews = viewsResult.data?.getViews ?? [];
|
||||
|
||||
const {
|
||||
flatViews,
|
||||
flatViewFields,
|
||||
flatViewFilters,
|
||||
flatViewSorts,
|
||||
flatViewGroups,
|
||||
flatViewFilterGroups,
|
||||
flatViewFieldGroups,
|
||||
} = splitViewWithRelated(fetchedViews);
|
||||
|
||||
addToDraft({ key: 'views', items: flatViews });
|
||||
addToDraft({ key: 'viewFields', items: flatViewFields });
|
||||
addToDraft({ key: 'viewFilters', items: flatViewFilters });
|
||||
addToDraft({ key: 'viewSorts', items: flatViewSorts });
|
||||
addToDraft({ key: 'viewGroups', items: flatViewGroups });
|
||||
addToDraft({ key: 'viewFilterGroups', items: flatViewFilterGroups });
|
||||
addToDraft({ key: 'viewFieldGroups', items: flatViewFieldGroups });
|
||||
|
||||
replaceDraft(
|
||||
'navigationMenuItems',
|
||||
navItemsResult.data?.navigationMenuItems ?? [],
|
||||
);
|
||||
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response: createdObjectMetadata,
|
||||
|
||||
+6
-1
@@ -3,6 +3,7 @@ import { DeleteOneFieldMetadataItemDocument } from '~/generated-metadata/graphql
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { recordIndexGroupAggregateFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState';
|
||||
import { recordIndexGroupAggregateOperationComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState';
|
||||
@@ -21,6 +22,7 @@ export const useDeleteOneFieldMetadataItem = () => {
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { removeFromDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const setRecordIndexGroupAggregateOperation = useSetAtomComponentState(
|
||||
recordIndexGroupAggregateOperationComponentState,
|
||||
@@ -63,7 +65,10 @@ export const useDeleteOneFieldMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: see if we can remove this lin altogether
|
||||
removeFromDraft({ key: 'fieldMetadataItems', itemIds: [idToDelete] });
|
||||
applyChanges();
|
||||
|
||||
// TODO: see if we can remove this line altogether
|
||||
await resetRecordIndexKanbanAggregateOperation(idToDelete);
|
||||
|
||||
return {
|
||||
|
||||
+5
@@ -2,6 +2,7 @@ import { useMutation } from '@apollo/client/react';
|
||||
import { DeleteOneObjectMetadataItemDocument } from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
@@ -15,6 +16,7 @@ export const useDeleteOneObjectMetadataItem = () => {
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { removeFromDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const deleteOneObjectMetadataItem = async (
|
||||
idToDelete: string,
|
||||
@@ -30,6 +32,9 @@ export const useDeleteOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
removeFromDraft({ key: 'objectMetadataItems', itemIds: [idToDelete] });
|
||||
applyChanges();
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
+5
-5
@@ -3,7 +3,7 @@ import { splitObjectMetadataItemWithRelated } from '@/metadata-store/utils/split
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useLoadMockedObjectMetadataItems = () => {
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
const { replaceDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const loadMockedObjectMetadataItems = useCallback(async () => {
|
||||
const { generatedMockObjectMetadataItems } = await import(
|
||||
@@ -13,11 +13,11 @@ export const useLoadMockedObjectMetadataItems = () => {
|
||||
const { flatObjects, flatFields, flatIndexes } =
|
||||
splitObjectMetadataItemWithRelated(generatedMockObjectMetadataItems);
|
||||
|
||||
updateDraft('objectMetadataItems', flatObjects);
|
||||
updateDraft('fieldMetadataItems', flatFields);
|
||||
updateDraft('indexMetadataItems', flatIndexes);
|
||||
replaceDraft('objectMetadataItems', flatObjects);
|
||||
replaceDraft('fieldMetadataItems', flatFields);
|
||||
replaceDraft('indexMetadataItems', flatIndexes);
|
||||
applyChanges();
|
||||
}, [updateDraft, applyChanges]);
|
||||
}, [replaceDraft, applyChanges]);
|
||||
|
||||
return {
|
||||
loadMockedObjectMetadataItems,
|
||||
|
||||
+18
@@ -5,12 +5,15 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type FlatFieldMetadataItem } from '@/metadata-store/types/FlatFieldMetadataItem';
|
||||
import { lastFieldMetadataItemUpdateState } from '@/object-metadata/states/lastFieldMetadataItemUpdateState';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
@@ -22,6 +25,7 @@ export const useUpdateOneFieldMetadataItem = () => {
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { updateInDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const setLastFieldMetadataItemUpdate = useSetAtomState(
|
||||
lastFieldMetadataItemUpdateState,
|
||||
@@ -58,6 +62,20 @@ export const useUpdateOneFieldMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const updatedField = response.data?.updateOneField;
|
||||
|
||||
if (isDefined(updatedField)) {
|
||||
const { __typename, object, ...fieldData } = updatedField;
|
||||
|
||||
updateInDraft('fieldMetadataItems', [
|
||||
{
|
||||
...fieldData,
|
||||
objectMetadataId: object?.id ?? objectMetadataId,
|
||||
} as FlatFieldMetadataItem,
|
||||
]);
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
setLastFieldMetadataItemUpdate({
|
||||
fieldMetadataItemId: fieldMetadataIdToUpdate,
|
||||
objectMetadataId,
|
||||
|
||||
+15
@@ -5,10 +5,13 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type FlatObjectMetadataItem } from '@/metadata-store/types/FlatObjectMetadataItem';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
|
||||
// TODO: Slice the Apollo store synchronously in the update function instead of subscribing, so we can use update after read in the same function call
|
||||
@@ -19,6 +22,7 @@ export const useUpdateOneObjectMetadataItem = () => {
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { updateInDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const updateOneObjectMetadataItem = async ({
|
||||
idToUpdate,
|
||||
@@ -39,6 +43,17 @@ export const useUpdateOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const updatedObject = response.data?.updateOneObject;
|
||||
|
||||
if (isDefined(updatedObject)) {
|
||||
const { __typename, ...objectData } = updatedObject;
|
||||
|
||||
updateInDraft('objectMetadataItems', [
|
||||
objectData as FlatObjectMetadataItem,
|
||||
]);
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
Reference in New Issue
Block a user