ft: JsonSchema components are now ImmutableJS compliant (#5952)
bug: JsonSchema components should validate schema properties exists - schema - type - format - enum bug: fix a debounce error in JsonSchema_string if value is null ft: new simplified JsonSchemaArrayItemText component test: use immutableJS for `json-schema-form` test test: add dev scripts to run `cypress open` test: new cypress `schema-form` tests
This commit is contained in:
@@ -42,7 +42,7 @@ export default class ParameterRow extends Component {
|
||||
|
||||
if(isOAS3) {
|
||||
let { schema } = getParameterSchema(parameterWithMeta, { isOAS3 })
|
||||
enumValue = schema.get("enum")
|
||||
enumValue = schema ? schema.get("enum") : undefined
|
||||
} else {
|
||||
enumValue = parameterWithMeta ? parameterWithMeta.get("enum") : undefined
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export default class ParameterRow extends Component {
|
||||
if ( value !== undefined && value !== paramValue ) {
|
||||
this.onChangeWrapper(numberToString(value))
|
||||
}
|
||||
|
||||
// todo: could check if schema here; if not, do not call. impact?
|
||||
this.setDefaultValue()
|
||||
}
|
||||
|
||||
@@ -97,17 +97,16 @@ export default class ParameterRow extends Component {
|
||||
let { specSelectors, pathMethod, rawParam, oas3Selectors } = this.props
|
||||
|
||||
const paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam) || Map()
|
||||
|
||||
const { schema } = getParameterSchema(paramWithMeta, { isOAS3: specSelectors.isOAS3() })
|
||||
|
||||
const parameterMediaType = paramWithMeta
|
||||
.get("content", Map())
|
||||
.keySeq()
|
||||
.first()
|
||||
|
||||
const generatedSampleValue = getSampleSchema(schema.toJS(), parameterMediaType, {
|
||||
// getSampleSchema could return null
|
||||
const generatedSampleValue = schema ? getSampleSchema(schema.toJS(), parameterMediaType, {
|
||||
includeWriteOnly: true
|
||||
})
|
||||
}) : null
|
||||
|
||||
if (!paramWithMeta || paramWithMeta.get("value") !== undefined) {
|
||||
return
|
||||
@@ -121,14 +120,14 @@ export default class ParameterRow extends Component {
|
||||
if (specSelectors.isSwagger2()) {
|
||||
initialValue = paramWithMeta.get("x-example")
|
||||
|| paramWithMeta.getIn(["schema", "example"])
|
||||
|| schema.getIn(["default"])
|
||||
|| (schema && schema.getIn(["default"]))
|
||||
} else if (specSelectors.isOAS3()) {
|
||||
const currentExampleKey = oas3Selectors.activeExamplesMember(...pathMethod, "parameters", this.getParamKey())
|
||||
initialValue = paramWithMeta.getIn(["examples", currentExampleKey, "value"])
|
||||
|| paramWithMeta.getIn(["content", parameterMediaType, "example"])
|
||||
|| paramWithMeta.get("example")
|
||||
|| schema.get("example")
|
||||
|| schema.get("default")
|
||||
|| (schema && schema.get("example"))
|
||||
|| (schema && schema.get("default"))
|
||||
|| paramWithMeta.get("default") // ensures support for `parameterMacro`
|
||||
}
|
||||
|
||||
@@ -144,7 +143,7 @@ export default class ParameterRow extends Component {
|
||||
if(initialValue !== undefined) {
|
||||
this.onChangeWrapper(initialValue)
|
||||
} else if(
|
||||
schema.get("type") === "object"
|
||||
schema && schema.get("type") === "object"
|
||||
&& generatedSampleValue
|
||||
&& !paramWithMeta.get("examples")
|
||||
) {
|
||||
@@ -212,12 +211,12 @@ export default class ParameterRow extends Component {
|
||||
let { schema } = getParameterSchema(param, { isOAS3 })
|
||||
let paramWithMeta = specSelectors.parameterWithMetaByIdentity(pathMethod, rawParam) || Map()
|
||||
|
||||
let format = schema.get("format")
|
||||
let type = schema.get("type")
|
||||
let format = schema ? schema.get("format") : null
|
||||
let type = schema ? schema.get("type") : null
|
||||
let itemType = schema ? schema.getIn(["items", "type"]) : null
|
||||
let isFormData = inType === "formData"
|
||||
let isFormDataSupported = "FormData" in win
|
||||
let required = param.get("required")
|
||||
let itemType = schema.getIn(["items", "type"])
|
||||
|
||||
let value = paramWithMeta ? paramWithMeta.get("value") : ""
|
||||
let commonExt = showCommonExtensions ? getCommonExtensions(schema) : null
|
||||
@@ -229,24 +228,26 @@ export default class ParameterRow extends Component {
|
||||
let paramExample // undefined
|
||||
let isDisplayParamEnum = false
|
||||
|
||||
if ( param !== undefined ) {
|
||||
if ( param !== undefined && schema ) {
|
||||
paramItems = schema.get("items")
|
||||
}
|
||||
|
||||
if (paramItems !== undefined) {
|
||||
paramEnum = paramItems.get("enum")
|
||||
paramDefaultValue = paramItems.get("default")
|
||||
} else {
|
||||
} else if (schema) {
|
||||
paramEnum = schema.get("enum")
|
||||
}
|
||||
|
||||
if ( paramEnum !== undefined && paramEnum.size > 0) {
|
||||
if ( paramEnum && paramEnum.size && paramEnum.size > 0) {
|
||||
isDisplayParamEnum = true
|
||||
}
|
||||
|
||||
// Default and Example Value for readonly doc
|
||||
if ( param !== undefined ) {
|
||||
paramDefaultValue = schema.get("default")
|
||||
if (schema) {
|
||||
paramDefaultValue = schema.get("default")
|
||||
}
|
||||
if (paramDefaultValue === undefined) {
|
||||
paramDefaultValue = param.get("default")
|
||||
}
|
||||
|
||||
@@ -45,37 +45,37 @@ export class JsonSchemaForm extends Component {
|
||||
|
||||
render() {
|
||||
let { schema, errors, value, onChange, getComponent, fn, disabled } = this.props
|
||||
|
||||
if(schema.toJS)
|
||||
schema = schema.toJS()
|
||||
|
||||
let { type, format="" } = schema
|
||||
// In the json schema rendering code, we optimistically query our system for a number of components.
|
||||
// If the component doesn't exist, we optionally suppress these warnings.
|
||||
const format = schema && schema.get ? schema.get("format") : null
|
||||
const type = schema && schema.get ? schema.get("type") : null
|
||||
let getComponentSilently = (name) => getComponent(name, false, { failSilently: true })
|
||||
|
||||
let Comp = (format ?
|
||||
let Comp = type ? format ?
|
||||
getComponentSilently(`JsonSchema_${type}_${format}`) :
|
||||
getComponentSilently(`JsonSchema_${type}`)) ||
|
||||
getComponentSilently("JsonSchema_string")
|
||||
|
||||
getComponentSilently(`JsonSchema_${type}`) :
|
||||
getComponent("JsonSchema_string")
|
||||
if (!Comp) {
|
||||
Comp = getComponent("JsonSchema_string")
|
||||
}
|
||||
return <Comp { ...this.props } errors={errors} fn={fn} getComponent={getComponent} value={value} onChange={onChange} schema={schema} disabled={disabled}/>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class JsonSchema_string extends Component {
|
||||
static propTypes = JsonSchemaPropShape
|
||||
static defaultProps = JsonSchemaDefaultProps
|
||||
onChange = (e) => {
|
||||
const value = this.props.schema["type"] === "file" ? e.target.files[0] : e.target.value
|
||||
const value = this.props.schema && this.props.schema["type"] === "file" ? e.target.files[0] : e.target.value
|
||||
this.props.onChange(value, this.props.keyName)
|
||||
}
|
||||
onEnumChange = (val) => this.props.onChange(val)
|
||||
render() {
|
||||
let { getComponent, value, schema, errors, required, description, disabled } = this.props
|
||||
let enumValue = schema["enum"]
|
||||
|
||||
const enumValue = schema && schema.get ? schema.get("enum") : null
|
||||
const format = schema && schema.get ? schema.get("format") : null
|
||||
const type = schema && schema.get ? schema.get("type") : null
|
||||
const schemaIn = schema && schema.get ? schema.get("in") : null
|
||||
if (!value) {
|
||||
value = "" // value should not be null; this fixes a Debounce error
|
||||
}
|
||||
errors = errors.toJS ? errors.toJS() : []
|
||||
|
||||
if ( enumValue ) {
|
||||
@@ -89,9 +89,9 @@ export class JsonSchema_string extends Component {
|
||||
onChange={ this.onEnumChange }/>)
|
||||
}
|
||||
|
||||
const isDisabled = disabled || (schema["in"] === "formData" && !("FormData" in window))
|
||||
const isDisabled = disabled || (schemaIn && schemaIn === "formData" && !("FormData" in window))
|
||||
const Input = getComponent("Input")
|
||||
if (schema["type"] === "file") {
|
||||
if (type && type === "file") {
|
||||
return (<Input type="file"
|
||||
className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
@@ -100,7 +100,7 @@ export class JsonSchema_string extends Component {
|
||||
}
|
||||
else {
|
||||
return (<DebounceInput
|
||||
type={ schema.format === "password" ? "password" : "text" }
|
||||
type={ format && format === "password" ? "password" : "text" }
|
||||
className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
value={value}
|
||||
@@ -120,35 +120,35 @@ export class JsonSchema_array extends PureComponent {
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { value: valueOrEmptyList(props.value)}
|
||||
this.state = { value: valueOrEmptyList(props.value) }
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
if(props.value !== this.state.value)
|
||||
this.setState({value: props.value})
|
||||
this.setState({ value: props.value })
|
||||
}
|
||||
|
||||
onChange = () => this.props.onChange(this.state.value)
|
||||
onChange = () => {
|
||||
this.props.onChange(this.state.value)
|
||||
}
|
||||
|
||||
onItemChange = (itemVal, i) => {
|
||||
this.setState(state => ({
|
||||
value: state.value.set(i, itemVal)
|
||||
this.setState(({ value }) => ({
|
||||
value: value.set(i, itemVal)
|
||||
}), this.onChange)
|
||||
}
|
||||
|
||||
removeItem = (i) => {
|
||||
this.setState(state => ({
|
||||
value: state.value.remove(i)
|
||||
this.setState(({ value }) => ({
|
||||
value: value.delete(i)
|
||||
}), this.onChange)
|
||||
}
|
||||
|
||||
|
||||
addItem = () => {
|
||||
this.setState(state => {
|
||||
state.value = valueOrEmptyList(state.value)
|
||||
return {
|
||||
value: state.value.push("")
|
||||
}
|
||||
}, this.onChange)
|
||||
let newValue = valueOrEmptyList(this.state.value)
|
||||
this.setState(() => ({
|
||||
value: newValue.push("")
|
||||
}), this.onChange)
|
||||
}
|
||||
|
||||
onEnumChange = (value) => {
|
||||
@@ -161,69 +161,120 @@ export class JsonSchema_array extends PureComponent {
|
||||
let { getComponent, required, schema, errors, fn, disabled } = this.props
|
||||
|
||||
errors = errors.toJS ? errors.toJS() : []
|
||||
const value = this.state.value // expect Im List
|
||||
const shouldRenderValue =
|
||||
value && value.count && value.count() > 0 ? true : false
|
||||
const schemaItemsEnum = schema.getIn(["items", "enum"])
|
||||
const schemaItemsType = schema.getIn(["items", "type"])
|
||||
const schemaItemsFormat = schema.getIn(["items", "format"])
|
||||
const schemaItemsSchema = schema.getIn(["items", "schema"])
|
||||
let ArrayItemsComponent
|
||||
let isArrayItemText = false
|
||||
if (schemaItemsType && schemaItemsFormat) {
|
||||
ArrayItemsComponent = getComponent(`JsonSchema_${schemaItemsType}_${schemaItemsFormat}`)
|
||||
} else if (schemaItemsType === "boolean" || schemaItemsType === "array" || schemaItemsType === "object") {
|
||||
ArrayItemsComponent = getComponent(`JsonSchema_${schemaItemsType}`)
|
||||
}
|
||||
// if ArrayItemsComponent not assigned or does not exist,
|
||||
// use default schemaItemsType === "string" & JsonSchemaArrayItemText component
|
||||
if (!ArrayItemsComponent) {
|
||||
isArrayItemText = true
|
||||
}
|
||||
|
||||
let itemSchema = fn.inferSchema(schema.items)
|
||||
|
||||
const JsonSchemaForm = getComponent("JsonSchemaForm")
|
||||
const Button = getComponent("Button")
|
||||
|
||||
let enumValue = itemSchema["enum"]
|
||||
let value = this.state.value
|
||||
|
||||
if ( enumValue ) {
|
||||
if ( schemaItemsEnum ) {
|
||||
const Select = getComponent("Select")
|
||||
return (<Select className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
multiple={ true }
|
||||
value={ value }
|
||||
disabled={disabled}
|
||||
allowedValues={ enumValue }
|
||||
allowedValues={ schemaItemsEnum }
|
||||
allowEmptyValue={ !required }
|
||||
onChange={ this.onEnumChange }/>)
|
||||
}
|
||||
|
||||
const Button = getComponent("Button")
|
||||
return (
|
||||
<div className="json-schema-array">
|
||||
{ !value || !value.count || value.count() < 1 ? null :
|
||||
value.map( (item,i) => {
|
||||
let schema = Object.assign({}, itemSchema)
|
||||
if ( errors.length ) {
|
||||
{shouldRenderValue ?
|
||||
(value.map((item, i) => {
|
||||
if (errors.length) {
|
||||
let err = errors.filter((err) => err.index === i)
|
||||
if (err.length) errors = [ err[0].error + i ]
|
||||
if (err.length) errors = [err[0].error + i]
|
||||
}
|
||||
return (
|
||||
<div key={i} className="json-schema-form-item">
|
||||
<JsonSchemaForm
|
||||
fn={fn}
|
||||
getComponent={getComponent}
|
||||
value={item}
|
||||
onChange={(val) => this.onItemChange(val, i)}
|
||||
schema={schema}
|
||||
disabled={disabled}
|
||||
/>
|
||||
{ !disabled ? (
|
||||
<Button
|
||||
className="btn btn-sm json-schema-form-item-remove"
|
||||
onClick={()=> this.removeItem(i)}
|
||||
> - </Button>
|
||||
) : null }
|
||||
</div>
|
||||
return (
|
||||
<div key={i} className="json-schema-form-item">
|
||||
{
|
||||
isArrayItemText ?
|
||||
<JsonSchemaArrayItemText
|
||||
value={item}
|
||||
onChange={(val) => this.onItemChange(val, i)}
|
||||
disabled={disabled}
|
||||
errors={errors}
|
||||
/>
|
||||
: <ArrayItemsComponent {...this.props}
|
||||
value={item}
|
||||
onChange={(val) => this.onItemChange(val, i)}
|
||||
disabled={disabled}
|
||||
errors={errors}
|
||||
schema={schemaItemsSchema}
|
||||
getComponent={getComponent}
|
||||
fn={fn}
|
||||
/>
|
||||
}
|
||||
{!disabled ? (
|
||||
<Button
|
||||
className="btn btn-sm json-schema-form-item-remove"
|
||||
onClick={() => this.removeItem(i)}
|
||||
> - </Button>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}).toArray()
|
||||
})
|
||||
) : null
|
||||
}
|
||||
{ !disabled ? (
|
||||
{!disabled ? (
|
||||
<Button
|
||||
className={`btn btn-sm json-schema-form-item-add ${errors.length ? "invalid" : null}`}
|
||||
onClick={this.addItem}
|
||||
>
|
||||
Add item
|
||||
</Button>
|
||||
) : null }
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class JsonSchemaArrayItemText extends Component {
|
||||
static propTypes = JsonSchemaPropShape
|
||||
static defaultProps = JsonSchemaDefaultProps
|
||||
|
||||
onChange = (e) => {
|
||||
const value = e.target.value
|
||||
this.props.onChange(value, this.props.keyName)
|
||||
}
|
||||
|
||||
render() {
|
||||
let { value, errors, description, disabled } = this.props
|
||||
if (!value) {
|
||||
value = "" // value should not be null
|
||||
}
|
||||
errors = errors.toJS ? errors.toJS() : []
|
||||
|
||||
return (<DebounceInput
|
||||
type={"text"}
|
||||
className={errors.length ? "invalid" : ""}
|
||||
title={errors.length ? errors : ""}
|
||||
value={value}
|
||||
minLength={0}
|
||||
debounceTimeout={350}
|
||||
placeholder={description}
|
||||
onChange={this.onChange}
|
||||
disabled={disabled} />)
|
||||
}
|
||||
}
|
||||
|
||||
export class JsonSchema_boolean extends Component {
|
||||
static propTypes = JsonSchemaPropShape
|
||||
static defaultProps = JsonSchemaDefaultProps
|
||||
@@ -232,15 +283,19 @@ export class JsonSchema_boolean extends Component {
|
||||
render() {
|
||||
let { getComponent, value, errors, schema, required, disabled } = this.props
|
||||
errors = errors.toJS ? errors.toJS() : []
|
||||
|
||||
let enumValue = schema && schema.get ? schema.get("enum") : null
|
||||
if (!enumValue) {
|
||||
// in case schema.get() also returns undefined/null
|
||||
enumValue = fromJS(["true", "false"])
|
||||
}
|
||||
const Select = getComponent("Select")
|
||||
|
||||
return (<Select className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
value={ String(value) }
|
||||
disabled={disabled}
|
||||
allowedValues={ fromJS(schema.enum || ["true", "false"]) }
|
||||
allowEmptyValue={ !schema.enum || !required }
|
||||
disabled={ disabled }
|
||||
allowedValues={ enumValue }
|
||||
allowEmptyValue={ !required }
|
||||
onChange={ this.onEnumChange }/>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ export default OAS3ComponentWrapFactory(({ Ori, ...props }) => {
|
||||
onChange
|
||||
} = props
|
||||
|
||||
const { type, format } = schema
|
||||
const format = schema && schema.get ? schema.get("format") : null
|
||||
const type = schema && schema.get ? schema.get("type") : null
|
||||
const Input = getComponent("Input")
|
||||
|
||||
if(type === "string" && (format === "binary" || format === "base64")) {
|
||||
if(type && type === "string" && (format && (format === "binary" || format === "base64"))) {
|
||||
return <Input type="file"
|
||||
className={ errors.length ? "invalid" : ""}
|
||||
title={ errors.length ? errors : ""}
|
||||
|
||||
@@ -100,7 +100,6 @@ const wrapRender = (component) => {
|
||||
return target
|
||||
}
|
||||
|
||||
|
||||
export const getComponent = (getSystem, getStore, getComponents, componentName, container, config = {}) => {
|
||||
|
||||
if(typeof componentName !== "string")
|
||||
|
||||
Reference in New Issue
Block a user