Update CreateWallet with FormattedMessage (#4298)
* Allow FormattedMessage as hint & label * tests for basic rendering * convert component messages * Typo * id typos (insubstantial, but annoying) * 2015-2017 * 2015-2017 * 2015-2017 * 2015-2017 * 2015-2017
This commit is contained in:
parent
82a7a17e6e
commit
2ac7655355
@ -14,8 +14,9 @@
|
|||||||
// 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 React, { Component, PropTypes } from 'react';
|
|
||||||
import { omitBy } from 'lodash';
|
import { omitBy } from 'lodash';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { Form, TypedInput, Input, AddressSelect, InputAddress } from '~/ui';
|
import { Form, TypedInput, Input, AddressSelect, InputAddress } from '~/ui';
|
||||||
|
|
||||||
@ -46,24 +47,54 @@ export default class WalletDetails extends Component {
|
|||||||
return (
|
return (
|
||||||
<Form>
|
<Form>
|
||||||
<InputAddress
|
<InputAddress
|
||||||
label='wallet address'
|
hint={
|
||||||
hint='the wallet contract address'
|
<FormattedMessage
|
||||||
|
id='createWallet.details.address.hint'
|
||||||
|
defaultMessage='the wallet contract address'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.address.label'
|
||||||
|
defaultMessage='wallet address'
|
||||||
|
/>
|
||||||
|
}
|
||||||
value={ wallet.address }
|
value={ wallet.address }
|
||||||
error={ errors.address }
|
error={ errors.address }
|
||||||
onChange={ this.onAddressChange }
|
onChange={ this.onAddressChange }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label='wallet name'
|
|
||||||
hint='the local name for this wallet'
|
|
||||||
value={ wallet.name }
|
|
||||||
error={ errors.name }
|
error={ errors.name }
|
||||||
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.name.hint'
|
||||||
|
defaultMessage='the local name for this wallet'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.name.label'
|
||||||
|
defaultMessage='wallet name'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={ wallet.name }
|
||||||
onChange={ this.onNameChange }
|
onChange={ this.onNameChange }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label='wallet description (optional)'
|
hint={
|
||||||
hint='the local description for this wallet'
|
<FormattedMessage
|
||||||
|
id='createWallet.details.description.hint'
|
||||||
|
defaultMessage='the local description for this wallet'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.description.label'
|
||||||
|
defaultMessage='wallet description (optional)'
|
||||||
|
/>
|
||||||
|
}
|
||||||
value={ wallet.description }
|
value={ wallet.description }
|
||||||
onChange={ this.onDescriptionChange }
|
onChange={ this.onDescriptionChange }
|
||||||
/>
|
/>
|
||||||
@ -80,43 +111,88 @@ export default class WalletDetails extends Component {
|
|||||||
return (
|
return (
|
||||||
<Form>
|
<Form>
|
||||||
<AddressSelect
|
<AddressSelect
|
||||||
label='from account (contract owner)'
|
|
||||||
hint='the owner account for this contract'
|
|
||||||
value={ wallet.account }
|
|
||||||
error={ errors.account }
|
|
||||||
onChange={ this.onAccoutChange }
|
|
||||||
accounts={ _accounts }
|
accounts={ _accounts }
|
||||||
|
error={ errors.account }
|
||||||
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.ownerMulti.hint'
|
||||||
|
defaultMessage='the owner account for this contract'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.ownerMulti.label'
|
||||||
|
defaultMessage='from account (contract owner)'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={ wallet.account }
|
||||||
|
onChange={ this.onAccoutChange }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label='wallet name'
|
|
||||||
hint='the local name for this wallet'
|
|
||||||
value={ wallet.name }
|
|
||||||
error={ errors.name }
|
error={ errors.name }
|
||||||
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.nameMulti.hint'
|
||||||
|
defaultMessage='the local name for this wallet'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.nameMulti.label'
|
||||||
|
defaultMessage='wallet name'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={ wallet.name }
|
||||||
onChange={ this.onNameChange }
|
onChange={ this.onNameChange }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
label='wallet description (optional)'
|
hint={
|
||||||
hint='the local description for this wallet'
|
<FormattedMessage
|
||||||
|
id='createWallet.details.descriptionMulti.hint'
|
||||||
|
defaultMessage='the local description for this wallet'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.descriptionMulti.label'
|
||||||
|
defaultMessage='wallet description (optional)'
|
||||||
|
/>
|
||||||
|
}
|
||||||
value={ wallet.description }
|
value={ wallet.description }
|
||||||
onChange={ this.onDescriptionChange }
|
onChange={ this.onDescriptionChange }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TypedInput
|
<TypedInput
|
||||||
label='other wallet owners'
|
|
||||||
value={ wallet.owners.slice() }
|
|
||||||
onChange={ this.onOwnersChange }
|
|
||||||
accounts={ accounts }
|
accounts={ accounts }
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.ownersMulti.label'
|
||||||
|
defaultMessage='other wallet owners'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onChange={ this.onOwnersChange }
|
||||||
param='address[]'
|
param='address[]'
|
||||||
|
value={ wallet.owners.slice() }
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={ styles.splitInput }>
|
<div className={ styles.splitInput }>
|
||||||
<TypedInput
|
<TypedInput
|
||||||
label='required owners'
|
|
||||||
hint='number of required owners to accept a transaction'
|
|
||||||
value={ wallet.required }
|
|
||||||
error={ errors.required }
|
error={ errors.required }
|
||||||
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.ownersMultiReq.hint'
|
||||||
|
defaultMessage='number of required owners to accept a transaction'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.ownersMultiReq.label'
|
||||||
|
defaultMessage='required owners'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
value={ wallet.required }
|
||||||
onChange={ this.onRequiredChange }
|
onChange={ this.onRequiredChange }
|
||||||
param='uint'
|
param='uint'
|
||||||
min={ 1 }
|
min={ 1 }
|
||||||
@ -124,13 +200,23 @@ export default class WalletDetails extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TypedInput
|
<TypedInput
|
||||||
label='wallet day limit'
|
|
||||||
hint='amount of ETH spendable without confirmations'
|
|
||||||
value={ wallet.daylimit }
|
|
||||||
error={ errors.daylimit }
|
error={ errors.daylimit }
|
||||||
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.dayLimitMulti.hint'
|
||||||
|
defaultMessage='amount of ETH spendable without confirmations'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
isEth
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.details.dayLimitMulti.label'
|
||||||
|
defaultMessage='wallet day limit'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onChange={ this.onDaylimitChange }
|
onChange={ this.onDaylimitChange }
|
||||||
param='uint'
|
param='uint'
|
||||||
isEth
|
value={ wallet.daylimit }
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import WalletDetails from './';
|
||||||
|
|
||||||
|
import { ACCOUNTS } from '../createWallet.test.js';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let onChange;
|
||||||
|
|
||||||
|
function render (walletType = 'MULTISIG') {
|
||||||
|
onChange = sinon.stub();
|
||||||
|
component = shallow(
|
||||||
|
<WalletDetails
|
||||||
|
accounts={ ACCOUNTS }
|
||||||
|
errors={ {} }
|
||||||
|
onChange={ onChange }
|
||||||
|
wallet={ {
|
||||||
|
owners: []
|
||||||
|
} }
|
||||||
|
walletType={ walletType }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WalletDetails', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
});
|
@ -15,9 +15,10 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { CompletedStep, IdentityIcon, CopyToClipboard } from '~/ui';
|
|
||||||
import { fromWei } from '~/api/util/wei';
|
import { fromWei } from '~/api/util/wei';
|
||||||
|
import { CompletedStep, IdentityIcon, CopyToClipboard } from '~/ui';
|
||||||
|
|
||||||
import styles from '../createWallet.css';
|
import styles from '../createWallet.css';
|
||||||
|
|
||||||
@ -48,24 +49,73 @@ export default class WalletInfo extends Component {
|
|||||||
return (
|
return (
|
||||||
<CompletedStep>
|
<CompletedStep>
|
||||||
<div>
|
<div>
|
||||||
<code>{ name }</code>
|
<span>
|
||||||
<span> has been </span>
|
<FormattedMessage
|
||||||
<span> { deployed ? 'deployed' : 'added' } at </span>
|
id='createWallet.info.created'
|
||||||
|
defaultMessage='{name} has been {deployedOrAdded} at '
|
||||||
|
values={ {
|
||||||
|
name: <code>{ name }</code>,
|
||||||
|
deployedOrAdded: deployed
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.info.deployed'
|
||||||
|
defaultMessage='deployed'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.info.added'
|
||||||
|
defaultMessage='added'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<CopyToClipboard data={ address } label='copy address to clipboard' />
|
<CopyToClipboard
|
||||||
<IdentityIcon address={ address } inline center className={ styles.identityicon } />
|
data={ address }
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.info.copyAddress'
|
||||||
|
defaultMessage='copy address to clipboard'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<IdentityIcon
|
||||||
|
address={ address }
|
||||||
|
className={ styles.identityicon }
|
||||||
|
center
|
||||||
|
inline
|
||||||
|
/>
|
||||||
<div className={ styles.address }>{ address }</div>
|
<div className={ styles.address }>{ address }</div>
|
||||||
</div>
|
</div>
|
||||||
<div>with the following owners</div>
|
<div>
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.info.owners'
|
||||||
|
defaultMessage='The following are wallet owners'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{ this.renderOwners() }
|
{ this.renderOwners() }
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<code>{ required }</code> owners are required to confirm a transaction.
|
<FormattedMessage
|
||||||
|
id='createWallet.info.numOwners'
|
||||||
|
defaultMessage='{numOwners} owners are required to confirm a transaction.'
|
||||||
|
values={ {
|
||||||
|
numOwners: <code>{ required }</code>
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The daily limit is set to <code>{ fromWei(daylimit).toFormat() }</code> ETH.
|
<FormattedMessage
|
||||||
|
id='createWallet.info.dayLimit'
|
||||||
|
defaultMessage='The daily limit is set to {dayLimit} ETH.'
|
||||||
|
values={ {
|
||||||
|
dayLimit: <code>{ fromWei(daylimit).toFormat() }</code>
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</CompletedStep>
|
</CompletedStep>
|
||||||
);
|
);
|
||||||
@ -74,12 +124,27 @@ export default class WalletInfo extends Component {
|
|||||||
renderOwners () {
|
renderOwners () {
|
||||||
const { account, owners, deployed } = this.props;
|
const { account, owners, deployed } = this.props;
|
||||||
|
|
||||||
return [].concat(deployed ? account : null, owners).filter((a) => a).map((address, id) => (
|
return []
|
||||||
<div key={ id } className={ styles.owner }>
|
.concat(deployed ? account : null, owners)
|
||||||
<IdentityIcon address={ address } inline center className={ styles.identityicon } />
|
.filter((account) => account)
|
||||||
<div className={ styles.address }>{ this.addressToString(address) }</div>
|
.map((address, id) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ styles.owner }
|
||||||
|
key={ id }
|
||||||
|
>
|
||||||
|
<IdentityIcon
|
||||||
|
address={ address }
|
||||||
|
className={ styles.identityicon }
|
||||||
|
center
|
||||||
|
inline
|
||||||
|
/>
|
||||||
|
<div className={ styles.address }>
|
||||||
|
{ this.addressToString(address) }
|
||||||
</div>
|
</div>
|
||||||
));
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addressToString (address) {
|
addressToString (address) {
|
||||||
|
46
js/src/modals/CreateWallet/WalletInfo/walletInfo.spec.js
Normal file
46
js/src/modals/CreateWallet/WalletInfo/walletInfo.spec.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import WalletInfo from './';
|
||||||
|
|
||||||
|
import { ACCOUNTS } from '../createWallet.test.js';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
component = shallow(
|
||||||
|
<WalletInfo
|
||||||
|
accounts={ ACCOUNTS }
|
||||||
|
account='0x1234567890123456789012345678901234567890'
|
||||||
|
address='0x0987654321098765432109876543210987654321'
|
||||||
|
daylimit='5'
|
||||||
|
name='testWallet'
|
||||||
|
owners={ [] }
|
||||||
|
required='5'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WalletInfo', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
});
|
@ -15,11 +15,53 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { RadioButtons } from '~/ui';
|
|
||||||
import { walletSourceURL } from '~/contracts/code/wallet';
|
import { walletSourceURL } from '~/contracts/code/wallet';
|
||||||
|
import { RadioButtons } from '~/ui';
|
||||||
|
|
||||||
// import styles from '../createWallet.css';
|
const TYPES = [
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.type.multisig.label'
|
||||||
|
defaultMessage='Multi-Sig wallet'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
key: 'MULTISIG',
|
||||||
|
description: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.type.multisig.description'
|
||||||
|
defaultMessage='Create/Deploy a {link} Wallet'
|
||||||
|
values={ {
|
||||||
|
link: (
|
||||||
|
<a href={ walletSourceURL } target='_blank'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.type.multisig.link'
|
||||||
|
defaultMessage='standard multi-signature'
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.type.watch.label'
|
||||||
|
defaultMessage='Watch a wallet'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
key: 'WATCH',
|
||||||
|
description: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.type.watch.description'
|
||||||
|
defaultMessage='Add an existing wallet to your accounts'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export default class WalletType extends Component {
|
export default class WalletType extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -33,34 +75,13 @@ export default class WalletType extends Component {
|
|||||||
return (
|
return (
|
||||||
<RadioButtons
|
<RadioButtons
|
||||||
name='contractType'
|
name='contractType'
|
||||||
value={ type }
|
|
||||||
values={ this.getTypes() }
|
|
||||||
onChange={ this.onTypeChange }
|
onChange={ this.onTypeChange }
|
||||||
|
value={ type }
|
||||||
|
values={ TYPES }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTypes () {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Multi-Sig wallet', key: 'MULTISIG',
|
|
||||||
description: (
|
|
||||||
<span>
|
|
||||||
<span>Create/Deploy a </span>
|
|
||||||
<a href={ walletSourceURL } target='_blank'>
|
|
||||||
standard multi-signature
|
|
||||||
</a>
|
|
||||||
<span> Wallet</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Watch a wallet', key: 'WATCH',
|
|
||||||
description: 'Add an existing wallet to your accounts'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
onTypeChange = (type) => {
|
onTypeChange = (type) => {
|
||||||
this.props.onChange(type.key);
|
this.props.onChange(type.key);
|
||||||
}
|
}
|
||||||
|
42
js/src/modals/CreateWallet/WalletType/walletType.spec.js
Normal file
42
js/src/modals/CreateWallet/WalletType/walletType.spec.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import WalletType from './';
|
||||||
|
|
||||||
|
let component;
|
||||||
|
let onChange;
|
||||||
|
|
||||||
|
function render (walletType = 'MULTISIG') {
|
||||||
|
onChange = sinon.stub();
|
||||||
|
component = shallow(
|
||||||
|
<WalletType
|
||||||
|
onChange={ onChange }
|
||||||
|
type={ walletType }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('WalletType', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
});
|
@ -14,20 +14,17 @@
|
|||||||
// 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 React, { Component, PropTypes } from 'react';
|
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
import ActionDone from 'material-ui/svg-icons/action/done';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ContentClear from 'material-ui/svg-icons/content/clear';
|
|
||||||
import NavigationArrowForward from 'material-ui/svg-icons/navigation/arrow-forward';
|
|
||||||
|
|
||||||
import { Button, Modal, TxHash, BusyStep } from '~/ui';
|
import { Button, Modal, TxHash, BusyStep } from '~/ui';
|
||||||
|
import { CancelIcon, DoneIcon, NextIcon } from '~/ui/Icons';
|
||||||
|
|
||||||
import WalletType from './WalletType';
|
import WalletType from './WalletType';
|
||||||
import WalletDetails from './WalletDetails';
|
import WalletDetails from './WalletDetails';
|
||||||
import WalletInfo from './WalletInfo';
|
import WalletInfo from './WalletInfo';
|
||||||
import CreateWalletStore from './createWalletStore';
|
import CreateWalletStore from './createWalletStore';
|
||||||
// import styles from './createWallet.css';
|
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export default class CreateWallet extends Component {
|
export default class CreateWallet extends Component {
|
||||||
@ -49,12 +46,27 @@ export default class CreateWallet extends Component {
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible
|
visible
|
||||||
title='rejected'
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.rejected.title'
|
||||||
|
defaultMessage='rejected'
|
||||||
|
/>
|
||||||
|
}
|
||||||
actions={ this.renderDialogActions() }
|
actions={ this.renderDialogActions() }
|
||||||
>
|
>
|
||||||
<BusyStep
|
<BusyStep
|
||||||
title='The deployment has been rejected'
|
title={
|
||||||
state='The wallet will not be created. You can safely close this window.'
|
<FormattedMessage
|
||||||
|
id='createWallet.rejected.message'
|
||||||
|
defaultMessage='The deployment has been rejected'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
state={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.rejected.state'
|
||||||
|
defaultMessage='The wallet will not be created. You can safely close this window.'
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
@ -65,7 +77,7 @@ export default class CreateWallet extends Component {
|
|||||||
visible
|
visible
|
||||||
actions={ this.renderDialogActions() }
|
actions={ this.renderDialogActions() }
|
||||||
current={ stage }
|
current={ stage }
|
||||||
steps={ steps.map((s) => s.title) }
|
steps={ steps.map((step) => step.title) }
|
||||||
waiting={ waiting }
|
waiting={ waiting }
|
||||||
>
|
>
|
||||||
{ this.renderPage() }
|
{ this.renderPage() }
|
||||||
@ -81,10 +93,19 @@ export default class CreateWallet extends Component {
|
|||||||
case 'DEPLOYMENT':
|
case 'DEPLOYMENT':
|
||||||
return (
|
return (
|
||||||
<BusyStep
|
<BusyStep
|
||||||
title='The deployment is currently in progress'
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.deployment.message'
|
||||||
|
defaultMessage='The deployment is currently in progress'
|
||||||
|
/>
|
||||||
|
}
|
||||||
state={ this.store.deployState }
|
state={ this.store.deployState }
|
||||||
>
|
>
|
||||||
{ this.store.txhash ? (<TxHash hash={ this.store.txhash } />) : null }
|
{
|
||||||
|
this.store.txhash
|
||||||
|
? <TxHash hash={ this.store.txhash } />
|
||||||
|
: null
|
||||||
|
}
|
||||||
</BusyStep>
|
</BusyStep>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -92,15 +113,13 @@ export default class CreateWallet extends Component {
|
|||||||
return (
|
return (
|
||||||
<WalletInfo
|
<WalletInfo
|
||||||
accounts={ accounts }
|
accounts={ accounts }
|
||||||
|
|
||||||
account={ this.store.wallet.account }
|
account={ this.store.wallet.account }
|
||||||
address={ this.store.wallet.address }
|
address={ this.store.wallet.address }
|
||||||
|
daylimit={ this.store.wallet.daylimit }
|
||||||
|
deployed={ this.store.deployed }
|
||||||
|
name={ this.store.wallet.name }
|
||||||
owners={ this.store.wallet.owners.slice() }
|
owners={ this.store.wallet.owners.slice() }
|
||||||
required={ this.store.wallet.required }
|
required={ this.store.wallet.required }
|
||||||
daylimit={ this.store.wallet.daylimit }
|
|
||||||
name={ this.store.wallet.name }
|
|
||||||
|
|
||||||
deployed={ this.store.deployed }
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -108,10 +127,10 @@ export default class CreateWallet extends Component {
|
|||||||
return (
|
return (
|
||||||
<WalletDetails
|
<WalletDetails
|
||||||
accounts={ accounts }
|
accounts={ accounts }
|
||||||
wallet={ this.store.wallet }
|
|
||||||
errors={ this.store.errors }
|
errors={ this.store.errors }
|
||||||
walletType={ this.store.walletType }
|
|
||||||
onChange={ this.store.onChange }
|
onChange={ this.store.onChange }
|
||||||
|
wallet={ this.store.wallet }
|
||||||
|
walletType={ this.store.walletType }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -131,40 +150,65 @@ export default class CreateWallet extends Component {
|
|||||||
|
|
||||||
const cancelBtn = (
|
const cancelBtn = (
|
||||||
<Button
|
<Button
|
||||||
icon={ <ContentClear /> }
|
icon={ <CancelIcon /> }
|
||||||
label='Cancel'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.cancel'
|
||||||
|
defaultMessage='Cancel'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ this.onClose }
|
onClick={ this.onClose }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const closeBtn = (
|
const closeBtn = (
|
||||||
<Button
|
<Button
|
||||||
icon={ <ContentClear /> }
|
icon={ <CancelIcon /> }
|
||||||
label='Close'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.close'
|
||||||
|
defaultMessage='Close'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ this.onClose }
|
onClick={ this.onClose }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const doneBtn = (
|
const doneBtn = (
|
||||||
<Button
|
<Button
|
||||||
icon={ <ActionDone /> }
|
icon={ <DoneIcon /> }
|
||||||
label='Done'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.done'
|
||||||
|
defaultMessage='Done'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ this.onClose }
|
onClick={ this.onClose }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const sendingBtn = (
|
const sendingBtn = (
|
||||||
<Button
|
<Button
|
||||||
icon={ <ActionDone /> }
|
icon={ <DoneIcon /> }
|
||||||
label='Sending...'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.sending'
|
||||||
|
defaultMessage='Sending...'
|
||||||
|
/>
|
||||||
|
}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const nextBtn = (
|
const nextBtn = (
|
||||||
<Button
|
<Button
|
||||||
icon={ <NavigationArrowForward /> }
|
icon={ <NextIcon /> }
|
||||||
label='Next'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.next'
|
||||||
|
defaultMessage='Next'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ onNext }
|
onClick={ onNext }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -184,9 +228,14 @@ export default class CreateWallet extends Component {
|
|||||||
if (this.store.walletType === 'WATCH') {
|
if (this.store.walletType === 'WATCH') {
|
||||||
return [ cancelBtn, (
|
return [ cancelBtn, (
|
||||||
<Button
|
<Button
|
||||||
icon={ <NavigationArrowForward /> }
|
|
||||||
label='Add'
|
|
||||||
disabled={ hasErrors }
|
disabled={ hasErrors }
|
||||||
|
icon={ <NextIcon /> }
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.add'
|
||||||
|
defaultMessage='Add'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ onAdd }
|
onClick={ onAdd }
|
||||||
/>
|
/>
|
||||||
) ];
|
) ];
|
||||||
@ -194,9 +243,14 @@ export default class CreateWallet extends Component {
|
|||||||
|
|
||||||
return [ cancelBtn, (
|
return [ cancelBtn, (
|
||||||
<Button
|
<Button
|
||||||
icon={ <NavigationArrowForward /> }
|
|
||||||
label='Create'
|
|
||||||
disabled={ hasErrors }
|
disabled={ hasErrors }
|
||||||
|
icon={ <NextIcon /> }
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.button.create'
|
||||||
|
defaultMessage='Create'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ onCreate }
|
onClick={ onCreate }
|
||||||
/>
|
/>
|
||||||
) ];
|
) ];
|
||||||
|
54
js/src/modals/CreateWallet/createWallet.spec.js
Normal file
54
js/src/modals/CreateWallet/createWallet.spec.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { shallow } from 'enzyme';
|
||||||
|
import React from 'react';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import CreateWallet from './';
|
||||||
|
|
||||||
|
import { ACCOUNTS } from './createWallet.test.js';
|
||||||
|
|
||||||
|
let api;
|
||||||
|
let component;
|
||||||
|
let onClose;
|
||||||
|
|
||||||
|
function createApi () {
|
||||||
|
api = {};
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render () {
|
||||||
|
onClose = sinon.stub();
|
||||||
|
component = shallow(
|
||||||
|
<CreateWallet
|
||||||
|
accounts={ ACCOUNTS }
|
||||||
|
onClose={ onClose }
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
context: { api: createApi() }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('CreateWallet', () => {
|
||||||
|
it('renders defaults', () => {
|
||||||
|
expect(render()).to.be.ok;
|
||||||
|
});
|
||||||
|
});
|
25
js/src/modals/CreateWallet/createWallet.test.js
Normal file
25
js/src/modals/CreateWallet/createWallet.test.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const ACCOUNTS = {
|
||||||
|
'0x1234567890123456789012345678901234567890': {
|
||||||
|
address: '0x1234567890123456789012345678901234567890'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
ACCOUNTS
|
||||||
|
};
|
@ -15,10 +15,12 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import { observable, computed, action, transaction } from 'mobx';
|
import { observable, computed, action, transaction } from 'mobx';
|
||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import Contract from '~/api/contract';
|
import Contract from '~/api/contract';
|
||||||
import Contracts from '~/contracts';
|
|
||||||
import { ERROR_CODES } from '~/api/transport/error';
|
import { ERROR_CODES } from '~/api/transport/error';
|
||||||
|
import Contracts from '~/contracts';
|
||||||
import { wallet as walletAbi } from '~/contracts/abi';
|
import { wallet as walletAbi } from '~/contracts/abi';
|
||||||
import { wallet as walletCode, walletLibraryRegKey, fullWalletCode } from '~/contracts/code/wallet';
|
import { wallet as walletCode, walletLibraryRegKey, fullWalletCode } from '~/contracts/code/wallet';
|
||||||
|
|
||||||
@ -27,10 +29,39 @@ import { toWei } from '~/api/util/wei';
|
|||||||
import WalletsUtils from '~/util/wallets';
|
import WalletsUtils from '~/util/wallets';
|
||||||
|
|
||||||
const STEPS = {
|
const STEPS = {
|
||||||
TYPE: { title: 'wallet type' },
|
TYPE: {
|
||||||
DETAILS: { title: 'wallet details' },
|
title: (
|
||||||
DEPLOYMENT: { title: 'wallet deployment', waiting: true },
|
<FormattedMessage
|
||||||
INFO: { title: 'wallet informaton' }
|
id='createWallet.steps.type'
|
||||||
|
defaultMessage='wallet type'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
DETAILS: {
|
||||||
|
title: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.steps.details'
|
||||||
|
defaultMessage='wallet details'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
DEPLOYMENT: {
|
||||||
|
title: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.steps.deployment'
|
||||||
|
defaultMessage='wallet deployment'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
waiting: true
|
||||||
|
},
|
||||||
|
INFO: {
|
||||||
|
title: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.steps.info'
|
||||||
|
defaultMessage='wallet informaton'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CreateWalletStore {
|
export default class CreateWalletStore {
|
||||||
@ -227,25 +258,50 @@ export default class CreateWalletStore {
|
|||||||
switch (data.state) {
|
switch (data.state) {
|
||||||
case 'estimateGas':
|
case 'estimateGas':
|
||||||
case 'postTransaction':
|
case 'postTransaction':
|
||||||
this.deployState = 'Preparing transaction for network transmission';
|
this.deployState = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.states.preparing'
|
||||||
|
defaultMessage='Preparing transaction for network transmission'
|
||||||
|
/>
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'checkRequest':
|
case 'checkRequest':
|
||||||
this.deployState = 'Waiting for confirmation of the transaction in the Parity Secure Signer';
|
this.deployState = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.states.waitingConfirm'
|
||||||
|
defaultMessage='Waiting for confirmation of the transaction in the Parity Secure Signer'
|
||||||
|
/>
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'getTransactionReceipt':
|
case 'getTransactionReceipt':
|
||||||
this.deployState = 'Waiting for the contract deployment transaction receipt';
|
this.deployState = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.states.waitingReceipt'
|
||||||
|
defaultMessage='Waiting for the contract deployment transaction receipt'
|
||||||
|
/>
|
||||||
|
);
|
||||||
this.txhash = data.txhash;
|
this.txhash = data.txhash;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'hasReceipt':
|
case 'hasReceipt':
|
||||||
case 'getCode':
|
case 'getCode':
|
||||||
this.deployState = 'Validating the deployed contract code';
|
this.deployState = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.states.validatingCode'
|
||||||
|
defaultMessage='Validating the deployed contract code'
|
||||||
|
/>
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'completed':
|
case 'completed':
|
||||||
this.deployState = 'The contract deployment has been completed';
|
this.deployState = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='createWallet.states.completed'
|
||||||
|
defaultMessage='The contract deployment has been completed'
|
||||||
|
/>
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -28,6 +28,7 @@ import Input from '~/ui/Form/Input';
|
|||||||
import InputAddressSelect from '~/ui/Form/InputAddressSelect';
|
import InputAddressSelect from '~/ui/Form/InputAddressSelect';
|
||||||
import Select from '~/ui/Form/Select';
|
import Select from '~/ui/Form/Select';
|
||||||
import { ABI_TYPES, parseAbiType } from '~/util/abi';
|
import { ABI_TYPES, parseAbiType } from '~/util/abi';
|
||||||
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
import styles from './typedInput.css';
|
import styles from './typedInput.css';
|
||||||
|
|
||||||
@ -42,9 +43,9 @@ export default class TypedInput extends Component {
|
|||||||
allowCopy: PropTypes.bool,
|
allowCopy: PropTypes.bool,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
error: PropTypes.any,
|
error: PropTypes.any,
|
||||||
hint: PropTypes.string,
|
hint: nodeOrStringProptype(),
|
||||||
isEth: PropTypes.bool,
|
isEth: PropTypes.bool,
|
||||||
label: PropTypes.string,
|
label: nodeOrStringProptype(),
|
||||||
max: PropTypes.number,
|
max: PropTypes.number,
|
||||||
min: PropTypes.number,
|
min: PropTypes.number,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
|
Loading…
Reference in New Issue
Block a user