Add peer management to the Status tab (#5566)
* Add peer management to the Status tab * Fix propTypes issue
This commit is contained in:
parent
945c1a9478
commit
0f1a857576
@ -39,9 +39,9 @@ export default class Parity {
|
|||||||
.then(outAccountInfo);
|
.then(outAccountInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
addReservedPeer (encode) {
|
addReservedPeer (enode) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_addReservedPeer', encode);
|
.execute('parity_addReservedPeer', enode);
|
||||||
}
|
}
|
||||||
|
|
||||||
chainStatus () {
|
chainStatus () {
|
||||||
@ -429,9 +429,9 @@ export default class Parity {
|
|||||||
.execute('parity_releasesInfo');
|
.execute('parity_releasesInfo');
|
||||||
}
|
}
|
||||||
|
|
||||||
removeReservedPeer (encode) {
|
removeReservedPeer (enode) {
|
||||||
return this._transport
|
return this._transport
|
||||||
.execute('parity_removeReservedPeer', encode);
|
.execute('parity_removeReservedPeer', enode);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTransaction (hash) {
|
removeTransaction (hash) {
|
||||||
|
@ -21,6 +21,12 @@ $bylineMaxHeight: 2.4rem;
|
|||||||
$titleLineHeight: 2rem;
|
$titleLineHeight: 2rem;
|
||||||
$smallFontSize: 0.75rem;
|
$smallFontSize: 0.75rem;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.byline,
|
.byline,
|
||||||
.description {
|
.description {
|
||||||
color: $bylineColor;
|
color: $bylineColor;
|
||||||
|
@ -22,22 +22,44 @@ import styles from './title.css';
|
|||||||
|
|
||||||
export default class Title extends Component {
|
export default class Title extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
actions: PropTypes.array,
|
||||||
byline: nodeOrStringProptype(),
|
byline: nodeOrStringProptype(),
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
description: nodeOrStringProptype(),
|
description: nodeOrStringProptype(),
|
||||||
title: nodeOrStringProptype()
|
title: nodeOrStringProptype()
|
||||||
}
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
actions: []
|
||||||
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, title } = this.props;
|
const { className, title } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ className }>
|
<div className={ [ className, styles.container ].join(' ') }>
|
||||||
<h3 className={ styles.title }>
|
<div>
|
||||||
{ title }
|
<h3 className={ styles.title }>
|
||||||
</h3>
|
{ title }
|
||||||
{ this.renderByline() }
|
</h3>
|
||||||
{ this.renderDescription() }
|
{ this.renderByline() }
|
||||||
|
{ this.renderDescription() }
|
||||||
|
</div>
|
||||||
|
{ this.renderActions() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderActions () {
|
||||||
|
const { actions } = this.props;
|
||||||
|
|
||||||
|
if (actions.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ actions }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,8 @@ const bodyStyle = {
|
|||||||
backgroundColor: darkBlack,
|
backgroundColor: darkBlack,
|
||||||
borderStyle: 'solid',
|
borderStyle: 'solid',
|
||||||
borderColor: grey800,
|
borderColor: grey800,
|
||||||
borderWidth: '1px 1px 0 1px'
|
borderWidth: '1px 1px 0 1px',
|
||||||
|
minWidth: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
class Snackbar extends Component {
|
class Snackbar extends Component {
|
||||||
|
@ -45,3 +45,16 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
float: right;
|
||||||
|
width: 40em;
|
||||||
|
|
||||||
|
.input {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,23 +16,84 @@
|
|||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { Container, ContainerTitle, ScrollableText, ShortenedHash } from '~/ui';
|
import { Button, Container, ContainerTitle, Input, ScrollableText, ShortenedHash } from '~/ui';
|
||||||
|
import { showSnackbar } from '~/redux/providers/snackbarActions';
|
||||||
|
import { newError } from '~/redux/actions';
|
||||||
|
|
||||||
import styles from './peers.css';
|
import styles from './peers.css';
|
||||||
|
|
||||||
class Peers extends Component {
|
class Peers extends Component {
|
||||||
static propTypes = {
|
static contextTypes = {
|
||||||
peers: PropTypes.array.isRequired
|
api: PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
peers: PropTypes.array.isRequired,
|
||||||
|
newError: PropTypes.func,
|
||||||
|
showSnackbar: PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
action: '',
|
||||||
|
formInput: '',
|
||||||
|
showForm: false
|
||||||
|
};
|
||||||
|
|
||||||
|
getActions () {
|
||||||
|
return [
|
||||||
|
<Button
|
||||||
|
key='btn_acceptNonReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.acceptNonReserved.label'
|
||||||
|
defaultMessage='Accept non-reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleAcceptNonReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_dropNonReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.dropNonReserved.label'
|
||||||
|
defaultMessage='Drop non-reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleDropNonReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_addReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.addReserved.label'
|
||||||
|
defaultMessage='Add reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleAddReserved }
|
||||||
|
/>,
|
||||||
|
<Button
|
||||||
|
key='btn_removeReserved'
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.removeReserved.label'
|
||||||
|
defaultMessage='Remove reserved'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleRemoveReserved }
|
||||||
|
/>
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { peers } = this.props;
|
const { peers } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<ContainerTitle
|
<ContainerTitle
|
||||||
|
actions={ this.getActions() }
|
||||||
title={
|
title={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='status.peers.title'
|
id='status.peers.title'
|
||||||
@ -40,6 +101,7 @@ class Peers extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{ this.renderForm() }
|
||||||
<div className={ styles.peers }>
|
<div className={ styles.peers }>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -92,6 +154,52 @@ class Peers extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderForm () {
|
||||||
|
const { action, showForm } = this.state;
|
||||||
|
|
||||||
|
if (!showForm) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.form }>
|
||||||
|
<div className={ styles.input }>
|
||||||
|
<Input
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.label'
|
||||||
|
defaultMessage='Peer enode URL'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onChange={ this.handleInputChange }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.action.label'
|
||||||
|
defaultMessage='{add, select, true {Add} false {}}{remove, select, true {Remove} false {}}'
|
||||||
|
values={ {
|
||||||
|
add: action === 'add',
|
||||||
|
remove: action === 'remove'
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleConfirmForm }
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.cancel.label'
|
||||||
|
defaultMessage='Cancel'
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={ this.handleCancelForm }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderPeers (peers) {
|
renderPeers (peers) {
|
||||||
return peers.map((peer, index) => this.renderPeer(peer, index));
|
return peers.map((peer, index) => this.renderPeer(peer, index));
|
||||||
}
|
}
|
||||||
@ -140,6 +248,92 @@ class Peers extends Component {
|
|||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAcceptNonReserved = () => {
|
||||||
|
return this.context.api.parity.acceptNonReservedPeers()
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.acceptNonReservedPeers.success'
|
||||||
|
defaultMessage='Accepting non-reserved peers'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleDropNonReserved = () => {
|
||||||
|
return this.context.api.parity.dropNonReservedPeers()
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.dropNonReservedPeers.success'
|
||||||
|
defaultMessage='Dropping non-reserved peers'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddReserved = () => {
|
||||||
|
this.setState({ showForm: true, action: 'add' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRemoveReserved = () => {
|
||||||
|
this.setState({ showForm: true, action: 'remove' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleInputChange = (event, value) => {
|
||||||
|
this.setState({ formInput: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancelForm = () => {
|
||||||
|
this.setState({ showForm: false, action: '', formInput: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleConfirmForm = () => {
|
||||||
|
const { action, formInput } = this.state;
|
||||||
|
let method;
|
||||||
|
|
||||||
|
if (action === 'add') {
|
||||||
|
method = 'addReservedPeer';
|
||||||
|
} else if (action === 'remove') {
|
||||||
|
method = 'removeReservedPeer';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ showForm: false, action: '', formInput: '' });
|
||||||
|
|
||||||
|
if (!method) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.context.api.parity[method](formInput)
|
||||||
|
.then(() => {
|
||||||
|
const message = (
|
||||||
|
<FormattedMessage
|
||||||
|
id='peers.form.action.success'
|
||||||
|
defaultMessage='Successfully {add, select, true {added} false {}}{remove, select, true {removed} false {}} a reserved peer'
|
||||||
|
values={ {
|
||||||
|
add: action === 'add',
|
||||||
|
remove: action === 'remove'
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
this.props.showSnackbar(message, 3000);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.props.newError(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStateToProps (state) {
|
function mapStateToProps (state) {
|
||||||
@ -160,4 +354,11 @@ function mapStateToProps (state) {
|
|||||||
return { peers: realPeers };
|
return { peers: realPeers };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps)(Peers);
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({
|
||||||
|
newError,
|
||||||
|
showSnackbar
|
||||||
|
}, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Peers);
|
||||||
|
Loading…
Reference in New Issue
Block a user