Skip to content

Commit f4f8ee5

Browse files
committed
Merge branch 'master' of github.com:swagger-api/swagger-ui into v/3.0.20
2 parents 4b404f6 + b448c48 commit f4f8ee5

File tree

18 files changed

+481
-116
lines changed

18 files changed

+481
-116
lines changed

src/core/components/array-model.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ export default class ArrayModel extends Component {
1515
}
1616

1717
render(){
18-
let { getComponent, required, schema, depth, expandDepth } = this.props
18+
let { getComponent, required, schema, depth, expandDepth, name } = this.props
1919
let items = schema.get("items")
2020
let title = schema.get("title") || name
2121
let properties = schema.filter( ( v, key) => ["type", "items", "$$ref"].indexOf(key) === -1 )
2222

2323
const ModelCollapse = getComponent("ModelCollapse")
2424
const Model = getComponent("Model")
2525

26-
const titleEl = title &&
26+
const titleEl = title &&
2727
<span className="model-title">
2828
<span className="model-title__text">{ title }</span>
2929
</span>
@@ -44,4 +44,4 @@ export default class ArrayModel extends Component {
4444
{ required && <span style={{ color: "red" }}>*</span>}
4545
</span>
4646
}
47-
}
47+
}

src/core/components/layout-utils.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ export class Select extends React.Component {
129129
value: PropTypes.any,
130130
onChange: PropTypes.func,
131131
multiple: PropTypes.bool,
132-
allowEmptyValue: PropTypes.bool
132+
allowEmptyValue: PropTypes.bool,
133+
className: PropTypes.string
133134
}
134135

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

143144
let value
144145

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

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

src/core/components/model.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default class Model extends Component {
4848
switch(type) {
4949
case "object":
5050
return <ObjectModel className="object" { ...this.props } schema={ modelSchema }
51-
name={ name || modelName }
51+
name={ name || modelName } required={ required }
5252
isRef={ isRef!== undefined ? isRef : !!$$ref }/>
5353
case "array":
5454
return <ArrayModel className="array" { ...this.props } schema={ modelSchema } required={ required } />

src/core/components/models.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ export default class Models extends Component {
2424
return <section className={ showModels ? "models is-open" : "models"}>
2525
<h4 onClick={() => layoutActions.show("models", !showModels)}>
2626
<span>Models</span>
27-
<svg width="20" height="20">
28-
<use xlinkHref="#large-arrow" />
27+
<svg className="arrow" width="20" height="20">
28+
<use xlinkHref={showModels ? "#large-arrow-down" : "#large-arrow"} />
2929
</svg>
3030
</h4>
3131
<Collapse isOpened={showModels}>

src/core/components/object-model.jsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export default class ObjectModel extends Component {
2323
let properties = schema.get("properties")
2424
let additionalProperties = schema.get("additionalProperties")
2525
let title = schema.get("title") || name
26-
let required = schema.get("required")
26+
let requiredProperties = schema.get("required")
2727

2828
const JumpToPath = getComponent("JumpToPath", true)
2929
const Markdown = getComponent("Markdown")
@@ -63,14 +63,16 @@ export default class ObjectModel extends Component {
6363
{
6464
!(properties && properties.size) ? null : properties.entrySeq().map(
6565
([key, value]) => {
66-
let isRequired = List.isList(required) && required.contains(key)
66+
let isRequired = List.isList(requiredProperties) && requiredProperties.contains(key)
6767
let propertyStyle = { verticalAlign: "top", paddingRight: "0.2em" }
6868
if ( isRequired ) {
6969
propertyStyle.fontWeight = "bold"
7070
}
7171

7272
return (<tr key={key}>
73-
<td style={ propertyStyle }>{ key }:</td>
73+
<td style={ propertyStyle }>
74+
{ key }{ isRequired && <span style={{ color: "red" }}>*</span> }
75+
</td>
7476
<td style={{ verticalAlign: "top" }}>
7577
<Model key={ `object-${name}-${key}_${value}` } { ...props }
7678
required={ isRequired }

src/core/components/response-body.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class ResponseBody extends React.Component {
4040

4141
// Image
4242
} else if (/^image\//i.test(contentType)) {
43-
bodyEl = <img src={ url } />
43+
bodyEl = <img style={{ maxWidth: "100%" }} src={ window.URL.createObjectURL(content) } />
4444

4545
// Audio
4646
} else if (/^audio\//i.test(contentType)) {

src/core/components/schemes.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ export default class Schemes extends React.Component {
1919
}
2020

2121
componentWillReceiveProps(nextProps) {
22-
if ( this.props.operationScheme && !nextProps.schemes.has(this.props.operationScheme) ) {
23-
//fire 'change' event if our selected scheme is no longer an option
22+
if ( !this.props.operationScheme || !nextProps.schemes.has(this.props.operationScheme) ) {
23+
// if we don't have a selected operationScheme or if our selected scheme is no longer an option,
24+
// then fire 'change' event and select the first scheme in the list of options
2425
this.setScheme(nextProps.schemes.first())
2526
}
2627
}

src/core/json-schema-components.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export class JsonSchema_string extends Component {
5757

5858
if ( enumValue ) {
5959
const Select = getComponent("Select")
60-
return (<Select allowedValues={ enumValue }
60+
return (<Select className={ errors.length ? "invalid" : ""}
61+
allowedValues={ enumValue }
6162
value={ value }
6263
allowEmptyValue={ !required }
6364
onChange={ this.onEnumChange }/>)
@@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent {
121122
render() {
122123
let { getComponent, required, schema, fn } = this.props
123124

125+
let errors = schema.errors || []
124126
let itemSchema = fn.inferSchema(schema.items)
125127

126128
const JsonSchemaForm = getComponent("JsonSchemaForm")
@@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent {
131133

132134
if ( enumValue ) {
133135
const Select = getComponent("Select")
134-
return (<Select multiple={ true }
136+
return (<Select className={ errors.length ? "invalid" : ""}
137+
multiple={ true }
135138
value={ value }
136139
allowedValues={ enumValue }
137140
allowEmptyValue={ !required }
138141
onChange={ this.onEnumChange }/>)
139142
}
140143

141-
let errors = schema.errors || []
142-
143144
return (
144145
<div>
145-
{ !value || value.count() < 1 ?
146-
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
146+
{ !value || value.count() < 1 ? null :
147147
value.map( (item,i) => {
148148
let schema = Object.assign({}, itemSchema)
149149
if ( errors.length ) {
@@ -153,12 +153,12 @@ export class JsonSchema_array extends PureComponent {
153153
return (
154154
<div key={i} className="json-schema-form-item">
155155
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
156-
<Button className="json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
156+
<Button className="btn btn-sm json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
157157
</div>
158158
)
159159
}).toArray()
160160
}
161-
<Button className="json-schema-form-item-add" onClick={this.addItem}> Add item </Button>
161+
<Button className={`btn btn-sm json-schema-form-item-add ${errors.length ? "invalid" : null}`} onClick={this.addItem}> Add item </Button>
162162
</div>
163163
)
164164
}
@@ -170,12 +170,14 @@ export class JsonSchema_boolean extends Component {
170170

171171
onEnumChange = (val) => this.props.onChange(val)
172172
render() {
173-
let { getComponent, required, value } = this.props
173+
let { getComponent, value, schema } = this.props
174+
let errors = schema.errors || []
174175
const Select = getComponent("Select")
175176

176-
return (<Select value={ String(value) }
177+
return (<Select className={ errors.length ? "invalid" : ""}
178+
value={ String(value) }
177179
allowedValues={ fromJS(["true", "false"]) }
178-
allowEmptyValue={ !required }
180+
allowEmptyValue={true}
179181
onChange={ this.onEnumChange }/>)
180182
}
181183
}

src/core/utils.js

Lines changed: 71 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function fromJSOrdered (js) {
4141
return !isObject(js) ? js :
4242
Array.isArray(js) ?
4343
Im.Seq(js).map(fromJSOrdered).toList() :
44-
Im.Seq(js).map(fromJSOrdered).toOrderedMap()
44+
Im.OrderedMap(js).map(fromJSOrdered)
4545
}
4646

4747
export function bindToState(obj, state) {
@@ -468,59 +468,85 @@ export const validateFile = ( val ) => {
468468
}
469469
}
470470

471+
export const validateBoolean = ( val ) => {
472+
if ( !(val === "true" || val === "false" || val === true || val === false) ) {
473+
return "Value must be a boolean"
474+
}
475+
}
476+
477+
export const validateString = ( val ) => {
478+
if ( val && typeof val !== "string" ) {
479+
return "Value must be a string"
480+
}
481+
}
482+
471483
// validation of parameters before execute
472484
export const validateParam = (param, isXml) => {
473485
let errors = []
474486
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
475487
let required = param.get("required")
476488
let type = param.get("type")
477489

478-
let stringCheck = type === "string" && !value
479-
let arrayCheck = type === "array" && Array.isArray(value) && !value.length
480-
let listCheck = type === "array" && Im.List.isList(value) && !value.count()
481-
let fileCheck = type === "file" && !(value instanceof win.File)
482-
483-
if ( required && (stringCheck || arrayCheck || listCheck || fileCheck) ) {
484-
errors.push("Required field is not provided")
485-
return errors
486-
}
487-
488-
if ( value === null || value === undefined ) {
489-
return errors
490-
}
491-
492-
if ( type === "number" ) {
493-
let err = validateNumber(value)
494-
if (!err) return errors
495-
errors.push(err)
496-
} else if ( type === "integer" ) {
497-
let err = validateInteger(value)
498-
if (!err) return errors
499-
errors.push(err)
500-
} else if ( type === "array" ) {
501-
let itemType
502-
503-
if ( !value.count() ) { return errors }
504-
505-
itemType = param.getIn(["items", "type"])
506-
507-
value.forEach((item, index) => {
508-
let err
490+
// If the parameter is required OR the parameter has a value (meaning optional, but filled in)
491+
// then we should do our validation routine
492+
if ( required || value ) {
493+
// These checks should evaluate to true if the parameter's value is valid
494+
let stringCheck = type === "string" && value && !validateString(value)
495+
let arrayCheck = type === "array" && Array.isArray(value) && value.length
496+
let listCheck = type === "array" && Im.List.isList(value) && value.count()
497+
let fileCheck = type === "file" && value instanceof win.File
498+
let booleanCheck = type === "boolean" && !validateBoolean(value)
499+
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
500+
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
501+
502+
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
503+
errors.push("Required field is not provided")
504+
return errors
505+
}
509506

510-
if (itemType === "number") {
511-
err = validateNumber(item)
512-
} else if (itemType === "integer") {
513-
err = validateInteger(item)
514-
}
507+
if ( type === "string" ) {
508+
let err = validateString(value)
509+
if (!err) return errors
510+
errors.push(err)
511+
} else if ( type === "boolean" ) {
512+
let err = validateBoolean(value)
513+
if (!err) return errors
514+
errors.push(err)
515+
} else if ( type === "number" ) {
516+
let err = validateNumber(value)
517+
if (!err) return errors
518+
errors.push(err)
519+
} else if ( type === "integer" ) {
520+
let err = validateInteger(value)
521+
if (!err) return errors
522+
errors.push(err)
523+
} else if ( type === "array" ) {
524+
let itemType
525+
526+
if ( !value.count() ) { return errors }
527+
528+
itemType = param.getIn(["items", "type"])
529+
530+
value.forEach((item, index) => {
531+
let err
532+
533+
if (itemType === "number") {
534+
err = validateNumber(item)
535+
} else if (itemType === "integer") {
536+
err = validateInteger(item)
537+
} else if (itemType === "string") {
538+
err = validateString(item)
539+
}
515540

516-
if ( err ) {
517-
errors.push({ index: index, error: err})
518-
}
519-
})
520-
} else if ( type === "file" ) {
521-
let err = validateFile(value)
522-
if (!err) return errors
523-
errors.push(err)
541+
if ( err ) {
542+
errors.push({ index: index, error: err})
543+
}
544+
})
545+
} else if ( type === "file" ) {
546+
let err = validateFile(value)
547+
if (!err) return errors
548+
errors.push(err)
549+
}
524550
}
525551

526552
return errors

src/plugins/add-plugin.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ SwaggerUI({
2020
})
2121
```
2222

23-
Or if you're updating the core plugins.. you'll add it to [src/js/bootstrap-plugin](https://github.com/SmartBear/swagger-ux/blob/master/src/js/bootstrap-plugin.js)
23+
Or if you're updating the core plugins.. you'll add it to the base preset: [src/core/presets/base.js](https://github.com/swagger-api/swagger-ui/blob/master/src/core/presets/base.js)
2424

2525
Each Plugin is a function that returns an object. That object will get merged with the `system` and later bound to the state.
2626
Here is an example of each `type`

0 commit comments

Comments
 (0)