Browse Source

Merge branch 'master' into ft/oas3

bubble
shockey 7 years ago
committed by GitHub
parent
commit
84f6653fcf
8 changed files with 398 additions and 97 deletions
  1. +4
    -3
      src/core/components/layout-utils.jsx
  2. +13
    -11
      src/core/json-schema-components.js
  3. +73
    -45
      src/core/utils.js
  4. +11
    -1
      src/style/_buttons.scss
  5. +5
    -4
      src/style/_form.scss
  6. +6
    -0
      src/style/_mixins.scss
  7. +4
    -0
      src/style/_table.scss
  8. +282
    -33
      test/core/utils.js

+ 4
- 3
src/core/components/layout-utils.jsx View File

@@ -129,7 +129,8 @@ export class Select extends React.Component {
value: PropTypes.any,
onChange: PropTypes.func,
multiple: PropTypes.bool,
allowEmptyValue: PropTypes.bool
allowEmptyValue: PropTypes.bool,
className: PropTypes.string
}

static defaultProps = {
@@ -142,7 +143,7 @@ export class Select extends React.Component {

let value

if (props.value !== undefined) {
if (props.value) {
value = props.value
} else {
value = props.multiple ? [""] : ""
@@ -178,7 +179,7 @@ export class Select extends React.Component {
let value = this.state.value.toJS ? this.state.value.toJS() : this.state.value

return (
<select multiple={ multiple } value={ value } onChange={ this.onChange } >
<select className={this.props.className} multiple={ multiple } value={ value } onChange={ this.onChange } >
{ allowEmptyValue ? <option value="">--</option> : null }
{
allowedValues.map(function (item, key) {


+ 13
- 11
src/core/json-schema-components.js View File

@@ -57,7 +57,8 @@ export class JsonSchema_string extends Component {

if ( enumValue ) {
const Select = getComponent("Select")
return (<Select allowedValues={ enumValue }
return (<Select className={ errors.length ? "invalid" : ""}
allowedValues={ enumValue }
value={ value }
allowEmptyValue={ !required }
onChange={ this.onEnumChange }/>)
@@ -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 (<Select multiple={ true }
return (<Select className={ errors.length ? "invalid" : ""}
multiple={ true }
value={ value }
allowedValues={ enumValue }
allowEmptyValue={ !required }
onChange={ this.onEnumChange }/>)
}

let errors = schema.errors || []

return (
<div>
{ !value || value.count() < 1 ?
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
{ !value || value.count() < 1 ? null :
value.map( (item,i) => {
let schema = Object.assign({}, itemSchema)
if ( errors.length ) {
@@ -153,12 +153,12 @@ export class JsonSchema_array extends PureComponent {
return (
<div key={i} className="json-schema-form-item">
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
<Button className="json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
<Button className="btn btn-sm json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
</div>
)
}).toArray()
}
<Button className="json-schema-form-item-add" onClick={this.addItem}> Add item </Button>
<Button className={`btn btn-sm json-schema-form-item-add ${errors.length ? "invalid" : null}`} onClick={this.addItem}> Add item </Button>
</div>
)
}
@@ -170,12 +170,14 @@ export class JsonSchema_boolean extends Component {

onEnumChange = (val) => this.props.onChange(val)
render() {
let { getComponent, required, value } = this.props
let { getComponent, value, schema } = this.props
let errors = schema.errors || []
const Select = getComponent("Select")

return (<Select value={ String(value) }
return (<Select className={ errors.length ? "invalid" : ""}
value={ String(value) }
allowedValues={ fromJS(["true", "false"]) }
allowEmptyValue={ !required }
allowEmptyValue={ true }
onChange={ this.onEnumChange }/>)
}
}

+ 73
- 45
src/core/utils.js View File

@@ -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,53 +487,69 @@ 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)
let nullUndefinedCheck = value === null || value === undefined

if ( required && (stringCheck || arrayCheck || listCheck || fileCheck || nullUndefinedCheck) ) {
errors.push("Required field is not provided")
return errors
}

if ( value === null || value === undefined ) {
return errors
}

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 }

itemType = param.getIn(["items", "type"])

value.forEach((item, index) => {
let err
/*
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
then we should do our validation routine.
Only bother validating the parameter if the type was specified.
*/
if ( type && (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 || booleanCheck || numberCheck || integerCheck) ) {
errors.push("Required field is not provided")
return errors
}

if (itemType === "number") {
err = validateNumber(item)
} else if (itemType === "integer") {
err = validateInteger(item)
}
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 ( !value.count() ) { return errors }

itemType = param.getIn(["items", "type"])

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 ( 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


+ 11
- 1
src/style/_buttons.scss View File

@@ -14,6 +14,12 @@

@include text_headline();

&.btn-sm
{
font-size: 12px;
padding: 4px 23px;
}

&[disabled]
{
cursor: not-allowed;
@@ -165,6 +171,10 @@
button
{
cursor: pointer;

outline: none;

&.invalid
{
@include invalidFormElement();
}
}

+ 5
- 4
src/style/_form.scss View File

@@ -21,6 +21,10 @@ select

background: #f7f7f7;
}

&.invalid {
@include invalidFormElement();
}
}

.opblock-body select
@@ -55,10 +59,7 @@ input[type=file]

&.invalid
{
animation: shake .4s 1;

border-color: $_color-delete;
background: lighten($_color-delete, 35%);
@include invalidFormElement();
}
}



+ 6
- 0
src/style/_mixins.scss View File

@@ -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%);
}

+ 4
- 0
src/style/_table.scss View File

@@ -97,6 +97,10 @@ table
width: 100%;
max-width: 340px;
}

select {
border-width: 1px;
}
}

.parameter__name


+ 282
- 33
test/core/utils.js View File

@@ -175,7 +175,19 @@ describe("utils", function() {
let param = null
let result = null

it("skips validation when `type` is not specified", function() {
// invalid type
param = fromJS({
required: false,
type: undefined,
value: ""
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})

it("validates required strings", function() {
// invalid string
param = fromJS({
required: true,
type: "string",
@@ -183,9 +195,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 +235,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,17 +285,191 @@ 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: undefined
})
result = validateParam( param, false )
expect( result ).toEqual( ["Required field is not provided"] )

// invalid array, items do not match correct type
param = fromJS({
required: true,
type: "array",
value: [1],
items: {
type: "string"
}
})
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )

// valid array, with no 'type' for items
param = fromJS({
required: true,
type: "array",
value: ["1"]
})
result = validateParam( param, false )
expect( result ).toEqual( [] )

// valid array, items match type
param = fromJS({
required: true,
type: "array",
value: ["1"],
items: {
type: "string"
}
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})

it("validates optional arrays", function() {
// valid, empty array
param = fromJS({
required: false,
type: "array",
value: []
})
result = validateParam( param, false )
expect( result ).toEqual( [] )

// invalid, items do not match correct type
param = fromJS({
required: false,
type: "array",
value: ["number"],
items: {
type: "number"
}
})
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )

// valid
param = fromJS({
required: false,
type: "array",
value: ["test"],
items: {
type: "string"
}
})
result = validateParam( param, false )
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 numbers", function() {
// string instead of a number
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",
@@ -223,7 +478,7 @@ describe("utils", function() {
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be a number"] )

// undefined value
// valid (empty) number
param = fromJS({
required: false,
type: "number",
@@ -232,78 +487,72 @@ describe("utils", function() {
result = validateParam( param, false )
expect( result ).toEqual( [] )

// null value
// valid number
param = fromJS({
required: false,
type: "number",
value: null
value: 10
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})

it("validates integers", function() {
// string instead of integer
it("validates required integers", function() {
// invalid integer, string instead of an integer
param = fromJS({
required: false,
required: true,
type: "integer",
value: "test"
})
result = validateParam( param, false )
expect( result ).toEqual( ["Value must be an integer"] )
expect( result ).toEqual( ["Required field is not provided"] )

// undefined value
// invalid integer, undefined value
param = fromJS({
required: false,
required: true,
type: "integer",
value: undefined
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
expect( result ).toEqual( ["Required field is not provided"] )

// null value
// valid integer
param = fromJS({
required: false,
required: true,
type: "integer",
value: null
value: 10
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
})

it("validates arrays", function() {
// empty array
it("validates optional integers", function() {
// invalid integer, string instead of an integer
param = fromJS({
required: false,
type: "array",
value: []
type: "integer",
value: "test"
})
result = validateParam( param, false )
expect( result ).toEqual( [] )
expect( result ).toEqual( ["Value must be an integer"] )

// numbers
// valid (empty) integer
param = fromJS({
required: false,
type: "array",
value: ["number"],
items: {
type: "number"
}
type: "integer",
value: undefined
})
result = validateParam( param, false )
expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
expect( result ).toEqual( [] )

// integers
param = fromJS({
required: false,
type: "array",
value: ["not", "numbers"],
items: {
type: "integer"
}
type: "integer",
value: 10
})
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( [] )
})
})



Loading…
Cancel
Save