Extract i18n from shared UI components (#4834)
* Actionbar i18n * ui Errors i18n * Features i18n * GapPriceSelector i18n * WIP * WIP #2 * Update methodDecoding * ModalBox -> functional * Signer pages i18n (missed previously) * Update ModalBox tests * Update variable
This commit is contained in:
parent
d98b7aab61
commit
4e5fd92e67
@ -15,11 +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 React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
import FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
|
|
||||||
|
|
||||||
import Button from '../../Button';
|
import Button from '../../Button';
|
||||||
|
import { FileDownloadIcon } from '../../Icons';
|
||||||
|
|
||||||
class ActionbarExport extends Component {
|
class ActionbarExport extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -38,7 +39,12 @@ class ActionbarExport extends Component {
|
|||||||
<Button
|
<Button
|
||||||
className={ className }
|
className={ className }
|
||||||
icon={ <FileDownloadIcon /> }
|
icon={ <FileDownloadIcon /> }
|
||||||
label='export'
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.actionbar.export.button.export'
|
||||||
|
defaultMessage='export'
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={ this.handleExport }
|
onClick={ this.handleExport }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -46,9 +52,7 @@ class ActionbarExport extends Component {
|
|||||||
|
|
||||||
handleExport = () => {
|
handleExport = () => {
|
||||||
const { filename, content } = this.props;
|
const { filename, content } = this.props;
|
||||||
|
|
||||||
const text = JSON.stringify(content, null, 4);
|
const text = JSON.stringify(content, null, 4);
|
||||||
|
|
||||||
const blob = new Blob([ text ], { type: 'application/json' });
|
const blob = new Blob([ text ], { type: 'application/json' });
|
||||||
|
|
||||||
FileSaver.saveAs(blob, `${filename}.json`);
|
FileSaver.saveAs(blob, `${filename}.json`);
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
// 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 ActionSearch from 'material-ui/svg-icons/action/search';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import Button from '../../Button';
|
import Button from '../../Button';
|
||||||
import InputChip from '../../Form/InputChip';
|
import InputChip from '../../Form/InputChip';
|
||||||
|
import { SearchIcon } from '../../Icons';
|
||||||
|
|
||||||
import styles from './search.css';
|
import styles from './search.css';
|
||||||
|
|
||||||
@ -74,7 +75,12 @@ export default class ActionbarSearch extends Component {
|
|||||||
<InputChip
|
<InputChip
|
||||||
addOnBlur
|
addOnBlur
|
||||||
className={ styles.input }
|
className={ styles.input }
|
||||||
hint='Enter search input...'
|
hint={
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.actionbar.search.hint'
|
||||||
|
defaultMessage='Enter search input...'
|
||||||
|
/>
|
||||||
|
}
|
||||||
ref='inputChip'
|
ref='inputChip'
|
||||||
tokens={ tokens }
|
tokens={ tokens }
|
||||||
|
|
||||||
@ -86,7 +92,7 @@ export default class ActionbarSearch extends Component {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
className={ styles.searchButton }
|
className={ styles.searchButton }
|
||||||
icon={ <ActionSearch /> }
|
icon={ <SearchIcon /> }
|
||||||
label=''
|
label=''
|
||||||
onClick={ this.handleSearchClick }
|
onClick={ this.handleSearchClick }
|
||||||
/>
|
/>
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// 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 { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { Snackbar } from 'material-ui';
|
import { Snackbar } from 'material-ui';
|
||||||
@ -24,6 +25,19 @@ import { closeErrors } from './actions';
|
|||||||
import styles from './errors.css';
|
import styles from './errors.css';
|
||||||
|
|
||||||
const ERROR_REGEX = /-(\d+): (.+)$/;
|
const ERROR_REGEX = /-(\d+): (.+)$/;
|
||||||
|
const DURATION_OPEN = 60000;
|
||||||
|
const STYLE_BODY = {
|
||||||
|
height: 'auto',
|
||||||
|
whiteSpace: 'pre-line'
|
||||||
|
};
|
||||||
|
const STYLE_CONTENT = {
|
||||||
|
alignItems: 'center',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
lineHeight: '1.5em',
|
||||||
|
padding: '0.75em 0'
|
||||||
|
};
|
||||||
|
|
||||||
class Errors extends Component {
|
class Errors extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -46,23 +60,18 @@ class Errors extends Component {
|
|||||||
<Snackbar
|
<Snackbar
|
||||||
className={ styles.container }
|
className={ styles.container }
|
||||||
open
|
open
|
||||||
action='close'
|
action={
|
||||||
autoHideDuration={ 60000 }
|
<FormattedMessage
|
||||||
|
id='ui.errors.close'
|
||||||
|
defaultMessage='close'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
autoHideDuration={ DURATION_OPEN }
|
||||||
message={ text }
|
message={ text }
|
||||||
onActionTouchTap={ onCloseErrors }
|
onActionTouchTap={ onCloseErrors }
|
||||||
onRequestClose={ this.onRequestClose }
|
onRequestClose={ this.onRequestClose }
|
||||||
bodyStyle={ {
|
bodyStyle={ STYLE_BODY }
|
||||||
whiteSpace: 'pre-line',
|
contentStyle={ STYLE_CONTENT }
|
||||||
height: 'auto'
|
|
||||||
} }
|
|
||||||
contentStyle={ {
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'row',
|
|
||||||
lineHeight: '1.5em',
|
|
||||||
padding: '0.75em 0',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'space-between'
|
|
||||||
} }
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +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 from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
const MODES = {
|
const MODES = {
|
||||||
DEVELOPMENT: 1000, // only in dev mode, disabled by default, can be toggled
|
DEVELOPMENT: 1000, // only in dev mode, disabled by default, can be toggled
|
||||||
TESTING: 1011, // feature is available in dev mode
|
TESTING: 1011, // feature is available in dev mode
|
||||||
@ -28,13 +31,33 @@ const FEATURES = {
|
|||||||
const DEFAULTS = {
|
const DEFAULTS = {
|
||||||
[FEATURES.LANGUAGE]: {
|
[FEATURES.LANGUAGE]: {
|
||||||
mode: MODES.TESTING,
|
mode: MODES.TESTING,
|
||||||
name: 'Language Selection',
|
name: (
|
||||||
description: 'Allows changing the default interface language'
|
<FormattedMessage
|
||||||
|
id='ui.features.defaults.i18n.name'
|
||||||
|
defaultMssage='Language Selection'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.features.defaults.i18n.desc'
|
||||||
|
defaultMssage='Allows changing the default interface language'
|
||||||
|
/>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
[FEATURES.LOGLEVELS]: {
|
[FEATURES.LOGLEVELS]: {
|
||||||
mode: MODES.TESTING,
|
mode: MODES.TESTING,
|
||||||
name: 'Logging Level Selection',
|
name: (
|
||||||
description: 'Allows changing of the log levels for various components'
|
<FormattedMessage
|
||||||
|
id='ui.features.defaults.logging.name'
|
||||||
|
defaultMssage='Logging Level Selection'
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.features.defaults.logging.desc'
|
||||||
|
defaultMssage='Allows changing of the log levels for various components'
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// 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';
|
||||||
|
|
||||||
export default class CustomTooltip extends Component {
|
export default class CustomTooltip extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@ -41,11 +42,15 @@ export default class CustomTooltip extends Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p className='label'>
|
<p className='label'>
|
||||||
{ count.toNumber() } transactions
|
<FormattedMessage
|
||||||
with gas price set from
|
id='ui.gasPriceSelector.customTooltip.transactions'
|
||||||
<span> { minprice.toFormat(0) } </span>
|
defaultMessage='{number} {number, plural, one {transaction} other {transactions}} with gas price set from {minPrice} to {maxPrice}'
|
||||||
to
|
values={ {
|
||||||
<span> { maxprice.toFormat(0) } </span>
|
number: count.toNumber(),
|
||||||
|
minPrice: <span>{ minprice.toFormat(0) }</span>,
|
||||||
|
maxPrice: <span>{ maxprice.toFormat(0) }</span>
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -34,6 +34,7 @@ export DoneIcon from 'material-ui/svg-icons/action/done-all';
|
|||||||
export DialIcon from 'material-ui/svg-icons/communication/dialpad';
|
export DialIcon from 'material-ui/svg-icons/communication/dialpad';
|
||||||
export EditIcon from 'material-ui/svg-icons/content/create';
|
export EditIcon from 'material-ui/svg-icons/content/create';
|
||||||
export ErrorIcon from 'material-ui/svg-icons/alert/error';
|
export ErrorIcon from 'material-ui/svg-icons/alert/error';
|
||||||
|
export FileDownloadIcon from 'material-ui/svg-icons/file/file-download';
|
||||||
export FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
|
export FileUploadIcon from 'material-ui/svg-icons/file/file-upload';
|
||||||
export FileIcon from 'material-ui/svg-icons/editor/insert-drive-file';
|
export FileIcon from 'material-ui/svg-icons/editor/insert-drive-file';
|
||||||
export FingerprintIcon from 'material-ui/svg-icons/action/fingerprint';
|
export FingerprintIcon from 'material-ui/svg-icons/action/fingerprint';
|
||||||
@ -55,6 +56,7 @@ export RefreshIcon from 'material-ui/svg-icons/action/autorenew';
|
|||||||
export ReorderIcon from 'material-ui/svg-icons/action/reorder';
|
export ReorderIcon from 'material-ui/svg-icons/action/reorder';
|
||||||
export ReplayIcon from 'material-ui/svg-icons/av/replay';
|
export ReplayIcon from 'material-ui/svg-icons/av/replay';
|
||||||
export SaveIcon from 'material-ui/svg-icons/content/save';
|
export SaveIcon from 'material-ui/svg-icons/content/save';
|
||||||
|
export SearchIcon from 'material-ui/svg-icons/action/search';
|
||||||
export SendIcon from 'material-ui/svg-icons/content/send';
|
export SendIcon from 'material-ui/svg-icons/content/send';
|
||||||
export SettingsIcon from 'material-ui/svg-icons/action/settings';
|
export SettingsIcon from 'material-ui/svg-icons/action/settings';
|
||||||
export SnoozeIcon from 'material-ui/svg-icons/av/snooze';
|
export SnoozeIcon from 'material-ui/svg-icons/av/snooze';
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { CircularProgress } from 'material-ui';
|
import { CircularProgress } from 'material-ui';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { TypedInput, InputAddress } from '../Form';
|
import { TypedInput, InputAddress } from '../Form';
|
||||||
@ -112,28 +113,50 @@ class MethodDecoding extends Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gasValue = gas.mul(gasPrice);
|
const gasProvided = (
|
||||||
|
<span className={ styles.highlight }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.gasValues'
|
||||||
|
defaultMessage='{gas} gas ({gasPrice}M/{tag})'
|
||||||
|
values={ {
|
||||||
|
gas: gas.toFormat(0),
|
||||||
|
gasPrice: gasPrice.div(1000000).toFormat(0),
|
||||||
|
tag: <small>ETH</small>
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
const gasProvidedEth = (
|
||||||
|
<span className={ styles.highlight }>
|
||||||
|
{ this.renderEtherValue(gas.mul(gasPrice)) }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
const gasUsed = transaction.gasUsed
|
||||||
|
? (
|
||||||
|
<span className={ styles.highlight }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.gasUsed'
|
||||||
|
defaultMessage=' ({gas} gas used)'
|
||||||
|
values={ {
|
||||||
|
gas: transaction.gasUsed.toFormat(0)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.gasDetails }>
|
<div className={ styles.gasDetails }>
|
||||||
<span>{ historic ? 'Provided' : 'Provides' } </span>
|
<FormattedMessage
|
||||||
<span className={ styles.highlight }>
|
id='ui.methodDecoding.txValues'
|
||||||
{ gas.toFormat(0) } gas ({ gasPrice.div(1000000).toFormat(0) }M/<small>ETH</small>)
|
defaultMessage='{historic, select, true {Provided} false {Provides}} {gasProvided}{gasUsed} for a total transaction value of {gasProvidedEth}'
|
||||||
</span>
|
values={ {
|
||||||
{
|
historic,
|
||||||
transaction.gasUsed
|
gasProvided,
|
||||||
? (
|
gasProvidedEth,
|
||||||
<span>
|
gasUsed
|
||||||
<span>used</span>
|
} }
|
||||||
<span className={ styles.highlight }>
|
/>
|
||||||
{ transaction.gasUsed.toFormat(0) } gas
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
<span> for a total transaction value of </span>
|
|
||||||
<span className={ styles.highlight }>{ this.renderEtherValue(gasValue) }</span>
|
|
||||||
{ this.renderMinBlock() }
|
{ this.renderMinBlock() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -148,14 +171,40 @@ class MethodDecoding extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (condition.block && condition.block.gt(0)) {
|
if (condition.block && condition.block.gt(0)) {
|
||||||
|
const blockNumber = (
|
||||||
|
<span className={ styles.highlight }>
|
||||||
|
#{ condition.block.toFormat(0) }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>, { historic ? 'Submitted' : 'Submission' } at block <span className={ styles.highlight }>#{ condition.block.toFormat(0) }</span></span>
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.condition.block'
|
||||||
|
defaultMessage=', {historic, select, true {Submitted} false {Submission}} at block {blockNumber}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
blockNumber
|
||||||
|
} }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (condition.time) {
|
if (condition.time) {
|
||||||
|
const timestamp = (
|
||||||
|
<span className={ styles.highlight }>
|
||||||
|
{ moment(condition.time).format('LLLL') }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>, { historic ? 'Submitted' : 'Submission' } at <span className={ styles.highlight }>{ moment(condition.time).format('LLLL') }</span></span>
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.condition.time'
|
||||||
|
defaultMessage=', {historic, select, true {Submitted} false {Submission}} at {timestamp}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
timestamp
|
||||||
|
} }
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,9 +239,12 @@ class MethodDecoding extends Component {
|
|||||||
getAscii () {
|
getAscii () {
|
||||||
const { api } = this.context;
|
const { api } = this.context;
|
||||||
const { transaction } = this.props;
|
const { transaction } = this.props;
|
||||||
const ascii = api.util.hexToAscii(transaction.input || transaction.data);
|
const value = api.util.hexToAscii(transaction.input || transaction.data);
|
||||||
|
|
||||||
return { value: ascii, valid: ASCII_INPUT.test(ascii) };
|
return {
|
||||||
|
value,
|
||||||
|
valid: ASCII_INPUT.test(value)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderInputValue () {
|
renderInputValue () {
|
||||||
@ -218,16 +270,29 @@ class MethodDecoding extends Component {
|
|||||||
? text
|
? text
|
||||||
: text.slice(0, 50) + '...';
|
: text.slice(0, 50) + '...';
|
||||||
|
|
||||||
return (
|
const inputDesc = (
|
||||||
<div className={ styles.details }>
|
|
||||||
<span>with the </span>
|
|
||||||
<span
|
<span
|
||||||
onClick={ this.toggleInputType }
|
onClick={ this.toggleInputType }
|
||||||
className={ [ styles.clickable, styles.noSelect ].join(' ') }
|
className={ [ styles.clickable, styles.noSelect ].join(' ') }
|
||||||
>
|
>
|
||||||
{ type === 'ascii' ? 'input' : 'data' }
|
{
|
||||||
|
type === 'ascii'
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.input.input'
|
||||||
|
defaultMessage='input'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.input.data'
|
||||||
|
defaultMessage='data'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
<span> </span>
|
);
|
||||||
|
const inputValue = (
|
||||||
<span
|
<span
|
||||||
onClick={ this.toggleInputExpand }
|
onClick={ this.toggleInputExpand }
|
||||||
className={ expandable ? styles.clickable : '' }
|
className={ expandable ? styles.clickable : '' }
|
||||||
@ -236,6 +301,18 @@ class MethodDecoding extends Component {
|
|||||||
{ textToShow }
|
{ textToShow }
|
||||||
</code>
|
</code>
|
||||||
</span>
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.details }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.input.withInput'
|
||||||
|
defaultMessage='with the {inputDesc} {inputValue}'
|
||||||
|
values={ {
|
||||||
|
inputDesc,
|
||||||
|
inputValue
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -251,15 +328,19 @@ class MethodDecoding extends Component {
|
|||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<div className={ styles.details }>
|
<div className={ styles.details }>
|
||||||
<div>
|
<FormattedMessage
|
||||||
<span>{ historic ? 'Transferred' : 'Will transfer' } </span>
|
id='ui.methodDecoding.token.transfer'
|
||||||
|
defaultMessage='{historic, select, true {Transferred} false {Will transfer}} {value} to {address}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
value: (
|
||||||
<span className={ styles.highlight }>
|
<span className={ styles.highlight }>
|
||||||
{ this.renderTokenValue(value.value) }
|
{ this.renderTokenValue(value.value) }
|
||||||
</span>
|
</span>
|
||||||
<span> to </span>
|
),
|
||||||
</div>
|
address: this.renderAddressName(address)
|
||||||
|
} }
|
||||||
{ this.renderAddressName(address) }
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -272,7 +353,10 @@ class MethodDecoding extends Component {
|
|||||||
if (!historic) {
|
if (!historic) {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.details }>
|
<div className={ styles.details }>
|
||||||
Will deploy a contract.
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.deploy.willDeploy'
|
||||||
|
defaultMessage='Will deploy a contract'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -280,15 +364,24 @@ class MethodDecoding extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={ styles.details }>
|
<div className={ styles.details }>
|
||||||
<div>
|
<div>
|
||||||
<span>Deployed a contract at address </span>
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.deploy.address'
|
||||||
|
defaultMessage='Deployed a contract at address '
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ this.renderAddressName(transaction.creates, false) }
|
{ this.renderAddressName(transaction.creates, false) }
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{ methodInputs && methodInputs.length ? 'with the following parameters:' : ''}
|
{
|
||||||
|
methodInputs && methodInputs.length
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.deploy.params'
|
||||||
|
defaultMessage='with the following parameters:'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: ''
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={ styles.inputs }>
|
<div className={ styles.inputs }>
|
||||||
{ this.renderInputs() }
|
{ this.renderInputs() }
|
||||||
</div>
|
</div>
|
||||||
@ -300,17 +393,32 @@ class MethodDecoding extends Component {
|
|||||||
const { historic, transaction } = this.props;
|
const { historic, transaction } = this.props;
|
||||||
const { isContract } = this.state;
|
const { isContract } = this.state;
|
||||||
|
|
||||||
return (
|
const valueEth = (
|
||||||
<div className={ styles.details }>
|
|
||||||
<div>
|
|
||||||
<span>{ historic ? 'Received' : 'Will receive' } </span>
|
|
||||||
<span className={ styles.highlight }>
|
<span className={ styles.highlight }>
|
||||||
{ this.renderEtherValue(transaction.value) }
|
{ this.renderEtherValue(transaction.value) }
|
||||||
</span>
|
</span>
|
||||||
<span> from { isContract ? 'the contract' : '' } </span>
|
);
|
||||||
</div>
|
const aContract = isContract
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.receive.contract'
|
||||||
|
defaultMessage='the contract '
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: '';
|
||||||
|
|
||||||
{ this.renderAddressName(transaction.from) }
|
return (
|
||||||
|
<div className={ styles.details }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.receive.info'
|
||||||
|
defaultMessage='{historic, select, true {Received} false {Will receive}} {valueEth} from {aContract}{address}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
valueEth,
|
||||||
|
aContract,
|
||||||
|
address: this.renderAddressName(transaction.from)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
{ this.renderInputValue() }
|
{ this.renderInputValue() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -320,17 +428,32 @@ class MethodDecoding extends Component {
|
|||||||
const { historic, transaction } = this.props;
|
const { historic, transaction } = this.props;
|
||||||
const { isContract } = this.state;
|
const { isContract } = this.state;
|
||||||
|
|
||||||
return (
|
const valueEth = (
|
||||||
<div className={ styles.details }>
|
|
||||||
<div>
|
|
||||||
<span>{ historic ? 'Transferred' : 'Will transfer' } </span>
|
|
||||||
<span className={ styles.highlight }>
|
<span className={ styles.highlight }>
|
||||||
{ this.renderEtherValue(transaction.value) }
|
{ this.renderEtherValue(transaction.value) }
|
||||||
</span>
|
</span>
|
||||||
<span> to { isContract ? 'the contract' : '' } </span>
|
);
|
||||||
</div>
|
const aContract = isContract
|
||||||
|
? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.transfer.contract'
|
||||||
|
defaultMessage='the contract '
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: '';
|
||||||
|
|
||||||
{ this.renderAddressName(transaction.to) }
|
return (
|
||||||
|
<div className={ styles.details }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.transfer.info'
|
||||||
|
defaultMessage='{historic, select, true {Transferred} false {Will transfer}} {valueEth} to {aContract}{address}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
valueEth,
|
||||||
|
aContract,
|
||||||
|
address: this.renderAddressName(transaction.to)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
{ this.renderInputValue() }
|
{ this.renderInputValue() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -340,26 +463,31 @@ class MethodDecoding extends Component {
|
|||||||
const { historic, transaction } = this.props;
|
const { historic, transaction } = this.props;
|
||||||
const { methodName, methodInputs } = this.state;
|
const { methodName, methodInputs } = this.state;
|
||||||
|
|
||||||
return (
|
const method = (
|
||||||
<div className={ styles.details }>
|
<span className={ styles.name }>
|
||||||
<div className={ styles.description }>
|
{ methodName }
|
||||||
<div>
|
</span>
|
||||||
<span>{ historic ? 'Executed' : 'Will execute' } the </span>
|
);
|
||||||
<span className={ styles.name }>{ methodName }</span>
|
const ethValue = (
|
||||||
<span> function on the contract </span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{ this.renderAddressName(transaction.to) }
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span>transferring </span>
|
|
||||||
<span className={ styles.highlight }>
|
<span className={ styles.highlight }>
|
||||||
{ this.renderEtherValue(transaction.value) }
|
{ this.renderEtherValue(transaction.value) }
|
||||||
</span>
|
</span>
|
||||||
<span>
|
);
|
||||||
{ methodInputs.length ? ', passing the following parameters:' : '.' }
|
|
||||||
</span>
|
return (
|
||||||
</div>
|
<div className={ styles.details }>
|
||||||
|
<div className={ styles.description }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.signature.info'
|
||||||
|
defaultMessage='{historic, select, true {Executed} false {Will execute}} the {method} function on the contract {address} trsansferring {ethValue}{inputLength, plural, zero {,} other {passing the following {inputLength, plural, one {parameter} other {parameters}}}}'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
method,
|
||||||
|
ethValue,
|
||||||
|
address: this.renderAddressName(transaction.to),
|
||||||
|
inputLength: methodInputs.length
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.inputs }>
|
<div className={ styles.inputs }>
|
||||||
{ this.renderInputs() }
|
{ this.renderInputs() }
|
||||||
@ -371,23 +499,29 @@ class MethodDecoding extends Component {
|
|||||||
renderUnknownMethod () {
|
renderUnknownMethod () {
|
||||||
const { historic, transaction } = this.props;
|
const { historic, transaction } = this.props;
|
||||||
|
|
||||||
return (
|
const method = (
|
||||||
<div className={ styles.details }>
|
<span className={ styles.name }>
|
||||||
<div>
|
an unknown/unregistered
|
||||||
<span>{ historic ? 'Executed' : 'Will execute' } </span>
|
</span>
|
||||||
<span className={ styles.name }>an unknown/unregistered</span>
|
);
|
||||||
<span> method on the contract </span>
|
const ethValue = (
|
||||||
</div>
|
|
||||||
|
|
||||||
{ this.renderAddressName(transaction.to) }
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<span>transferring </span>
|
|
||||||
<span className={ styles.highlight }>
|
<span className={ styles.highlight }>
|
||||||
{ this.renderEtherValue(transaction.value) }
|
{ this.renderEtherValue(transaction.value) }
|
||||||
</span>
|
</span>
|
||||||
<span>.</span>
|
);
|
||||||
</div>
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.details }>
|
||||||
|
<FormattedMessage
|
||||||
|
id='ui.methodDecoding.unknown.info'
|
||||||
|
defaultMessage='{historic, select, true {Executed} false {Will execute}} the {method} on the contract {address} transferring {ethValue}.'
|
||||||
|
values={ {
|
||||||
|
historic,
|
||||||
|
method,
|
||||||
|
ethValue,
|
||||||
|
address: this.renderAddressName(transaction.to)
|
||||||
|
} }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
35
js/src/ui/ModalBox/body.js
Normal file
35
js/src/ui/ModalBox/body.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 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 React, { PropTypes } from 'react';
|
||||||
|
|
||||||
|
import styles from './modalBox.css';
|
||||||
|
|
||||||
|
export default function Body ({ children }) {
|
||||||
|
if (!children) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.body }>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Body.propTypes = {
|
||||||
|
children: PropTypes.node
|
||||||
|
};
|
@ -14,60 +14,30 @@
|
|||||||
// 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 React, { PropTypes } from 'react';
|
||||||
|
|
||||||
import { nodeOrStringProptype } from '~/util/proptypes';
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
|
import Body from './body';
|
||||||
|
import Summary from './summary';
|
||||||
import styles from './modalBox.css';
|
import styles from './modalBox.css';
|
||||||
|
|
||||||
export default class ModalBox extends Component {
|
export default function ModalBox ({ children, icon, summary }) {
|
||||||
static propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
icon: PropTypes.node.isRequired,
|
|
||||||
summary: nodeOrStringProptype()
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { icon } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ styles.body }>
|
<div className={ styles.body }>
|
||||||
<div className={ styles.icon }>
|
<div className={ styles.icon }>
|
||||||
{ icon }
|
{ icon }
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.content }>
|
<div className={ styles.content }>
|
||||||
{ this.renderSummary() }
|
<Summary summary={ summary } />
|
||||||
{ this.renderBody() }
|
<Body children={ children } />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBody () {
|
ModalBox.propTypes = {
|
||||||
const { children } = this.props;
|
children: PropTypes.node,
|
||||||
|
icon: PropTypes.node.isRequired,
|
||||||
if (!children) {
|
summary: nodeOrStringProptype()
|
||||||
return null;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={ styles.body }>
|
|
||||||
{ children }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSummary () {
|
|
||||||
const { summary } = this.props;
|
|
||||||
|
|
||||||
if (!summary) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={ styles.summary }>
|
|
||||||
{ summary }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -21,12 +21,16 @@ import ModalBox from './';
|
|||||||
|
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
|
const CHILDREN = <div id='testChild'>testChild</div>;
|
||||||
|
const ICON = <div id='testIcon'>testIcon</div>;
|
||||||
|
const SUMMARY = <div id='testSummary'>testSummary</div>;
|
||||||
|
|
||||||
function render () {
|
function render () {
|
||||||
component = shallow(
|
component = shallow(
|
||||||
<ModalBox
|
<ModalBox
|
||||||
children={ <div id='testChild'>testChild</div> }
|
children={ CHILDREN }
|
||||||
icon={ <div id='testIcon'>testIcon</div> }
|
icon={ ICON }
|
||||||
summary={ <div id='testSummary'>testSummary</div> }
|
summary={ SUMMARY }
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -42,15 +46,17 @@ describe('ui/ModalBox', () => {
|
|||||||
expect(component).to.be.ok;
|
expect(component).to.be.ok;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds the children as supplied', () => {
|
|
||||||
expect(component.find('#testChild').text()).to.equal('testChild');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds the icon as supplied', () => {
|
it('adds the icon as supplied', () => {
|
||||||
expect(component.find('#testIcon').text()).to.equal('testIcon');
|
expect(component.find('#testIcon').text()).to.equal('testIcon');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds the summary as supplied', () => {
|
describe('components', () => {
|
||||||
expect(component.find('#testSummary').text()).to.equal('testSummary');
|
it('adds the Body as supplied', () => {
|
||||||
|
expect(component.find('Body').props().children).to.deep.equal(CHILDREN);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds the Summary as supplied', () => {
|
||||||
|
expect(component.find('Summary').props().summary).to.deep.equal(SUMMARY);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
37
js/src/ui/ModalBox/summary.js
Normal file
37
js/src/ui/ModalBox/summary.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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 React from 'react';
|
||||||
|
|
||||||
|
import { nodeOrStringProptype } from '~/util/proptypes';
|
||||||
|
|
||||||
|
import styles from './modalBox.css';
|
||||||
|
|
||||||
|
export default function Summary ({ summary }) {
|
||||||
|
if (!summary) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.summary }>
|
||||||
|
{ summary }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Summary.propTypes = {
|
||||||
|
summary: nodeOrStringProptype()
|
||||||
|
};
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
@ -65,7 +66,10 @@ class Embedded extends Component {
|
|||||||
if (!pending.length) {
|
if (!pending.length) {
|
||||||
return (
|
return (
|
||||||
<div className={ styles.none }>
|
<div className={ styles.none }>
|
||||||
There are currently no pending requests awaiting your confirmation
|
<FormattedMessage
|
||||||
|
id='signer.embedded.noPending'
|
||||||
|
defaultMessage='There are currently no pending requests awaiting your confirmation'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
// 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 BigNumber from 'bignumber.js';
|
||||||
import React, { Component, PropTypes } from 'react';
|
|
||||||
import { bindActionCreators } from 'redux';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component, PropTypes } from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
import Store from '../../store';
|
import Store from '../../store';
|
||||||
import * as RequestsActions from '~/redux/providers/signerActions';
|
import * as RequestsActions from '~/redux/providers/signerActions';
|
||||||
@ -74,7 +75,14 @@ class RequestsPage extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container title='Local Transactions'>
|
<Container
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='signer.requestsPage.queueTitle'
|
||||||
|
defaultMessage='Local Transactions'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
<TxList
|
<TxList
|
||||||
address=''
|
address=''
|
||||||
hashes={ localHashes }
|
hashes={ localHashes }
|
||||||
@ -90,7 +98,10 @@ class RequestsPage extends Component {
|
|||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<div className={ styles.noRequestsMsg }>
|
<div className={ styles.noRequestsMsg }>
|
||||||
There are no requests requiring your confirmation.
|
<FormattedMessage
|
||||||
|
id='signer.requestsPage.noPending'
|
||||||
|
defaultMessage='There are no requests requiring your confirmation.'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
@ -99,7 +110,14 @@ class RequestsPage extends Component {
|
|||||||
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
const items = pending.sort(this._sortRequests).map(this.renderPending);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container title='Pending Requests'>
|
<Container
|
||||||
|
title={
|
||||||
|
<FormattedMessage
|
||||||
|
id='signer.requestsPage.pendingTitle'
|
||||||
|
defaultMessage='Pending Requests'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
{ items }
|
{ items }
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user