@inceptiongt/json-schema-editor-visual-new
Version:
jsonschema-draft07 editor
529 lines (493 loc) • 15.8 kB
JavaScript
import React from 'react';
import {
Input,
Row,
Tooltip,
Col,
Form,
Select,
Checkbox,
Button,
Icon,
Modal,
message,
Tabs,
AutoComplete
} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
const { TextArea } = Input;
const TabPane = Tabs.TabPane;
import './index.css';
import AceEditor from './components/AceEditor/AceEditor.js';
import _ from 'underscore';
import { connect } from 'react-redux';
import SchemaJson from './components/SchemaComponents/SchemaJson.js';
import PropTypes from 'prop-types';
import { SCHEMA_TYPE, debounce } from './utils.js';
import handleSchema from './schema';
const GenerateSchema = require('generate-schema/src/schemas/json.js');
const utils = require('./utils');
import CustomItem from './components/SchemaComponents/SchemaOther.js';
import LocalProvider from './components/LocalProvider/index.js';
import MockSelect from './components/MockSelect/index.js';
class jsonSchema extends React.Component {
constructor(props) {
super(props);
this.alterMsg = debounce(this.alterMsg, 2000);
this.state = {
visible: false,
show: true,
editVisible: false,
description: '',
descriptionKey: null,
advVisible: false,
itemKey: [],
curItemCustomValue: null,
checked: false,
editorModalName: '', // 弹窗名称desctiption | mock
mock: ''
};
this.Model = this.props.Model.schema;
this.jsonSchemaData = null;
this.jsonData = null;
}
// json 导入弹窗
showModal = () => {
this.setState({
visible: true
});
};
handleOk = () => {
if (this.importJsonType !== 'schema') {
if (!this.jsonData) {
return message.error('json 数据格式有误');
}
let jsonData = GenerateSchema(this.jsonData);
this.Model.changeEditorSchemaAction({ value: jsonData });
} else {
if (!this.jsonSchemaData) {
return message.error('json 数据格式有误');
}
this.Model.changeEditorSchemaAction({ value: this.jsonSchemaData });
}
this.setState({ visible: false });
};
handleCancel = () => {
this.setState({ visible: false });
};
componentWillReceiveProps(nextProps) {
if (typeof this.props.onChange === 'function' && this.props.schema !== nextProps.schema) {
let oldData = JSON.stringify(this.props.schema || '');
let newData = JSON.stringify(nextProps.schema || '');
if (oldData !== newData) return this.props.onChange(newData);
}
if (this.props.data && this.props.data !== nextProps.data) {
this.Model.changeEditorSchemaAction({ value: JSON.parse(nextProps.data) });
}
}
componentWillMount() {
let data = this.props.data;
if (!data) {
data = `{
"type": "object",
"title": "title",
"properties":{},
"additionalProperties": false,
"default": {}
}`;
}
this.Model.changeEditorSchemaAction({ value: JSON.parse(data) });
}
getChildContext() {
return {
getOpenValue: keys => {
return utils.getData(this.props.open, keys);
},
changeCustomValue: this.changeCustomValue,
Model: this.props.Model,
isMock: this.props.isMock
};
}
alterMsg = () => {
// return message.error(LocalProvider('valid_json'));
};
// AceEditor 中的数据
handleParams = e => {
if (!e.text) return;
// 将数据map 到store中
if (e.format !== true) {
return this.alterMsg();
}
handleSchema(e.jsonData);
this.Model.changeEditorSchemaAction({
value: e.jsonData
});
};
// 修改数据类型
changeType = (key, value) => {
this.Model.changeTypeAction({ key: [key], value });
};
handleImportJson = e => {
if (!e.text || e.format !== true) {
return (this.jsonData = null);
}
this.jsonData = e.jsonData;
};
handleImportJsonSchema = e => {
if (!e.text || e.format !== true) {
return (this.jsonSchemaData = null);
}
this.jsonSchemaData = e.jsonData;
};
// 增加子节点
addChildField = key => {
this.Model.addChildFieldAction({ key: [key] });
this.setState({ show: true });
};
clickIcon = () => {
this.setState({ show: !this.state.show });
};
// 修改备注信息
changeValue = (key, value) => {
if (key[0] === 'mock') {
value = value ? { mock: value } : '';
}
this.Model.changeValueAction({ key, value });
};
// 备注/mock弹窗 点击ok 时
handleEditOk = name => {
this.setState({
editVisible: false
});
let value = this.state[name];
if (name === 'mock') {
value = value ? { mock: value } : '';
}
this.Model.changeValueAction({ key: this.state.descriptionKey, value });
};
handleEditCancel = () => {
this.setState({
editVisible: false
});
};
/*
展示弹窗modal
prefix: 节点前缀信息
name: 弹窗的名称 ['description', 'mock']
value: 输入值
type: 如果当前字段是object || array showEdit 不可用
*/
showEdit = (prefix, name, value, type) => {
if (type === 'object' || type === 'array') {
return;
}
let descriptionKey = [].concat(prefix, name);
value = name === 'mock' ? (value ? value.mock : '') : value;
this.setState({
editVisible: true,
[name]: value,
descriptionKey,
editorModalName: name
});
};
// 修改备注/mock参数信息
changeDesc = (e, name) => {
this.setState({
[name]: e
});
};
// 高级设置
handleAdvOk = () => {
if (this.state.itemKey.length === 0) {
this.Model.changeEditorSchemaAction({
value: this.state.curItemCustomValue
});
} else {
this.Model.changeValueAction({
key: this.state.itemKey,
value: this.state.curItemCustomValue
});
}
this.setState({
advVisible: false
});
};
handleAdvCancel = () => {
this.setState({
advVisible: false
});
};
showAdv = (key, value) => {
this.setState({
advVisible: true,
itemKey: key,
curItemCustomValue: value // 当前节点的数据信息
});
};
// 修改弹窗中的json-schema 值
changeCustomValue = newValue => {
this.setState({
curItemCustomValue: newValue
});
};
changeCheckBox = e => {
this.setState({ checked: e });
this.Model.requireAllAction({ required: e, value: this.props.schema });
};
render() {
const {
visible,
editVisible,
description,
advVisible,
type,
checked,
editorModalName
} = this.state;
const { schema } = this.props;
let disabled =
this.props.schema.type === 'object' || this.props.schema.type === 'array' ? false : true;
return (
<div className="json-schema-react-editor">
<Button className="import-json-button" type="primary" onClick={this.showModal}>
{LocalProvider('import_json')}
</Button>
<Modal
maskClosable={false}
visible={visible}
title={LocalProvider('import_json')}
onOk={this.handleOk}
onCancel={this.handleCancel}
className="json-schema-react-editor-import-modal"
okText={'ok'}
cancelText={LocalProvider('cancel')}
footer={[
<Button key="back" onClick={this.handleCancel}>
{LocalProvider('cancel')}
</Button>,
<Button key="submit" type="primary" onClick={this.handleOk}>
{LocalProvider('ok')}
</Button>
]}
>
<Tabs
defaultActiveKey="json"
onChange={key => {
this.importJsonType = key;
}}
>
<TabPane tab="JSON" key="json">
<AceEditor data="" mode="json" onChange={this.handleImportJson} />
</TabPane>
<TabPane tab="JSON-SCHEMA" key="schema">
<AceEditor data="" mode="json" onChange={this.handleImportJsonSchema} />
</TabPane>
</Tabs>
</Modal>
<Modal
title={
<div>
{LocalProvider(editorModalName)}
{editorModalName === 'mock' && (
<Tooltip title={LocalProvider('mockLink')}>
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/YMFE/json-schema-editor-visual/issues/38"
>
<Icon type="question-circle-o" />
</a>
</Tooltip>
)}
</div>
}
maskClosable={false}
visible={editVisible}
onOk={() => this.handleEditOk(editorModalName)}
onCancel={this.handleEditCancel}
okText={LocalProvider('ok')}
cancelText={LocalProvider('cancel')}
>
<TextArea
value={this.state[editorModalName]}
placeholder={LocalProvider(editorModalName)}
onChange={e => this.changeDesc(e.target.value, editorModalName)}
autosize={{ minRows: 6, maxRows: 10 }}
/>
</Modal>
{advVisible && (
<Modal
title={LocalProvider('adv_setting')}
maskClosable={false}
visible={advVisible}
onOk={this.handleAdvOk}
onCancel={this.handleAdvCancel}
okText={LocalProvider('ok')}
width={780}
cancelText={LocalProvider('cancel')}
className="json-schema-react-editor-adv-modal"
>
<CustomItem data={JSON.stringify(this.state.curItemCustomValue, null, 2)} />
</Modal>
)}
<Row>
{this.props.showEditor && (
<Col span={8}>
<AceEditor
className="pretty-editor"
mode="json"
data={JSON.stringify(schema, null, 2)}
onChange={this.handleParams}
/>
</Col>
)}
<Col span={this.props.showEditor ? 16 : 24} className="wrapper object-style">
<Row type="flex" align="middle">
<Col span={8} className="col-item name-item col-item-name">
<Row type="flex" justify="space-around" align="middle">
<Col span={2} className="down-style-col">
{schema.type === 'object' ? (
<span className="down-style" onClick={this.clickIcon}>
{this.state.show ? (
<Icon className="icon-object" type="caret-down" />
) : (
<Icon className="icon-object" type="caret-right" />
)}
</span>
) : null}
</Col>
<Col span={22}>
<Input
addonAfter={
<Tooltip placement="top" title={'checked_all'}>
<Checkbox
checked={checked}
disabled={disabled}
onChange={e => this.changeCheckBox(e.target.checked)}
/>
</Tooltip>
}
disabled
value="root"
/>
</Col>
</Row>
</Col>
<Col span={3} className="col-item col-item-type">
<Select
className="type-select-style"
onChange={e => this.changeType(`type`, e)}
value={schema.type || 'object'}
>
{SCHEMA_TYPE.map((item, index) => {
return (
<Option value={item} key={index}>
{item}
</Option>
);
})}
</Select>
</Col>
{this.props.isMock && (
<Col span={3} className="col-item col-item-mock">
<MockSelect
schema={schema}
showEdit={() => this.showEdit([], 'mock', schema.mock, schema.type)}
onChange={value => this.changeValue(['mock'], value)}
/>
</Col>
)}
{/* title列 */}
{/* <Col span={this.props.isMock ? 4 : 5} className="col-item col-item-mock">
<Input
addonAfter={
<Icon
type="edit"
onClick={() =>
this.showEdit([], 'title', this.props.schema.title)
}
/>
}
placeholder={'Title'}
value={this.props.schema.title}
onChange={e => this.changeValue(['title'], e.target.value)}
/>
</Col> */}
<Col span={this.props.isMock ? 4 : 5} className="col-item col-item-mock">
<Input
// addonAfter={
// <Icon
// type="edit"
// onClick={() =>
// this.showEdit([], 'default', this.props.schema.default)
// }
// />
// }
placeholder={'default'}
value={JSON.stringify(this.props.schema.default)}
// onChange={e => this.changeValue(['default'], e.target.value)}
disabled
/>
</Col>
<Col span={this.props.isMock ? 4 : 5} className="col-item col-item-desc">
<Input
addonAfter={
<Icon
type="edit"
onClick={() =>
this.showEdit([], 'description', this.props.schema.description)
}
/>
}
placeholder={'description'}
value={schema.description}
onChange={e => this.changeValue(['description'], e.target.value)}
/>
</Col>
<Col span={2} className="col-item col-item-setting">
<span className="adv-set" onClick={() => this.showAdv([], this.props.schema)}>
<Tooltip placement="top" title={LocalProvider('adv_setting')}>
<Icon type="setting" />
</Tooltip>
</span>
{schema.type === 'object' ? (
<span onClick={() => this.addChildField('properties')}>
<Tooltip placement="top" title={LocalProvider('add_child_node')}>
<Icon type="plus" className="plus" />
</Tooltip>
</span>
) : null}
</Col>
</Row>
{this.state.show && (
<SchemaJson
data={this.props.schema}
showEdit={this.showEdit}
showAdv={this.showAdv}
/>
)}
</Col>
</Row>
</div>
);
}
}
jsonSchema.childContextTypes = {
getOpenValue: PropTypes.func,
changeCustomValue: PropTypes.func,
Model: PropTypes.object,
isMock: PropTypes.bool
};
jsonSchema.propTypes = {
data: PropTypes.string,
onChange: PropTypes.func,
showEditor: PropTypes.bool,
isMock: PropTypes.bool,
Model: PropTypes.object
};
export default connect(state => ({
schema: state.schema.data,
open: state.schema.open
}))(jsonSchema);