Feat/multivalue limit (#14961)
## Summary 1. This change introduces the ability to limit how many values a multi-value field can contain (for example: maximum number of emails, phone numbers, links, or array items). 2. It centralizes the limit as a shared constant and type, validates settings on the server, updates front-end types and components to consume the setting, and adds a small settings UI so workspace admins can change the limit per field. 3. Default behavior is preserved: if no max is configured, the existing default (10) is used. ## **Fixes Issue:** [#14740 ](https://github.com/twentyhq/twenty/issues/14740) ## Manual Test Screenshot <img width="383" height="451" alt="Screenshot 2025-10-08 002413" src="https://github.com/user-attachments/assets/a7704af6-10ef-4d10-b8c9-a9eeca03bfd9" /> ### Values in fields https://github.com/user-attachments/assets/7f59c4f7-3aca-4f83-8c04-3d44988316e3 Let me know if any changes are needed --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
This commit is contained in:
+5
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
type AllowedAddressSubField,
|
||||
type FieldMetadataMultiItemSettings,
|
||||
type FieldMetadataType,
|
||||
type IsExactly,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -62,6 +63,10 @@ type FieldMetadataSettingsMapping = {
|
||||
[FieldMetadataType.ADDRESS]: FieldMetadataAddressSettings | null;
|
||||
[FieldMetadataType.MORPH_RELATION]: FieldMetadataRelationSettings;
|
||||
[FieldMetadataType.TS_VECTOR]: FieldMetadataTsVectorSettings | null;
|
||||
[FieldMetadataType.PHONES]: FieldMetadataMultiItemSettings | null;
|
||||
[FieldMetadataType.EMAILS]: FieldMetadataMultiItemSettings | null;
|
||||
[FieldMetadataType.LINKS]: FieldMetadataMultiItemSettings | null;
|
||||
[FieldMetadataType.ARRAY]: FieldMetadataMultiItemSettings | null;
|
||||
};
|
||||
|
||||
export type AllFieldMetadataSettings =
|
||||
|
||||
+18
@@ -12,6 +12,7 @@ import {
|
||||
type ValidationError,
|
||||
validateOrReject,
|
||||
} from 'class-validator';
|
||||
import { MULTI_ITEM_FIELD_MIN_MAX_VALUES } from 'twenty-shared/constants';
|
||||
import {
|
||||
ALLOWED_ADDRESS_SUBFIELDS,
|
||||
type AllowedAddressSubField,
|
||||
@@ -72,6 +73,13 @@ class AddressSettingsValidation {
|
||||
@IsEnum(ALLOWED_ADDRESS_SUBFIELDS, { each: true })
|
||||
subFields?: AllowedAddressSubField[];
|
||||
}
|
||||
|
||||
class MultipleValuesSettingsValidation {
|
||||
@IsOptional()
|
||||
@IsInt()
|
||||
@Min(MULTI_ITEM_FIELD_MIN_MAX_VALUES)
|
||||
maxNumberOfValues?: number;
|
||||
}
|
||||
@Injectable()
|
||||
export class FieldMetadataValidationService {
|
||||
constructor(
|
||||
@@ -107,6 +115,16 @@ export class FieldMetadataValidationService {
|
||||
settings,
|
||||
});
|
||||
break;
|
||||
case FieldMetadataType.PHONES:
|
||||
case FieldMetadataType.EMAILS:
|
||||
case FieldMetadataType.LINKS:
|
||||
case FieldMetadataType.ARRAY:
|
||||
await this.validateSettings({
|
||||
type: fieldType,
|
||||
validator: MultipleValuesSettingsValidation,
|
||||
settings,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+25
-4
@@ -1,5 +1,6 @@
|
||||
import { type Expect, type HasAllProperties } from 'twenty-shared/testing';
|
||||
import {
|
||||
type FieldMetadataMultiItemSettings,
|
||||
type FieldMetadataType,
|
||||
type NullablePartial,
|
||||
} from 'twenty-shared/types';
|
||||
@@ -133,10 +134,6 @@ type SettingsAssertions = [
|
||||
Expect<HasAllProperties<RawJsonFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<RichTextFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<ActorFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<ArrayFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<PhonesFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<EmailsFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<LinksFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<UUIDFieldMetadata, NotDefinedSettings>>,
|
||||
Expect<HasAllProperties<BooleanFieldMetadata, NotDefinedSettings>>,
|
||||
|
||||
@@ -164,6 +161,30 @@ type SettingsAssertions = [
|
||||
{ settings: FieldMetadataDateTimeSettings | null }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
HasAllProperties<
|
||||
ArrayFieldMetadata,
|
||||
{ settings: FieldMetadataMultiItemSettings | null }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
HasAllProperties<
|
||||
PhonesFieldMetadata,
|
||||
{ settings: FieldMetadataMultiItemSettings | null }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
HasAllProperties<
|
||||
EmailsFieldMetadata,
|
||||
{ settings: FieldMetadataMultiItemSettings | null }
|
||||
>
|
||||
>,
|
||||
Expect<
|
||||
HasAllProperties<
|
||||
LinksFieldMetadata,
|
||||
{ settings: FieldMetadataMultiItemSettings | null }
|
||||
>
|
||||
>,
|
||||
|
||||
Expect<
|
||||
HasAllProperties<
|
||||
|
||||
Reference in New Issue
Block a user