[v2_FIX] Update standard object/field (#15233)
# Introduction Refactoring the standard overrides dispatcher to only pass over fields to has to be dispatched in the standardOverrides entry and let the other side effects resulting from out of standard overrides mutation trigger Related to https://github.com/twentyhq/core-team-issues/issues/1753 ## This allows - standard field settings, options etc updates and so on ## Remark - Determine what we should do on object deactivation ( right now in production we can still access deactivated object relation properties and so on e.g deactivate opportunities still accessible from a view field on company ( still have to re-create it as it has been deleted ) => decided to leave as it is right now, `isActive` could be considered as uiDeactivated in the end - We should also add forbidden standard field mutations validation inside the builder itself ( here we want to early return in the api input transpiler too as we don't want to spread invalid side effects ) => or in the end we could just centralize both but it will generate several errors ## Coverage ```ts PASS test/integration/metadata/suites/object-metadata/successful-update-one-standard-object-metadata.integration-spec.ts PASS test/integration/metadata/suites/field-metadata/successful-update-one-standard-field-metadata.integration-spec.ts PASS test/integration/metadata/suites/object-metadata/failing-update-one-standard-object-metadata.integration-spec.ts PASS test/integration/metadata/suites/field-metadata/failing-update-one-standard-field-metadata.integration-spec.ts Test Suites: 4 passed, 4 total Tests: 18 passed, 18 total Snapshots: 16 passed, 16 total Time: 8.721 s, estimated 10 s ``` ## Update post review Faced a behavior where updating back the company label to its original value would result in storing this value in the standard overrides Refactored both field and object transpilation behavior to rather remove the standard override value instead and let fallback on original value Yes it's quite duplicated will factorize once we move this inside the builder
This commit is contained in:
+18
-67
@@ -5,13 +5,11 @@ import {
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { type FieldMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-standard-overrides-properties.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
|
||||
@@ -23,6 +21,7 @@ import {
|
||||
type FlatFieldMetadataUpdateSideEffects,
|
||||
handleFlatFieldMetadataUpdateSideEffect,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-flat-field-metadata-update-side-effect.util';
|
||||
import { sanitizeRawUpdateFieldInput } from 'src/engine/metadata-modules/flat-field-metadata/utils/sanitize-raw-update-field-input';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
|
||||
|
||||
@@ -57,10 +56,6 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
'objectMetadataId',
|
||||
'id',
|
||||
]);
|
||||
const updatedEditableFieldProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateFieldInput,
|
||||
FLAT_FIELD_METADATA_EDITABLE_PROPERTIES,
|
||||
);
|
||||
|
||||
const existingFlatFieldMetadataToUpdate = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: updateFieldInputInformalProperties.id,
|
||||
@@ -78,62 +73,12 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
};
|
||||
}
|
||||
|
||||
if (isStandardMetadata(existingFlatFieldMetadataToUpdate)) {
|
||||
const invalidUpdatedProperties = Object.keys(
|
||||
updatedEditableFieldProperties,
|
||||
).filter((property) =>
|
||||
FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES.includes(
|
||||
property as FieldMetadataStandardOverridesProperties,
|
||||
),
|
||||
);
|
||||
|
||||
if (invalidUpdatedProperties.length > 0) {
|
||||
const invalidProperties = invalidUpdatedProperties.join(', ');
|
||||
|
||||
return {
|
||||
status: 'fail',
|
||||
error: {
|
||||
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
message: `Cannot update standard field metadata properties: ${invalidProperties}`,
|
||||
userFriendlyMessage: msg`Cannot update standard field properties: ${invalidProperties}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const updatedStandardFlatFieldMetadata =
|
||||
FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES.reduce((acc, property) => {
|
||||
const isPropertyUpdated =
|
||||
updatedEditableFieldProperties[property] !== undefined;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
standardOverrides: {
|
||||
...acc.standardOverrides,
|
||||
...(isPropertyUpdated
|
||||
? { [property]: updatedEditableFieldProperties[property] }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
}, existingFlatFieldMetadataToUpdate);
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
result: {
|
||||
flatViewsToUpdate: [],
|
||||
flatViewsToDelete: [],
|
||||
flatViewGroupsToCreate: [],
|
||||
flatViewGroupsToDelete: [],
|
||||
flatViewGroupsToUpdate: [],
|
||||
flatFieldMetadatasToUpdate: [updatedStandardFlatFieldMetadata],
|
||||
flatIndexMetadatasToUpdate: [],
|
||||
flatIndexMetadatasToDelete: [],
|
||||
flatIndexMetadatasToCreate: [],
|
||||
flatViewFiltersToDelete: [],
|
||||
flatViewFiltersToUpdate: [],
|
||||
flatViewFieldsToDelete: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
const isStandardField = isStandardMetadata(existingFlatFieldMetadataToUpdate);
|
||||
const { standardOverrides, updatedEditableFieldProperties } =
|
||||
sanitizeRawUpdateFieldInput({
|
||||
existingFlatFieldMetadata: existingFlatFieldMetadataToUpdate,
|
||||
rawUpdateFieldInput,
|
||||
});
|
||||
|
||||
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: existingFlatFieldMetadataToUpdate.objectMetadataId,
|
||||
@@ -176,11 +121,17 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
const optimisticiallyUpdatedFlatFieldMetadatas =
|
||||
flatFieldMetadatasToUpdate.reduce<FlatFieldMetadataAndIndexToUpdate>(
|
||||
(accumulator, fromFlatFieldMetadata) => {
|
||||
const toFlatFieldMetadata = mergeUpdateInExistingRecord({
|
||||
existing: fromFlatFieldMetadata,
|
||||
properties: FLAT_FIELD_METADATA_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableFieldProperties,
|
||||
});
|
||||
const toFlatFieldMetadata = {
|
||||
...mergeUpdateInExistingRecord({
|
||||
existing: fromFlatFieldMetadata,
|
||||
properties:
|
||||
FLAT_FIELD_METADATA_EDITABLE_PROPERTIES[
|
||||
isStandardField ? 'standard' : 'custom'
|
||||
],
|
||||
update: updatedEditableFieldProperties,
|
||||
}),
|
||||
standardOverrides,
|
||||
};
|
||||
|
||||
const {
|
||||
flatViewGroupsToCreate,
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
|
||||
import { type FlatFieldMetadataEditableProperties } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-editable-properties.constant';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
|
||||
type SanitizeRawUpdateFieldInputArgs = {
|
||||
rawUpdateFieldInput: UpdateFieldInput;
|
||||
existingFlatFieldMetadata: FlatFieldMetadata;
|
||||
};
|
||||
export const sanitizeRawUpdateFieldInput = ({
|
||||
existingFlatFieldMetadata,
|
||||
rawUpdateFieldInput,
|
||||
}: SanitizeRawUpdateFieldInputArgs) => {
|
||||
const isStandardField = isStandardMetadata(existingFlatFieldMetadata);
|
||||
const updatedEditableFieldProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateFieldInput,
|
||||
[
|
||||
...new Set([
|
||||
...FLAT_FIELD_METADATA_EDITABLE_PROPERTIES.standard,
|
||||
...FLAT_FIELD_METADATA_EDITABLE_PROPERTIES.custom,
|
||||
]),
|
||||
],
|
||||
);
|
||||
|
||||
if (!isStandardField) {
|
||||
return {
|
||||
updatedEditableFieldProperties,
|
||||
standardOverrides: null,
|
||||
};
|
||||
}
|
||||
|
||||
const invalidUpdatedProperties = Object.keys(
|
||||
updatedEditableFieldProperties,
|
||||
).filter(
|
||||
(property: FlatFieldMetadataEditableProperties) =>
|
||||
!FLAT_FIELD_METADATA_EDITABLE_PROPERTIES.standard.includes(
|
||||
property as (typeof FLAT_FIELD_METADATA_EDITABLE_PROPERTIES.standard)[number],
|
||||
),
|
||||
);
|
||||
|
||||
if (invalidUpdatedProperties.length > 0) {
|
||||
throw new FieldMetadataException(
|
||||
`Cannot edit standard field metadata properties: ${invalidUpdatedProperties.join(', ')}`,
|
||||
FieldMetadataExceptionCode.FIELD_MUTATION_NOT_ALLOWED,
|
||||
);
|
||||
}
|
||||
|
||||
const standardOverrides = FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES.reduce(
|
||||
(standardOverrides, property) => {
|
||||
const propertyValue = updatedEditableFieldProperties[property];
|
||||
|
||||
const isPropertyUpdated =
|
||||
updatedEditableFieldProperties[property] !== undefined;
|
||||
|
||||
if (!isPropertyUpdated) {
|
||||
return standardOverrides;
|
||||
}
|
||||
delete updatedEditableFieldProperties[property];
|
||||
|
||||
if (propertyValue === existingFlatFieldMetadata[property]) {
|
||||
if (
|
||||
isDefined(standardOverrides) &&
|
||||
Object.prototype.hasOwnProperty.call(standardOverrides, property)
|
||||
) {
|
||||
const { [property]: _, ...restOverrides } = standardOverrides;
|
||||
|
||||
return restOverrides;
|
||||
}
|
||||
|
||||
return standardOverrides;
|
||||
}
|
||||
|
||||
return {
|
||||
...standardOverrides,
|
||||
[property]: propertyValue,
|
||||
};
|
||||
},
|
||||
existingFlatFieldMetadata.standardOverrides,
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(standardOverrides) &&
|
||||
Object.keys(standardOverrides).length === 0
|
||||
) {
|
||||
return {
|
||||
standardOverrides: null,
|
||||
updatedEditableFieldProperties,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
standardOverrides,
|
||||
updatedEditableFieldProperties,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user