Skip to content

Commit 1ecc096

Browse files
committed
chore(server): wip post peer session
1 parent 9cade56 commit 1ecc096

File tree

4 files changed

+199
-39
lines changed

4 files changed

+199
-39
lines changed

packages/twenty-server/src/engine/metadata-modules/field-metadata/services/field-metadata-enum-validation.service.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { FieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-met
99
import { FieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-options.interface';
1010

1111
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
12+
import { FieldMetadataDefaultValueString } from 'src/engine/metadata-modules/field-metadata/dtos/default-value.input';
1213
import { UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
1314
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
1415
import {
@@ -33,6 +34,8 @@ type ValidateEnumFieldMetadataArgs = {
3334
fieldMetadataType: FieldMetadataType;
3435
};
3536

37+
const QUOTED_STRING_REGEX = /^['"](.*)['"]$/;
38+
3639
@Injectable()
3740
export class FieldMetadataEnumValidationService {
3841
constructor() {}
@@ -206,52 +209,48 @@ export class FieldMetadataEnumValidationService {
206209

207210
private validateMultiSelectDefaultValue(
208211
options: FieldMetadataOptions,
209-
defaultValues: FieldMetadataDefaultValue,
212+
defaulValue: FieldMetadataDefaultValueString['value'],
210213
) {
211-
if (!isDefined(defaultValues)) {
212-
return;
213-
}
214+
// TMP force cast should be fixed
215+
const parsedDefaultValues: string[] = JSON.parse(defaulValue as string);
214216

215-
if (!Array.isArray(defaultValues)) {
217+
if (!Array.isArray(parsedDefaultValues)) {
216218
throw new FieldMetadataException(
217219
'Default value for multi-select must be an array',
218220
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
219221
);
220222
}
221223

222-
const sanitizedValues = defaultValues.map(
223-
(value) =>
224-
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
225-
{ value: value as string },
226-
['value'],
227-
).value,
228-
);
229-
230224
const validators: Validator<string[]>[] = [
231225
{
226+
// praise: nice
232227
validator: (values) => new Set(values).size !== values.length,
233228
message: 'Default values must be unique',
234229
},
235230
{
236-
validator: (values) =>
237-
!values.every((value) =>
231+
validator: (values) => {
232+
const unQuotedValues = values.map((value) =>
233+
value.replace(QUOTED_STRING_REGEX, '$1'),
234+
);
235+
return !unQuotedValues.every((value) =>
238236
options.some((option) => option.value === value),
239-
),
240-
message: `Default values must be one of the option values: ${sanitizedValues.join(
237+
);
238+
},
239+
message: `Default values must be one of the option values: ${parsedDefaultValues.join(
241240
', ',
242241
)}`,
243242
},
244243
];
245244

246245
validators.forEach((validator) =>
247-
this.validatorRunner(sanitizedValues, validator),
246+
this.validatorRunner(parsedDefaultValues, validator),
248247
);
249248
}
250249

251250
private validateDefaultValueByType(
252251
fieldType: FieldMetadataType,
253252
options: FieldMetadataOptions,
254-
defaultValue: FieldMetadataDefaultValue,
253+
defaultValue: FieldMetadataDefaultValueString['value'],
255254
) {
256255
switch (fieldType) {
257256
case FieldMetadataType.SELECT:
@@ -297,6 +296,7 @@ export class FieldMetadataEnumValidationService {
297296
this.validateDefaultValueByType(
298297
fieldMetadataType,
299298
options,
299+
// @ts-expect-error temporary fix, we gonna have to type the input default value
300300
fieldMetadataInput.defaultValue,
301301
);
302302
}

packages/twenty-server/src/utils/__test__/trim-and-remove-duplicated-whitespaces-from-object-string-properties.spec.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,6 @@ describe('trim-and-remove-duplicated-whitespaces-from-object-string-properties',
9494
expected: { name: ' John Doe ', description: 'this is a test' },
9595
},
9696
},
97-
{
98-
title: 'should strip quotes from string properties',
99-
context: {
100-
input: {
101-
name: '"John Doe"',
102-
description: "'This is a test'",
103-
value: 'OPTION_1', // no quotes
104-
},
105-
keys: ['name', 'description', 'value'],
106-
expected: {
107-
name: 'John Doe',
108-
description: 'This is a test',
109-
value: 'OPTION_1',
110-
},
111-
},
112-
},
11397
];
11498

11599
test.each(testCases)('$title', ({ context: { input, keys, expected } }) => {

packages/twenty-server/src/utils/trim-and-remove-duplicated-whitespaces-from-object-string-properties.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ type StringPropertyKeys<T> = {
1111
const sanitizeString = (str: string | null) =>
1212
isDefined(str) ? str.trim().replace(/\s+/g, ' ') : str;
1313

14-
const stripQuotes = (str: string | null) =>
15-
isDefined(str) ? str.replace(/^['"](.*)['"]$/, '$1') : str;
16-
1714
export const trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties = <T>(
1815
obj: T,
1916
keys: StringPropertyKeys<T>[],
@@ -27,7 +24,7 @@ export const trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties = <T>(
2724

2825
return {
2926
...acc,
30-
[key]: stripQuotes(sanitizeString(acc[key] as string | null)),
27+
[key]: sanitizeString(acc[key] as string | null),
3128
};
3229
}, obj);
3330
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import { UpdateCreateFieldMetadataSelectTestCase } from 'test/integration/metadata/suites/field-metadata/update-create-one-field-metadata-select-tests-cases';
2+
import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util';
3+
import {
4+
LISTING_NAME_PLURAL,
5+
LISTING_NAME_SINGULAR,
6+
} from 'test/integration/metadata/suites/object-metadata/constants/test-object-names.constant';
7+
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
8+
import { FieldMetadataType } from 'twenty-shared/types';
9+
import { isDefined } from 'twenty-shared/utils';
10+
11+
import { FieldMetadataComplexOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
12+
import { forceCreateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/force-create-one-object-metadata.util';
13+
14+
describe('Field metadata select creation tests group', () => {
15+
let createdObjectMetadataId: string;
16+
17+
beforeEach(async () => {
18+
const { data, errors } = await forceCreateOneObjectMetadata({
19+
input: {
20+
labelSingular: LISTING_NAME_SINGULAR,
21+
labelPlural: LISTING_NAME_PLURAL,
22+
nameSingular: LISTING_NAME_SINGULAR,
23+
namePlural: LISTING_NAME_PLURAL,
24+
icon: 'IconBuildingSkyscraper',
25+
isLabelSyncedWithName: false,
26+
},
27+
});
28+
29+
console.log(errors);
30+
31+
createdObjectMetadataId = data.createOneObject.id;
32+
});
33+
34+
afterEach(async () => {
35+
await deleteOneObjectMetadata({
36+
input: { idToDelete: createdObjectMetadataId },
37+
});
38+
});
39+
40+
const successfullTestCases: UpdateCreateFieldMetadataSelectTestCase[] = [
41+
// {
42+
// title: 'should succeed with provided option id',
43+
// context: {
44+
// input: {
45+
// options: [
46+
// {
47+
// label: 'Option 1',
48+
// value: 'OPTION_1',
49+
// color: 'green',
50+
// position: 1,
51+
// id: '26c602c3-cba9-4d83-92d4-4ba7dbae2f31',
52+
// },
53+
// ],
54+
// },
55+
// },
56+
// },
57+
{
58+
title: 'should succeed with valid multi-select default values',
59+
context: {
60+
input: {
61+
defaultValue: JSON.stringify(["'OPTION_1'", "'OPTION_2'"]),
62+
options: [
63+
{
64+
label: 'Option 1',
65+
value: 'OPTION_1',
66+
color: 'green',
67+
position: 1,
68+
},
69+
{
70+
label: 'Option 2',
71+
value: 'OPTION_2',
72+
color: 'blue',
73+
position: 2,
74+
},
75+
],
76+
},
77+
},
78+
},
79+
// {
80+
// title: 'should succeed with empty multi-select default values array',
81+
// context: {
82+
// input: {
83+
// defaultValue: [],
84+
// options: [
85+
// {
86+
// label: 'Option 1',
87+
// value: 'OPTION_1',
88+
// color: 'green',
89+
// position: 1,
90+
// },
91+
// ],
92+
// },
93+
// },
94+
// },
95+
];
96+
97+
test.each(successfullTestCases)(
98+
'Create $title',
99+
async ({ context: { input, expectedOptions } }) => {
100+
const { data, errors } = await createOneFieldMetadata({
101+
input: {
102+
objectMetadataId: createdObjectMetadataId,
103+
type: FieldMetadataType.MULTI_SELECT,
104+
name: 'testField',
105+
label: 'Test Field',
106+
isLabelSyncedWithName: false,
107+
...input,
108+
},
109+
gqlFields: `
110+
id
111+
options
112+
defaultValue
113+
`,
114+
});
115+
116+
console.log({ data, errors });
117+
118+
expect(data).not.toBeNull();
119+
expect(data.createOneField).toBeDefined();
120+
const createdOptions: FieldMetadataComplexOption[] =
121+
data.createOneField.options;
122+
123+
const optionsToCompare = expectedOptions ?? input.options;
124+
125+
expect(errors).toBeUndefined();
126+
expect(createdOptions.length).toBe(optionsToCompare.length);
127+
createdOptions.forEach((option) => expect(option.id).toBeDefined());
128+
expect(createdOptions).toMatchObject(optionsToCompare);
129+
130+
if (isDefined(input.defaultValue)) {
131+
expect(data.createOneField.defaultValue).toEqual(input.defaultValue);
132+
}
133+
},
134+
);
135+
136+
const failingTestCases: UpdateCreateFieldMetadataSelectTestCase[] = [
137+
{
138+
title: 'should succeed with empty multi-select default values array',
139+
context: {
140+
input: {
141+
defaultValue: 'Option_1',
142+
options: [
143+
{
144+
label: 'Option 1',
145+
value: 'OPTION_1',
146+
color: 'green',
147+
position: 1,
148+
},
149+
],
150+
},
151+
},
152+
},
153+
];
154+
155+
// test.each(failingTestCases)(
156+
// 'Create $title',
157+
// async ({ context: { input } }) => {
158+
// const { data, errors } = await createOneFieldMetadata({
159+
// input: {
160+
// objectMetadataId: createdObjectMetadataId,
161+
// type: FieldMetadataType.MULTI_SELECT,
162+
// name: 'testField',
163+
// label: 'Test Field',
164+
// isLabelSyncedWithName: false,
165+
// ...input,
166+
// },
167+
// gqlFields: `
168+
// id
169+
// options
170+
// defaultValue
171+
// `,
172+
// });
173+
174+
// expect(data).toBeNull();
175+
// expect(errors).toBeDefined();
176+
// expect(errors).toMatchSnapshot();
177+
// },
178+
// );
179+
});

0 commit comments

Comments
 (0)