import React, { PureComponent, Component } from "react" import PropTypes from "prop-types" import { List, fromJS } from "immutable" import cx from "classnames" import ImPropTypes from "react-immutable-proptypes" import DebounceInput from "react-debounce-input" import { stringify } from "core/utils" const noop = ()=> {} const JsonSchemaPropShape = { getComponent: PropTypes.func.isRequired, value: PropTypes.any, onChange: PropTypes.func, keyName: PropTypes.any, fn: PropTypes.object.isRequired, schema: PropTypes.object, errors: ImPropTypes.list, required: PropTypes.bool, dispatchInitialValue: PropTypes.bool, description: PropTypes.any, disabled: PropTypes.bool, } const JsonSchemaDefaultProps = { value: "", onChange: noop, schema: {}, keyName: "", required: false, errors: List() } export class JsonSchemaForm extends Component { static propTypes = JsonSchemaPropShape static defaultProps = JsonSchemaDefaultProps componentDidMount() { const { dispatchInitialValue, value, onChange } = this.props if(dispatchInitialValue) { onChange(value) } else if(dispatchInitialValue === false) { onChange("") } } render() { let { schema, errors, value, onChange, getComponent, fn, disabled } = this.props 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 = type ? format ? getComponentSilently(`JsonSchema_${type}_${format}`) : getComponentSilently(`JsonSchema_${type}`) : getComponent("JsonSchema_string") if (!Comp) { Comp = getComponent("JsonSchema_string") } return } } export class JsonSchema_string extends Component { static propTypes = JsonSchemaPropShape static defaultProps = JsonSchemaDefaultProps onChange = (e) => { const value = this.props.schema && this.props.schema.get("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 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 ) { const Select = getComponent("Select") return ( ) } else { return ( ) } } } export class JsonSchema_array extends PureComponent { static propTypes = JsonSchemaPropShape static defaultProps = JsonSchemaDefaultProps constructor(props, context) { super(props, context) this.state = { value: valueOrEmptyList(props.value), schema: props.schema} } UNSAFE_componentWillReceiveProps(props) { const value = valueOrEmptyList(props.value) if(value !== this.state.value) this.setState({ value }) if(props.schema !== this.state.schema) this.setState({ schema: props.schema }) } onChange = () => { this.props.onChange(this.state.value) } onItemChange = (itemVal, i) => { this.setState(({ value }) => ({ value: value.set(i, itemVal) }), this.onChange) } removeItem = (i) => { this.setState(({ value }) => ({ value: value.delete(i) }), this.onChange) } addItem = () => { const { fn } = this.props let newValue = valueOrEmptyList(this.state.value) this.setState(() => ({ value: newValue.push(fn.getSampleSchema(this.state.schema.get("items"), false, { includeWriteOnly: true })) }), this.onChange) } onEnumChange = (value) => { this.setState(() => ({ value: value }), this.onChange) } render() { let { getComponent, required, schema, errors, fn, disabled } = this.props errors = errors.toJS ? errors.toJS() : Array.isArray(errors) ? errors : [] const arrayErrors = errors.filter(e => typeof e === "string") const needsRemoveError = errors.filter(e => e.needRemove !== undefined) .map(e => e.error) 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.get("items") let ArrayItemsComponent let isArrayItemText = false let isArrayItemFile = (schemaItemsType === "file" || (schemaItemsType === "string" && schemaItemsFormat === "binary")) ? true : 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 && !isArrayItemFile) { isArrayItemText = true } if ( schemaItemsEnum ) { const Select = getComponent("Select") return () } } export class JsonSchema_boolean extends Component { static propTypes = JsonSchemaPropShape static defaultProps = JsonSchemaDefaultProps onEnumChange = (val) => this.props.onChange(val) render() { let { getComponent, value, errors, schema, required, disabled } = this.props errors = errors.toJS ? errors.toJS() : [] let enumValue = schema && schema.get ? schema.get("enum") : null let allowEmptyValue = !enumValue || !required let booleanValue = !enumValue && ["true", "false"] const Select = getComponent("Select") return (