Form generation for view/constant/pure functions

This commit is contained in:
Richard Ramos 2018-05-10 17:02:47 -04:00 committed by Pascal Precht
parent 8acf136c01
commit d80d16f4ca
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
4 changed files with 144 additions and 8 deletions

View File

@ -125,7 +125,7 @@ Plugin.prototype.registerPipeline = function(matcthingFiles, cb) {
Plugin.prototype.registerCustomType = function(type){
this.pluginTypes.push(type);
}
};
Plugin.prototype.addFileToPipeline = function(file, intendedPath, options) {
this.pipelineFiles.push({file: file, intendedPath: intendedPath, options: options});

View File

@ -1,8 +1,41 @@
const Handlebars = require('handlebars');
const fs = require('../../core/fs');
const utils = require('../../utils/utils');
Handlebars.registerHelper('capitalize', function(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
});
Handlebars.registerHelper('ifview', function(stateMutability, options) {
let result = stateMutability == 'view' || stateMutability == 'pure' || stateMutability == 'constant';
if (result) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Handlebars.registerHelper('ifarrlengthgt', function(arr, val, options) {
if (arr.length > val) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Handlebars.registerHelper('emptyname', function(name, index) {
return name ? name : 'outputParam' + index;
});
Handlebars.registerHelper('methodname', function(abiDefinition, functionName, inputs){
let funCount = abiDefinition.filter(x => x.name == functionName).length;
if(funCount == 1){
return '.' + functionName;
} else {
return new Handlebars.SafeString(`['${functionName}(${inputs !== null ? inputs.map(input => input.type).join(',') : '' })']`);
}
});
class ScaffoldingReact {
constructor(embark, options){
@ -43,7 +76,8 @@ class ScaffoldingReact {
this._generateFile(contract, 'dapp.js.tpl', 'js',
{
'title': contract.className + ' autogenerated UI',
'contractName': contract.className
'contractName': contract.className,
'functions': contract.abiDefinition.filter(x => x.type == 'function')
});
// Update config
@ -51,10 +85,8 @@ class ScaffoldingReact {
let embarkJson = JSON.parse(contents);
embarkJson.app["js/" + filename + ".js"] = "app/" + filename + '.js';
embarkJson.app[filename + ".html"] = "app/" + filename + '.html';
fs.writeFileSync("./embark.json", JSON.stringify(embarkJson, null, 4));
}
}

View File

@ -3,7 +3,102 @@ import {{contractName}} from 'Embark/contracts/{{contractName}}';
import React from 'react';
import ReactDOM from 'react-dom';
import { Tabs, Tab } from 'react-bootstrap';
import { FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap';
{{#each functions}}
class {{capitalize name}}_{{@index}}_Form extends React.Component {
constructor(props){
super(props);
this.state = {
{{#if inputs.length}}
input: {
{{#each inputs}}
{{name}}: ''{{#unless @last}},{{/unless}}
{{/each}}
},
{{/if}}
{{#ifview stateMutability}}
output: null,
{{/ifview}}
message: ''
};
}
handleChange(e, name){
this.state[name] = e.target.value;
this.setState(this.state);
}
async handleClick(e){
e.preventDefault();
{{#ifview stateMutability}}
this.setState({output: null});
let result = await {{../contractName}}.methods{{methodname ../functions name inputs}}({{#each inputs}}this.state.{{name}}{{#unless @last}}, {{/unless}}{{/each}}).call();
{{#ifarrlengthgt outputs 1}}
this.setState({output: {
{{#each outputs}}
{{emptyname name @index}}: result[{{@index}}]{{#unless @last}},{{/unless}}
{{/each}}
}});
{{else}}
this.setState({output: result});
{{/ifarrlengthgt}}
// TODO show on screen
{{/ifview}}
// TODO validate
}
render(){
return <div className="formSection">
<h3>{{name}}</h3>
<form>
{{#if inputs.length}}
{{#each inputs}}
<FormGroup>
<ControlLabel>{{name}}</ControlLabel>
<FormControl
type="text"
defaultValue={ this.state.input.{{name}} }
placeholder="{{type}}"
onChange={(e) => this.handleChange(e, '{{name}}')}
/>
</FormGroup>
{{/each}}
{{/if}}
{{#ifview stateMutability}}
<Button type="submit" bsStyle="primary" onClick={(e) => this.handleClick(e)}>Call</Button>
{
this.state.output != null ?
<React.Fragment>
<h4>Results</h4>
{{#ifarrlengthgt outputs 1}}
<ul>
{{#each outputs}}
<li>{{emptyname name @index}}: { this.state.output.{{emptyname name @index}} }</li>
{{/each}}
</ul>
{{else}}
{this.state.output}
{{/ifarrlengthgt}}
</React.Fragment>
: ''
}
{{/ifview}}
</form>
</div>;
}
}
{{/each}}
class {{contractName}}UI extends React.Component {
constructor (props) {
@ -13,7 +108,11 @@ class {{contractName}}UI extends React.Component {
}
render(){
return (<h2>Test</h2>);
return (<div>
{{#each functions}}
<{{capitalize name}}_{{@index}}_Form />
{{/each}}
</div>);
}
}

View File

@ -3,6 +3,11 @@
<head>
<title>{{title}}</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style type="text/css">
.formSection{
margin-bottom: 5em;
}
</style>
</head>
<body class="container">
<div id="app"></div>