From 666e22f9895ec70095d4cf29ade8fd625b96b1fb Mon Sep 17 00:00:00 2001 From: Owen Conti Date: Thu, 20 Jul 2017 21:33:57 -0600 Subject: [PATCH] Update parameter elements. Rework validateParam() function. Added .btn-sm class for "Add item" and "Remove item" buttons in array parameters. Reduce border-width on + ) @@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent { render() { let { getComponent, required, schema, fn } = this.props + let errors = schema.errors || [] let itemSchema = fn.inferSchema(schema.items) const JsonSchemaForm = getComponent("JsonSchemaForm") @@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent { if ( enumValue ) { const Select = getComponent("Select") - return () } } diff --git a/src/core/utils.js b/src/core/utils.js index 95771fb4..9e114dae 100644 --- a/src/core/utils.js +++ b/src/core/utils.js @@ -468,6 +468,18 @@ export const validateFile = ( val ) => { } } +export const validateBoolean = ( val ) => { + if ( !(val === "true" || val === "false" || val === true || val === false) ) { + return "Value must be a boolean" + } +} + +export const validateString = ( val ) => { + if ( val && typeof val !== "string" ) { + return "Value must be a string" + } +} + // validation of parameters before execute export const validateParam = (param, isXml) => { let errors = [] @@ -475,52 +487,66 @@ export const validateParam = (param, isXml) => { let required = param.get("required") let type = param.get("type") - let stringCheck = type === "string" && !value - let arrayCheck = type === "array" && Array.isArray(value) && !value.length - let listCheck = type === "array" && Im.List.isList(value) && !value.count() - let fileCheck = type === "file" && !(value instanceof win.File) + // If the parameter is required OR the parameter has a value (meaning optional, but filled in) + // then we should do our validation routine + if ( required || value ) { + // These checks should evaluate to true if the parameter's value is valid + let stringCheck = type === "string" && value && !validateString(value) + let arrayCheck = type === "array" && Array.isArray(value) && value.length + let listCheck = type === "array" && Im.List.isList(value) && value.count() + let fileCheck = type === "file" && value instanceof win.File + let booleanCheck = type === "boolean" && !validateBoolean(value) + let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number + let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer - if ( required && (stringCheck || arrayCheck || listCheck || fileCheck) ) { - errors.push("Required field is not provided") - return errors - } + if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) { + errors.push("Required field is not provided") + return errors + } - if ( value === null || value === undefined ) { - return errors - } + if ( type === "string" ) { + let err = validateString(value) + if (!err) return errors + errors.push(err) + } else if ( type === "boolean" ) { + let err = validateBoolean(value) + if (!err) return errors + errors.push(err) + } else if ( type === "number" ) { + let err = validateNumber(value) + if (!err) return errors + errors.push(err) + } else if ( type === "integer" ) { + let err = validateInteger(value) + if (!err) return errors + errors.push(err) + } else if ( type === "array" ) { + let itemType - if ( type === "number" ) { - let err = validateNumber(value) - if (!err) return errors - errors.push(err) - } else if ( type === "integer" ) { - let err = validateInteger(value) - if (!err) return errors - errors.push(err) - } else if ( type === "array" ) { - let itemType + if ( !value.count() ) { return errors } - if ( !value.count() ) { return errors } + itemType = param.getIn(["items", "type"]) - itemType = param.getIn(["items", "type"]) + value.forEach((item, index) => { + let err - value.forEach((item, index) => { - let err + if (itemType === "number") { + err = validateNumber(item) + } else if (itemType === "integer") { + err = validateInteger(item) + } else if (itemType === "string") { + err = validateString(item) + } - if (itemType === "number") { - err = validateNumber(item) - } else if (itemType === "integer") { - err = validateInteger(item) - } - - if ( err ) { - errors.push({ index: index, error: err}) - } - }) - } else if ( type === "file" ) { - let err = validateFile(value) - if (!err) return errors - errors.push(err) + if ( err ) { + errors.push({ index: index, error: err}) + } + }) + } else if ( type === "file" ) { + let err = validateFile(value) + if (!err) return errors + errors.push(err) + } } return errors diff --git a/src/style/_buttons.scss b/src/style/_buttons.scss index 2470f8b0..bfb85023 100644 --- a/src/style/_buttons.scss +++ b/src/style/_buttons.scss @@ -14,6 +14,11 @@ @include text_headline(); + &.btn-sm { + font-size: 12px; + padding: 4px 23px; + } + &[disabled] { cursor: not-allowed; @@ -165,6 +170,9 @@ button { cursor: pointer; - outline: none; + + &.invalid { + @include invalidFormElement(); + } } diff --git a/src/style/_form.scss b/src/style/_form.scss index 185b836e..e54d5438 100644 --- a/src/style/_form.scss +++ b/src/style/_form.scss @@ -21,6 +21,10 @@ select background: #f7f7f7; } + + &.invalid { + @include invalidFormElement(); + } } .opblock-body select @@ -53,12 +57,8 @@ input[type=file] border-radius: 4px; background: #fff; - &.invalid - { - animation: shake .4s 1; - - border-color: $_color-delete; - background: lighten($_color-delete, 35%); + &.invalid { + @include invalidFormElement(); } } diff --git a/src/style/_mixins.scss b/src/style/_mixins.scss index a2a27d48..8fd01720 100644 --- a/src/style/_mixins.scss +++ b/src/style/_mixins.scss @@ -166,3 +166,9 @@ $browser-context: 16; @warn 'Breakpoint mixin supports: tablet, mobile, desktop'; } } + +@mixin invalidFormElement() { + animation: shake .4s 1; + border-color: $_color-delete; + background: lighten($_color-delete, 35%); +} diff --git a/src/style/_table.scss b/src/style/_table.scss index 3d58f3d8..d1481709 100644 --- a/src/style/_table.scss +++ b/src/style/_table.scss @@ -97,6 +97,10 @@ table width: 100%; max-width: 340px; } + + select { + border-width: 1px; + } } .parameter__name diff --git a/test/core/utils.js b/test/core/utils.js index a63da13d..65ed7435 100644 --- a/test/core/utils.js +++ b/test/core/utils.js @@ -176,6 +176,7 @@ describe("utils", function(){ let result = null it("validates required strings", function() { + // invalid string param = fromJS({ required: true, type: "string", @@ -183,9 +184,39 @@ describe("utils", function(){ }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + + // valid string + param = fromJS({ + required: true, + type: "string", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional strings", function() { + // valid (empty) string + param = fromJS({ + required: false, + type: "string", + value: "" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid string + param = fromJS({ + required: false, + type: "string", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) it("validates required files", function() { + // invalid file param = fromJS({ required: true, type: "file", @@ -193,9 +224,48 @@ describe("utils", function(){ }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + + // valid file + param = fromJS({ + required: true, + type: "file", + value: new win.File() + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional files", function() { + // invalid file + param = fromJS({ + required: false, + type: "file", + value: "not a file" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a file"] ) + + // valid (empty) file + param = fromJS({ + required: false, + type: "file", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid file + param = fromJS({ + required: false, + type: "file", + value: new win.File() + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) it("validates required arrays", function() { + // invalid (empty) array param = fromJS({ required: true, type: "array", @@ -204,75 +274,51 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) + // invalid (not an array) param = fromJS({ required: true, type: "array", - value: [] + value: undefined }) result = validateParam( param, false ) expect( result ).toEqual( ["Required field is not provided"] ) - }) - it("validates numbers", function() { - // string instead of a number + // invalid array, items do not match correct type param = fromJS({ - required: false, - type: "number", - value: "test" + required: true, + type: "array", + value: [1], + items: { + type: "string" + } }) result = validateParam( param, false ) - expect( result ).toEqual( ["Value must be a number"] ) + expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] ) - // undefined value + // valid array, with no 'type' for items param = fromJS({ - required: false, - type: "number", - value: undefined + required: true, + type: "array", + value: ["1"] }) result = validateParam( param, false ) expect( result ).toEqual( [] ) - // null value + // valid array, items match type param = fromJS({ - required: false, - type: "number", - value: null + required: true, + type: "array", + value: ["1"], + items: { + type: "string" + } }) result = validateParam( param, false ) expect( result ).toEqual( [] ) }) - it("validates integers", function() { - // string instead of integer - param = fromJS({ - required: false, - type: "integer", - value: "test" - }) - result = validateParam( param, false ) - expect( result ).toEqual( ["Value must be an integer"] ) - - // undefined value - param = fromJS({ - required: false, - type: "integer", - value: undefined - }) - result = validateParam( param, false ) - expect( result ).toEqual( [] ) - - // null value - param = fromJS({ - required: false, - type: "integer", - value: null - }) - result = validateParam( param, false ) - expect( result ).toEqual( [] ) - }) - - it("validates arrays", function() { - // empty array + it("validates optional arrays", function() { + // valid, empty array param = fromJS({ required: false, type: "array", @@ -281,7 +327,7 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( [] ) - // numbers + // invalid, items do not match correct type param = fromJS({ required: false, type: "array", @@ -293,17 +339,209 @@ describe("utils", function(){ result = validateParam( param, false ) expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] ) - // integers + // valid param = fromJS({ required: false, type: "array", - value: ["not", "numbers"], + value: ["test"], items: { - type: "integer" + type: "string" } }) result = validateParam( param, false ) - expect( result ).toEqual( [{index: 0, error: "Value must be an integer"}, {index: 1, error: "Value must be an integer"}] ) + expect( result ).toEqual( [] ) + }) + + it("validates required booleans", function() { + // invalid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid boolean value (not a boolean) + param = fromJS({ + required: true, + type: "boolean", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: "true" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid boolean value + param = fromJS({ + required: true, + type: "boolean", + value: false + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional booleans", function() { + // valid (empty) boolean value + param = fromJS({ + required: false, + type: "boolean", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // invalid boolean value (not a boolean) + param = fromJS({ + required: false, + type: "boolean", + value: "test string" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a boolean"] ) + + // valid boolean value + param = fromJS({ + required: false, + type: "boolean", + value: "true" + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid boolean value + param = fromJS({ + required: false, + type: "boolean", + value: false + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates required numbers", function() { + // invalid number, string instead of a number + param = fromJS({ + required: true, + type: "number", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid number, undefined value + param = fromJS({ + required: true, + type: "number", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid number + param = fromJS({ + required: true, + type: "number", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional numbers", function() { + // invalid number, string instead of a number + param = fromJS({ + required: false, + type: "number", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be a number"] ) + + // valid (empty) number + param = fromJS({ + required: false, + type: "number", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid number + param = fromJS({ + required: false, + type: "number", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates required integers", function() { + // invalid integer, string instead of an integer + param = fromJS({ + required: true, + type: "integer", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // invalid integer, undefined value + param = fromJS({ + required: true, + type: "integer", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Required field is not provided"] ) + + // valid integer + param = fromJS({ + required: true, + type: "integer", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + }) + + it("validates optional integers", function() { + // invalid integer, string instead of an integer + param = fromJS({ + required: false, + type: "integer", + value: "test" + }) + result = validateParam( param, false ) + expect( result ).toEqual( ["Value must be an integer"] ) + + // valid (empty) integer + param = fromJS({ + required: false, + type: "integer", + value: undefined + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) + + // valid number + param = fromJS({ + required: false, + type: "integer", + value: 10 + }) + result = validateParam( param, false ) + expect( result ).toEqual( [] ) }) }) })