Commit c5b323da authored by Jérome Perrin's avatar Jérome Perrin Committed by Cédric Le Ninivin

erp5_json_form: Introduce React Json Schema Form Gadget

parent cc9004fc
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_json_form_react_jsonschema_form</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-dom.production.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>react-dom.production.min.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
.rjsf button.array-item-move-down::before {
font-family: "FontAwesome";
content: "\f0d7"
}
.rjsf button.array-item-move-up::before {
font-family: "FontAwesome";
content: "\f0d8"
}
.rjsf button.array-item-remove::before {
font-family: "FontAwesome";
content: "\f1f8"
}
.rjsf button.btn-add::before {
font-family: "FontAwesome";
content: "\f067"
}
.rjsf legend {
color: hsl(0, 0%, 42%)
}
.rjsf label {
color: hsl(0, 0%, 42%)
}
.rjsf fieldset {
display: block;
margin-inline-start: 2px;
margin-inline-end: 2px;
padding-block-start: 0.35em;
padding-inline-start: 0.75em;
padding-inline-end: 0.75em;
padding-block-end: 0.625em;
min-inline-size: min-content;
border-width: 2px;
border-style: groove;
border-color: threedface;
border-image: initial;
}
/** XXX hide submit button ... */
.rjsf button[type="submit"] {
display: none;
}
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-jsonschema-form-gadget.css</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/css</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSON schema form editor</title>
<script src="./react.production.min.js" type="text/javascript"></script>
<script src="./react-dom.production.min.js" type="text/javascript"></script>
<script src="./react-jsonschema-form-workaround-2503.js" type="text/javascript"></script>
<script src="./react-jsonschema-form.js" type="text/javascript"></script>
<script src="./ref-parser.min.js" type="text/javascript"></script>
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="./react-jsonschema-form-gadget.js" type="text/javascript"></script>
<link rel="stylesheet" href="react-jsonschema-form-gadget.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-jsonschema-form-gadget.html</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
/*jslint nomen: true, indent: 2 */
/*global window, rJS, RSVP, document*/
(function (window, rJS, RSVP, document) {
'use strict';
/**
* Prepare a ui-schema from the conventions of SlapOS instance parameters schema.
* This does the following:
* - remove `default` from schema. In SlapOS schemas we use `default` as a documentation
* and we don't expect to pre-fill the form data with default.
* TODO: we don't always want to remove default (maybe we never want ?)
* - support textearea, like we have with SlapOS parameter editor
*
* TODO: if this is really needed - if we use a theme this is probably not, don't mutate
* arguments like this but return new copies instead.
* Also, this does not support cyclic schemas (like for example https://json-schema.org/draft-07/schema )
*
* @param {{ properties: any; }} schema
* @param {{ [x: string]: any; }} uiSchema
* @param {Set<any>} visited
*/
function makeUiSchema(schema, uiSchema, visited) {
if (visited.has(schema)) {
return
}
visited.add(schema)
if (schema.properties) {
for (const [key, value] of Object.entries(schema.properties)) {
uiSchema[key] = {};
if (value.default && !(value.default instanceof Object)) {
if (value?.type === 'string' && value.const === undefined) {
uiSchema[key]['ui:placeholder'] = value.default;
}
if (value.const === undefined) {
delete value.default;
}
}
// This is something used in SlapOS schemas
if (value.textarea) {
uiSchema[key]["ui:widget"] = "textarea"
}
if (value?.type === 'object') {
makeUiSchema(value, uiSchema[key], visited);
}
for (const oneOf of value.oneOf || []) {
makeUiSchema(oneOf, uiSchema[key], visited);
}
for (const allOf of value.allOf || []) {
makeUiSchema(allOf, uiSchema[key], visited);
}
for (const anyOf of value.anyOf || []) {
makeUiSchema(anyOf, uiSchema[key], visited);
}
}
}
}
rJS(window)
.declareMethod('render', function (options) {
return this.changeState({
data: {},
value: options.value,
key: options.key,
schema_url: options.schema,
});
})
.onStateChange(function (modification_dict) {
var gadget = this;
if (modification_dict.schema_url) {
return $RefParser
.dereference(modification_dict.schema_url)
.then(function (schema) {
let uiSchema = {};
makeUiSchema(schema, uiSchema, new Set())
console.log('after simplification', schema, uiSchema);
const log = (type) => console.log.bind(console, type);
ReactDOM.render(
// XXX we can use withTheme here if we want a theme
React.createElement(JSONSchemaForm.withTheme({}), {
schema: schema,
uiSchema: uiSchema,
// XXX don't make a <form> by default
tagName: 'div',
// TODO: handle malformed json
formData: JSON.parse(modification_dict.value),
// TODO: change state in a job to keep promise chain
onChange: (state) =>
gadget.changeState({
data: state.formData,
errors: state.errors,
}),
// onSubmit: log('submitted'),
onError: log('errors'),
}),
gadget.element
);
});
}
console.log(this.element, modification_dict);
})
.declareMethod(
'getContent',
function () {
var result = {};
result[this.state.key] = JSON.stringify(this.state.data, null, ' ');
return result;
},
{ mutex: 'changestate' }
)
.declareMethod('checkValidity', function () {
// TODO
return true;
});
})(window, rJS, RSVP, document);
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-jsonschema-form-gadget.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
// XXX (jerome) workaround https://github.com/rjsf-team/react-jsonschema-form/issues/2503
window.react = React;
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-jsonschema-form-workaround-2503.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react-jsonschema-form.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>react-jsonschema-form.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>react.production.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>react.production.min.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
This source diff could not be displayed because it is too large. You can view the blob instead.
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>ref-parser.min.js.map</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/octet-stream</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ref-parser.min.js.map</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>ref-parser.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>ref-parser.min.js</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_json_form
\ No newline at end of file
erp5_json_form
erp5_json_form_react_jsonschema_form
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment