From 5ea59e17fcbe8a5a4a8612504b29e14937f80a29 Mon Sep 17 00:00:00 2001 From: Jack Mallers Date: Mon, 30 Oct 2017 12:44:03 -0500 Subject: [PATCH] fix(lint): fix linting errors --- app/components/ChannelForm/StepThree.js | 2 +- app/components/ChannelForm/StepTwo.js | 2 +- app/components/Channels/CardChannel.js | 15 -- app/components/Channels/CardChannel.scss | 6 - app/components/Channels/NetworkChannels.js | 133 ++++++++++++++++++ app/components/Channels/NetworkChannels.scss | 114 +++++++++++++++ app/lnd/methods/index.js | 11 ++ app/reducers/channels.js | 25 ++-- app/reducers/index.js | 2 + app/reducers/ipc.js | 7 +- app/reducers/network.js | 129 +++++++++++++++++ app/routes/channels/components/Channels.js | 70 +++++---- app/routes/channels/components/Channels.scss | 5 + .../channels/containers/ChannelsContainer.js | 10 +- package.json | 2 +- yarn.lock | 51 ++++--- 16 files changed, 507 insertions(+), 77 deletions(-) delete mode 100644 app/components/Channels/CardChannel.js delete mode 100644 app/components/Channels/CardChannel.scss create mode 100644 app/components/Channels/NetworkChannels.js create mode 100644 app/components/Channels/NetworkChannels.scss create mode 100644 app/reducers/network.js diff --git a/app/components/ChannelForm/StepThree.js b/app/components/ChannelForm/StepThree.js index d864bdfa..fef38172 100644 --- a/app/components/ChannelForm/StepThree.js +++ b/app/components/ChannelForm/StepThree.js @@ -26,7 +26,7 @@ class StepThree extends Component { type='number' min='0' max='0.16' - ref={input => (this.input = input)} + ref={(input) => { this.input = input }} size='' value={push_amt} onChange={event => setPushAmount(event.target.value)} diff --git a/app/components/ChannelForm/StepTwo.js b/app/components/ChannelForm/StepTwo.js index ed777351..723653f4 100644 --- a/app/components/ChannelForm/StepTwo.js +++ b/app/components/ChannelForm/StepTwo.js @@ -25,7 +25,7 @@ class StepTwo extends Component { type='number' min='0' max='0.16' - ref={input => (this.input = input)} + ref={(input) => { this.input = input }} size='' value={local_amt} onChange={event => setLocalAmount(event.target.value)} diff --git a/app/components/Channels/CardChannel.js b/app/components/Channels/CardChannel.js deleted file mode 100644 index e24ba320..00000000 --- a/app/components/Channels/CardChannel.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import styles from './CardChannel.scss' - -const CardChannel = ({ channel }) => ( -
  • - {channel.chan_id} -
  • -) - -CardChannel.propTypes = { - channel: PropTypes.object.isRequired -} - -export default CardChannel diff --git a/app/components/Channels/CardChannel.scss b/app/components/Channels/CardChannel.scss deleted file mode 100644 index b8138c58..00000000 --- a/app/components/Channels/CardChannel.scss +++ /dev/null @@ -1,6 +0,0 @@ -.channel { - width: 40%; - margin: 0 5% 20px 5%; - height: 500px; - background: red; -} \ No newline at end of file diff --git a/app/components/Channels/NetworkChannels.js b/app/components/Channels/NetworkChannels.js new file mode 100644 index 00000000..5689fa9d --- /dev/null +++ b/app/components/Channels/NetworkChannels.js @@ -0,0 +1,133 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { ForceGraph, ForceGraphNode, ForceGraphLink } from 'react-vis-force' +import { FaCircle } from 'react-icons/lib/fa' +import styles from './NetworkChannels.scss' + +class NetworkChannels extends Component { + constructor(props) { + super(props) + this.state = { + ready: false + } + } + + componentWillMount() { + setTimeout(() => { + this.setState({ ready: true }) + }, 1000) + + this.props.setCurrentChannel(this.props.channels[0]) + } + + render() { + const { ready } = this.state + const { + channels, + network: { nodes, edges, selectedChannel, networkLoading }, + identity_pubkey, + setCurrentChannel + } = this.props + + if (!ready || networkLoading) { + return ( +
    +

    loading network graph

    +
    + ) + } + + return ( +
    +
    + + { + nodes.map(node => ( + + )) + } + { + edges.map(edge => ( + + )) + } + +
    +
    +
      + { + channels.map((channel, index) => ( +
    • setCurrentChannel(channel)} + > +
      + { + channel.active ? + + + active + + : + + + not active + + } +
      +
      +
      +

      Remote Pubkey

      +

      {`${channel.remote_pubkey.substring(30, channel.remote_pubkey.length)}...`}

      +
      +
      +

      Channel Point

      +

      {`${channel.channel_point.substring(30, channel.channel_point.length)}...`}

      +
      +
      +
    • + )) + } +
    +
    +
    + ) + } +} + +NetworkChannels.propTypes = { + channels: PropTypes.array.isRequired, + network: PropTypes.object.isRequired, + identity_pubkey: PropTypes.string.isRequired, + setCurrentChannel: PropTypes.func.isRequired +} + +export default NetworkChannels diff --git a/app/components/Channels/NetworkChannels.scss b/app/components/Channels/NetworkChannels.scss new file mode 100644 index 00000000..6febd4db --- /dev/null +++ b/app/components/Channels/NetworkChannels.scss @@ -0,0 +1,114 @@ +@import '../../variables.scss'; + +@keyframes dash { + to { + stroke-dashoffset: 1000; + } +} + +.networkLoading { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background: $black; + + h1 { + font-size: 22px; + color: $green; + font-family: 'courier'; + text-align: center; + margin-top: 25%; + } +} + +.networkchannels { + position: relative; +} + +.network, .channels { + display: inline-block; + vertical-align: top; +} + +.network { + width: 70%; +} + +.channels { + width: calc(30% - 2px); + border: 1px solid $darkestgrey; + border-radius: 5px; +} + +.node { + r: 15; + fill: $darkestgrey; + + .active { + r: 25; + fill: $green; + stroke: $green; + } +} + +.line.active { + stroke-width: 10; + opacity: 1; + stroke: $green; + stroke-dasharray: 100; + animation: dash 2.5s infinite linear; +} + +.channel { + padding: 10px; + background: rgba(0, 0, 0, 0.7); + cursor: pointer; + transition: all 0.25s; + border-bottom: 1px solid $white; + + &.active, &:hover { + background: rgba(255, 255, 255, 0.4); + } + + header { + margin-bottom: 10px; + + .active { + color: $green; + } + + .notactive { + color: $green; + } + + span svg { + font-size: 10px; + } + + i { + text-transform: uppercase; + font-size: 10px; + margin-left: 5px; + } + } + + .content { + div { + margin-bottom: 5px; + } + + h4 { + text-transform: uppercase; + margin-bottom: 5px; + font-size: 10px; + color: $main; + } + + h2 { + font-size: 14px; + color: $white; + } + } +} \ No newline at end of file diff --git a/app/lnd/methods/index.js b/app/lnd/methods/index.js index 98e82106..ca2603e2 100644 --- a/app/lnd/methods/index.js +++ b/app/lnd/methods/index.js @@ -33,6 +33,17 @@ export default function (lnd, event, msg, data) { }) .catch(error => console.log('info error: ', error)) break + case 'describeNetwork': + networkController.describeGraph(lnd) + .then(networkData => event.sender.send('receiveDescribeNetwork', networkData)) + .catch(error => console.log('describeGraph error: ', error)) + break + case 'queryRoutes': + // Data looks like { pubkey: String, amount: Number } + networkController.queryRoutes(lnd, data) + .then(routes => event.sender.send('receiveQueryRoutes', routes)) + .catch(error => console.log('queryRoutes error: ', error)) + break case 'newaddress': // Data looks like { address: '' } walletController.newAddress(lnd, data.type) diff --git a/app/reducers/channels.js b/app/reducers/channels.js index 09c15711..57309216 100644 --- a/app/reducers/channels.js +++ b/app/reducers/channels.js @@ -118,8 +118,7 @@ export const pushchannelupdated = () => (dispatch) => { } // Receive IPC event for channel end -export const pushchannelend = (event, channelEndData) => (dispatch) => { - console.log('channelEndData: ', channelEndData) +export const pushchannelend = event => (dispatch) => { dispatch(fetchChannels()) } @@ -130,8 +129,7 @@ export const pushchannelerror = (event, { error }) => (dispatch) => { } // Receive IPC event for channel status -export const pushchannelstatus = (event, channelStatusData) => (dispatch) => { - console.log('channel Status data: ', channelStatusData) +export const pushchannelstatus = event => (dispatch) => { dispatch(fetchChannels()) } @@ -224,11 +222,20 @@ channelsSelectors.allChannels = createSelector( pendingClosedChannelsSelector, pendingForceClosedChannelsSelector, channelSearchQuerySelector, - (channels, pendingOpenChannels, pendingClosedChannels, pendingForcedClosedChannels, searchQuery) => ( - [...channels, ...pendingOpenChannels, ...pendingClosedChannels, ...pendingForcedClosedChannels].filter(channel => - channel.remote_pubkey.includes(searchQuery) || channel.channel_point.includes(searchQuery) - ) - ) + (channels, pendingOpenChannels, pendingClosedChannels, pendingForcedClosedChannels, searchQuery) => { + const filteredChannels = channels.filter(channel => channel.remote_pubkey.includes(searchQuery) || channel.channel_point.includes(searchQuery)) // eslint-disable-line + const filteredPendingOpenChannels = pendingOpenChannels.filter(channel => channel.channel.remote_node_pub.includes(searchQuery) || channel.channel.channel_point.includes(searchQuery)) // eslint-disable-line + const filteredPendingClosedChannels = pendingClosedChannels.filter(channel => channel.channel.remote_node_pub.includes(searchQuery) || channel.channel.channel_point.includes(searchQuery)) // eslint-disable-line + const filteredPendingForcedClosedChannels = pendingForcedClosedChannels.filter(channel => channel.channel.remote_node_pub.includes(searchQuery) || channel.channel.channel_point.includes(searchQuery)) // eslint-disable-line + + + return [...filteredChannels, ...filteredPendingOpenChannels, ...filteredPendingClosedChannels, ...filteredPendingForcedClosedChannels] + } +) + +channelsSelectors.activeChanIds = createSelector( + channelsSelector, + channels => channels.map(channel => channel.chan_id) ) export { channelsSelectors } diff --git a/app/reducers/index.js b/app/reducers/index.js index 17c4855a..6e77afba 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -19,6 +19,7 @@ import modal from './modal' import address from './address' import transaction from './transaction' import activity from './activity' +import network from './network' import error from './error' const rootReducer = combineReducers({ @@ -41,6 +42,7 @@ const rootReducer = combineReducers({ address, transaction, activity, + network, error }) diff --git a/app/reducers/ipc.js b/app/reducers/ipc.js index 0b3f7a8f..2afcdff5 100644 --- a/app/reducers/ipc.js +++ b/app/reducers/ipc.js @@ -31,6 +31,8 @@ import { newTransaction } from './transaction' +import { receiveDescribeNetwork, receiveQueryRoutes } from './network' + // Import all receiving IPC event handlers and pass them into createIpc const ipc = createIpc({ lndSyncing, @@ -79,7 +81,10 @@ const ipc = createIpc({ receiveTransactions, transactionSuccessful, transactionError, - newTransaction + newTransaction, + + receiveDescribeNetwork, + receiveQueryRoutes }) export default ipc diff --git a/app/reducers/network.js b/app/reducers/network.js new file mode 100644 index 00000000..ff8417dc --- /dev/null +++ b/app/reducers/network.js @@ -0,0 +1,129 @@ +import { createSelector } from 'reselect' +import { ipcRenderer } from 'electron' + +// ------------------------------------ +// Constants +// ------------------------------------ +export const GET_DESCRIBE_NETWORK = 'GET_DESCRIBE_NETWORK' +export const RECEIVE_DESCRIBE_NETWORK = 'RECEIVE_DESCRIBE_NETWORK' + +export const GET_QUERY_ROUTES = 'GET_QUERY_ROUTES' +export const RECEIVE_QUERY_ROUTES = 'RECEIVE_QUERY_ROUTES' + +export const SET_CURRENT_ROUTE = 'SET_CURRENT_ROUTE' + +export const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL' + +// ------------------------------------ +// Actions +// ------------------------------------ +export function getDescribeNetwork() { + return { + type: GET_DESCRIBE_NETWORK + } +} + +export function getQueryRoutes(pubkey) { + return { + type: GET_QUERY_ROUTES, + pubkey + } +} + +export function setCurrentRoute(route) { + return { + type: SET_CURRENT_ROUTE, + route + } +} + +export function setCurrentChannel(selectedChannel) { + return { + type: SET_CURRENT_CHANNEL, + selectedChannel + } +} + +// Send IPC event for describeNetwork +export const fetchDescribeNetwork = () => (dispatch) => { + dispatch(getDescribeNetwork()) + ipcRenderer.send('lnd', { msg: 'describeNetwork' }) +} + +// Receive IPC event for describeNetwork +export const receiveDescribeNetwork = (event, { nodes, edges }) => dispatch => dispatch({ type: RECEIVE_DESCRIBE_NETWORK, nodes, edges }) + +export const queryRoutes = (pubkey, amount) => (dispatch) => { + dispatch(getQueryRoutes(pubkey)) + ipcRenderer.send('lnd', { msg: 'queryRoutes', data: { pubkey, amount } }) +} + +export const receiveQueryRoutes = (event, { routes }) => dispatch => dispatch({ type: RECEIVE_QUERY_ROUTES, routes }) + +// ------------------------------------ +// Action Handlers +// ------------------------------------ +const ACTION_HANDLERS = { + [GET_DESCRIBE_NETWORK]: state => ({ ...state, networkLoading: true }), + [RECEIVE_DESCRIBE_NETWORK]: (state, { nodes, edges }) => ({ ...state, networkLoading: false, nodes, edges }), + + [GET_QUERY_ROUTES]: (state, { pubkey }) => ({ ...state, networkLoading: true, selectedNode: { pubkey, routes: [], currentRoute: {} } }), + [RECEIVE_QUERY_ROUTES]: (state, { routes }) => ( + { + ...state, + networkLoading: false, + selectedNode: { pubkey: state.selectedNode.pubkey, routes, currentRoute: routes[0] } + } + ), + + [SET_CURRENT_ROUTE]: (state, { route }) => ( + { + ...state, + selectedNode: { pubkey: state.selectedNode.pubkey, routes: state.selectedNode.routes, currentRoute: route } + } + ), + + [SET_CURRENT_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel }) +} + +// ------------------------------------ +// Selectors +// ------------------------------------ +const networkSelectors = {} +const currentRouteSelector = state => state.network.selectedNode.currentRoute + +networkSelectors.currentRouteHopChanIds = createSelector( + currentRouteSelector, + (currentRoute) => { + if (!currentRoute.hops) { return [] } + + return currentRoute.hops.map(hop => hop.chan_id) + } +) + +export { networkSelectors } + +// ------------------------------------ +// Initial State +// ------------------------------------ +const initialState = { + networkLoading: false, + nodes: [], + edges: [], + selectedNode: { + pubkey: '', + routes: [], + currentRoute: {} + }, + selectedChannel: {} +} + + +// ------------------------------------ +// Reducer +// ------------------------------------ +export default function activityReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + + return handler ? handler(state, action) : state +} diff --git a/app/routes/channels/components/Channels.js b/app/routes/channels/components/Channels.js index 371392db..46055f5c 100644 --- a/app/routes/channels/components/Channels.js +++ b/app/routes/channels/components/Channels.js @@ -1,27 +1,29 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import { FaAlignJustify, FaThLarge } from 'react-icons/lib/fa' +import { FaAlignJustify, FaGlobe } from 'react-icons/lib/fa' import { MdSearch } from 'react-icons/lib/md' import Channel from 'components/Channels/Channel' -import CardChannel from 'components/Channels/CardChannel' +import NetworkChannels from 'components/Channels/NetworkChannels' import ChannelForm from 'components/ChannelForm' import styles from './Channels.scss' class Channels extends Component { componentWillMount() { - const { fetchChannels, fetchPeers } = this.props + const { fetchChannels, fetchPeers, fetchDescribeNetwork } = this.props fetchChannels() fetchPeers() + fetchDescribeNetwork() } render() { const { channels: { searchQuery, viewType }, allChannels, + openChannels, updateChannelSearchQuery, setViewType, @@ -30,11 +32,15 @@ class Channels extends Component { ticker, currentTicker, - channelFormProps + channelFormProps, + + network, + identity_pubkey, + setCurrentChannel } = this.props return ( -
    +
    @@ -55,8 +61,8 @@ class Channels extends Component { setViewType(0)}> - - + setViewType(1)}> +
    @@ -67,24 +73,30 @@ class Channels extends Component {
    -
      - { viewType === 0 && allChannels.map((channel, index) => ( - console.log('hi')} - currentTicker={currentTicker} - /> - )) - } - { viewType === 1 && allChannels.map((channel, index) => ( - - card channel - - )) - } -
    + { + viewType === 0 && +
      + { + allChannels.map((channel, index) => ( + {}} + currentTicker={currentTicker} + /> + )) + } +
    + } + { viewType === 1 && + + }
    ) @@ -97,15 +109,21 @@ Channels.propTypes = { channels: PropTypes.object.isRequired, allChannels: PropTypes.array.isRequired, + openChannels: PropTypes.array.isRequired, updateChannelSearchQuery: PropTypes.func.isRequired, setViewType: PropTypes.func.isRequired, + setCurrentChannel: PropTypes.func.isRequired, openChannelForm: PropTypes.func.isRequired, ticker: PropTypes.object.isRequired, currentTicker: PropTypes.object.isRequired, - channelFormProps: PropTypes.object.isRequired + channelFormProps: PropTypes.object.isRequired, + + network: PropTypes.object.isRequired, + fetchDescribeNetwork: PropTypes.func.isRequired, + identity_pubkey: PropTypes.string.isRequired } export default Channels diff --git a/app/routes/channels/components/Channels.scss b/app/routes/channels/components/Channels.scss index bd6c207e..dc552d74 100644 --- a/app/routes/channels/components/Channels.scss +++ b/app/routes/channels/components/Channels.scss @@ -1,9 +1,14 @@ @import '../../../variables.scss'; +.container.graphview { + background: $black; +} + .search { height: 75px; padding: 2px 25px; border-bottom: 1px solid $darkgrey; + background: $white; .input { display: inline-block; diff --git a/app/routes/channels/containers/ChannelsContainer.js b/app/routes/channels/containers/ChannelsContainer.js index 407c4ec4..9a1861a6 100644 --- a/app/routes/channels/containers/ChannelsContainer.js +++ b/app/routes/channels/containers/ChannelsContainer.js @@ -24,6 +24,8 @@ import { fetchPeers } from 'reducers/peers' import { tickerSelectors } from 'reducers/ticker' +import { fetchDescribeNetwork, setCurrentChannel } from '../../../reducers/network' + import Channels from '../components/Channels' const mapDispatchToProps = { @@ -39,17 +41,23 @@ const mapDispatchToProps = { setPushAmount, changeStep, + fetchPeers, - fetchPeers + fetchDescribeNetwork, + setCurrentChannel } const mapStateToProps = state => ({ channels: state.channels, + openChannels: state.channels.channels, channelform: state.channelform, peers: state.peers, ticker: state.ticker, + network: state.network, + identity_pubkey: state.info.data.identity_pubkey, allChannels: channelsSelectors.allChannels(state), + activeChanIds: channelsSelectors.activeChanIds(state), currentTicker: tickerSelectors.currentTicker(state), channelFormHeader: channelFormSelectors.channelFormHeader(state), channelFormProgress: channelFormSelectors.channelFormProgress(state), diff --git a/package.json b/package.json index fc27b684..dfa4ff29 100644 --- a/package.json +++ b/package.json @@ -213,7 +213,6 @@ "react-dom": "^15.6.1", "react-hot-loader": "3.0.0-beta.6", "react-inlinesvg": "^0.6.2", - "react-input-autosize": "^2.0.1", "react-modal": "^2.2.2", "react-moment": "^0.6.0", "react-redux": "^5.0.5", @@ -222,6 +221,7 @@ "react-router-redux": "^5.0.0-alpha.6", "react-svg": "^2.1.21", "react-svg-morph": "^0.1.10", + "react-vis-force": "^0.3.1", "react-websocket": "^1.1.7", "redux": "^3.7.1", "redux-electron-ipc": "^1.1.10", diff --git a/yarn.lock b/yarn.lock index 8d5ab8e0..35894bd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2286,14 +2286,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.3, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@^15.5.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.2.tgz#cf1ed15f12aad7f14ef5f2dfe05e6c42f91ef02a" - dependencies: - fbjs "^0.8.9" - loose-envify "^1.3.1" - object-assign "^4.1.1" - create-react-class@^15.5.3: version "15.5.3" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.3.tgz#fb0f7cae79339e9a179e194ef466efa3923820fe" @@ -2540,6 +2532,31 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +d3-collection@1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2" + +d3-dispatch@1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8" + +d3-force@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.1.0.tgz#cebf3c694f1078fcc3d4daf8e567b2fbd70d4ea3" + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-quadtree "1" + d3-timer "1" + +d3-quadtree@1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.3.tgz#ac7987e3e23fe805a990f28e1b50d38fcb822438" + +d3-timer@1: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -5586,7 +5603,7 @@ lodash.range@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.range/-/lodash.range-3.2.0.tgz#f461e588f66683f7eadeade513e38a69a565a15d" -lodash.reduce@^4.4.0: +lodash.reduce@^4.4.0, lodash.reduce@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" @@ -7128,13 +7145,6 @@ react-inlinesvg@^0.6.2: httpplease "^0.16" once "^1.4" -react-input-autosize@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.0.1.tgz#e92190497b4026c2780ad0f2fd703c835ba03e33" - dependencies: - create-react-class "^15.5.2" - prop-types "^15.5.8" - react-modal@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-2.2.4.tgz#a32483c3555bd7677f09bca65d82f51da3abcbc0" @@ -7246,6 +7256,15 @@ react-transition-group@^1.2.0: prop-types "^15.5.6" warning "^3.0.0" +react-vis-force@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/react-vis-force/-/react-vis-force-0.3.1.tgz#c7bc96a4e872409f5d4c0fa93fe89c94554d47b7" + dependencies: + d3-force "^1.0.2" + global "^4.3.0" + lodash.reduce "^4.6.0" + prop-types "^15.5.10" + react-websocket@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/react-websocket/-/react-websocket-1.1.7.tgz#0a761f3de354d4731f55343456e03b1f6005b492"