Fixes to the Registry dapp (#4984)
* Don't show fee warning when there is none * Hide Warning in Registry onclick * Use the default account in the Registry * Fix Etherscan links in Regsitry
This commit is contained in:
parent
b725829bfd
commit
a028e445fe
@ -42,7 +42,7 @@ export default class Personal {
|
|||||||
|
|
||||||
// FIXME: Because of the different API instances, the "wait for valid changes" approach
|
// FIXME: Because of the different API instances, the "wait for valid changes" approach
|
||||||
// doesn't work. Since the defaultAccount is critical to operation, we poll in exactly
|
// doesn't work. Since the defaultAccount is critical to operation, we poll in exactly
|
||||||
// same way we do in ../eth (ala same as eth_blockNumber) and update. This should be moved
|
// same way we do in ../eth (ala eth_blockNumber) and update. This should be moved
|
||||||
// to pub-sub as it becomes available
|
// to pub-sub as it becomes available
|
||||||
_defaultAccount = (timerDisabled = false) => {
|
_defaultAccount = (timerDisabled = false) => {
|
||||||
const nextTimeout = (timeout = 1000) => {
|
const nextTimeout = (timeout = 1000) => {
|
||||||
|
@ -15,24 +15,10 @@
|
|||||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.button {
|
|
||||||
/* TODO remove !important once material design lite is used */
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
/* TODO remove !important once material design lite is used */
|
/* TODO remove !important once material design lite is used */
|
||||||
margin: 0 !important;
|
|
||||||
width: 30px !important;
|
|
||||||
height: 30px !important;
|
height: 30px !important;
|
||||||
}
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
.menuIcon {
|
width: 30px !important;
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.menuText {
|
|
||||||
display: inline-block;
|
|
||||||
line-height: 24px;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
}
|
||||||
|
@ -17,83 +17,50 @@
|
|||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import IconMenu from 'material-ui/IconMenu';
|
|
||||||
import IconButton from 'material-ui/IconButton/IconButton';
|
|
||||||
import AccountIcon from 'material-ui/svg-icons/action/account-circle';
|
import AccountIcon from 'material-ui/svg-icons/action/account-circle';
|
||||||
import MenuItem from 'material-ui/MenuItem';
|
|
||||||
|
|
||||||
|
import { init } from './actions';
|
||||||
import IdentityIcon from '../IdentityIcon';
|
import IdentityIcon from '../IdentityIcon';
|
||||||
import Address from '../ui/address';
|
|
||||||
|
|
||||||
import { select } from './actions';
|
|
||||||
import styles from './accounts.css';
|
import styles from './accounts.css';
|
||||||
|
|
||||||
class Accounts extends Component {
|
class Accounts extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
all: PropTypes.object.isRequired,
|
selected: PropTypes.oneOfType([
|
||||||
selected: PropTypes.object,
|
PropTypes.oneOf([ null ]),
|
||||||
|
PropTypes.string
|
||||||
|
]),
|
||||||
|
onInit: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
select: PropTypes.func.isRequired
|
componentWillMount () {
|
||||||
|
this.props.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { all, selected } = this.props;
|
const { selected } = this.props;
|
||||||
|
|
||||||
const origin = { horizontal: 'right', vertical: 'top' };
|
if (!selected) {
|
||||||
|
return (
|
||||||
const accountsButton = (
|
|
||||||
<IconButton className={ styles.button }>
|
|
||||||
{ selected
|
|
||||||
? (
|
|
||||||
<IdentityIcon
|
|
||||||
className={ styles.icon }
|
|
||||||
address={ selected.address }
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<AccountIcon
|
<AccountIcon
|
||||||
className={ styles.icon }
|
className={ styles.icon }
|
||||||
color='white'
|
color='white'
|
||||||
/>
|
/>
|
||||||
)
|
|
||||||
}
|
|
||||||
</IconButton>);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<IconMenu
|
|
||||||
value={ selected ? this.renderAccount(selected) : null }
|
|
||||||
onChange={ this.onAccountSelect }
|
|
||||||
iconButtonElement={ accountsButton }
|
|
||||||
|
|
||||||
anchorOrigin={ origin }
|
|
||||||
targetOrigin={ origin }
|
|
||||||
>
|
|
||||||
{ Object.values(all).map(this.renderAccount) }
|
|
||||||
</IconMenu>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAccount = (account) => {
|
|
||||||
const { selected } = this.props;
|
|
||||||
const isSelected = selected && selected.address === account.address;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuItem
|
<IdentityIcon
|
||||||
key={ account.address }
|
className={ styles.icon }
|
||||||
value={ account.address }
|
address={ selected }
|
||||||
checked={ isSelected }
|
/>
|
||||||
insetChildren={ !isSelected }
|
|
||||||
>
|
|
||||||
<Address address={ account.address } />
|
|
||||||
</MenuItem>
|
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
onAccountSelect = (e, address) => {
|
|
||||||
this.props.select(address);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state) => state.accounts;
|
const mapStateToProps = (state) => state.accounts;
|
||||||
const mapDispatchToProps = (dispatch) => bindActionCreators({ select }, dispatch);
|
const mapDispatchToProps = (dispatch) => bindActionCreators({
|
||||||
|
onInit: init
|
||||||
|
}, dispatch);
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Accounts);
|
export default connect(mapStateToProps, mapDispatchToProps)(Accounts);
|
||||||
|
@ -14,4 +14,27 @@
|
|||||||
// 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 { api } from '../parity';
|
||||||
|
|
||||||
export const select = (address) => ({ type: 'accounts select', address });
|
export const select = (address) => ({ type: 'accounts select', address });
|
||||||
|
|
||||||
|
export const init = () => (dispatch) => {
|
||||||
|
api.subscribe('parity_defaultAccount', (error, accountAddress) => {
|
||||||
|
if (error) {
|
||||||
|
return console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accountAddress) {
|
||||||
|
dispatch(select(accountAddress));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return api.parity
|
||||||
|
.defaultAccount()
|
||||||
|
.then((accountAddress) => {
|
||||||
|
dispatch(select(accountAddress));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -16,9 +16,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: 0; padding: .3em 1em;
|
margin: 0;
|
||||||
|
padding: 0.3em 1em;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
}
|
}
|
||||||
@ -54,6 +56,7 @@
|
|||||||
background: #f80;
|
background: #f80;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
left: 0;
|
left: 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
|
@ -49,6 +49,10 @@ export default class Application extends Component {
|
|||||||
fee: nullableProptype(PropTypes.object.isRequired)
|
fee: nullableProptype(PropTypes.object.isRequired)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
showWarning: true
|
||||||
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { contract, fee } = this.props;
|
const { contract, fee } = this.props;
|
||||||
let warning = null;
|
let warning = null;
|
||||||
@ -65,9 +69,7 @@ export default class Application extends Component {
|
|||||||
<Lookup />
|
<Lookup />
|
||||||
{ this.renderActions() }
|
{ this.renderActions() }
|
||||||
<Events />
|
<Events />
|
||||||
<div className={ styles.warning }>
|
{ this.renderWarning() }
|
||||||
WARNING: The name registry is experimental. Please ensure that you understand the risks, benefits & consequences of registering a name before doing so. A non-refundable fee of { api.util.fromWei(fee).toFormat(3) }<small>ETH</small> is required for all registrations.
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<CircularProgress size={ 60 } />
|
<CircularProgress size={ 60 } />
|
||||||
@ -98,4 +100,39 @@ export default class Application extends Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderWarning () {
|
||||||
|
const { showWarning } = this.state;
|
||||||
|
const { fee } = this.props;
|
||||||
|
|
||||||
|
if (!showWarning) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ styles.warning }
|
||||||
|
onClick={ this.handleHideWarning }
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
WARNING: The name registry is experimental. Please ensure that you understand the risks,
|
||||||
|
benefits & consequences of registering a name before doing so.
|
||||||
|
</span>
|
||||||
|
{
|
||||||
|
fee && api.util.fromWei(fee).gt(0)
|
||||||
|
? (
|
||||||
|
<span>
|
||||||
|
A non-refundable fee of { api.util.fromWei(fee).toFormat(3) } <small>ETH</small>
|
||||||
|
is required for all registrations.
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHideWarning = () => {
|
||||||
|
this.setState({ showWarning: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,11 @@ export const reserveFail = (name, error) => ({ type: 'names reserve fail', name,
|
|||||||
|
|
||||||
export const reserve = (name) => (dispatch, getState) => {
|
export const reserve = (name) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = state.accounts.selected;
|
const accountAddress = state.accounts.selected;
|
||||||
const contract = state.contract;
|
const contract = state.contract;
|
||||||
const fee = state.fee;
|
const fee = state.fee;
|
||||||
|
|
||||||
if (!contract || !account) {
|
if (!contract || !accountAddress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ export const reserve = (name) => (dispatch, getState) => {
|
|||||||
const { reserve } = contract.instance;
|
const { reserve } = contract.instance;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: account.address,
|
from: accountAddress,
|
||||||
value: fee
|
value: fee
|
||||||
};
|
};
|
||||||
const values = [
|
const values = [
|
||||||
@ -88,10 +88,10 @@ export const dropFail = (name, error) => ({ type: 'names drop fail', name, error
|
|||||||
|
|
||||||
export const drop = (name) => (dispatch, getState) => {
|
export const drop = (name) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = state.accounts.selected;
|
const accountAddress = state.accounts.selected;
|
||||||
const contract = state.contract;
|
const contract = state.contract;
|
||||||
|
|
||||||
if (!contract || !account) {
|
if (!contract || !accountAddress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,14 +105,14 @@ export const drop = (name) => (dispatch, getState) => {
|
|||||||
|
|
||||||
return getOwner(contract, name)
|
return getOwner(contract, name)
|
||||||
.then((owner) => {
|
.then((owner) => {
|
||||||
if (owner.toLowerCase() !== account.address.toLowerCase()) {
|
if (owner.toLowerCase() !== accountAddress.toLowerCase()) {
|
||||||
throw new Error(`you are not the owner of "${name}"`);
|
throw new Error(`you are not the owner of "${name}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { drop } = contract.instance;
|
const { drop } = contract.instance;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: account.address
|
from: accountAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
|
@ -30,10 +30,10 @@ export const fail = (error) => ({ type: 'records update fail', error });
|
|||||||
|
|
||||||
export const update = (name, key, value) => (dispatch, getState) => {
|
export const update = (name, key, value) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = state.accounts.selected;
|
const accountAddress = state.accounts.selected;
|
||||||
const contract = state.contract;
|
const contract = state.contract;
|
||||||
|
|
||||||
if (!contract || !account) {
|
if (!contract || !accountAddress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ export const update = (name, key, value) => (dispatch, getState) => {
|
|||||||
|
|
||||||
return getOwner(contract, name)
|
return getOwner(contract, name)
|
||||||
.then((owner) => {
|
.then((owner) => {
|
||||||
if (owner.toLowerCase() !== account.address.toLowerCase()) {
|
if (owner.toLowerCase() !== accountAddress.toLowerCase()) {
|
||||||
throw new Error(`you are not the owner of "${name}"`);
|
throw new Error(`you are not the owner of "${name}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ export const update = (name, key, value) => (dispatch, getState) => {
|
|||||||
: contract.instance.setData || contract.instance.set;
|
: contract.instance.setData || contract.instance.set;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: account.address
|
from: accountAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
|
@ -30,10 +30,10 @@ export const fail = (action, error) => ({ type: `reverse ${action} fail`, error
|
|||||||
|
|
||||||
export const propose = (name, address) => (dispatch, getState) => {
|
export const propose = (name, address) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = state.accounts.selected;
|
const accountAddress = state.accounts.selected;
|
||||||
const contract = state.contract;
|
const contract = state.contract;
|
||||||
|
|
||||||
if (!contract || !account) {
|
if (!contract || !accountAddress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ export const propose = (name, address) => (dispatch, getState) => {
|
|||||||
|
|
||||||
return getOwner(contract, name)
|
return getOwner(contract, name)
|
||||||
.then((owner) => {
|
.then((owner) => {
|
||||||
if (owner.toLowerCase() !== account.address.toLowerCase()) {
|
if (owner.toLowerCase() !== accountAddress.toLowerCase()) {
|
||||||
throw new Error(`you are not the owner of "${name}"`);
|
throw new Error(`you are not the owner of "${name}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { proposeReverse } = contract.instance;
|
const { proposeReverse } = contract.instance;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: account.address
|
from: accountAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
@ -74,10 +74,10 @@ export const propose = (name, address) => (dispatch, getState) => {
|
|||||||
|
|
||||||
export const confirm = (name) => (dispatch, getState) => {
|
export const confirm = (name) => (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const account = state.accounts.selected;
|
const accountAddress = state.accounts.selected;
|
||||||
const contract = state.contract;
|
const contract = state.contract;
|
||||||
|
|
||||||
if (!contract || !account) {
|
if (!contract || !accountAddress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,14 +86,14 @@ export const confirm = (name) => (dispatch, getState) => {
|
|||||||
|
|
||||||
return getOwner(contract, name)
|
return getOwner(contract, name)
|
||||||
.then((owner) => {
|
.then((owner) => {
|
||||||
if (owner.toLowerCase() !== account.address.toLowerCase()) {
|
if (owner.toLowerCase() !== accountAddress.toLowerCase()) {
|
||||||
throw new Error(`you are not the owner of "${name}"`);
|
throw new Error(`you are not the owner of "${name}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { confirmReverse } = contract.instance;
|
const { confirmReverse } = contract.instance;
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: account.address
|
from: accountAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
|
@ -31,8 +31,8 @@ export default (state = initialState, action) => {
|
|||||||
return { ...state, all: accounts };
|
return { ...state, all: accounts };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === 'accounts select' && state.all[action.address]) {
|
if (action.type === 'accounts select') {
|
||||||
return { ...state, selected: state.all[action.address] };
|
return { ...state, selected: action.address };
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
@ -22,7 +22,7 @@ const etherscanUrl = (hash, isTestnet, netVersion) => {
|
|||||||
hash = hash.toLowerCase().replace(leading0x, '');
|
hash = hash.toLowerCase().replace(leading0x, '');
|
||||||
const type = hash.length === 40 ? 'address' : 'tx';
|
const type = hash.length === 40 ? 'address' : 'tx';
|
||||||
|
|
||||||
return `https://${externalUrl(isTestnet, netVersion)}/${type}/0x${hash}`;
|
return `${externalUrl(isTestnet, netVersion)}/${type}/0x${hash}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default etherscanUrl;
|
export default etherscanUrl;
|
||||||
|
Loading…
Reference in New Issue
Block a user