Use TypedInputs in Contracts view (#4015)

* Use TypedInput in Contracts

* Add right readOnly Bool TypedInput

* PR Grumbles
This commit is contained in:
Nicolas Gotchac 2017-01-03 17:41:46 +01:00 committed by Jaco Greeff
parent 0f41c5b847
commit e8ef7b357d
8 changed files with 127 additions and 112 deletions

View File

@ -58,11 +58,13 @@ class AddressSelect extends Component {
tokens: PropTypes.object, tokens: PropTypes.object,
// Optional props // Optional props
allowCopy: PropTypes.bool,
allowInput: PropTypes.bool, allowInput: PropTypes.bool,
disabled: PropTypes.bool, disabled: PropTypes.bool,
error: nodeOrStringProptype(), error: nodeOrStringProptype(),
hint: nodeOrStringProptype(), hint: nodeOrStringProptype(),
label: nodeOrStringProptype(), label: nodeOrStringProptype(),
readOnly: PropTypes.bool,
value: nodeOrStringProptype() value: nodeOrStringProptype()
}; };
@ -121,12 +123,12 @@ class AddressSelect extends Component {
renderInput () { renderInput () {
const { focused } = this.state; const { focused } = this.state;
const { accountsInfo, disabled, error, hint, label, value } = this.props; const { accountsInfo, allowCopy, disabled, error, hint, label, readOnly, value } = this.props;
const input = ( const input = (
<InputAddress <InputAddress
accountsInfo={ accountsInfo } accountsInfo={ accountsInfo }
allowCopy={ false } allowCopy={ allowCopy }
disabled={ disabled } disabled={ disabled }
error={ error } error={ error }
hint={ hint } hint={ hint }
@ -139,7 +141,7 @@ class AddressSelect extends Component {
/> />
); );
if (disabled) { if (disabled || readOnly) {
return input; return input;
} }
@ -152,10 +154,10 @@ class AddressSelect extends Component {
renderContent () { renderContent () {
const { muiTheme } = this.context; const { muiTheme } = this.context;
const { hint, disabled, label } = this.props; const { hint, disabled, label, readOnly } = this.props;
const { expanded, inputFocused } = this.state; const { expanded, inputFocused } = this.state;
if (disabled) { if (disabled || readOnly) {
return null; return null;
} }
@ -507,6 +509,10 @@ class AddressSelect extends Component {
} }
handleMainBlur = () => { handleMainBlur = () => {
if (this.props.readOnly) {
return;
}
if (window.document.hasFocus() && !this.state.expanded) { if (window.document.hasFocus() && !this.state.expanded) {
this.closing = false; this.closing = false;
this.setState({ focused: false }); this.setState({ focused: false });
@ -514,7 +520,7 @@ class AddressSelect extends Component {
} }
handleMainFocus = () => { handleMainFocus = () => {
if (this.state.focused) { if (this.state.focused || this.props.readOnly) {
return; return;
} }
@ -529,6 +535,12 @@ class AddressSelect extends Component {
} }
handleFocus = () => { handleFocus = () => {
const { disabled, readOnly } = this.props;
if (disabled || readOnly) {
return;
}
this.setState({ expanded: true, focusedItem: null, focusedCat: null }, () => { this.setState({ expanded: true, focusedItem: null, focusedCat: null }, () => {
window.setTimeout(() => { window.setTimeout(() => {
this.handleDOMAction(this.inputRef, 'focus'); this.handleDOMAction(this.inputRef, 'focus');

View File

@ -185,7 +185,7 @@ export default class Input extends Component {
const text = typeof allowCopy === 'string' const text = typeof allowCopy === 'string'
? allowCopy ? allowCopy
: value; : value.toString();
const style = hideUnderline const style = hideUnderline
? {} ? {}

View File

@ -78,7 +78,7 @@ class InputAddress extends Component {
return ( return (
<div className={ containerClasses.join(' ') }> <div className={ containerClasses.join(' ') }>
<Input <Input
allowCopy={ allowCopy && (disabled ? value : false) } allowCopy={ allowCopy && ((disabled || readOnly) ? value : false) }
className={ classes.join(' ') } className={ classes.join(' ') }
disabled={ disabled } disabled={ disabled }
error={ error } error={ error }
@ -103,13 +103,13 @@ class InputAddress extends Component {
} }
renderIcon () { renderIcon () {
const { value, disabled, label, allowCopy, hideUnderline } = this.props; const { value, disabled, label, allowCopy, hideUnderline, readOnly } = this.props;
if (!value || !value.length || !util.isAddressValid(value)) { if (!value || !value.length || !util.isAddressValid(value)) {
return null; return null;
} }
const classes = [disabled ? styles.iconDisabled : styles.icon]; const classes = [(disabled || readOnly) ? styles.iconDisabled : styles.icon];
if (!label) { if (!label) {
classes.push(styles.noLabel); classes.push(styles.noLabel);

View File

@ -25,27 +25,33 @@ class InputAddressSelect extends Component {
accounts: PropTypes.object.isRequired, accounts: PropTypes.object.isRequired,
contacts: PropTypes.object.isRequired, contacts: PropTypes.object.isRequired,
contracts: PropTypes.object.isRequired, contracts: PropTypes.object.isRequired,
allowCopy: PropTypes.bool,
error: PropTypes.string, error: PropTypes.string,
label: PropTypes.string,
hint: PropTypes.string, hint: PropTypes.string,
value: PropTypes.string, label: PropTypes.string,
onChange: PropTypes.func onChange: PropTypes.func,
readOnly: PropTypes.bool,
value: PropTypes.string
}; };
render () { render () {
const { accounts, contacts, contracts, label, hint, error, value, onChange } = this.props; const { accounts, allowCopy, contacts, contracts, label, hint, error, value, onChange, readOnly } = this.props;
return ( return (
<AddressSelect <AddressSelect
allowCopy={ allowCopy }
allowInput allowInput
accounts={ accounts } accounts={ accounts }
contacts={ contacts } contacts={ contacts }
contracts={ contracts } contracts={ contracts }
error={ error } error={ error }
label={ label }
hint={ hint } hint={ hint }
label={ label }
onChange={ onChange }
readOnly={ readOnly }
value={ value } value={ value }
onChange={ onChange } /> />
); );
} }
} }

View File

@ -17,6 +17,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { MenuItem, Toggle } from 'material-ui'; import { MenuItem, Toggle } from 'material-ui';
import { range } from 'lodash'; import { range } from 'lodash';
import BigNumber from 'bignumber.js';
import IconButton from 'material-ui/IconButton'; import IconButton from 'material-ui/IconButton';
import AddIcon from 'material-ui/svg-icons/content/add'; import AddIcon from 'material-ui/svg-icons/content/add';
@ -33,26 +34,31 @@ import styles from './typedInput.css';
export default class TypedInput extends Component { export default class TypedInput extends Component {
static propTypes = { static propTypes = {
onChange: PropTypes.func.isRequired, param: PropTypes.oneOfType([
PropTypes.object,
PropTypes.string
]).isRequired,
accounts: PropTypes.object, accounts: PropTypes.object,
allowCopy: PropTypes.bool,
error: PropTypes.any, error: PropTypes.any,
hint: PropTypes.string, hint: PropTypes.string,
isEth: PropTypes.bool, isEth: PropTypes.bool,
label: PropTypes.string, label: PropTypes.string,
max: PropTypes.number, max: PropTypes.number,
min: PropTypes.number, min: PropTypes.number,
param: PropTypes.oneOfType([ onChange: PropTypes.func,
PropTypes.object, readOnly: PropTypes.bool,
PropTypes.string
]).isRequired,
value: PropTypes.any value: PropTypes.any
}; };
static defaultProps = { static defaultProps = {
allowCopy: false,
isEth: null,
min: null, min: null,
max: null, max: null,
isEth: null onChange: () => {},
readOnly: false
}; };
state = { state = {
@ -61,8 +67,11 @@ export default class TypedInput extends Component {
}; };
componentWillMount () { componentWillMount () {
if (this.props.isEth && this.props.value) { const { isEth, value } = this.props;
this.setState({ isEth: true, ethValue: fromWei(this.props.value) });
if (typeof isEth === 'boolean' && value) {
const ethValue = isEth ? fromWei(value) : value;
this.setState({ isEth, ethValue });
} }
} }
@ -78,7 +87,7 @@ export default class TypedInput extends Component {
} }
renderParam (param) { renderParam (param) {
const { isEth } = this.props; const { allowCopy, isEth, readOnly } = this.props;
const { type } = param; const { type } = param;
if (type === ABI_TYPES.ARRAY) { if (type === ABI_TYPES.ARRAY) {
@ -96,10 +105,12 @@ export default class TypedInput extends Component {
return ( return (
<TypedInput <TypedInput
accounts={ accounts }
allowCopy={ allowCopy }
key={ `${subtype.type}_${index}` } key={ `${subtype.type}_${index}` }
onChange={ onChange } onChange={ onChange }
accounts={ accounts }
param={ subtype } param={ subtype }
readOnly={ readOnly }
value={ value[index] } value={ value[index] }
/> />
); );
@ -226,21 +237,23 @@ export default class TypedInput extends Component {
} }
renderInteger (value = this.props.value, onChange = this.onChange) { renderInteger (value = this.props.value, onChange = this.onChange) {
const { label, error, hint, min, max } = this.props; const { allowCopy, label, error, hint, min, max, readOnly } = this.props;
const param = this.getParam(); const param = this.getParam();
const realValue = value && typeof value.toNumber === 'function' const realValue = value
? value.toNumber() ? (new BigNumber(value))[readOnly ? 'toFormat' : 'toNumber']()
: value; : value;
return ( return (
<Input <Input
allowCopy={ allowCopy }
label={ label } label={ label }
hint={ hint } hint={ hint }
value={ realValue } value={ realValue }
error={ error } error={ error }
onChange={ onChange } onChange={ onChange }
type='number' readOnly={ readOnly }
type={ readOnly ? 'text' : 'number' }
step={ 1 } step={ 1 }
min={ min !== null ? min : (param.signed ? null : 0) } min={ min !== null ? min : (param.signed ? null : 0) }
max={ max !== null ? max : null } max={ max !== null ? max : null }
@ -256,20 +269,22 @@ export default class TypedInput extends Component {
* @see https://github.com/facebook/react/issues/1549 * @see https://github.com/facebook/react/issues/1549
*/ */
renderFloat (value = this.props.value, onChange = this.onChange) { renderFloat (value = this.props.value, onChange = this.onChange) {
const { label, error, hint, min, max } = this.props; const { allowCopy, label, error, hint, min, max, readOnly } = this.props;
const param = this.getParam(); const param = this.getParam();
const realValue = value && typeof value.toNumber === 'function' const realValue = value
? value.toNumber() ? (new BigNumber(value))[readOnly ? 'toFormat' : 'toNumber']()
: value; : value;
return ( return (
<Input <Input
allowCopy={ allowCopy }
label={ label } label={ label }
hint={ hint } hint={ hint }
value={ realValue } value={ realValue }
error={ error } error={ error }
onChange={ onChange } onChange={ onChange }
readOnly={ readOnly }
type='text' type='text'
min={ min !== null ? min : (param.signed ? null : 0) } min={ min !== null ? min : (param.signed ? null : 0) }
max={ max !== null ? max : null } max={ max !== null ? max : null }
@ -278,37 +293,44 @@ export default class TypedInput extends Component {
} }
renderDefault () { renderDefault () {
const { label, value, error, hint } = this.props; const { allowCopy, label, value, error, hint, readOnly } = this.props;
return ( return (
<Input <Input
allowCopy={ allowCopy }
label={ label } label={ label }
hint={ hint } hint={ hint }
value={ value } value={ value }
error={ error } error={ error }
onSubmit={ this.onSubmit } onSubmit={ this.onSubmit }
readOnly={ readOnly }
/> />
); );
} }
renderAddress () { renderAddress () {
const { accounts, label, value, error, hint } = this.props; const { accounts, allowCopy, label, value, error, hint, readOnly } = this.props;
return ( return (
<InputAddressSelect <InputAddressSelect
allowCopy={ allowCopy }
accounts={ accounts } accounts={ accounts }
label={ label }
hint={ hint }
value={ value }
error={ error } error={ error }
hint={ hint }
label={ label }
onChange={ this.onChange } onChange={ this.onChange }
editing readOnly={ readOnly }
value={ value }
/> />
); );
} }
renderBoolean () { renderBoolean () {
const { label, value, error, hint } = this.props; const { allowCopy, label, value, error, hint, readOnly } = this.props;
if (readOnly) {
return this.renderDefault();
}
const boolitems = ['false', 'true'].map((bool) => { const boolitems = ['false', 'true'].map((bool) => {
return ( return (
@ -323,6 +345,7 @@ export default class TypedInput extends Component {
return ( return (
<Select <Select
allowCopy={ allowCopy }
error={ error } error={ error }
hint={ hint } hint={ hint }
label={ label } label={ label }

View File

@ -19,29 +19,31 @@ 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 { Button, Input, InputAddress, InputAddressSelect } from '~/ui'; import { Button, TypedInput } from '~/ui';
import { arrayOrObjectProptype } from '~/util/proptypes';
import styles from './queries.css'; import styles from './queries.css';
export default class InputQuery extends Component { export default class InputQuery extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object api: PropTypes.object
} };
static propTypes = { static propTypes = {
accountsInfo: PropTypes.object.isRequired,
contract: PropTypes.object.isRequired, contract: PropTypes.object.isRequired,
inputs: PropTypes.array.isRequired, inputs: arrayOrObjectProptype().isRequired,
outputs: PropTypes.array.isRequired, outputs: arrayOrObjectProptype().isRequired,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
signature: PropTypes.string.isRequired, signature: PropTypes.string.isRequired,
className: PropTypes.string className: PropTypes.string
} };
state = { state = {
isValid: true, isValid: true,
results: [], results: [],
values: {} values: {}
} };
render () { render () {
const { name, className } = this.props; const { name, className } = this.props;
@ -89,7 +91,7 @@ export default class InputQuery extends Component {
renderResults () { renderResults () {
const { results, isLoading } = this.state; const { results, isLoading } = this.state;
const { outputs } = this.props; const { accountsInfo, outputs } = this.props;
if (isLoading) { if (isLoading) {
return (<LinearProgress mode='indeterminate' />); return (<LinearProgress mode='indeterminate' />);
@ -108,25 +110,16 @@ export default class InputQuery extends Component {
})) }))
.sort((outA, outB) => outA.display.length - outB.display.length) .sort((outA, outB) => outA.display.length - outB.display.length)
.map((out, index) => { .map((out, index) => {
let input = null; const input = (
if (out.type === 'address') { <TypedInput
input = ( accounts={ accountsInfo }
<InputAddress allowCopy
className={ styles.queryValue } isEth={ false }
disabled param={ out.type }
value={ out.display } readOnly
/> value={ out.display }
); />
} else { );
input = (
<Input
className={ styles.queryValue }
readOnly
allowCopy
value={ out.display }
/>
);
}
return ( return (
<div key={ index }> <div key={ index }>
@ -144,8 +137,7 @@ export default class InputQuery extends Component {
const { name, type } = input; const { name, type } = input;
const label = `${name ? `${name}: ` : ''}${type}`; const label = `${name ? `${name}: ` : ''}${type}`;
const onChange = (event, input) => { const onChange = (value) => {
const value = event && event.target.value || input;
const { values } = this.state; const { values } = this.state;
this.setState({ this.setState({
@ -156,28 +148,15 @@ export default class InputQuery extends Component {
}); });
}; };
if (type === 'address') {
return (
<div key={ name }>
<InputAddressSelect
hint={ type }
label={ label }
value={ values[name] }
required
onChange={ onChange }
/>
</div>
);
}
return ( return (
<div key={ name }> <div key={ name }>
<Input <TypedInput
hint={ type } hint={ type }
label={ label } label={ label }
value={ values[name] } isEth={ false }
required
onChange={ onChange } onChange={ onChange }
param={ type }
value={ values[name] }
/> />
</div> </div>
); );
@ -192,7 +171,9 @@ export default class InputQuery extends Component {
if (api.util.isInstanceOf(value, BigNumber)) { if (api.util.isInstanceOf(value, BigNumber)) {
return value.toFormat(0); return value.toFormat(0);
} else if (api.util.isArray(value)) { }
if (api.util.isArray(value)) {
return api.util.bytesToHex(value); return api.util.bytesToHex(value);
} }

View File

@ -14,12 +14,11 @@
// 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 { Card, CardTitle, CardText } from 'material-ui/Card'; import { Card, CardTitle, CardText } from 'material-ui/Card';
import InputQuery from './inputQuery'; import InputQuery from './inputQuery';
import { Container, Input, InputAddress } from '~/ui'; import { Container, TypedInput } from '~/ui';
import styles from './queries.css'; import styles from './queries.css';
@ -29,6 +28,7 @@ export default class Queries extends Component {
} }
static propTypes = { static propTypes = {
accountsInfo: PropTypes.object.isRequired,
contract: PropTypes.object, contract: PropTypes.object,
values: PropTypes.object values: PropTypes.object
} }
@ -74,11 +74,12 @@ export default class Queries extends Component {
renderInputQuery (fn) { renderInputQuery (fn) {
const { abi, name, signature } = fn; const { abi, name, signature } = fn;
const { contract } = this.props; const { accountsInfo, contract } = this.props;
return ( return (
<div className={ styles.container } key={ fn.signature }> <div className={ styles.container } key={ fn.signature }>
<InputQuery <InputQuery
accountsInfo={ accountsInfo }
className={ styles.method } className={ styles.method }
inputs={ abi.inputs } inputs={ abi.inputs }
outputs={ abi.outputs } outputs={ abi.outputs }
@ -116,34 +117,23 @@ export default class Queries extends Component {
} }
const { api } = this.context; const { api } = this.context;
let valueToDisplay = null; const { accountsInfo } = this.props;
if (api.util.isInstanceOf(value, BigNumber)) { let valueToDisplay = value;
valueToDisplay = value.toFormat(0);
} else if (api.util.isArray(value)) { if (api.util.isArray(value)) {
valueToDisplay = api.util.bytesToHex(value); valueToDisplay = api.util.bytesToHex(value);
} else if (typeof value === 'boolean') { } else if (typeof value === 'boolean') {
valueToDisplay = value ? 'true' : 'false'; valueToDisplay = value ? 'true' : 'false';
} else {
valueToDisplay = value.toString();
} }
if (type === 'address') {
return (
<InputAddress
className={ styles.queryValue }
value={ valueToDisplay }
disabled
/>
);
}
return ( return (
<Input <TypedInput
className={ styles.queryValue } accounts={ accountsInfo }
value={ valueToDisplay }
readOnly
allowCopy allowCopy
isEth={ false }
param={ type }
readOnly
value={ valueToDisplay }
/> />
); );
} }

View File

@ -46,6 +46,7 @@ class Contract extends Component {
setVisibleAccounts: PropTypes.func.isRequired, setVisibleAccounts: PropTypes.func.isRequired,
accounts: PropTypes.object, accounts: PropTypes.object,
accountsInfo: PropTypes.object,
balances: PropTypes.object, balances: PropTypes.object,
contracts: PropTypes.object, contracts: PropTypes.object,
isTest: PropTypes.bool, isTest: PropTypes.bool,
@ -115,7 +116,7 @@ class Contract extends Component {
} }
render () { render () {
const { balances, contracts, params, isTest } = this.props; const { accountsInfo, balances, contracts, params, isTest } = this.props;
const { allEvents, contract, queryValues, loadingEvents } = this.state; const { allEvents, contract, queryValues, loadingEvents } = this.state;
const account = contracts[params.address]; const account = contracts[params.address];
const balance = balances[params.address]; const balance = balances[params.address];
@ -138,6 +139,7 @@ class Contract extends Component {
/> />
<Queries <Queries
accountsInfo={ accountsInfo }
contract={ contract } contract={ contract }
values={ queryValues } values={ queryValues }
/> />
@ -447,13 +449,14 @@ class Contract extends Component {
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { accounts, contracts } = state.personal; const { accounts, accountsInfo, contracts } = state.personal;
const { balances } = state.balances; const { balances } = state.balances;
const { isTest } = state.nodeStatus; const { isTest } = state.nodeStatus;
return { return {
isTest, isTest,
accounts, accounts,
accountsInfo,
contracts, contracts,
balances balances
}; };