Use defaultValue in currency input (#4911)
- Fix default value sent to backend, using single quotes by default - Use default value in field definition and column definition so that field inputs can access it - Used currency default value in CurrencyFieldInput --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -3,104 +3,103 @@ import { validateDefaultValueForType } from 'src/engine/metadata-modules/field-m
|
||||
|
||||
describe('validateDefaultValueForType', () => {
|
||||
it('should return true for null defaultValue', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.TEXT, null)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.TEXT, null).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
// Dynamic default values
|
||||
it('should validate uuid dynamic default value for UUID type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.UUID, 'uuid')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.UUID, 'uuid').isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should validate now dynamic default value for DATE_TIME type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.DATE_TIME, 'now'),
|
||||
validateDefaultValueForType(FieldMetadataType.DATE_TIME, 'now').isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for mismatched dynamic default value', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.UUID, 'now')).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.UUID, 'now').isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// Static default values
|
||||
it('should validate string default value for TEXT type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.TEXT, "'test'")).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.TEXT, "'test'").isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for TEXT type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.TEXT, 123)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.TEXT, 123).isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate string default value for PHONE type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PHONE, "'+123456789'"),
|
||||
validateDefaultValueForType(FieldMetadataType.PHONE, "'+123456789'")
|
||||
.isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for PHONE type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.PHONE, 123)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PHONE, 123).isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate string default value for EMAIL type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(
|
||||
FieldMetadataType.EMAIL,
|
||||
"'test@example.com'",
|
||||
),
|
||||
validateDefaultValueForType(FieldMetadataType.EMAIL, "'test@example.com'")
|
||||
.isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid string default value for EMAIL type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.EMAIL, 123)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.EMAIL, 123).isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate number default value for NUMBER type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.NUMBER, 100)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.NUMBER, 100).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid number default value for NUMBER type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.NUMBER, '100')).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.NUMBER, '100').isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate number default value for PROBABILITY type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, 0.5),
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, 0.5).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid number default value for PROBABILITY type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, '50%'),
|
||||
validateDefaultValueForType(FieldMetadataType.PROBABILITY, '50%').isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should validate boolean default value for BOOLEAN type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.BOOLEAN, true)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.BOOLEAN, true).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid boolean default value for BOOLEAN type', () => {
|
||||
expect(validateDefaultValueForType(FieldMetadataType.BOOLEAN, 'true')).toBe(
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
validateDefaultValueForType(FieldMetadataType.BOOLEAN, 'true').isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// LINK type
|
||||
@ -109,7 +108,7 @@ describe('validateDefaultValueForType', () => {
|
||||
validateDefaultValueForType(FieldMetadataType.LINK, {
|
||||
label: "'http://example.com'",
|
||||
url: "'Example'",
|
||||
}),
|
||||
}).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
@ -120,7 +119,7 @@ describe('validateDefaultValueForType', () => {
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ label: 123, url: {} },
|
||||
FieldMetadataType.LINK,
|
||||
),
|
||||
).isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
@ -130,7 +129,7 @@ describe('validateDefaultValueForType', () => {
|
||||
validateDefaultValueForType(FieldMetadataType.CURRENCY, {
|
||||
amountMicros: '100',
|
||||
currencyCode: "'USD'",
|
||||
}),
|
||||
}).isValid,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
@ -141,14 +140,15 @@ describe('validateDefaultValueForType', () => {
|
||||
// @ts-expect-error Just for testing purposes
|
||||
{ amountMicros: 100, currencyCode: "'USD'" },
|
||||
FieldMetadataType.CURRENCY,
|
||||
),
|
||||
).isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// Unknown type
|
||||
it('should return false for unknown type', () => {
|
||||
expect(
|
||||
validateDefaultValueForType('unknown' as FieldMetadataType, "'test'"),
|
||||
validateDefaultValueForType('unknown' as FieldMetadataType, "'test'")
|
||||
.isValid,
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { validateSync } from 'class-validator';
|
||||
import { ValidationError, validateSync } from 'class-validator';
|
||||
|
||||
import {
|
||||
FieldMetadataClassValidation,
|
||||
@ -49,17 +49,32 @@ export const defaultValueValidatorsMap = {
|
||||
[FieldMetadataType.RAW_JSON]: [FieldMetadataDefaultValueRawJson],
|
||||
};
|
||||
|
||||
type ValidationResult = {
|
||||
isValid: boolean;
|
||||
errors: ValidationError[];
|
||||
};
|
||||
|
||||
export const validateDefaultValueForType = (
|
||||
type: FieldMetadataType,
|
||||
defaultValue: FieldMetadataDefaultValue,
|
||||
): boolean => {
|
||||
if (defaultValue === null) return true;
|
||||
): ValidationResult => {
|
||||
if (defaultValue === null) {
|
||||
return {
|
||||
isValid: true,
|
||||
errors: [],
|
||||
};
|
||||
}
|
||||
|
||||
const validators = defaultValueValidatorsMap[type];
|
||||
const validators = defaultValueValidatorsMap[type] as any[];
|
||||
|
||||
if (!validators) return false;
|
||||
if (!validators) {
|
||||
return {
|
||||
isValid: false,
|
||||
errors: [],
|
||||
};
|
||||
}
|
||||
|
||||
const isValid = validators.some((validator) => {
|
||||
const validationResults = validators.map((validator) => {
|
||||
const conputedDefaultValue = isCompositeFieldMetadataType(type)
|
||||
? defaultValue
|
||||
: { value: defaultValue };
|
||||
@ -69,14 +84,24 @@ export const validateDefaultValueForType = (
|
||||
FieldMetadataClassValidation
|
||||
>(validator, conputedDefaultValue as FieldMetadataClassValidation);
|
||||
|
||||
return (
|
||||
validateSync(defaultValueInstance, {
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
forbidUnknownValues: true,
|
||||
}).length === 0
|
||||
);
|
||||
const errors = validateSync(defaultValueInstance, {
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
|
||||
const isValid = errors.length === 0;
|
||||
|
||||
return {
|
||||
isValid,
|
||||
errors,
|
||||
};
|
||||
});
|
||||
|
||||
return isValid;
|
||||
const isValid = validationResults.some((result) => result.isValid);
|
||||
|
||||
return {
|
||||
isValid,
|
||||
errors: validationResults.flatMap((result) => result.errors),
|
||||
};
|
||||
};
|
||||
|
||||
@ -14,13 +14,17 @@ import {
|
||||
FieldMetadataType,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { validateDefaultValueForType } from 'src/engine/metadata-modules/field-metadata/utils/validate-default-value-for-type.util';
|
||||
import { LoggerService } from 'src/engine/integrations/logger/logger.service';
|
||||
|
||||
@Injectable()
|
||||
@ValidatorConstraint({ name: 'isFieldMetadataDefaultValue', async: true })
|
||||
export class IsFieldMetadataDefaultValue
|
||||
implements ValidatorConstraintInterface
|
||||
{
|
||||
constructor(private readonly fieldMetadataService: FieldMetadataService) {}
|
||||
constructor(
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
private readonly loggerService: LoggerService,
|
||||
) {}
|
||||
|
||||
async validate(
|
||||
value: FieldMetadataDefaultValue,
|
||||
@ -48,7 +52,19 @@ export class IsFieldMetadataDefaultValue
|
||||
type = fieldMetadata.type;
|
||||
}
|
||||
|
||||
return validateDefaultValueForType(type, value);
|
||||
const validationResult = validateDefaultValueForType(type, value);
|
||||
|
||||
if (!validationResult.isValid) {
|
||||
this.loggerService.error(
|
||||
{
|
||||
message: 'Error during field validation',
|
||||
errors: validationResult.errors,
|
||||
},
|
||||
'Field Metadata Validation',
|
||||
);
|
||||
}
|
||||
|
||||
return validationResult.isValid;
|
||||
}
|
||||
|
||||
defaultMessage(): string {
|
||||
|
||||
Reference in New Issue
Block a user