Fix contract queries bug (#4534)

* Fix contract queries and multiple Address Selector issues

* Linting

* Use standard new Error
This commit is contained in:
Nicolas Gotchac 2017-02-14 13:08:38 +01:00 committed by Jaco Greeff
parent fefd53d4f4
commit e8597e2e91
7 changed files with 109 additions and 38 deletions

View File

@ -241,13 +241,32 @@ export default class Contract {
_bindFunction = (func) => { _bindFunction = (func) => {
func.contract = this; func.contract = this;
func.call = (options, values = []) => { func.call = (_options = {}, values = []) => {
const callParams = this._encodeOptions(func, this._addOptionsTo(options), values); const rawTokens = !!_options.rawTokens;
const options = {
..._options
};
delete options.rawTokens;
let callParams;
try {
callParams = this._encodeOptions(func, this._addOptionsTo(options), values);
} catch (error) {
return Promise.reject(error);
}
return this._api.eth return this._api.eth
.call(callParams) .call(callParams)
.then((encoded) => func.decodeOutput(encoded)) .then((encoded) => func.decodeOutput(encoded))
.then((tokens) => tokens.map((token) => token.value)) .then((tokens) => {
if (rawTokens) {
return tokens;
}
return tokens.map((token) => token.value);
})
.then((returns) => returns.length === 1 ? returns[0] : returns) .then((returns) => returns.length === 1 ? returns[0] : returns)
.catch((error) => { .catch((error) => {
console.warn(`${func.name}.call`, values, error); console.warn(`${func.name}.call`, values, error);
@ -257,7 +276,13 @@ export default class Contract {
if (!func.constant) { if (!func.constant) {
func.postTransaction = (options, values = []) => { func.postTransaction = (options, values = []) => {
const _options = this._encodeOptions(func, this._addOptionsTo(options), values); let _options;
try {
_options = this._encodeOptions(func, this._addOptionsTo(options), values);
} catch (error) {
return Promise.reject(error);
}
return this._api.parity return this._api.parity
.postTransaction(_options) .postTransaction(_options)

View File

@ -107,6 +107,10 @@
} }
} }
.container {
margin-bottom: 1em;
}
.categories { .categories {
display: flex; display: flex;
flex: 1; flex: 1;

View File

@ -206,12 +206,11 @@ class AddressSelect extends Component {
style={ BOTTOM_BORDER_STYLE } style={ BOTTOM_BORDER_STYLE }
/> />
</div> </div>
{ this.renderCurrentInput() }
{ this.renderRegistryValues() }
</div> </div>
} }
> >
{ this.renderCurrentInput() }
{ this.renderRegistryValues() }
{ this.renderAccounts() } { this.renderAccounts() }
</Portal> </Portal>
); );
@ -245,8 +244,8 @@ class AddressSelect extends Component {
} }
return ( return (
<div> <div className={ styles.container }>
{ this.renderAccountCard({ address }) } { this.renderAccountCard({ address, index: 'currentInput_0' }) }
</div> </div>
); );
} }
@ -266,7 +265,7 @@ class AddressSelect extends Component {
}); });
return ( return (
<div> <div className={ styles.container }>
{ accounts } { accounts }
</div> </div>
); );
@ -361,7 +360,7 @@ class AddressSelect extends Component {
validateCustomInput = () => { validateCustomInput = () => {
const { allowInput } = this.props; const { allowInput } = this.props;
const { inputValue } = this.store; const { inputValue } = this.state;
const { values } = this.store; const { values } = this.store;
// If input is HEX and allowInput === true, send it // If input is HEX and allowInput === true, send it
@ -587,7 +586,13 @@ class AddressSelect extends Component {
this.handleDOMAction('inputAddress', 'focus'); this.handleDOMAction('inputAddress', 'focus');
} }
this.setState({ expanded: false }); this.store.resetRegistryValues();
this.setState({
expanded: false,
focusedItem: null,
inputValue: ''
});
} }
handleInputBlur = () => { handleInputBlur = () => {

View File

@ -204,6 +204,10 @@ export default class AddressSelectStore {
this.handleChange(); this.handleChange();
} }
@action resetRegistryValues = () => {
this.registryValues = [];
}
@action handleChange = (value = '') => { @action handleChange = (value = '') => {
let index = 0; let index = 0;

View File

@ -125,7 +125,7 @@ export default class TypedInput extends Component {
return ( return (
<div className={ styles.inputs }> <div className={ styles.inputs }>
<label>{ label }</label> <label>{ label }</label>
{ fixedLength ? null : this.renderLength() } { fixedLength || readOnly ? null : this.renderLength() }
{ inputs } { inputs }
</div> </div>
); );

View File

@ -14,17 +14,19 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import LinearProgress from 'material-ui/LinearProgress'; import LinearProgress from 'material-ui/LinearProgress';
import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card'; import { Card, CardActions, CardTitle, CardText } from 'material-ui/Card';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { newError } from '~/redux/actions';
import { Button, TypedInput } from '~/ui'; import { Button, TypedInput } from '~/ui';
import { arrayOrObjectProptype } from '~/util/proptypes'; import { arrayOrObjectProptype } from '~/util/proptypes';
import styles from './queries.css'; import styles from './queries.css';
export default class InputQuery extends Component { class InputQuery extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object api: PropTypes.object
}; };
@ -35,6 +37,7 @@ export default class InputQuery extends Component {
inputs: arrayOrObjectProptype().isRequired, inputs: arrayOrObjectProptype().isRequired,
outputs: arrayOrObjectProptype().isRequired, outputs: arrayOrObjectProptype().isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
newError: PropTypes.func.isRequired,
signature: PropTypes.string.isRequired, signature: PropTypes.string.isRequired,
className: PropTypes.string className: PropTypes.string
}; };
@ -65,7 +68,7 @@ export default class InputQuery extends Component {
const { isValid } = this.state; const { isValid } = this.state;
const inputsFields = inputs const inputsFields = inputs
.map(input => this.renderInput(input)); .map((input, index) => this.renderInput(input, index));
return ( return (
<div> <div>
@ -119,7 +122,7 @@ export default class InputQuery extends Component {
); );
return ( return (
<div key={ index }> <div key={ `${out.name}_${out.type}_${index}` }>
<div className={ styles.queryResultName }> <div className={ styles.queryResultName }>
{ out.name } { out.name }
</div> </div>
@ -129,7 +132,7 @@ export default class InputQuery extends Component {
}); });
} }
renderInput (input) { renderInput (input, index) {
const { values } = this.state; const { values } = this.state;
const { name, type } = input; const { name, type } = input;
const label = `${name ? `${name}: ` : ''}${type}`; const label = `${name ? `${name}: ` : ''}${type}`;
@ -140,41 +143,42 @@ export default class InputQuery extends Component {
this.setState({ this.setState({
values: { values: {
...values, ...values,
[ name ]: value [ index ]: value
} }
}); });
}; };
return ( return (
<div key={ name }> <div key={ `${name}_${type}_${index}` }>
<TypedInput <TypedInput
hint={ type } hint={ type }
label={ label } label={ label }
isEth={ false } isEth={ false }
onChange={ onChange } onChange={ onChange }
param={ type } param={ type }
value={ values[name] } value={ values[index] }
/> />
</div> </div>
); );
} }
renderValue (value) { renderValue (token) {
const { api } = this.context;
const { type, value } = token;
if (value === null || value === undefined) { if (value === null || value === undefined) {
return 'no data'; return 'no data';
} }
const { api } = this.context; if (type === 'array' || type === 'fixedArray') {
return value.map((tok) => this.renderValue(tok));
if (api.util.isInstanceOf(value, BigNumber)) {
return value.toFormat(0);
} }
if (api.util.isArray(value)) { if (Array.isArray(value)) {
return api.util.bytesToHex(value); return api.util.bytesToHex(value);
} }
return value.toString(); return value;
} }
onClick = () => { onClick = () => {
@ -186,11 +190,11 @@ export default class InputQuery extends Component {
results: [] results: []
}); });
const inputValues = inputs.map(input => values[input.name]); const inputValues = inputs.map((input, index) => values[index] || '');
contract contract
.instance[signature] .instance[signature]
.call({}, inputValues) .call({ rawTokens: true }, inputValues)
.then(results => { .then(results => {
if (outputs.length === 1) { if (outputs.length === 1) {
results = [ results ]; results = [ results ];
@ -201,8 +205,24 @@ export default class InputQuery extends Component {
results results
}); });
}) })
.catch(e => { .catch((error) => {
console.error(`sending ${name} with params`, inputValues, e); console.error(`sending ${name} with params`, inputValues, error.message);
this.props.newError(error);
this.setState({
isLoading: false
});
}); });
}; };
} }
function mapDispatchToProps (dispatch) {
return bindActionCreators({
newError
}, dispatch);
}
export default connect(
null,
mapDispatchToProps
)(InputQuery);

View File

@ -61,12 +61,25 @@ export default class Queries extends Component {
return ( return (
<Container title='queries'> <Container title='queries'>
<div className={ styles.methods }> <div className={ styles.methods }>
<div className={ styles.vMethods }> {
{ noInputQueries } noInputQueries.length > 0
</div> ? (
<div className={ styles.hMethods }> <div className={ styles.vMethods }>
{ withInputQueries } { noInputQueries }
</div> </div>
)
: null
}
{
withInputQueries.length > 0
? (
<div className={ styles.hMethods }>
{ withInputQueries }
</div>
)
: null
}
</div> </div>
</Container> </Container>
); );