Fix creation of objects with acronym names (e.g. "O&J") (#17633)
Fixes https://github.com/twentyhq/twenty/issues/17544 **Problem** When users create custom objects with short acronym names like "O&J", the system generates an object name oJ. When creating relation fields, the morph field name was built using string concatenation: const morphFieldName = `target${capitalize("oJ")}`; // → "targetOJ" This produced "targetOJ", which failed validation because the camelCase check performed in `validateFlatFieldMetadataName` (camelCase(name) === name) returns "targetOj" for "targetOJ". The issue comes from consecutive camelCase() operations. **Solution** Actually, the `camelCase(name) === name` check is questionnable. What we want to check is that a name is in camelCase format, not that it corresponds to the camelCase version of a given string, while that's we are doing here. lodash does not provide camelCase validator, only camelCase convertor, so we used it as a way to validate the format of the name. We may feel like `camelCase(name) === name` checks whether a name is camel-cased, but in addition to that it is also checking for a camel case "idempotency" we don't necessarily have and do not need: for instance if an object's name is "iOS" (which could be inferred from a label "I O S"), it won't pass the check: camelCase("iOS") is "ios" and "ios" !== "iOS". The existing check with `STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX` acts as a camel case validator, so we don't need that camelCase() check.
This commit is contained in:
-10
@@ -1,5 +1,4 @@
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import camelCase from 'lodash.camelcase';
|
||||
import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata';
|
||||
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
@@ -38,15 +37,6 @@ export const validateFlatFieldMetadataName = ({
|
||||
});
|
||||
}
|
||||
|
||||
if (name !== camelCase(name)) {
|
||||
errors.push({
|
||||
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
message: t`Name should be in camelCase`,
|
||||
userFriendlyMessage: msg`Name should be in camelCase`,
|
||||
value: name,
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!name.match(
|
||||
STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX,
|
||||
|
||||
-11
@@ -1,5 +1,4 @@
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import camelCase from 'lodash.camelcase';
|
||||
import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata';
|
||||
|
||||
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
|
||||
@@ -41,16 +40,6 @@ export const validateFlatObjectMetadataNames = ({
|
||||
});
|
||||
}
|
||||
|
||||
// CamelCase check
|
||||
if (name !== camelCase(name)) {
|
||||
errors.push({
|
||||
code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
message: `Name should be in camelCase`,
|
||||
userFriendlyMessage: msg`Name should be in camelCase`,
|
||||
value: name,
|
||||
});
|
||||
}
|
||||
|
||||
// Format check
|
||||
if (
|
||||
!name.match(
|
||||
|
||||
-6
@@ -9,12 +9,6 @@ exports[`Field metadata relation update should fail relation when name is not in
|
||||
"fieldMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "New Name",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
|
||||
-90
@@ -6802,12 +6802,6 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas
|
||||
"objectMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "Not_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7399,12 +7393,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetA a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7429,12 +7417,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "a a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7459,12 +7441,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetA a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7489,12 +7465,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "a a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7519,12 +7489,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "a a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -7575,12 +7539,6 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only
|
||||
"objectMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "a a",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -8921,12 +8879,6 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetΜ",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -8975,12 +8927,6 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetΜ",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10406,12 +10352,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetNot_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10436,12 +10376,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "Not_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10466,12 +10400,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "targetNot_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10496,12 +10424,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "Not_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10526,12 +10448,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
},
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "Not_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_FIELD_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
@@ -10582,12 +10498,6 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC
|
||||
"objectMetadata": [
|
||||
{
|
||||
"errors": [
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name should be in camelCase",
|
||||
"userFriendlyMessage": "Name should be in camelCase",
|
||||
"value": "Not_Camel_Case",
|
||||
},
|
||||
{
|
||||
"code": "INVALID_OBJECT_INPUT",
|
||||
"message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters",
|
||||
|
||||
Reference in New Issue
Block a user