diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js
index 674091563..22b3f9751 100644
--- a/js/src/api/rpc/parity/parity.js
+++ b/js/src/api/rpc/parity/parity.js
@@ -39,9 +39,9 @@ export default class Parity {
.then(outAccountInfo);
}
- addReservedPeer (encode) {
+ addReservedPeer (enode) {
return this._transport
- .execute('parity_addReservedPeer', encode);
+ .execute('parity_addReservedPeer', enode);
}
chainStatus () {
@@ -429,9 +429,9 @@ export default class Parity {
.execute('parity_releasesInfo');
}
- removeReservedPeer (encode) {
+ removeReservedPeer (enode) {
return this._transport
- .execute('parity_removeReservedPeer', encode);
+ .execute('parity_removeReservedPeer', enode);
}
removeTransaction (hash) {
diff --git a/js/src/ui/Container/Title/title.css b/js/src/ui/Container/Title/title.css
index 64317600c..1c0383bd2 100644
--- a/js/src/ui/Container/Title/title.css
+++ b/js/src/ui/Container/Title/title.css
@@ -21,6 +21,12 @@ $bylineMaxHeight: 2.4rem;
$titleLineHeight: 2rem;
$smallFontSize: 0.75rem;
+.container {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
.byline,
.description {
color: $bylineColor;
diff --git a/js/src/ui/Container/Title/title.js b/js/src/ui/Container/Title/title.js
index 217ad13bf..50f6cc2e5 100644
--- a/js/src/ui/Container/Title/title.js
+++ b/js/src/ui/Container/Title/title.js
@@ -22,22 +22,44 @@ import styles from './title.css';
export default class Title extends Component {
static propTypes = {
+ actions: PropTypes.array,
byline: nodeOrStringProptype(),
className: PropTypes.string,
description: nodeOrStringProptype(),
title: nodeOrStringProptype()
- }
+ };
+
+ static defaultProps = {
+ actions: []
+ };
render () {
const { className, title } = this.props;
return (
-
-
- { title }
-
- { this.renderByline() }
- { this.renderDescription() }
+
+
+
+ { title }
+
+ { this.renderByline() }
+ { this.renderDescription() }
+
+ { this.renderActions() }
+
+ );
+ }
+
+ renderActions () {
+ const { actions } = this.props;
+
+ if (actions.length === 0) {
+ return null;
+ }
+
+ return (
+
+ { actions }
);
}
diff --git a/js/src/views/Application/Snackbar/snackbar.js b/js/src/views/Application/Snackbar/snackbar.js
index 8965d9f28..a93161abc 100644
--- a/js/src/views/Application/Snackbar/snackbar.js
+++ b/js/src/views/Application/Snackbar/snackbar.js
@@ -27,7 +27,8 @@ const bodyStyle = {
backgroundColor: darkBlack,
borderStyle: 'solid',
borderColor: grey800,
- borderWidth: '1px 1px 0 1px'
+ borderWidth: '1px 1px 0 1px',
+ minWidth: 0
};
class Snackbar extends Component {
diff --git a/js/src/views/Status/Peers/peers.css b/js/src/views/Status/Peers/peers.css
index 854d91cb0..a164aea81 100644
--- a/js/src/views/Status/Peers/peers.css
+++ b/js/src/views/Status/Peers/peers.css
@@ -45,3 +45,16 @@
white-space: nowrap;
}
}
+
+.form {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ float: right;
+ width: 40em;
+
+ .input {
+ flex: 1;
+ margin-right: 1em;
+ }
+}
diff --git a/js/src/views/Status/Peers/peers.js b/js/src/views/Status/Peers/peers.js
index 43fcbff30..08bed0955 100644
--- a/js/src/views/Status/Peers/peers.js
+++ b/js/src/views/Status/Peers/peers.js
@@ -16,23 +16,84 @@
import React, { Component, PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
+import { bindActionCreators } from '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';
class Peers extends Component {
- static propTypes = {
- peers: PropTypes.array.isRequired
+ static contextTypes = {
+ api: PropTypes.object
};
+ static propTypes = {
+ peers: PropTypes.array.isRequired,
+ newError: PropTypes.func,
+ showSnackbar: PropTypes.func
+ };
+
+ state = {
+ action: '',
+ formInput: '',
+ showForm: false
+ };
+
+ getActions () {
+ return [
+
+ }
+ onClick={ this.handleAcceptNonReserved }
+ />,
+
+ }
+ onClick={ this.handleDropNonReserved }
+ />,
+
+ }
+ onClick={ this.handleAddReserved }
+ />,
+
+ }
+ onClick={ this.handleRemoveReserved }
+ />
+ ];
+ }
+
render () {
const { peers } = this.props;
return (
}
/>
+ { this.renderForm() }
@@ -92,6 +154,52 @@ class Peers extends Component {
);
}
+ renderForm () {
+ const { action, showForm } = this.state;
+
+ if (!showForm) {
+ return null;
+ }
+
+ return (
+
+
+
+ }
+ onChange={ this.handleInputChange }
+ />
+
+
+ }
+ onClick={ this.handleConfirmForm }
+ />
+
+ }
+ onClick={ this.handleCancelForm }
+ />
+
+ );
+ }
+
renderPeers (peers) {
return peers.map((peer, index) => this.renderPeer(peer, index));
}
@@ -140,6 +248,92 @@ class Peers extends Component {
);
}
+
+ handleAcceptNonReserved = () => {
+ return this.context.api.parity.acceptNonReservedPeers()
+ .then(() => {
+ const message = (
+
+ );
+
+ this.props.showSnackbar(message, 3000);
+ })
+ .catch((error) => {
+ this.props.newError(error);
+ });
+ };
+
+ handleDropNonReserved = () => {
+ return this.context.api.parity.dropNonReservedPeers()
+ .then(() => {
+ const message = (
+
+ );
+
+ 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 = (
+
+ );
+
+ this.props.showSnackbar(message, 3000);
+ })
+ .catch((error) => {
+ this.props.newError(error);
+ });
+ };
}
function mapStateToProps (state) {
@@ -160,4 +354,11 @@ function mapStateToProps (state) {
return { peers: realPeers };
}
-export default connect(mapStateToProps)(Peers);
+function mapDispatchToProps (dispatch) {
+ return bindActionCreators({
+ newError,
+ showSnackbar
+ }, dispatch);
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Peers);