Skip to content

Commit 3309290

Browse files
authored
feat(input_schema): datepicker dateType property (#485)
This PR replace `allowAbsolute`/`allowRelative` boolean properties for datepicker with single `dateType` property that accepts values `absolute`, `relative` and `absoluteOrRelative` based on: - apify/apify-docs#1227 - https://apify.slack.com/archives/C010Q0FBYG3/p1730210649660309?thread_ts=1728907212.870409&cid=C010Q0FBYG3 `dateType` property: - is optional - is valid only when `editor` is `datepicker` - is only for ui input representation, no validation is executed based on this property
1 parent bcf9e6f commit 3309290

File tree

8 files changed

+25
-435
lines changed

8 files changed

+25
-435
lines changed

packages/input_schema/src/input_schema.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,7 @@ export function parseAjvError(
4848
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
4949
} else if (error.keyword === 'required') {
5050
fieldKey = error.params.missingProperty;
51-
if (fieldKey === 'allowRelative') {
52-
// this is the case, when allowAbsolute is set to false, but allowRelative is not set
53-
message = m('inputSchema.validation.datepickerNoType', { rootName });
54-
} else {
55-
message = m('inputSchema.validation.required', { rootName, fieldKey });
56-
}
51+
message = m('inputSchema.validation.required', { rootName, fieldKey });
5752
} else if (error.keyword === 'additionalProperties') {
5853
fieldKey = error.params.additionalProperty;
5954
message = m('inputSchema.validation.additionalProperty', { rootName, fieldKey });
@@ -63,12 +58,7 @@ export function parseAjvError(
6358
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: errorMessage });
6459
} else if (error.keyword === 'const') {
6560
fieldKey = error.instancePath.split('/').pop()!;
66-
// This is a special case for datepicker fields, where both allowAbsolute and allowRelative properties are set to false
67-
if (fieldKey === 'allowRelative' || fieldKey === 'allowAbsolute') {
68-
message = m('inputSchema.validation.datepickerNoType', { rootName });
69-
} else {
70-
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
71-
}
61+
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });
7262
} else {
7363
fieldKey = error.instancePath.split('/').pop()!;
7464
message = m('inputSchema.validation.generic', { rootName, fieldKey, message: error.message });

packages/input_schema/src/intl.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,6 @@ const intlStrings = {
3333
'Field schema.properties.{fieldKey} does not exist, but it is specified in schema.required. Either define the field or remove it from schema.required.',
3434
'inputSchema.validation.proxyGroupMustBeArrayOfStrings':
3535
'Field {rootName}.{fieldKey}.apifyProxyGroups must be an array of strings.',
36-
'inputSchema.validation.datepickerInvalidFormatAbsolute':
37-
'Field {rootName}.{fieldKey} must be a string in format "YYYY-MM-DD".',
38-
'inputSchema.validation.datepickerInvalidFormatRelative':
39-
'Field {rootName}.{fieldKey} must be a string in format "+/- number unit". Supported units are "day", "week", "month" and "year".',
40-
'inputSchema.validation.datepickerInvalidFormatBoth':
41-
'Field {rootName}.{fieldKey} must be a string in format "YYYY-MM-DD" or "+/- number unit". Supported units are "day", "week", "month" and "year".',
42-
'inputSchema.validation.datepickerInvalidDate':
43-
'Field {rootName}.{fieldKey} must be a valid date.',
44-
'inputSchema.validation.datepickerNoType':
45-
'Field {rootName} must accept absolute, relative or both dates. Set "allowAbsolute", "allowRelative" or both properties.',
4636
};
4737

4838
/**

packages/input_schema/src/schema.json

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,18 +123,8 @@
123123
"editor": { "enum": ["datepicker"] },
124124
"sectionCaption": { "type": "string" },
125125
"sectionDescription": { "type": "string" },
126-
"allowAbsolute": { "type": "boolean" },
127-
"allowRelative": { "type": "boolean" }
128-
},
129-
"if": {
130-
"required": ["allowAbsolute"],
131-
"properties": { "allowAbsolute": { "const": false } }
132-
},
133-
"then": { "required": ["type", "title", "description", "editor", "allowRelative"] },
134-
"anyOf": [
135-
{ "properties": { "allowAbsolute": { "const": true } } },
136-
{ "properties": { "allowRelative": { "const": true } } }
137-
]
126+
"dateType": { "enum": ["absolute", "relative", "absoluteOrRelative"] }
127+
}
138128
},
139129
"else": {
140130
"additionalProperties": false,
@@ -149,8 +139,8 @@
149139
"nullable": { "type": "boolean" },
150140
"minLength": { "type": "integer" },
151141
"maxLength": { "type": "integer" },
152-
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "datepicker", "hidden"] },
153-
"isSecret": { "type": "boolean" },
142+
"editor": { "enum": ["javascript", "python", "textfield", "textarea", "hidden"] },
143+
"isSecret": { "enum": [false] },
154144
"sectionCaption": { "type": "string" },
155145
"sectionDescription": { "type": "string" }
156146
}
@@ -165,7 +155,7 @@
165155
"example": { "type": "string" },
166156
"nullable": { "type": "boolean" },
167157
"editor": { "enum": ["textfield", "textarea", "hidden"] },
168-
"isSecret": { "type": "boolean" },
158+
"isSecret": { "enum": [true] },
169159
"sectionCaption": { "type": "string" },
170160
"sectionDescription": { "type": "string" }
171161
}

packages/input_schema/src/types.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@ export type StringFieldDefinition = CommonFieldDefinition<string> & {
1818
enum?: readonly string[]; // required if editor is 'select'
1919
enumTitles?: readonly string[]
2020
isSecret?: boolean;
21-
// Used for 'datepicker' editor, allowAbsolute is considered with default value true
22-
// If only relative time is wanted, allowAbsolute must be explicitly set to false
23-
allowAbsolute?: boolean;
24-
allowRelative?: boolean;
21+
// Used for 'datepicker' editor, absolute is considered as default value
22+
dateType?: 'absolute' | 'relative' | 'absoluteOrRelative';
2523
}
2624

2725
export type BooleanFieldDefinition = CommonFieldDefinition<boolean> & {

packages/input_schema/src/utilities.ts

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -248,50 +248,6 @@ export function validateInputUsingValidator(
248248
}
249249
}
250250

251-
// Check datepicker editor format
252-
// TODO: enable validation for datepicker editor later
253-
/* if (type === 'string' && editor === 'datepicker' && value && typeof value === 'string') {
254-
const acceptAbsolute = allowAbsolute !== false;
255-
const acceptRelative = allowRelative === true;
256-
const isValidAbsolute = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(value);
257-
const isValidRelative = /^[+-] [0-9]+ (day|week|month|year)s?$/.test(value);
258-
let isValidDate: boolean | undefined;
259-
260-
if (isValidAbsolute) {
261-
const [year, month, day] = value.split('-').map(Number);
262-
const date = new Date(`${year}-${month}-${day}`);
263-
264-
// Check if the date object is valid and matches the input string
265-
isValidDate = date.getFullYear() === year
266-
&& date.getMonth() + 1 === month
267-
&& date.getDate() === day;
268-
}
269-
270-
if (acceptAbsolute && !acceptRelative && !isValidAbsolute) {
271-
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatAbsolute', {
272-
rootName: 'input',
273-
fieldKey: property,
274-
}));
275-
} else if (acceptRelative && !acceptAbsolute && !isValidRelative) {
276-
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatRelative', {
277-
rootName: 'input',
278-
fieldKey: property,
279-
}));
280-
} else if ((acceptAbsolute && !acceptRelative && !isValidAbsolute)
281-
|| (acceptRelative && !acceptAbsolute && !isValidRelative)
282-
|| (acceptRelative && acceptAbsolute && !isValidAbsolute && !isValidRelative)) {
283-
fieldErrors.push(m('inputSchema.validation.datepickerInvalidFormatBoth', {
284-
rootName: 'input',
285-
fieldKey: property,
286-
}));
287-
} else if (isValidDate === false && acceptAbsolute) {
288-
fieldErrors.push(m('inputSchema.validation.datepickerInvalidDate', {
289-
rootName: 'input',
290-
fieldKey: property,
291-
}));
292-
}
293-
} */
294-
295251
if (fieldErrors.length > 0) {
296252
const message = fieldErrors.join(', ');
297253
errors.push({ fieldKey: property, message });

test/input_schema.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ describe('input_schema.json', () => {
156156

157157
expect(() => validateInputSchema(validator, schema)).toThrow(
158158
'Input schema is not valid (Field schema.properties.myField.editor must be equal to one of the allowed values: '
159-
+ '"javascript", "python", "textfield", "textarea", "datepicker", "hidden")',
159+
+ '"javascript", "python", "textfield", "textarea", "hidden")',
160160
);
161161
});
162162

test/input_schema_definition.test.ts

Lines changed: 15 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { inputSchema, parseAjvError } from '@apify/input_schema';
1+
import { inputSchema } from '@apify/input_schema';
22
import Ajv from 'ajv';
33

44
/**
@@ -301,7 +301,7 @@ describe('input_schema.json', () => {
301301
});
302302

303303
describe('special cases for datepicker editor type', () => {
304-
it('should accept allowAbsolute and allowRelative fields omitted', () => {
304+
it('should accept dateType field omitted', () => {
305305
expect(ajv.validate(inputSchema, {
306306
title: 'Test input schema',
307307
type: 'object',
@@ -317,96 +317,8 @@ describe('input_schema.json', () => {
317317
})).toBe(true);
318318
});
319319

320-
it('should accept allowAbsolute and allowRelative both set to true', () => {
321-
expect(ajv.validate(inputSchema, {
322-
title: 'Test input schema',
323-
type: 'object',
324-
schemaVersion: 1,
325-
properties: {
326-
myField: {
327-
title: 'Field title',
328-
description: 'My test field',
329-
type: 'string',
330-
editor: 'datepicker',
331-
allowAbsolute: true,
332-
allowRelative: true,
333-
},
334-
},
335-
})).toBe(true);
336-
});
337-
338-
it('should accept allowAbsolute=true and allowRelative=false', () => {
339-
expect(ajv.validate(inputSchema, {
340-
title: 'Test input schema',
341-
type: 'object',
342-
schemaVersion: 1,
343-
properties: {
344-
myField: {
345-
title: 'Field title',
346-
description: 'My test field',
347-
type: 'string',
348-
editor: 'datepicker',
349-
allowAbsolute: true,
350-
allowRelative: false,
351-
},
352-
},
353-
})).toBe(true);
354-
});
355-
356-
it('should accept allowAbsolute=false and allowRelative=true', () => {
357-
expect(ajv.validate(inputSchema, {
358-
title: 'Test input schema',
359-
type: 'object',
360-
schemaVersion: 1,
361-
properties: {
362-
myField: {
363-
title: 'Field title',
364-
description: 'My test field',
365-
type: 'string',
366-
editor: 'datepicker',
367-
allowAbsolute: false,
368-
allowRelative: true,
369-
},
370-
},
371-
})).toBe(true);
372-
});
373-
374-
it('should accept allowAbsolute=true', () => {
375-
expect(ajv.validate(inputSchema, {
376-
title: 'Test input schema',
377-
type: 'object',
378-
schemaVersion: 1,
379-
properties: {
380-
myField: {
381-
title: 'Field title',
382-
description: 'My test field',
383-
type: 'string',
384-
editor: 'datepicker',
385-
allowAbsolute: true,
386-
},
387-
},
388-
})).toBe(true);
389-
});
390-
391-
it('should accept allowRelative=true', () => {
392-
expect(ajv.validate(inputSchema, {
393-
title: 'Test input schema',
394-
type: 'object',
395-
schemaVersion: 1,
396-
properties: {
397-
myField: {
398-
title: 'Field title',
399-
description: 'My test field',
400-
type: 'string',
401-
editor: 'datepicker',
402-
allowRelative: true,
403-
},
404-
},
405-
})).toBe(true);
406-
});
407-
408-
it('should accept allowRelative=false', () => {
409-
expect(ajv.validate(inputSchema, {
320+
const isSchemaValid = (dateType: string) => {
321+
return ajv.validate(inputSchema, {
410322
title: 'Test input schema',
411323
type: 'object',
412324
schemaVersion: 1,
@@ -416,53 +328,22 @@ describe('input_schema.json', () => {
416328
description: 'My test field',
417329
type: 'string',
418330
editor: 'datepicker',
419-
allowRelative: false,
331+
dateType,
420332
},
421333
},
422-
})).toBe(true);
423-
});
334+
});
335+
};
424336

425-
it('should not accept allowAbsolute=false', () => {
426-
expect(ajv.validate(inputSchema, {
427-
title: 'Test input schema',
428-
type: 'object',
429-
schemaVersion: 1,
430-
properties: {
431-
myField: {
432-
title: 'Field title',
433-
description: 'My test field',
434-
type: 'string',
435-
editor: 'datepicker',
436-
allowAbsolute: false,
437-
},
438-
},
439-
})).toBe(false);
440-
expect(ajv.errorsText()).toContain('data/properties/myField must have required property \'allowRelative\'');
441-
expect(parseAjvError(ajv.errors![0], 'schema.properties.myField')?.message)
442-
.toEqual('Field schema.properties.myField must accept absolute, relative or both dates. '
443-
+ 'Set "allowAbsolute", "allowRelative" or both properties.');
337+
it('should accept valid dateType', () => {
338+
['absolute', 'relative', 'absoluteOrRelative'].forEach((dateType) => {
339+
expect(isSchemaValid(dateType)).toBe(true);
340+
});
444341
});
445342

446-
it('should not accept allowAbsolute=false allowRelative=false', () => {
447-
expect(ajv.validate(inputSchema, {
448-
title: 'Test input schema',
449-
type: 'object',
450-
schemaVersion: 1,
451-
properties: {
452-
myField: {
453-
title: 'Field title',
454-
description: 'My test field',
455-
type: 'string',
456-
editor: 'datepicker',
457-
allowAbsolute: false,
458-
allowRelative: false,
459-
},
460-
},
461-
})).toBe(false);
462-
expect(ajv.errorsText()).toContain('data/properties/myField/allowAbsolute must be equal to constant');
463-
expect(parseAjvError(ajv.errors![0], 'schema.properties.myField')?.message)
464-
.toEqual('Field schema.properties.myField must accept absolute, relative or both dates. '
465-
+ 'Set "allowAbsolute", "allowRelative" or both properties.');
343+
it('should not accept invalid dateType', () => {
344+
['xxx', 'invalid'].forEach((dateType) => {
345+
expect(isSchemaValid(dateType)).toBe(false);
346+
});
466347
});
467348
});
468349

0 commit comments

Comments
 (0)