diff --git a/js/src/ui/TxList/TxRow/txRow.js b/js/src/ui/TxList/TxRow/txRow.js index 10f78307c..e42f64159 100644 --- a/js/src/ui/TxList/TxRow/txRow.js +++ b/js/src/ui/TxList/TxRow/txRow.js @@ -16,8 +16,10 @@ import moment from 'moment'; import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; -import { txLink, addressLink } from '~/3rdparty/etherscan/links'; +import { txLink } from '~/3rdparty/etherscan/links'; import IdentityIcon from '../../IdentityIcon'; import IdentityName from '../../IdentityName'; @@ -25,19 +27,20 @@ import MethodDecoding from '../../MethodDecoding'; import styles from '../txList.css'; -export default class TxRow extends Component { +class TxRow extends Component { static contextTypes = { api: PropTypes.object.isRequired }; static propTypes = { - tx: PropTypes.object.isRequired, + accountAddresses: PropTypes.array.isRequired, address: PropTypes.string.isRequired, isTest: PropTypes.bool.isRequired, + tx: PropTypes.object.isRequired, block: PropTypes.object, - historic: PropTypes.bool, - className: PropTypes.string + className: PropTypes.string, + historic: PropTypes.bool }; static defaultProps = { @@ -77,22 +80,20 @@ export default class TxRow extends Component { } renderAddress (address) { - const { isTest } = this.props; - let esLink = null; if (address) { esLink = ( - - + ); } @@ -138,4 +139,30 @@ export default class TxRow extends Component { ); } + + addressLink (address) { + const { accountAddresses } = this.props; + const isAccount = accountAddresses.includes(address); + + if (isAccount) { + return `/accounts/${address}`; + } + + return `/addresses/${address}`; + } } + +function mapStateToProps (initState) { + const { accounts } = initState.personal; + const accountAddresses = Object.keys(accounts); + + return () => { + return { accountAddresses }; + }; +} + +export default connect( + mapStateToProps, + null +)(TxRow); + diff --git a/js/src/ui/TxList/TxRow/txRow.spec.js b/js/src/ui/TxList/TxRow/txRow.spec.js index f46f2e7fa..dc9f4d3cc 100644 --- a/js/src/ui/TxList/TxRow/txRow.spec.js +++ b/js/src/ui/TxList/TxRow/txRow.spec.js @@ -25,13 +25,28 @@ import TxRow from './txRow'; const api = new Api({ execute: sinon.stub() }); +const STORE = { + dispatch: sinon.stub(), + subscribe: sinon.stub(), + getState: () => { + return { + personal: { + accounts: { + '0x123': {} + } + } + }; + } +}; + function render (props) { return shallow( , { context: { api } } - ); + ).find('TxRow').shallow({ context: { api } }); } describe('ui/TxList/TxRow', () => { @@ -48,5 +63,37 @@ describe('ui/TxList/TxRow', () => { expect(render({ address: '0x123', block, isTest: true, tx })).to.be.ok; }); + + it('renders an account link', () => { + const block = { + timestamp: new Date() + }; + const tx = { + blockNumber: new BigNumber(123), + hash: '0x123456789abcdef0123456789abcdef0123456789abcdef', + to: '0x123', + value: new BigNumber(1) + }; + + const element = render({ address: '0x123', block, isTest: true, tx }); + + expect(element.find('Link').prop('to')).to.equal('/accounts/0x123'); + }); + + it('renders an address link', () => { + const block = { + timestamp: new Date() + }; + const tx = { + blockNumber: new BigNumber(123), + hash: '0x123456789abcdef0123456789abcdef0123456789abcdef', + to: '0x456', + value: new BigNumber(1) + }; + + const element = render({ address: '0x123', block, isTest: true, tx }); + + expect(element.find('Link').prop('to')).to.equal('/addresses/0x456'); + }); }); }); diff --git a/js/src/ui/TxList/txList.css b/js/src/ui/TxList/txList.css index 3913fea33..a38ba14fd 100644 --- a/js/src/ui/TxList/txList.css +++ b/js/src/ui/TxList/txList.css @@ -65,6 +65,11 @@ .link { vertical-align: top; + + &.currentLink { + color: white; + cursor: text; + } } .right { diff --git a/js/src/views/ParityBar/parityBar.js b/js/src/views/ParityBar/parityBar.js index 63036b9e4..ac251d0a3 100644 --- a/js/src/views/ParityBar/parityBar.js +++ b/js/src/views/ParityBar/parityBar.js @@ -285,6 +285,7 @@ class ParityBar extends Component { } renderExpanded () { + const { externalLink } = this.props; const { displayType } = this.state; return ( @@ -333,7 +334,7 @@ class ParityBar extends Component { /> ) : ( - + ) } diff --git a/js/src/views/Signer/components/Account/AccountLink/accountLink.js b/js/src/views/Signer/components/Account/AccountLink/accountLink.js index 265642246..81f25f4e1 100644 --- a/js/src/views/Signer/components/Account/AccountLink/accountLink.js +++ b/js/src/views/Signer/components/Account/AccountLink/accountLink.js @@ -15,16 +15,19 @@ // along with Parity. If not, see . import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; -import { addressLink } from '~/3rdparty/etherscan/links'; import styles from './accountLink.css'; -export default class AccountLink extends Component { +class AccountLink extends Component { static propTypes = { - isTest: PropTypes.bool.isRequired, + accountAddresses: PropTypes.array.isRequired, address: PropTypes.string.isRequired, className: PropTypes.string, - children: PropTypes.node + children: PropTypes.node, + externalLink: PropTypes.string.isRequired, + isTest: PropTypes.bool.isRequired } state = { @@ -32,36 +35,72 @@ export default class AccountLink extends Component { }; componentWillMount () { - const { address, isTest } = this.props; + const { address, externalLink, isTest } = this.props; - this.updateLink(address, isTest); + this.updateLink(address, externalLink, isTest); } componentWillReceiveProps (nextProps) { - const { address, isTest } = nextProps; + const { address, externalLink, isTest } = nextProps; - this.updateLink(address, isTest); + this.updateLink(address, externalLink, isTest); } render () { - const { children, address, className } = this.props; + const { children, address, className, externalLink } = this.props; + + if (externalLink) { + return ( + + { children || address } + + ); + } return ( - { children || address } - + ); } - updateLink (address, isTest) { - const link = addressLink(address, isTest); + updateLink (address, externalLink, isTest) { + const { accountAddresses } = this.props; + const isAccount = accountAddresses.includes(address); + + let link = isAccount + ? `/accounts/${address}` + : `/addresses/${address}`; + + if (externalLink) { + const path = externalLink.replace(/\/+$/, ''); + + link = `${path}/#${link}`; + } this.setState({ link }); } } + +function mapStateToProps (initState) { + const { accounts } = initState.personal; + const accountAddresses = Object.keys(accounts); + + return () => { + return { accountAddresses }; + }; +} + +export default connect( + mapStateToProps, + null +)(AccountLink); diff --git a/js/src/views/Signer/components/Account/account.js b/js/src/views/Signer/components/Account/account.js index b2b109634..1a7197d1a 100644 --- a/js/src/views/Signer/components/Account/account.js +++ b/js/src/views/Signer/components/Account/account.js @@ -25,6 +25,7 @@ export default class Account extends Component { static propTypes = { className: PropTypes.string, address: PropTypes.string.isRequired, + externalLink: PropTypes.string.isRequired, isTest: PropTypes.bool.isRequired, balance: PropTypes.object // eth BigNumber, not required since it mght take time to fetch }; @@ -51,12 +52,13 @@ export default class Account extends Component { } render () { - const { address, isTest, className } = this.props; + const { address, externalLink, isTest, className } = this.props; return (
; if (!name) { return ( [{ this.shortAddress(address) }] @@ -96,6 +99,7 @@ export default class Account extends Component { return ( diff --git a/js/src/views/Signer/components/SignRequest/signRequest.js b/js/src/views/Signer/components/SignRequest/signRequest.js index c76769763..21f5211e6 100644 --- a/js/src/views/Signer/components/SignRequest/signRequest.js +++ b/js/src/views/Signer/components/SignRequest/signRequest.js @@ -93,7 +93,9 @@ export default class SignRequest extends Component { renderDetails () { const { api } = this.context; const { address, isTest, store, data } = this.props; - const balance = store.balances[address]; + const { balances, externalLink } = store; + + const balance = balances[address]; if (!balance) { return
; @@ -105,6 +107,7 @@ export default class SignRequest extends Component {
diff --git a/js/src/views/Signer/components/TransactionMainDetails/transactionMainDetails.js b/js/src/views/Signer/components/TransactionMainDetails/transactionMainDetails.js index 812d1fb35..e73fee922 100644 --- a/js/src/views/Signer/components/TransactionMainDetails/transactionMainDetails.js +++ b/js/src/views/Signer/components/TransactionMainDetails/transactionMainDetails.js @@ -27,6 +27,7 @@ import styles from './transactionMainDetails.css'; export default class TransactionMainDetails extends Component { static propTypes = { children: PropTypes.node, + externalLink: PropTypes.string.isRequired, from: PropTypes.string.isRequired, fromBalance: PropTypes.object, gasStore: PropTypes.object, @@ -50,7 +51,7 @@ export default class TransactionMainDetails extends Component { } render () { - const { children, from, fromBalance, gasStore, isTest, transaction } = this.props; + const { children, externalLink, from, fromBalance, gasStore, isTest, transaction } = this.props; return (
@@ -59,6 +60,7 @@ export default class TransactionMainDetails extends Component {
diff --git a/js/src/views/Signer/components/TransactionPending/transactionPending.js b/js/src/views/Signer/components/TransactionPending/transactionPending.js index a49f5c2e0..1a96d0144 100644 --- a/js/src/views/Signer/components/TransactionPending/transactionPending.js +++ b/js/src/views/Signer/components/TransactionPending/transactionPending.js @@ -89,14 +89,16 @@ export default class TransactionPending extends Component { renderTransaction () { const { className, focus, id, isSending, isTest, store, transaction } = this.props; const { totalValue } = this.state; + const { balances, externalLink } = store; const { from, value } = transaction; - const fromBalance = store.balances[from]; + const fromBalance = balances[from]; return (