diff --git a/app/components/Network/CanvasNetworkGraph.js b/app/components/Network/CanvasNetworkGraph.js index 936d752e..96e46cda 100644 --- a/app/components/Network/CanvasNetworkGraph.js +++ b/app/components/Network/CanvasNetworkGraph.js @@ -1,11 +1,13 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import * as d3Force from 'd3-force'; -import * as d3Selection from 'd3-selection'; -import * as d3Zoom from 'd3-zoom'; -const d3 = Object.assign({}, d3Force, d3Selection, d3Zoom) +import * as d3Force from 'd3-force' +import * as d3Selection from 'd3-selection' +import * as d3Zoom from 'd3-zoom' + import styles from './CanvasNetworkGraph.scss' +const d3 = Object.assign({}, d3Force, d3Selection, d3Zoom) + function generateSimulationData(nodes, edges) { const resNodes = nodes.map(node => Object.assign(node, { id: node.pub_key })) const resEdges = edges.map(node => Object.assign(node, { source: node.node1_pub, target: node.node2_pub })) @@ -39,21 +41,6 @@ class CanvasNetworkGraph extends Component { this.restart = this.restart.bind(this) } - componentWillReceiveProps(nextProps) { - const { network } = nextProps - const { simulationData: { nodes, links } } = this.state - - const simulationDataEmpty = !nodes.length && !links.length - const networkDataLoaded = network.nodes.length || network.edges.length - - // if the simulationData is empty and we have network data - if (simulationDataEmpty && networkDataLoaded) { - this.setState({ - simulationData: generateSimulationData(network.nodes, network.edges) - }) - } - } - componentDidMount() { // wait for the svg to be in the DOM before we start the simulation const svgInterval = setInterval(() => { @@ -71,24 +58,33 @@ class CanvasNetworkGraph extends Component { }, 1000) } + componentWillReceiveProps(nextProps) { + const { network } = nextProps + const { simulationData: { nodes, links } } = this.state + + const simulationDataEmpty = !nodes.length && !links.length + const networkDataLoaded = network.nodes.length || network.edges.length + const prevNetwork = this.props.network + + if ( + // update the simulationData only if + // the simulationData is empty and we have network data + (simulationDataEmpty && networkDataLoaded) || + // the nodes or edges have changed + (prevNetwork.nodes.length !== network.nodes.length || prevNetwork.edges.length !== network.edges.length)) { + this.setState({ + simulationData: generateSimulationData(network.nodes, network.edges) + }) + } + } + componentDidUpdate(prevProps) { const { - network: { nodes, edges }, selectedPeerPubkeys, selectedChannelIds, currentRouteChanIds } = this.props - const prevNodes = prevProps.network.nodes - const prevEdges = prevProps.network.edges - - // update the simulationData only if the nodes or edges have changed - if (prevNodes.length !== nodes.length || prevEdges.length !== edges.length) { - this.setState({ - simulationData: generateSimulationData(nodes, edges) - }) - } - if (prevProps.selectedPeerPubkeys.length !== selectedPeerPubkeys.length) { this.updateSelectedPeers() } @@ -111,10 +107,7 @@ class CanvasNetworkGraph extends Component { const { selectedPeerPubkeys } = this.props // remove active class - d3.selectAll('.active-peer') - .each(function () { - d3.select(this).classed('active-peer', false) - }) + d3.selectAll('.active-peer').classed('active-peer', false) // add active class to all selected peers selectedPeerPubkeys.forEach((pubkey) => { @@ -126,10 +119,7 @@ class CanvasNetworkGraph extends Component { const { selectedChannelIds } = this.props // remove active class - d3.selectAll('.active-channel') - .each(function () { - d3.select(this).classed('active-channel', false) - }) + d3.selectAll('.active-channel').classed('active-channel', false) // add active class to all selected peers selectedChannelIds.forEach((chanid) => { @@ -137,53 +127,6 @@ class CanvasNetworkGraph extends Component { }) } - renderSelectedRoute() { - const { currentRouteChanIds } = this.props - - // remove all route animations before rendering new ones - d3.selectAll('.animated-route-circle') - .each(function () { - d3.select(this).remove() - }) - - currentRouteChanIds.forEach((chanId) => { - const link = document.getElementById(`link-${chanId}`) - - if (!link) { return } - const x1 = link.x1.baseVal.value - const x2 = link.x2.baseVal.value - const y1 = link.y1.baseVal.value - const y2 = link.y2.baseVal.value - - // create the circle that represent btc traveling through a channel - this.g - .append('circle') - .attr('id', `circle-${chanId}`) - .attr('class', 'animated-route-circle') - .attr('r', 50) - .attr('cx', x1) - .attr('cy', y1) - .attr('fill', '#FFDC53') - - // we want the animation to repeat back and forth, this function executes that visually - const repeat = () => { - d3.select(`#circle-${chanId}`) - .transition() - .attr('cx', x2) - .attr('cy', y2) - .duration(1000) - .transition() - .duration(1000) - .attr('cx', x1) - .attr('cy', y1) - .on('end', repeat) - } - - // call repeat to animate the circle - repeat() - }) - } - startSimulation() { const { simulationData: { nodes, links } } = this.state @@ -235,7 +178,7 @@ class CanvasNetworkGraph extends Component { this.node = this.node.enter() .append('circle') .attr('stroke', () => 'silver') - .attr('fill', d => d.pub_key === identity_pubkey ? '#FFF' : '#353535') + .attr('fill', d => (d.pub_key === identity_pubkey ? '#FFF' : '#353535')) .attr('r', () => 100) .attr('id', d => `node-${d.pub_key}`) .attr('class', 'network-node') @@ -257,6 +200,50 @@ class CanvasNetworkGraph extends Component { this.simulation.restart() } + renderSelectedRoute() { + const { currentRouteChanIds } = this.props + + // remove all route animations before rendering new ones + d3.selectAll('.animated-route-circle').remove() + + currentRouteChanIds.forEach((chanId) => { + const link = document.getElementById(`link-${chanId}`) + + if (!link) { return } + const x1 = link.x1.baseVal.value + const x2 = link.x2.baseVal.value + const y1 = link.y1.baseVal.value + const y2 = link.y2.baseVal.value + + // create the circle that represent btc traveling through a channel + this.g + .append('circle') + .attr('id', `circle-${chanId}`) + .attr('class', 'animated-route-circle') + .attr('r', 50) + .attr('cx', x1) + .attr('cy', y1) + .attr('fill', '#FFDC53') + + // we want the animation to repeat back and forth, this function executes that visually + const repeat = () => { + d3.select(`#circle-${chanId}`) + .transition() + .attr('cx', x2) + .attr('cy', y2) + .duration(1000) + .transition() + .duration(1000) + .attr('cx', x1) + .attr('cy', y1) + .on('end', repeat) + } + + // call repeat to animate the circle + repeat() + }) + } + render() { const { svgLoaded } = this.state diff --git a/app/components/Network/ChannelsList.js b/app/components/Network/ChannelsList.js index 15b3fae7..3c1c55dc 100644 --- a/app/components/Network/ChannelsList.js +++ b/app/components/Network/ChannelsList.js @@ -7,7 +7,7 @@ import styles from './ChannelsList.scss' const ChannelsList = ({ channels, updateSelectedChannels, selectedChannelIds }) => ( ) diff --git a/app/components/Network/PeersList.js b/app/components/Network/PeersList.js index 42d75f58..a7364c69 100644 --- a/app/components/Network/PeersList.js +++ b/app/components/Network/PeersList.js @@ -5,13 +5,13 @@ import styles from './PeersList.scss' const PeersList = ({ peers, updateSelectedPeers, selectedPeerPubkeys }) => ( ) diff --git a/app/components/Network/TransactionForm.js b/app/components/Network/TransactionForm.js index 9c643b5a..f681b14c 100644 --- a/app/components/Network/TransactionForm.js +++ b/app/components/Network/TransactionForm.js @@ -24,8 +24,8 @@ const TransactionForm = ({ updatePayReq, pay_req, loadingRoutes, payReqRoutes, s diff --git a/app/containers/Root.js b/app/containers/Root.js index da0e6794..23bb5de7 100644 --- a/app/containers/Root.js +++ b/app/containers/Root.js @@ -23,7 +23,7 @@ const Root = ({ store, history, lnd, - fetchBlockHeight, + fetchBlockHeight, // eslint-disable-line no-shadow syncPercentage }) => { // If we are syncing show the syncing screen diff --git a/app/lnd/lib/lightning.js b/app/lnd/lib/lightning.js index bb1c1587..42670f90 100644 --- a/app/lnd/lib/lightning.js +++ b/app/lnd/lib/lightning.js @@ -7,6 +7,6 @@ module.exports = (rpcpath, host) => { const lndCert = fs.readFileSync(config.cert) const credentials = grpc.credentials.createSsl(lndCert) const rpc = grpc.load(path.join(__dirname, 'rpc.proto')) - + return new rpc.lnrpc.Lightning(host, credentials) } diff --git a/app/reducers/channels.js b/app/reducers/channels.js index e28f60d1..5d468a48 100644 --- a/app/reducers/channels.js +++ b/app/reducers/channels.js @@ -2,7 +2,6 @@ import { createSelector } from 'reselect' import { ipcRenderer } from 'electron' import { btc } from 'utils' import { showNotification } from 'notifications' -import { fetchDescribeNetwork } from './network' import { closeChannelForm, resetChannelForm } from './channelform' import { setError } from './error' // ------------------------------------ @@ -202,7 +201,7 @@ export const channelGraphData = (event, data) => (dispatch, getState) => { // if there are any new channel updates if (channel_updates.length) { // The network has updated, so fetch a new result - // TODO: can't do this now because of the SVG performance issues, after we fix this we can uncomment the line below + // TODO: can't do this now because of the SVG performance issues, after we fix this we can uncomment the line below // dispatch(fetchDescribeNetwork()) // loop through the channel updates diff --git a/app/reducers/network.js b/app/reducers/network.js index 6e482680..511ba41a 100644 --- a/app/reducers/network.js +++ b/app/reducers/network.js @@ -134,7 +134,8 @@ export const fetchDescribeNetwork = () => (dispatch) => { } // Receive IPC event for describeNetwork -export const receiveDescribeNetwork = (event, { nodes, edges }) => dispatch => dispatch({ type: RECEIVE_DESCRIBE_NETWORK, nodes, edges }) +export const receiveDescribeNetwork = (event, { nodes, edges }) => dispatch => + dispatch({ type: RECEIVE_DESCRIBE_NETWORK, nodes, edges }) export const queryRoutes = (pubkey, amount) => (dispatch) => { dispatch(getQueryRoutes(pubkey)) @@ -149,9 +150,9 @@ export const fetchInvoiceAndQueryRoutes = payreq => (dispatch) => { ipcRenderer.send('lnd', { msg: 'getInvoiceAndQueryRoutes', data: { payreq } }) } -export const receiveInvoiceAndQueryRoutes = (event, { routes }) => dispatch => { +export const receiveInvoiceAndQueryRoutes = (event, { routes }) => dispatch => dispatch({ type: RECEIVE_INFO_AND_QUERY_ROUTES, routes }) -} + // ------------------------------------ // Action Handlers // ------------------------------------ @@ -185,7 +186,7 @@ const ACTION_HANDLERS = { [UPDATE_SELECTED_PEERS]: (state, { peer }) => { let selectedPeers - + if (state.selectedPeers.includes(peer)) { selectedPeers = state.selectedPeers.filter(selectedPeer => selectedPeer.pub_key !== peer.pub_key) } diff --git a/app/routes/channels/components/Channels.js b/app/routes/channels/components/Channels.js index c1191d28..89a3b326 100644 --- a/app/routes/channels/components/Channels.js +++ b/app/routes/channels/components/Channels.js @@ -127,7 +127,7 @@ class Channels extends Component {
- (this.repeat = ref)}> + { this.repeat = ref }}> { this.state.refreshing ? diff --git a/app/routes/peers/components/Peers.js b/app/routes/peers/components/Peers.js index 86739a4c..fa13d1ca 100644 --- a/app/routes/peers/components/Peers.js +++ b/app/routes/peers/components/Peers.js @@ -98,7 +98,7 @@ class Peers extends Component {
- (this.repeat = ref)}> + { this.repeat = ref }}> { this.state.refreshing ? diff --git a/package.json b/package.json index 4adea44e..8a0136ae 100644 --- a/package.json +++ b/package.json @@ -171,6 +171,7 @@ "jsdom": "^11.0.0", "minimist": "^1.2.0", "node-sass": "^4.5.3", + "ps-node": "^0.1.6", "react-addons-test-utils": "^15.6.0", "react-test-renderer": "^15.6.1", "redux-logger": "^3.0.6", diff --git a/yarn.lock b/yarn.lock index d1499617..dc47bf7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2244,6 +2244,10 @@ connect-history-api-fallback@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" +connected-domain@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/connected-domain/-/connected-domain-1.0.0.tgz#bfe77238c74be453a79f0cb6058deeb4f2358e93" + console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" @@ -7225,6 +7229,12 @@ prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +ps-node@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ps-node/-/ps-node-0.1.6.tgz#9af67a99d7b1d0132e51a503099d38a8d2ace2c3" + dependencies: + table-parser "^0.1.3" + pseudomap@^1.0.1, pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" @@ -8657,6 +8667,12 @@ synesthesia@^1.0.1: dependencies: css-color-names "0.0.3" +table-parser@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/table-parser/-/table-parser-0.1.3.tgz#0441cfce16a59481684c27d1b5a67ff15a43c7b0" + dependencies: + connected-domain "^1.0.0" + table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"