diff --git a/app/client/cypress/fixtures/testdata.json b/app/client/cypress/fixtures/testdata.json index 107a8d24ad..e83cde0823 100644 --- a/app/client/cypress/fixtures/testdata.json +++ b/app/client/cypress/fixtures/testdata.json @@ -116,8 +116,8 @@ "currentRowWithIdOutside": "#{{currentRow.email}}", "currentRowWithIdInside": "{{\"#\" + currentRow.email}}", "defaultdataBinding": "{'Test','This'}", - "dropdownErrorMsg": "This value does not evaluate to type \"Array<{ \"label\": \"string\", \"value\": \"string\" }>\".", - "tableWidgetErrorMsg": "This value does not evaluate to type \"Array\".", + "dropdownErrorMsg": "This value does not evaluate to type Array<{ \"label\": \"string\", \"value\": \"string\" }>", + "tableWidgetErrorMsg": "This value does not evaluate to type Array", "bindingDataPoint": "{{JSON.stringify(Chart1.selectedDataPoint)}}", "bindingSeriesTitle": "{{Chart1.selectedDataPoint.seriesTitle", "bindChartData": "{{Chart1.selectedDataPoint", diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DatePicker_2_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DatePicker_2_spec.js index 39a28826e2..7513b7dfd6 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DatePicker_2_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/FormWidgets/DatePicker_2_spec.js @@ -61,9 +61,7 @@ describe("DatePicker Widget Property pane tests with js bindings", function() { it("Datepicker default date validation message", function() { cy.openPropertyPane("datepickerwidget2"); cy.testJsontext("defaultdate", "24-12-2021"); - cy.evaluateErrorMessage( - `This value does not evaluate to type "ISO 8601 date string".`, - ); + cy.evaluateErrorMessage("Value does not match: ISO 8601 date string"); cy.closePropertyPane(); }); diff --git a/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx b/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx index c52cb52ec5..6aeef4055d 100644 --- a/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx +++ b/app/client/src/components/editorComponents/CodeEditor/EvaluatedValuePopup.tsx @@ -21,10 +21,7 @@ import { IPopoverSharedProps } from "@blueprintjs/core"; import { ReactComponent as CopyIcon } from "assets/icons/menu/copy-snippet.svg"; import copy from "copy-to-clipboard"; -import { - EvaluationError, - PropertyEvaluationErrorType, -} from "utils/DynamicBindingUtils"; +import { EvaluationError } from "utils/DynamicBindingUtils"; import * as Sentry from "@sentry/react"; import { Severity } from "@sentry/react"; import { CodeEditorExpected } from "components/editorComponents/CodeEditor/index"; @@ -387,9 +384,9 @@ function PopoverContent(props: PopoverContentProps) { {hasError && error && ( - {error.errorType === PropertyEvaluationErrorType.VALIDATION - ? `This value does not evaluate to type "${expected?.type}".` - : error.errorMessage} + {/* errorMessage could be an empty string */} + {error.errorMessage || + `This value does not evaluate to type "${expected?.type}".`} { + lintErrors.unshift({ + ...validation, + ...{ + errorType: PropertyEvaluationErrorType.VALIDATION, + errorMessage: message, + }, + }); }); } yield put( diff --git a/app/client/src/widgets/CheckboxGroupWidget/widget/index.tsx b/app/client/src/widgets/CheckboxGroupWidget/widget/index.tsx index 858aebb755..b5bdc26e86 100644 --- a/app/client/src/widgets/CheckboxGroupWidget/widget/index.tsx +++ b/app/client/src/widgets/CheckboxGroupWidget/widget/index.tsx @@ -57,7 +57,7 @@ function defaultSelectedValuesValidation( return { isValid: false, parsed: values, - message: messages.join(" "), + messages, }; } diff --git a/app/client/src/widgets/DatePickerWidget/widget/index.tsx b/app/client/src/widgets/DatePickerWidget/widget/index.tsx index d8454f4883..0f38289c27 100644 --- a/app/client/src/widgets/DatePickerWidget/widget/index.tsx +++ b/app/client/src/widgets/DatePickerWidget/widget/index.tsx @@ -24,14 +24,14 @@ function defaultDateValidation( return { isValid: true, parsed: "", - message: "", + messages: [""], }; } if (value === undefined) { return { isValid: false, parsed: "", - message: `This value does not evaluate to type: Date ${dateFormat}`, + messages: [`This value does not evaluate to type: Date ${dateFormat}`], }; } @@ -40,10 +40,10 @@ function defaultDateValidation( return { isValid, parsed: isValid ? value : "", - message: + messages: isValid === false - ? `Value does not match ISO 8601 standard date string` - : "", + ? [`Value does not match ISO 8601 standard date string`] + : [""], }; } @@ -58,8 +58,9 @@ function minDateValidation( return { isValid: false, parsed: "", - message: + messages: [ `Value does not match: Date String ` + (dateFormat ? dateFormat : ""), + ], }; } const parsedMinDate = moment(value as string, dateFormat); @@ -69,7 +70,7 @@ function minDateValidation( return { isValid: isValid, parsed: value, - message: "", + messages: [""], }; } const parsedDefaultDate = moment(props.defaultDate, dateFormat); @@ -85,14 +86,15 @@ function minDateValidation( return { isValid: isValid, parsed: "", - message: + messages: [ `Value does not match: Date String ` + (dateFormat ? dateFormat : ""), + ], }; } return { isValid: isValid, parsed: value, - message: "", + messages: [""], }; } @@ -107,9 +109,10 @@ function maxDateValidation( return { isValid: false, parsed: "", - message: + messages: [ `Value does not match type: Date String ` + - (dateFormat ? dateFormat : ""), + (dateFormat ? dateFormat : ""), + ], }; } const parsedMaxDate = moment(value as string, dateFormat); @@ -118,7 +121,7 @@ function maxDateValidation( return { isValid: isValid, parsed: value, - message: "", + messages: [""], }; } const parsedDefaultDate = moment(props.defaultDate, dateFormat); @@ -134,15 +137,16 @@ function maxDateValidation( return { isValid: isValid, parsed: "", - message: + messages: [ `Value does not match type: Date String ` + - (dateFormat ? dateFormat : ""), + (dateFormat ? dateFormat : ""), + ], }; } return { isValid: isValid, parsed: value, - message: "", + messages: [""], }; } class DatePickerWidget extends BaseWidget { diff --git a/app/client/src/widgets/DropdownWidget/widget/index.tsx b/app/client/src/widgets/DropdownWidget/widget/index.tsx index 6f990ba734..4f945b38cc 100644 --- a/app/client/src/widgets/DropdownWidget/widget/index.tsx +++ b/app/client/src/widgets/DropdownWidget/widget/index.tsx @@ -18,7 +18,7 @@ function defaultOptionValueValidation(value: unknown): ValidationResponse { return { isValid: false, parsed: "", - message: "This value does not evaluate to type: string", + messages: ["This value does not evaluate to type: string"], }; return { isValid: true, parsed: value }; } diff --git a/app/client/src/widgets/InputWidget/widget/index.test.tsx b/app/client/src/widgets/InputWidget/widget/index.test.tsx index f2a92caf6d..777bcf544c 100644 --- a/app/client/src/widgets/InputWidget/widget/index.test.tsx +++ b/app/client/src/widgets/InputWidget/widget/index.test.tsx @@ -37,24 +37,24 @@ describe("#defaultValueValidation", () => { "abcd", ]; const expectedOutputs = [ - { isValid: true, parsed: undefined, message: "" }, - { isValid: true, parsed: undefined, message: "" }, - { isValid: true, parsed: 0, message: "" }, - { isValid: true, parsed: 123, message: "" }, - { isValid: true, parsed: -23, message: "" }, - { isValid: true, parsed: 0.000001, message: "" }, - { isValid: true, parsed: -23, message: "" }, - { isValid: true, parsed: 0, message: "" }, - { isValid: true, parsed: 100, message: "" }, + { isValid: true, parsed: undefined, messages: [""] }, + { isValid: true, parsed: undefined, messages: [""] }, + { isValid: true, parsed: 0, messages: [""] }, + { isValid: true, parsed: 123, messages: [""] }, + { isValid: true, parsed: -23, messages: [""] }, + { isValid: true, parsed: 0.000001, messages: [""] }, + { isValid: true, parsed: -23, messages: [""] }, + { isValid: true, parsed: 0, messages: [""] }, + { isValid: true, parsed: 100, messages: [""] }, { isValid: false, parsed: undefined, - message: "This value must be a number", + messages: ["This value must be a number"], }, { isValid: false, parsed: undefined, - message: "This value must be a number", + messages: ["This value must be a number"], }, ]; diff --git a/app/client/src/widgets/InputWidget/widget/index.tsx b/app/client/src/widgets/InputWidget/widget/index.tsx index 21e965d7ef..74c2d5097d 100644 --- a/app/client/src/widgets/InputWidget/widget/index.tsx +++ b/app/client/src/widgets/InputWidget/widget/index.tsx @@ -43,7 +43,7 @@ export function defaultValueValidation( return { isValid: true, parsed: undefined, - message: "", + messages: [""], }; } @@ -51,7 +51,7 @@ export function defaultValueValidation( return { isValid: false, parsed: undefined, - message: "This value must be a number", + messages: ["This value must be a number"], }; } } @@ -59,14 +59,14 @@ export function defaultValueValidation( return { isValid: true, parsed, - message: "", + messages: [""], }; } if (_.isObject(value)) { return { isValid: false, parsed: JSON.stringify(value, null, 2), - message: "This value must be string", + messages: ["This value must be string"], }; } let parsed = value; @@ -78,14 +78,14 @@ export function defaultValueValidation( return { isValid: false, parsed: "", - message: "This value must be string", + messages: ["This value must be string"], }; } } return { isValid, parsed: parsed, - message: "", + messages: [""], }; } diff --git a/app/client/src/widgets/RateWidget/widget/index.tsx b/app/client/src/widgets/RateWidget/widget/index.tsx index 823593faba..b245467320 100644 --- a/app/client/src/widgets/RateWidget/widget/index.tsx +++ b/app/client/src/widgets/RateWidget/widget/index.tsx @@ -29,7 +29,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) { return { isValid: false, parsed: 0, - message: `Value must be a number`, + messages: [`Value must be a number`], }; } } @@ -43,7 +43,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) { return { isValid: false, parsed, - message: `This value must be less than or equal to max count`, + messages: [`This value must be less than or equal to max count`], }; } @@ -52,7 +52,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) { return { isValid: false, parsed, - message: `This value can be a decimal only if 'Allow half' is true`, + messages: [`This value can be a decimal only if 'Allow half' is true`], }; } @@ -61,7 +61,7 @@ function validateDefaultRate(value: unknown, props: any, _: any) { return { isValid: false, parsed: value, - message: `Could not validate `, + messages: [`Could not validate `], }; } } diff --git a/app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx b/app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx index f137cabc5b..94e64ce807 100644 --- a/app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx +++ b/app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx @@ -21,7 +21,7 @@ function defaultOptionValueValidation(value: unknown): ValidationResponse { return { isValid: false, parsed: "", - message: "This value does not evaluate to type: string", + messages: ["This value does not evaluate to type: string"], }; return { isValid: true, parsed: value }; } diff --git a/app/client/src/widgets/TabsWidget/widget/index.tsx b/app/client/src/widgets/TabsWidget/widget/index.tsx index 307e2818c5..c699e73c29 100644 --- a/app/client/src/widgets/TabsWidget/widget/index.tsx +++ b/app/client/src/widgets/TabsWidget/widget/index.tsx @@ -25,7 +25,7 @@ export function selectedTabValidation( return { isValid: value === "" ? true : tabNames.includes(value as string), parsed: value, - message: `Tab name ${value} does not exist`, + messages: [`Tab name ${value} does not exist`], }; } class TabsWidget extends BaseWidget< diff --git a/app/client/src/workers/DataTreeEvaluator.ts b/app/client/src/workers/DataTreeEvaluator.ts index 10ac6a4913..b2f7bcf6dc 100644 --- a/app/client/src/workers/DataTreeEvaluator.ts +++ b/app/client/src/workers/DataTreeEvaluator.ts @@ -2,6 +2,7 @@ import { DependencyMap, EvalError, EvalErrorTypes, + EvaluationError, getDynamicBindings, getEntityDynamicBindingPathList, getEvalErrorPath, @@ -731,7 +732,7 @@ export default class DataTreeEvaluator { } const validation = widget.validationPaths[propertyPath]; - const { isValid, message, parsed, transformed } = validateWidgetProperty( + const { isValid, messages, parsed, transformed } = validateWidgetProperty( validation, valueToValidate, widget, @@ -749,18 +750,16 @@ export default class DataTreeEvaluator { safeEvaluatedValue, ); if (!isValid) { - addErrorToEntityProperty( - [ - { + const evalErrors: EvaluationError[] = + messages?.map((message) => { + return { raw: unEvalPropertyValue, errorMessage: message || "", errorType: PropertyEvaluationErrorType.VALIDATION, severity: Severity.ERROR, - }, - ], - currentTree, - fullPropertyPath, - ); + }; + }) ?? []; + addErrorToEntityProperty(evalErrors, currentTree, fullPropertyPath); } if (isPathADynamicTrigger(widget, propertyPath)) { diff --git a/app/client/src/workers/evaluationUtils.ts b/app/client/src/workers/evaluationUtils.ts index 45b6a8fbfd..3fccb08c85 100644 --- a/app/client/src/workers/evaluationUtils.ts +++ b/app/client/src/workers/evaluationUtils.ts @@ -357,7 +357,7 @@ export function getValidatedTree(tree: DataTree) { Object.entries(entity.validationPaths).forEach(([property, validation]) => { const value = _.get(entity, property); // Pass it through parse - const { isValid, message, parsed, transformed } = validateWidgetProperty( + const { isValid, messages, parsed, transformed } = validateWidgetProperty( validation, value, entity, @@ -375,15 +375,15 @@ export function getValidatedTree(tree: DataTree) { safeEvaluatedValue, ); if (!isValid) { + const evalErrors: EvaluationError[] = + messages?.map((message) => ({ + errorType: PropertyEvaluationErrorType.VALIDATION, + errorMessage: message, + severity: Severity.ERROR, + raw: value, + })) ?? []; addErrorToEntityProperty( - [ - { - errorType: PropertyEvaluationErrorType.VALIDATION, - errorMessage: message || "", - severity: Severity.ERROR, - raw: value, - }, - ], + evalErrors, tree, getEvalErrorPath(`${entityKey}.${property}`, false), ); diff --git a/app/client/src/workers/validations.test.ts b/app/client/src/workers/validations.test.ts index 6c26978b24..27c90d851b 100644 --- a/app/client/src/workers/validations.test.ts +++ b/app/client/src/workers/validations.test.ts @@ -38,27 +38,35 @@ describe("Validate Validators", () => { { isValid: false, parsed: "abc", - message: "Value is not allowed", + messages: ["Value is not allowed"], }, { isValid: false, parsed: "abc", - message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + ], }, { isValid: false, parsed: "abc", - message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + ], }, { isValid: false, parsed: "{}", - message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + ], }, { isValid: false, parsed: "[]", - message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + ], }, { isValid: true, @@ -115,12 +123,14 @@ describe("Validate Validators", () => { { isValid: false, parsed: "abc", - message: "Value is not allowed", + messages: ["Value is not allowed"], }, { isValid: false, parsed: "abc", - message: `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} string ( abc | 123 | mno | test )`, + ], }, ]; inputs.forEach((input, index) => { @@ -166,7 +176,9 @@ describe("Validate Validators", () => { isValid: false, parsed: "https://cdn.dribbble.com/users/1787323/screenshots/4563995/dribbbe_hammer-01.png", - message: `${WIDGET_TYPE_VALIDATION_ERROR}: base64 encoded image | data uri | image url`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: base64 encoded image | data uri | image url`, + ], }, ]; @@ -195,27 +207,31 @@ describe("Validate Validators", () => { { isValid: false, parsed: 90, - message: "Minimum allowed value: 100", + messages: ["Minimum allowed value: 100"], }, { isValid: false, parsed: 220, - message: "Maximum allowed value: 200", + messages: ["Maximum allowed value: 200"], }, { isValid: false, parsed: 150, - message: "This value is required", + messages: ["This value is required"], }, { isValid: false, parsed: 150, - message: `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, + ], }, { isValid: false, parsed: 150, - message: `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} number Min: 100 Max: 200 Required`, + ], }, { isValid: true, @@ -224,7 +240,7 @@ describe("Validate Validators", () => { { isValid: false, parsed: 150, - message: "This value is required", + messages: ["This value is required"], }, ]; inputs.forEach((input, index) => { @@ -267,12 +283,12 @@ describe("Validate Validators", () => { const expected = [ { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`], parsed: false, }, { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`], parsed: false, }, { @@ -285,12 +301,12 @@ describe("Validate Validators", () => { }, { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`], parsed: false, }, { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR} boolean`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} boolean`], parsed: false, }, { @@ -304,7 +320,7 @@ describe("Validate Validators", () => { { isValid: false, parsed: false, - message: "This value does not evaluate to type boolean", + messages: ["This value does not evaluate to type boolean"], }, ]; @@ -388,27 +404,35 @@ describe("Validate Validators", () => { { isValid: false, parsed: { key1: 120, key2: "abc" }, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, + ], }, { isValid: false, parsed: { key1: 120, key2: "abc" }, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: { \"key1\": \"number Required\", \"key2\": \"string ( abc | mnop )\" }`, + ], }, { isValid: false, parsed: { key1: 120, key2: "abc" }, - message: `Value of key: key1 is invalid: This value does not evaluate to type number Required`, + messages: [ + `Value of key: key1 is invalid: This value does not evaluate to type number Required`, + ], }, { isValid: false, parsed: { key1: 120, key2: "abc" }, - message: `Value of key: key2 is invalid: This value does not evaluate to type string ( abc | mnop )`, + messages: [ + `Value of key: key2 is invalid: This value does not evaluate to type string ( abc | mnop )`, + ], }, { isValid: false, parsed: { key1: 120, key2: "abc" }, - message: `Missing required key: key1`, + messages: [`Missing required key: key1`], }, ]; inputs.forEach((input, index) => { @@ -451,73 +475,79 @@ describe("Validate Validators", () => { { isValid: true, parsed: ["a", "b", "c"], - message: "", + messages: [], }, { isValid: true, parsed: ["m", "n", "b"], - message: "", + messages: [], }, { isValid: false, parsed: [], - message: "Invalid entry at index: 2. Value is not allowed", + messages: ["Invalid entry at index: 2. Value is not allowed"], }, { isValid: true, parsed: [], - message: "", + messages: [], }, { isValid: false, parsed: [], - message: + messages: [ "This value does not evaluate to type Array", + ], }, { isValid: false, parsed: [], - message: + messages: [ "This property is required for the widget to function correctly", + ], }, { isValid: false, parsed: [], - message: + messages: [ "This property is required for the widget to function correctly", + ], }, { isValid: false, parsed: [], - message: + messages: [ "This value does not evaluate to type Array", + ], }, { isValid: true, parsed: ["a", "b", "c"], - message: "", + messages: [], }, { isValid: false, parsed: [], - message: + messages: [ "This value does not evaluate to type Array", + ], }, { isValid: false, parsed: [], - message: "Array must be unique. Duplicate values found", + messages: ["Array must be unique. Duplicate values found"], }, { isValid: false, parsed: [], - message: + messages: [ "This property is required for the widget to function correctly", + ], }, { isValid: true, parsed: [], - message: "", + messages: [], }, ]; inputs.forEach((input, index) => { @@ -594,39 +624,44 @@ describe("Validate Validators", () => { { isValid: true, parsed: [{ label: 123, value: 234 }], - message: "", + messages: [], }, { isValid: true, parsed: [{ label: 123, value: 234 }], - message: "", + messages: [], }, { isValid: false, parsed: [], - message: "Invalid entry at index: 0. Missing required key: label", + messages: ["Invalid entry at index: 0. Missing required key: label"], }, { isValid: false, parsed: [], - message: `Invalid entry at index: 0. Value of key: label is invalid: This value does not evaluate to type number Required`, + messages: [ + `Invalid entry at index: 0. Value of key: label is invalid: This value does not evaluate to type number Required`, + ], }, { isValid: false, parsed: [], - message: - "Invalid entry at index: 0. Missing required key: label Missing required key: value", + messages: [ + "Invalid entry at index: 0. Missing required key: label", + "Invalid entry at index: 0. Missing required key: value", + ], }, { isValid: true, parsed: [], - message: "", + messages: [], }, { isValid: false, parsed: [], - message: + messages: [ "This property is required for the widget to function correctly", + ], }, ]; inputs.forEach((input, index) => { @@ -711,16 +746,16 @@ describe("Validate Validators", () => { { isValid: false, parsed: defaultDate, - message: "Value does not match: ISO 8601 date string", + messages: ["Value does not match: ISO 8601 date string"], }, { isValid: false, parsed: defaultDate, - message: "Value does not match: ISO 8601 date string", + messages: ["Value does not match: ISO 8601 date string"], }, { isValid: false, - message: "Value does not match: ISO 8601 date string", + messages: ["Value does not match: ISO 8601 date string"], parsed: defaultDate, }, ]; @@ -800,52 +835,52 @@ describe("Validate Validators", () => { { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "Invalid object at index 0", + messages: ["Invalid object at index 0"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "Invalid object at index 1", + messages: ["Invalid object at index 1"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "Invalid object at index 1", + messages: ["Invalid object at index 1"], }, { isValid: false, parsed: [{ id: 1, name: "alpha" }], - message: "This value does not evaluate to type Array", + messages: ["This value does not evaluate to type Array"], }, ]; @@ -928,12 +963,12 @@ describe("Validate Validators", () => { }, { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: URL`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: URL`], parsed: "https://wikipedia.org", }, { isValid: false, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: URL`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: URL`], parsed: "https://wikipedia.org", }, ]; diff --git a/app/client/src/workers/validations.ts b/app/client/src/workers/validations.ts index 9a7ef08732..e882650b26 100644 --- a/app/client/src/workers/validations.ts +++ b/app/client/src/workers/validations.ts @@ -59,7 +59,7 @@ function validatePlainObject( const entryName = getPropertyEntry(value, entry.name, ignoreCase); if (value.hasOwnProperty(entryName)) { - const { isValid, message, parsed } = validate( + const { isValid, messages, parsed } = validate( entry, value[entryName], props, @@ -67,8 +67,12 @@ function validatePlainObject( if (!isValid) { value[entryName] = parsed; _valid = isValid; - message && - _messages.push(`Value of key: ${entryName} is invalid: ${message}`); + messages && + messages.map((message) => { + _messages.push( + `Value of key: ${entryName} is invalid: ${message}`, + ); + }); } } else if (entry.params?.required) { _valid = false; @@ -84,7 +88,7 @@ function validatePlainObject( return { isValid: false, parsed: config.params?.default || value, - message: _messages.join(" "), + messages: _messages, }; } return { @@ -107,7 +111,7 @@ function validateArray( return { isValid: false, parsed: value, - message: `Disallowed value: ${entry}`, + messages: [`Disallowed value: ${entry}`], }; } }); @@ -170,8 +174,8 @@ function validateArray( const validation = validate(children, entry, props); if (!validation.isValid) { _isValid = false; - _messages.push( - `Invalid entry at index: ${index}. ${validation.message}`, + validation.messages?.map((message) => + _messages.push(`Invalid entry at index: ${index}. ${message}`), ); } }); @@ -185,7 +189,7 @@ function validateArray( if (uniq(shouldBeUnique).length !== value.length) { _isValid = false; _messages.push( - `Array entry path:${param} must be unique. Duplicate values found`, + `path:${param} must be unique. Duplicate values found`, ); break; } @@ -201,7 +205,7 @@ function validateArray( return { isValid: _isValid, parsed: _isValid ? value : config.params?.default || [], - message: _messages.join(" "), + messages: _messages, }; } @@ -296,7 +300,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || "", - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } @@ -311,7 +317,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: JSON.stringify(value, null, 2), - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } @@ -319,7 +327,7 @@ export const VALIDATORS: Record = { const stringValidationError = { isValid: false, parsed: config.params?.default || "", - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`], }; if (!isValid) { try { @@ -335,7 +343,7 @@ export const VALIDATORS: Record = { if (!config.params?.allowedValues.includes((parsed as string).trim())) { return { parsed: config.params?.default || "", - message: "Value is not allowed", + messages: ["Value is not allowed"], isValid: false, }; } @@ -348,7 +356,9 @@ export const VALIDATORS: Record = { ) { return { parsed: config.params?.default || "", - message: `Value does not match expected regex: ${config.params?.regex.source}`, + messages: [ + `Value does not match expected regex: ${config.params?.regex.source}`, + ], isValid: false, }; } @@ -364,7 +374,7 @@ export const VALIDATORS: Record = { value: unknown, props: Record, ): ValidationResponse => { - const { isValid, message, parsed } = VALIDATORS[ValidationTypes.TEXT]( + const { isValid, messages, parsed } = VALIDATORS[ValidationTypes.TEXT]( config, value, props, @@ -374,11 +384,13 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: new RegExp(parsed), - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } - return { isValid, parsed, message }; + return { isValid, parsed, messages }; }, [ValidationTypes.NUMBER]: ( config: ValidationConfig, @@ -390,7 +402,7 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || 0, - message: "This value is required", + messages: ["This value is required"], }; } @@ -410,7 +422,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || 0, - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } @@ -423,7 +437,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || 0, - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } } @@ -436,7 +452,7 @@ export const VALIDATORS: Record = { return { isValid: false, parsed, - message: `Minimum allowed value: ${config.params.min}`, + messages: [`Minimum allowed value: ${config.params.min}`], }; } } @@ -449,7 +465,7 @@ export const VALIDATORS: Record = { return { isValid: false, parsed, - message: `Maximum allowed value: ${config.params.max}`, + messages: [`Maximum allowed value: ${config.params.max}`], }; } } @@ -457,7 +473,7 @@ export const VALIDATORS: Record = { return { isValid: false, parsed, - message: `Value should be a positive integer`, + messages: [`Value should be a positive integer`], }; } @@ -476,7 +492,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: !!config.params?.default, - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } @@ -500,7 +518,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || false, - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + ], }; } @@ -520,9 +540,9 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || {}, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType( - config, - )}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + ], }; } return { @@ -547,13 +567,17 @@ export const VALIDATORS: Record = { return { isValid: false, parsed: config.params?.default || {}, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + ], }; } catch (e) { return { isValid: false, parsed: config.params?.default || {}, - message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + messages: [ + `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + ], }; } }, @@ -565,7 +589,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: config.params?.default || [], - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`], }; if (value === undefined || value === null || value === "") { if ( @@ -573,8 +597,9 @@ export const VALIDATORS: Record = { config.params.required && !isArray(config.params.default) ) { - invalidResponse.message = - "This property is required for the widget to function correctly"; + invalidResponse.messages = [ + "This property is required for the widget to function correctly", + ]; return invalidResponse; } if (value === "") { @@ -622,7 +647,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: config.params?.default || [{}], - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`], }; if (value === undefined || value === null || value === "") { if (config.params?.required) return invalidResponse; @@ -666,7 +691,7 @@ export const VALIDATORS: Record = { if (!isPlainObject(parsedEntry)) { return { ...invalidResponse, - message: `Invalid object at index ${index}`, + messages: [`Invalid object at index ${index}`], }; } } @@ -683,7 +708,7 @@ export const VALIDATORS: Record = { let response: ValidationResponse = { isValid: false, parsed: config.params?.default || [], - message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`], }; response = VALIDATORS.ARRAY(config, value, props); @@ -702,7 +727,9 @@ export const VALIDATORS: Record = { response = { ...response, isValid: false, - message: `Array entry path:${param} must be unique. Duplicate values found`, + messages: [ + `path:${param} must be unique. Duplicate values found`, + ], }; } } @@ -718,7 +745,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: config.params?.default || moment().toISOString(true), - message: `Value does not match: ${getExpectedType(config)}`, + messages: [`Value does not match: ${getExpectedType(config)}`], }; if (value === undefined || value === null || !isString(value)) { if (!config.params?.required) { @@ -761,7 +788,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: undefined, - message: "Failed to validate", + messages: ["Failed to validate"], }; if (config.params?.fnString && isString(config.params?.fnString)) { try { @@ -786,7 +813,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: config.params?.default || "", - message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`], }; const base64Regex = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; const base64ImageRegex = /^data:image\/.*;base64/; @@ -822,7 +849,7 @@ export const VALIDATORS: Record = { const invalidResponse = { isValid: false, parsed: config?.params?.default || "", - message: `${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`, + messages: [`${WIDGET_TYPE_VALIDATION_ERROR}: ${getExpectedType(config)}`], }; if (typeof value === "string" && getIsSafeURL(value)) {