Browse Source

Merge pull request #60 from LN-Zap/feature/refresh-data

Feature/refresh data
renovate/lint-staged-8.x
JimmyMow 7 years ago
committed by GitHub
parent
commit
8242749293
  1. 4
      app/api/index.js
  2. 6
      app/app.global.scss
  3. 144
      app/components/Channels/Channels.js
  4. 24
      app/components/Channels/Channels.scss
  5. 30
      app/components/LndSyncing/LndSyncing.js
  6. 73
      app/components/Peers/Peers.js
  7. 14
      app/components/Peers/Peers.scss
  8. 10
      app/keyframes.scss
  9. 1
      app/lnd/lib/lightning.js
  10. 2
      app/lnd/subscribe/index.js
  11. 2
      app/reducers/balance.js
  12. 8
      app/reducers/lnd.js
  13. 1
      app/reducers/transaction.js
  14. 9
      app/routes/app/components/App.js
  15. 4
      app/routes/wallet/components/Wallet.js

4
app/api/index.js

@ -16,8 +16,8 @@ export function requestTickers(ids) {
} }
export function requestBlockHeight(id) { export function requestBlockHeight() {
const BASE_URL = `https://testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1` const BASE_URL = 'https://testnet-api.smartbit.com.au/v1/blockchain/blocks?limit=1'
return axios({ return axios({
method: 'get', method: 'get',
url: BASE_URL url: BASE_URL

6
app/app.global.scss

@ -67,3 +67,9 @@ body {
stroke: darken($main, 10%); stroke: darken($main, 10%);
} }
} }
@keyframes spin {
100% {
transform: rotate(360deg);
}
}

144
app/components/Channels/Channels.js

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { TiPlus } from 'react-icons/lib/ti' import { TiPlus } from 'react-icons/lib/ti'
import { FaRepeat } from 'react-icons/lib/fa'
import ChannelModal from './ChannelModal' import ChannelModal from './ChannelModal'
import ChannelForm from './ChannelForm' import ChannelForm from './ChannelForm'
import Channel from './Channel' import Channel from './Channel'
@ -9,6 +10,7 @@ import ClosedPendingChannel from './ClosedPendingChannel'
import styles from './Channels.scss' import styles from './Channels.scss'
const Channels = ({ const Channels = ({
fetchChannels,
ticker, ticker,
peers, peers,
channelsLoading, channelsLoading,
@ -22,69 +24,103 @@ const Channels = ({
closeChannel, closeChannel,
currentTicker, currentTicker,
explorerLinkBase explorerLinkBase
}) => ( }) => {
<div className={styles.channels}> const refreshClicked = (event) => {
<ChannelModal // store event in icon so we dont get an error when react clears it
isOpen={channelModalOpen} const icon = event.currentTarget
resetChannel={setChannel}
channel={modalChannel} // fetch channels
explorerLinkBase={explorerLinkBase} fetchChannels()
closeChannel={closeChannel}
/> // clear animation after the second so we can reuse it
<ChannelForm form={channelForm} setForm={setChannelForm} ticker={ticker} peers={peers} openChannel={openChannel} currentTicker={currentTicker} /> setTimeout(() => { icon.style.animation = '' }, 1000)
<div className={styles.header}>
<h3>Channels</h3> // spin icon for 1 sec
<div icon.style.animation = 'spin 1000ms linear 1'
className={`${styles.openChannel} hint--top`} }
data-hint='Open a channel'
onClick={() => setChannelForm({ isOpen: true })} return (
> <div className={styles.channels}>
<TiPlus /> <ChannelModal
isOpen={channelModalOpen}
resetChannel={setChannel}
channel={modalChannel}
explorerLinkBase={explorerLinkBase}
closeChannel={closeChannel}
/>
<ChannelForm
form={channelForm}
setForm={setChannelForm}
ticker={ticker}
peers={peers}
openChannel={openChannel}
currentTicker={currentTicker}
/>
<div className={styles.header}>
<h3>Channels</h3>
<span
className={`${styles.refresh} hint--top`}
data-hint='Refresh your channels list'
>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
</span>
<div
className={`${styles.openChannel} hint--top`}
data-hint='Open a channel'
onClick={() => setChannelForm({ isOpen: true })}
>
<TiPlus />
</div>
</div> </div>
</div> <ul>
<ul> {
{ !channelsLoading ?
!channelsLoading ? allChannels.map((channel, index) => {
allChannels.map((channel, index) => { if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) { return (
<OpenPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
}
return ( return (
<OpenPendingChannel <Channel
key={index} key={channel.chan_id}
channel={channel}
ticker={ticker} ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel} channel={channel}
ticker={ticker} setChannel={setChannel}
currentTicker={currentTicker} currentTicker={currentTicker}
explorerLinkBase={explorerLinkBase}
/> />
) )
} })
return ( :
<Channel 'Loading...'
key={channel.chan_id} }
ticker={ticker} </ul>
channel={channel} </div>
setChannel={setChannel} )
currentTicker={currentTicker} }
/>
)
})
:
'Loading...'
}
</ul>
</div>
)
Channels.propTypes = { Channels.propTypes = {
fetchChannels: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired,
peers: PropTypes.array.isRequired, peers: PropTypes.array.isRequired,
channelsLoading: PropTypes.bool.isRequired, channelsLoading: PropTypes.bool.isRequired,

24
app/components/Channels/Channels.scss

@ -1,5 +1,15 @@
@import '../../variables.scss'; @import '../../variables.scss';
@keyframes spin {
from {
transform: rotate(0deg)
}
to {
transform: rotate(360deg);
}
}
.channels { .channels {
width: 75%; width: 75%;
margin: 50px auto; margin: 50px auto;
@ -15,6 +25,20 @@
text-align: left; text-align: left;
} }
.refresh {
cursor: pointer;
margin-left: 5px;
font-size: 12px;
vertical-align: top;
color: $darkestgrey;
line-height: 14px;
transition: color 0.25s;
&:hover {
color: $main;
}
}
.openChannel { .openChannel {
float: right; float: right;
cursor: pointer; cursor: pointer;

30
app/components/LndSyncing/LndSyncing.js

@ -1,14 +1,15 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styles from './LndSyncing.scss' import styles from './LndSyncing.scss'
class LndSyncing extends Component { class LndSyncing extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
facts: [ facts: [
{ {
title: 'No2x', title: 'No2x',
description: 'Segwit2x is a hard fork proposal led by Barry Silbert and the NYA signers. The idea was drawn up and signed in a locked hotel room with select individuals and goes against everything that Bitcoin stands for. There is no favoritism in Bitcoin. There are no politicians. Hash power and business don\'t speak for us. Don\'t trust, verify.' description: 'Segwit2x is a hard fork proposal led by Barry Silbert and the NYA signers. The idea was drawn up and signed in a locked hotel room with select individuals and goes against everything that Bitcoin stands for. There is no favoritism in Bitcoin. There are no politicians. Hash power and business don\'t speak for us. Don\'t trust, verify.' // eslint-disable-line
}, },
{ {
title: 'Gang', title: 'Gang',
@ -41,8 +42,7 @@ class LndSyncing extends Component {
<h3>zap</h3> <h3>zap</h3>
<div className={styles.loading}> <div className={styles.loading}>
{!fetchingBlockHeight && <h4>{syncPercentage}%</h4>} {!fetchingBlockHeight && <h4>{syncPercentage}%</h4>}
<div className={styles.spinner}> <div className={styles.spinner} />
</div>
<h1>syncing your lightning node to the blockchain</h1> <h1>syncing your lightning node to the blockchain</h1>
</div> </div>
<div className={styles.facts}> <div className={styles.facts}>
@ -52,15 +52,13 @@ class LndSyncing extends Component {
</div> </div>
<ul> <ul>
{ {
facts.map((facts, index) => { facts.map((fact, index) => (
return ( <li
<li className={`${styles.factButton} ${currentFact === index && styles.active}`}
className={`${styles.factButton} ${currentFact === index && styles.active}`} key={index}
key={index} onClick={() => this.setState({ currentFact: index })}
onClick={() => this.setState({ currentFact: index })} />
/> ))
)
})
} }
</ul> </ul>
</div> </div>
@ -69,4 +67,10 @@ class LndSyncing extends Component {
} }
} }
LndSyncing.propTypes = {
fetchBlockHeight: PropTypes.func.isRequired,
fetchingBlockHeight: PropTypes.bool.isRequired,
syncPercentage: PropTypes.number.isRequired
}
export default LndSyncing export default LndSyncing

73
app/components/Peers/Peers.js

@ -1,12 +1,14 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { TiPlus } from 'react-icons/lib/ti' import { TiPlus } from 'react-icons/lib/ti'
import { FaRepeat } from 'react-icons/lib/fa'
import PeerModal from './PeerModal' import PeerModal from './PeerModal'
import PeerForm from './PeerForm' import PeerForm from './PeerForm'
import Peer from './Peer' import Peer from './Peer'
import styles from './Peers.scss' import styles from './Peers.scss'
const Peers = ({ const Peers = ({
fetchPeers,
peersLoading, peersLoading,
peers, peers,
setPeer, setPeer,
@ -16,32 +18,59 @@ const Peers = ({
setPeerForm, setPeerForm,
connect, connect,
disconnect disconnect
}) => ( }) => {
<div className={styles.peers}> const refreshClicked = (event) => {
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} /> // store event in icon so we dont get an error when react clears it
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} /> const icon = event.currentTarget
<div className={styles.header}>
<h3>Peers</h3> // fetch peers
<div fetchPeers()
className={`${styles.connectPeer} hint--top`}
data-hint='Connect to a peer' // clear animation after the second so we can reuse it
onClick={() => setPeerForm({ isOpen: true })} setTimeout(() => { icon.style.animation = '' }, 1000)
>
<TiPlus /> // spin icon for 1 sec
icon.style.animation = 'spin 1000ms linear 1'
}
return (
<div className={styles.peers}>
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} />
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} />
<div className={styles.header}>
<h3>Peers</h3>
<span
className={`${styles.refresh} hint--top`}
data-hint='Refresh your peers list'
>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
</span>
<div
className={`${styles.connectPeer} hint--top`}
data-hint='Connect to a peer'
onClick={() => setPeerForm({ isOpen: true })}
>
<TiPlus />
</div>
</div> </div>
<ul>
{
!peersLoading ?
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />)
:
'Loading...'
}
</ul>
</div> </div>
<ul> )
{ }
!peersLoading ?
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />)
:
'Loading...'
}
</ul>
</div>
)
Peers.propTypes = { Peers.propTypes = {
fetchPeers: PropTypes.func.isRequired,
peersLoading: PropTypes.bool.isRequired, peersLoading: PropTypes.bool.isRequired,
peers: PropTypes.array.isRequired, peers: PropTypes.array.isRequired,
setPeer: PropTypes.func.isRequired, setPeer: PropTypes.func.isRequired,

14
app/components/Peers/Peers.scss

@ -15,6 +15,20 @@
text-align: left; text-align: left;
} }
.refresh {
cursor: pointer;
margin-left: 5px;
font-size: 12px;
vertical-align: top;
color: $darkestgrey;
line-height: 14px;
transition: color 0.25s;
&:hover {
color: $main;
}
}
.connectPeer { .connectPeer {
float: right; float: right;
cursor: pointer; cursor: pointer;

10
app/keyframes.scss

@ -31,3 +31,13 @@
75% { color: $gold; } 75% { color: $gold; }
100% { color: $white; } 100% { color: $white; }
} }
@keyframes spin {
from {
transform:rotate(0deg)
}
to {
transform:rotate(360deg);
}
}

1
app/lnd/lib/lightning.js

@ -5,7 +5,6 @@ import config from '../config'
module.exports = (rpcpath, host) => { module.exports = (rpcpath, host) => {
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA' process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA'
console.log('RPC PATH: ', path.join(__dirname, 'rpc.proto'))
const rpc = grpc.load(path.join(__dirname, 'rpc.proto')) const rpc = grpc.load(path.join(__dirname, 'rpc.proto'))
const lndCert = fs.readFileSync(config.cert) const lndCert = fs.readFileSync(config.cert)

2
app/lnd/subscribe/index.js

@ -2,8 +2,6 @@ import subscribeToTransactions from './transactions'
import subscribeToInvoices from './invoices' import subscribeToInvoices from './invoices'
export default (mainWindow, lnd) => { export default (mainWindow, lnd) => {
console.log('mainWindow: ', mainWindow)
console.log('lnd: ', lnd)
subscribeToTransactions(mainWindow, lnd) subscribeToTransactions(mainWindow, lnd)
subscribeToInvoices(mainWindow, lnd) subscribeToInvoices(mainWindow, lnd)
} }

2
app/reducers/balance.js

@ -21,7 +21,7 @@ export const fetchBalance = () => async (dispatch) => {
} }
// Receive IPC event for balance // Receive IPC event for balance
export const receiveBalance = (event, { walletBalance, channelBalance }) => dispatch => { export const receiveBalance = (event, { walletBalance, channelBalance }) => (dispatch) => {
dispatch({ type: RECEIVE_BALANCE, walletBalance, channelBalance }) dispatch({ type: RECEIVE_BALANCE, walletBalance, channelBalance })
} }

8
app/reducers/lnd.js

@ -22,7 +22,7 @@ export const RECEIVE_BLOCK_HEIGHT = 'RECEIVE_BLOCK_HEIGHT'
export const lndSyncing = () => dispatch => dispatch({ type: START_SYNCING }) export const lndSyncing = () => dispatch => dispatch({ type: START_SYNCING })
// Receive IPC event for LND stoping sync // Receive IPC event for LND stoping sync
export const lndSynced = () => dispatch => { export const lndSynced = () => (dispatch) => {
// Fetch data now that we know LND is synced // Fetch data now that we know LND is synced
dispatch(fetchTicker()) dispatch(fetchTicker())
dispatch(fetchBalance()) dispatch(fetchBalance())
@ -32,7 +32,9 @@ export const lndSynced = () => dispatch => {
} }
// Receive IPC event for LND streaming a line // Receive IPC event for LND streaming a line
export const lndStdout = (event, lndBlockHeight) => dispatch => dispatch({ type: RECEIVE_LINE, lndBlockHeight: lndBlockHeight.split(' ')[0].split(/(\r\n|\n|\r)/gm)[0] }) export const lndStdout = (event, lndBlockHeight) => dispatch => (
dispatch({ type: RECEIVE_LINE, lndBlockHeight: lndBlockHeight.split(' ')[0].split(/(\r\n|\n|\r)/gm)[0] })
)
export function getBlockHeight() { export function getBlockHeight() {
return { return {
@ -64,7 +66,7 @@ const ACTION_HANDLERS = {
[RECEIVE_LINE]: (state, { lndBlockHeight }) => ({ ...state, lndBlockHeight }), [RECEIVE_LINE]: (state, { lndBlockHeight }) => ({ ...state, lndBlockHeight }),
[GET_BLOCK_HEIGHT]: state => ({ ...state, fetchingBlockHeight: true }), [GET_BLOCK_HEIGHT]: state => ({ ...state, fetchingBlockHeight: true }),
[RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({ ...state, blockHeight, fetchingBlockHeight: false }), [RECEIVE_BLOCK_HEIGHT]: (state, { blockHeight }) => ({ ...state, blockHeight, fetchingBlockHeight: false })
} }
// ------------------------------------ // ------------------------------------

1
app/reducers/transaction.js

@ -73,7 +73,6 @@ export const transactionError = () => (dispatch) => {
// Listener for when a new transaction is pushed from the subscriber // Listener for when a new transaction is pushed from the subscriber
export const newTransaction = (event, { transaction }) => (dispatch) => { export const newTransaction = (event, { transaction }) => (dispatch) => {
console.log('transaction: ', transaction)
// Fetch new balance // Fetch new balance
dispatch(fetchBalance()) dispatch(fetchBalance())

9
app/routes/app/components/App.js

@ -11,10 +11,6 @@ class App extends Component {
componentWillMount() { componentWillMount() {
const { fetchTicker, fetchBalance, fetchInfo, lnd: { syncing } } = this.props const { fetchTicker, fetchBalance, fetchInfo, lnd: { syncing } } = this.props
if (syncing) {
fetchBlockHeight()
}
if (!syncing) { if (!syncing) {
fetchTicker() fetchTicker()
fetchBalance() fetchBalance()
@ -86,6 +82,11 @@ class App extends Component {
} }
App.propTypes = { App.propTypes = {
lnd: PropTypes.object.isRequired,
syncPercentage: PropTypes.number.isRequired,
fetchBlockHeight: PropTypes.func.isRequired,
modal: PropTypes.object.isRequired, modal: PropTypes.object.isRequired,
ticker: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired,
balance: PropTypes.object.isRequired, balance: PropTypes.object.isRequired,

4
app/routes/wallet/components/Wallet.js

@ -21,6 +21,8 @@ class Wallet extends Component {
ticker, ticker,
peers: { peersLoading, peers, peer, peerForm }, peers: { peersLoading, peers, peer, peerForm },
channels: { channelsLoading, channels, channel, channelForm, pendingChannels }, channels: { channelsLoading, channels, channel, channelForm, pendingChannels },
fetchPeers,
fetchChannels,
setPeer, setPeer,
setChannel, setChannel,
peerModalOpen, peerModalOpen,
@ -53,6 +55,7 @@ class Wallet extends Component {
</section> </section>
<section className={styles.walletData}> <section className={styles.walletData}>
<Peers <Peers
fetchPeers={fetchPeers}
peersLoading={peersLoading} peersLoading={peersLoading}
peers={peers} peers={peers}
modalPeer={peer} modalPeer={peer}
@ -64,6 +67,7 @@ class Wallet extends Component {
disconnect={disconnectRequest} disconnect={disconnectRequest}
/> />
<Channels <Channels
fetchChannels={fetchChannels}
ticker={ticker} ticker={ticker}
peers={peers} peers={peers}
channelsLoading={channelsLoading} channelsLoading={channelsLoading}

Loading…
Cancel
Save