From 6092c387c3cf3f92a5a5a99c3cb1f1491f0fae0a Mon Sep 17 00:00:00 2001 From: pbca26 Date: Mon, 13 Nov 2017 15:28:00 +0300 Subject: [PATCH 1/9] spv lock, logout hide cond fix --- .../src/components/dashboard/coinTile/coinTileItem.js | 2 +- react/src/components/dashboard/navbar/navbar.js | 1 + react/src/components/dashboard/navbar/navbar.render.js | 10 ++++++---- react/src/translate/en.js | 2 ++ 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/react/src/components/dashboard/coinTile/coinTileItem.js b/react/src/components/dashboard/coinTile/coinTileItem.js index cbd3c6419..4c57625cf 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.js @@ -30,7 +30,7 @@ import Config from '../../../config'; import CoinTileItemRender from './coinTileItem.render'; -const SPV_DASHBOARD_UPDATE_TIMEOUT = 10000; +const SPV_DASHBOARD_UPDATE_TIMEOUT = 60000; const ACTIVE_HANDLE_TIMEOUT_COIND_NATIVE = 15000; const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; diff --git a/react/src/components/dashboard/navbar/navbar.js b/react/src/components/dashboard/navbar/navbar.js index ec62a38bb..ecb200729 100755 --- a/react/src/components/dashboard/navbar/navbar.js +++ b/react/src/components/dashboard/navbar/navbar.js @@ -130,6 +130,7 @@ const mapStateToProps = (state) => { }, Main: { isLoggedIn: state.Main.isLoggedIn, + coins: state.Main.coins, }, }; }; diff --git a/react/src/components/dashboard/navbar/navbar.render.js b/react/src/components/dashboard/navbar/navbar.render.js index 14a7f7054..5aaa9c92f 100644 --- a/react/src/components/dashboard/navbar/navbar.render.js +++ b/react/src/components/dashboard/navbar/navbar.render.js @@ -111,8 +111,9 @@ const NavbarRender = function() { { this.props.Main && this.props.Main.isLoggedIn && - this.props.Main.spv && - this.props.Main.spv.length && + this.props.Main.coins && + this.props.Main.coins.spv && + this.props.Main.coins.spv.length &&
  • Lock @@ -121,8 +122,9 @@ const NavbarRender = function() { } { this.props.Main && this.props.Main.isLoggedIn && - this.props.Main.spv && - this.props.Main.spv.length && + this.props.Main.coins && + this.props.Main.coins.spv && + this.props.Main.coins.spv.length &&
  • Logout diff --git a/react/src/translate/en.js b/react/src/translate/en.js index 848fdc62e..89591f20b 100644 --- a/react/src/translate/en.js +++ b/react/src/translate/en.js @@ -471,6 +471,8 @@ export const _lang = { 'CURRENT_BLOCK_SM': 'current block', }, 'TOASTR': { + 'PORT_IS_TAKEN': 'Port @template@ is already taken!', + 'ERROR_STARTING_DAEMON': 'Error starting @template@ daemon.', 'KOMODO_DATADIR_INVALID': 'Komodo datadir path is invalid.
    It must be an absolute path to an existing folder that doesn\'t contain spaces and/or any special characters.', 'KOMODO_DATADIR_NOT_DIR': 'Komodo datadir path is not a directory.
    It must be an absolute path to an existing folder that doesn\'t contain spaces and/or any special characters.', 'INVALID_ADDRESS': 'Invalid @template@ address', From 784242058a3b2b5a601d67661ae2806e9609e55b Mon Sep 17 00:00:00 2001 From: pbca26 Date: Mon, 13 Nov 2017 15:28:18 +0300 Subject: [PATCH 2/9] spv zeroconf tx timestamp fix --- react/src/components/dashboard/walletsData/walletsData.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/src/components/dashboard/walletsData/walletsData.js b/react/src/components/dashboard/walletsData/walletsData.js index 6b15b6166..02f97a112 100644 --- a/react/src/components/dashboard/walletsData/walletsData.js +++ b/react/src/components/dashboard/walletsData/walletsData.js @@ -177,7 +177,7 @@ class WalletsData extends React.Component { id: 'timestamp', Header: translate('INDEX.TIME'), Footer: translate('INDEX.TIME'), - accessor: (tx) => secondsToString(tx.blocktime || tx.timestamp || tx.time), + accessor: (tx) => secondsToString(tx.timestamp || tx.time || tx.blocktime), }]; if (itemsCount <= BOTTOM_BAR_DISPLAY_THRESHOLD) { From 443fca800dc61248e1e1b6fa454ee3f7cb061009 Mon Sep 17 00:00:00 2001 From: pbca26 Date: Tue, 14 Nov 2017 23:01:06 +0300 Subject: [PATCH 3/9] proper rpc getinfo con failure handling; disable coind down modal --- react/src/actions/actions/nativeSyncInfo.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/react/src/actions/actions/nativeSyncInfo.js b/react/src/actions/actions/nativeSyncInfo.js index 867605310..94af944df 100644 --- a/react/src/actions/actions/nativeSyncInfo.js +++ b/react/src/actions/actions/nativeSyncInfo.js @@ -5,7 +5,6 @@ import { import { triggerToaster, getDebugLog, - toggleCoindDownModal } from '../actionCreators'; import Config from '../../config'; import { translate } from '../../translate/translate'; @@ -138,7 +137,7 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) { { result: 'daemon is busy', error: null, - id: null + id: null, }, coin, true, @@ -146,16 +145,15 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) { ) ); } else { - if (!json) { + if (!json || + json.indexOf('"code":-777') > -1) { let _kmdMainPassiveMode; try { _kmdMainPassiveMode = window.require('electron').remote.getCurrentWindow().kmdMainPassiveMode; } catch (e) {} - if (!_kmdMainPassiveMode) { - dispatch(nativeGetinfoFailureState()); - } else { + if (_kmdMainPassiveMode) { dispatch( triggerToaster( translate('API.KMD_PASSIVE_ERROR'), @@ -171,7 +169,6 @@ export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) { } else { dispatch(getDebugLog('komodo', 50, coin)); } - dispatch(toggleCoindDownModal(true)); } else { json = JSON.parse(json); } From 41e06bb74407ffa556564e8560fe3f3dbe09536e Mon Sep 17 00:00:00 2001 From: pbca26 Date: Tue, 14 Nov 2017 23:01:53 +0300 Subject: [PATCH 4/9] on demand coind down modal; rpc con error icon --- .../dashboard/coinTile/coinTileItem.js | 38 +++++++++++++++++-- .../dashboard/coinTile/coinTileItem.render.js | 8 +++- .../coindDownModal/coindDownModal.js | 2 +- .../src/components/dashboard/navbar/navbar.js | 10 +++++ .../dashboard/navbar/navbar.render.js | 12 +----- react/src/components/overrides.scss | 11 +++++- react/src/reducers/activeCoin.js | 5 ++- 7 files changed, 67 insertions(+), 19 deletions(-) diff --git a/react/src/components/dashboard/coinTile/coinTileItem.js b/react/src/components/dashboard/coinTile/coinTileItem.js index 4c57625cf..eb84b22bc 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.js @@ -24,6 +24,7 @@ import { activeHandle, triggerToaster, shepherdRemoveCoin, + toggleCoindDownModal, } from '../../../actions/actionCreators'; import Store from '../../../store'; import Config from '../../../config'; @@ -32,17 +33,38 @@ import CoinTileItemRender from './coinTileItem.render'; const SPV_DASHBOARD_UPDATE_TIMEOUT = 60000; const ACTIVE_HANDLE_TIMEOUT_COIND_NATIVE = 15000; -const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; +const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 2; //window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; class CoinTileItem extends React.Component { constructor() { super(); this.state = { appConfig: {}, + activeCoin: null, + activeCoinMode: null, + propsUpdatedCounter: 0, }; this.autoSetActiveCoin = this.autoSetActiveCoin.bind(this); } + openCoindDownModal() { + Store.dispatch(toggleCoindDownModal(true)); + } + + renderCoinConError(item) { + if (this.props.ActiveCoin.getinfoFetchFailures >= COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD && + (this.props.ActiveCoin.mode === 'native' && + this.props.ActiveCoin.coin === this.state.activeCoin && + this.props.ActiveCoin.coin === item.coin && + this.state.activeCoin === item.coin && + this.state.activeCoinMode === 'native' && + this.props.ActiveCoin.mode === this.state.activeCoinMode && + this.state.propsUpdatedCounter > 1) || + (this.props.ActiveCoin.coins && this.props.ActiveCoin.coins[item.coin]) && this.props.ActiveCoin.coins[item.coin].getinfoFetchFailures >= COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD) { + return true; + } + } + renderStopCoinButton() { if (this.props.Main && this.props.Main.coins && @@ -87,11 +109,11 @@ class CoinTileItem extends React.Component { _coinMode[coin] = mode; }); - if (_coinMode['KMD'] && - _coinMode['KMD'] === 'native') { + if (_coinMode.KMD && + _coinMode.KMD === 'native') { _coin = 'KMD'; _mode = 'native'; - } else if (_coinMode['KMD'] && _coinMode['KMD'] === 'spv') { + } else if (_coinMode.KMD && _coinMode.KMD === 'spv') { _coin = 'KMD'; _mode = 'spv'; } @@ -271,6 +293,13 @@ class CoinTileItem extends React.Component { Store.dispatch(electrumServerChanged(false)); }, 100); } + + this.setState({ + activeCoin: props.ActiveCoin.coin, + activeCoinMode: props.ActiveCoin.mode, + // prevent native con error icon flashing on coin switch + propsUpdatedCounter: this.state.activeCoin === props.ActiveCoin.coin && this.state.activeCoinMode === props.ActiveCoin.mode ? this.state.propsUpdatedCounter + 1 : 0, + }); } render() { @@ -282,6 +311,7 @@ const mapStateToProps = (state) => { return { ActiveCoin: { coin: state.ActiveCoin.coin, + coins: state.ActiveCoin.coins, mode: state.ActiveCoin.mode, addresses: state.ActiveCoin.addresses, mainBasiliskAddress: state.ActiveCoin.mainBasiliskAddress, diff --git a/react/src/components/dashboard/coinTile/coinTileItem.render.js b/react/src/components/dashboard/coinTile/coinTileItem.render.js index 08578f0e6..333e5e107 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.render.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.render.js @@ -34,7 +34,7 @@ const CoinTileItemRender = function() { this.removeCoin(item.coin, item.mode) } title="Remove" - className={ 'icon fa-plus-circle ' + (item.mode === 'spv' ? 'coind-remove-icon coind-remove-icon-spv' : 'coind-remove-icon') }> + className={ 'icon fa-plus-circle coind-remove-icon' + (item.mode === 'spv' ? ' coind-remove-icon-spv' : '') }> } { this.props.Dashboard && this.props.Dashboard.electrumCoins && @@ -45,6 +45,12 @@ const CoinTileItemRender = function() { title={ translate('SETTINGS.SPV_SINGLE_SERVER_NOTICE') } className="icon fa-info-circle icon-spv-connection-warning"> } + { this.renderCoinConError(item) && + + } ); }; diff --git a/react/src/components/dashboard/coindDownModal/coindDownModal.js b/react/src/components/dashboard/coindDownModal/coindDownModal.js index c538ba327..919f27b6c 100644 --- a/react/src/components/dashboard/coindDownModal/coindDownModal.js +++ b/react/src/components/dashboard/coindDownModal/coindDownModal.js @@ -5,7 +5,7 @@ import Store from '../../../store'; import CoindDownModalRender from './coindDownModal.render'; -const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; +const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 2; //window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; class CoindDownModal extends React.Component { constructor() { diff --git a/react/src/components/dashboard/navbar/navbar.js b/react/src/components/dashboard/navbar/navbar.js index ecb200729..02ec2f5ab 100755 --- a/react/src/components/dashboard/navbar/navbar.js +++ b/react/src/components/dashboard/navbar/navbar.js @@ -31,6 +31,16 @@ class Navbar extends React.Component { this.spvLogout = this.spvLogout.bind(this); } + isRenderSpvLockLogout() { + if (this.props.Main && + this.props.Main.isLoggedIn && + this.props.Main.coins && + this.props.Main.coins.spv && + this.props.Main.coins.spv.length) { + return true; + } + } + spvLock() { shepherdElectrumLock() .then((res) => { diff --git a/react/src/components/dashboard/navbar/navbar.render.js b/react/src/components/dashboard/navbar/navbar.render.js index 5aaa9c92f..f6fd08bd8 100644 --- a/react/src/components/dashboard/navbar/navbar.render.js +++ b/react/src/components/dashboard/navbar/navbar.render.js @@ -109,22 +109,14 @@ const NavbarRender = function() { { translate('ABOUT.ABOUT_AGAMA') }
  • - { this.props.Main && - this.props.Main.isLoggedIn && - this.props.Main.coins && - this.props.Main.coins.spv && - this.props.Main.coins.spv.length && + { this.isRenderSpvLockLogout() &&
  • Lock
  • } - { this.props.Main && - this.props.Main.isLoggedIn && - this.props.Main.coins && - this.props.Main.coins.spv && - this.props.Main.coins.spv.length && + { this.isRenderSpvLockLogout() &&
  • Logout diff --git a/react/src/components/overrides.scss b/react/src/components/overrides.scss index 99a3facb8..c19580434 100644 --- a/react/src/components/overrides.scss +++ b/react/src/components/overrides.scss @@ -447,9 +447,10 @@ select{ padding-top: 5px; } -.icon-spv-connection-warning { +.icon-spv-connection-warning, +.icon-native-connection-warning { position: absolute; - bottom: 15px; + bottom: 20px; right: 15px; &:before { @@ -458,6 +459,12 @@ select{ } } +.icon-native-connection-warning { + &:before { + color: #e9595b; + } +} + .color-warning { color: #FF6600; } diff --git a/react/src/reducers/activeCoin.js b/react/src/reducers/activeCoin.js index 6ac7edcae..4b88843f0 100644 --- a/react/src/reducers/activeCoin.js +++ b/react/src/reducers/activeCoin.js @@ -59,6 +59,7 @@ export function ActiveCoin(state = { activeBasiliskAddress: state.activeBasiliskAddress, progress: state.progress, rescanInProgress: state.rescanInProgress, + getinfoFetchFailures: state.getinfoFetchFailures, }; let _coins = state.coins; _coins[state.coin] = _coinDataToStore; @@ -81,6 +82,7 @@ export function ActiveCoin(state = { activeBasiliskAddress: _coinData.activeBasiliskAddress, progress: _coinData.progress, rescanInProgress: _coinData.rescanInProgress, + getinfoFetchFailures: _coinData.getinfoFetchFailures, }; } else { if (state.coin) { @@ -100,6 +102,7 @@ export function ActiveCoin(state = { activeBasiliskAddress: state.activeBasiliskAddress, progress: state.progress, rescanInProgress: state.rescanInProgress, + getinfoFetchFailures: state.getinfoFetchFailures, }; let _coins = state.coins; _coins[state.coin] = _coinData; @@ -214,7 +217,7 @@ export function ActiveCoin(state = { return { ...state, progress: action.progress, - getinfoFetchFailures: !action.progress ? state.getinfoFetchFailures + 1 : 0, + getinfoFetchFailures: typeof action.progress === 'string' && action.progress.indexOf('"code":-777') ? state.getinfoFetchFailures + 1 : 0, }; case DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE: return { From fc5c0007d437c1c3e0d29fc2b42cb18b484cc0cd Mon Sep 17 00:00:00 2001 From: pbca26 Date: Wed, 15 Nov 2017 22:29:12 +0300 Subject: [PATCH 5/9] coind down modal fetch daemon stdout by default --- react/src/actions/actions/settings.js | 29 +++++++++++- .../dashboard/coinTile/coinTileItem.js | 2 +- .../coindDownModal/coindDownModal.js | 47 +++++++++++++++++-- .../coindDownModal/coindDownModal.render.js | 28 ++++++++++- react/src/components/overrides.scss | 7 +++ 5 files changed, 106 insertions(+), 7 deletions(-) diff --git a/react/src/actions/actions/settings.js b/react/src/actions/actions/settings.js index dfe0a429e..e7dc7fa2b 100644 --- a/react/src/actions/actions/settings.js +++ b/react/src/actions/actions/settings.js @@ -386,4 +386,31 @@ export function resetAppConfig() { ); }) } -} \ No newline at end of file +} + +export function coindGetStdout(chain) { + const _chain = chain === 'KMD' ? 'komodod' : chain; + + return new Promise((resolve, reject) => { + fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/coind/stdout?chain=${chain}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }) + .catch((error) => { + console.log(error); + dispatch( + triggerToaster( + 'coindGetStdout', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json); + }); + }); +} diff --git a/react/src/components/dashboard/coinTile/coinTileItem.js b/react/src/components/dashboard/coinTile/coinTileItem.js index eb84b22bc..12b824143 100644 --- a/react/src/components/dashboard/coinTile/coinTileItem.js +++ b/react/src/components/dashboard/coinTile/coinTileItem.js @@ -33,7 +33,7 @@ import CoinTileItemRender from './coinTileItem.render'; const SPV_DASHBOARD_UPDATE_TIMEOUT = 60000; const ACTIVE_HANDLE_TIMEOUT_COIND_NATIVE = 15000; -const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 2; //window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; +const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; class CoinTileItem extends React.Component { constructor() { diff --git a/react/src/components/dashboard/coindDownModal/coindDownModal.js b/react/src/components/dashboard/coindDownModal/coindDownModal.js index 919f27b6c..d43de7f8f 100644 --- a/react/src/components/dashboard/coindDownModal/coindDownModal.js +++ b/react/src/components/dashboard/coindDownModal/coindDownModal.js @@ -1,21 +1,58 @@ import React from 'react'; import { connect } from 'react-redux'; -import { toggleCoindDownModal } from '../../../actions/actionCreators'; +import { + toggleCoindDownModal, + coindGetStdout, + getDebugLog, +} from '../../../actions/actionCreators'; import Store from '../../../store'; import CoindDownModalRender from './coindDownModal.render'; -const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 2; //window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; +const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = window.require('electron').remote.getCurrentWindow().appConfig.failedRPCAttemptsThreshold || 10; class CoindDownModal extends React.Component { constructor() { super(); this.state = { display: false, - debugLogCrash: null, kmdMainPassiveMode: false, + coindStdOut: 'Loading...', + toggleDebugLog: true, }; this.dismiss = this.dismiss.bind(this); + this.getCoindGetStdout = this.getCoindGetStdout.bind(this); + this.toggleDebugLog = this.toggleDebugLog.bind(this); + this.refreshDebugLog = this.refreshDebugLog.bind(this); + } + + refreshDebugLog() { + const _coin = this.props.ActiveCoin.coin; + + if (!this.state.toggleDebugLog) { + if (_coin === 'KMD') { + Store.dispatch(getDebugLog('komodo', 50)); + } else { + Store.dispatch(getDebugLog('komodo', 50, _coin)); + } + } else { + this.getCoindGetStdout(); + } + } + + toggleDebugLog() { + this.setState({ + toggleDebugLog: !this.state.toggleDebugLog, + }); + } + + getCoindGetStdout() { + coindGetStdout(this.props.ActiveCoin.coin) + .then((res) => { + this.setState({ + coindStdOut: res.msg === 'success' ? res.result : `Error reading ${this.props.ActiveCoin.coin} stdout`, + }); + }); } dismiss() { @@ -39,6 +76,10 @@ class CoindDownModal extends React.Component { this.setState(Object.assign({}, this.state, { display: nextProps.displayCoindDownModal, })); + + if (nextProps.displayCoindDownModal) { + this.getCoindGetStdout(); + } } } diff --git a/react/src/components/dashboard/coindDownModal/coindDownModal.render.js b/react/src/components/dashboard/coindDownModal/coindDownModal.render.js index bbd5eb03b..e5acc9705 100644 --- a/react/src/components/dashboard/coindDownModal/coindDownModal.render.js +++ b/react/src/components/dashboard/coindDownModal/coindDownModal.render.js @@ -27,12 +27,36 @@ const CoindDownModalRender = function() {
    - Debug.log ({ translate('INDEX.LAST_50_LINES') }) + +
    + +
    + Show debug.log +
    +
    + { !this.state.toggleDebugLog && + Debug.log ({ translate('INDEX.LAST_50_LINES') }) + } + { this.state.toggleDebugLog && + { this.props.ActiveCoin.coin === 'KMD' ? 'Komodod' : `Komodod / ${this.props.ActiveCoin.coin} stdout` } + }
    + value={ !this.state.toggleDebugLog ? _debuglog : this.state.coindStdOut }>
    +
    +
    +
    + { this.state.keys && +
    +
    +
    + { this.renderKeys() } +
    +
    + } + + + ); + }; +} + +const mapStateToProps = (state) => { + return { + Dashboard: state.Dashboard, + }; +}; + +export default connect(mapStateToProps)(NativeWalletDatKeysPanel); \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.render.js b/react/src/components/dashboard/settings/settings.render.js index 373bdaecb..eba640c5b 100644 --- a/react/src/components/dashboard/settings/settings.render.js +++ b/react/src/components/dashboard/settings/settings.render.js @@ -15,6 +15,7 @@ import ExportKeysPanel from './settings.exportKeysPanel'; import SupportPanel from './settings.supportPanel'; import SPVServersPanel from './settings.spvServersPanel'; import DaemonStdoutPanel from './settings.daemonStdoutPanel'; +import NativeWalletDatKeysPanel from './settings.nativeWalletDatKeysPanel'; // import WalletInfoPanel from './settings.walletInfoPanel'; // import WalletBackupPanel from './settings.walletBackupPanel'; @@ -104,6 +105,15 @@ export const SettingsRender = function() { } + { this.props.Main.coins && + this.props.Main.coins.native && + Object.keys(this.props.Main.coins.native).length > 0 && + + + + } { this.props.Main.coins && this.props.Main.coins.spv && Object.keys(this.props.Main.coins.spv).length && diff --git a/react/src/util/coinHelper.js b/react/src/util/coinHelper.js index 06f96c43f..9b0d20679 100644 --- a/react/src/util/coinHelper.js +++ b/react/src/util/coinHelper.js @@ -402,4 +402,31 @@ export function getModeInfo(mode) { tip: modetip, color: modecolor, }; +} + +export function coindList() { + const _coins = [ + 'KMD', + 'CHIPS', + 'BET', + 'BOTS', + 'CEAL', + 'COQUI', + 'CRYPTO', + 'HODL', + 'DEX', + 'JUMBLR', + 'KV', + 'MGW', + 'MVP', + 'MNZ', + 'PANGEA', + 'REVS', + 'SHARK', + 'MESH', + 'SUPERNET', + 'WLC', + ]; + + return _coins; } \ No newline at end of file From 3c58075e9fffd8455ba59754b524e305ad896779 Mon Sep 17 00:00:00 2001 From: pbca26 Date: Thu, 16 Nov 2017 20:18:29 +0300 Subject: [PATCH 8/9] add back copy wif key; refactor receive coin buttons into context menu --- react/src/actions/actions/settings.js | 38 ++++++++++++++++ .../components/dashboard/qrModal/qrModal.js | 12 ++--- .../dashboard/qrModal/qrModal.render.js | 7 +-- .../dashboard/receiveCoin/receiveCoin.js | 34 +++++++++++++- .../receiveCoin/receiveCoin.render.js | 29 +++++++++--- react/src/components/overrides.scss | 45 +++++++++++++++++++ 6 files changed, 149 insertions(+), 16 deletions(-) diff --git a/react/src/actions/actions/settings.js b/react/src/actions/actions/settings.js index 4532c127d..5db5ebf8d 100644 --- a/react/src/actions/actions/settings.js +++ b/react/src/actions/actions/settings.js @@ -440,4 +440,42 @@ export function getWalletDatKeys(chain, keyMatchPattern) { resolve(json); }); }); +} + +export function dumpPrivKey(coin, address) { + return new Promise((resolve, reject) => { + const payload = { + mode: null, + chain: coin, + cmd: 'dumpprivkey', + params: [ address ] + }; + + const _fetchConfig = { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'payload': payload }), + }; + + fetch( + `http://127.0.0.1:${Config.agamaPort}/shepherd/cli`, + _fetchConfig + ) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'dumpPrivKey', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => { + resolve(json.result ? json.result : json); + }) + }); } \ No newline at end of file diff --git a/react/src/components/dashboard/qrModal/qrModal.js b/react/src/components/dashboard/qrModal/qrModal.js index b5e366f8a..85002acd9 100755 --- a/react/src/components/dashboard/qrModal/qrModal.js +++ b/react/src/components/dashboard/qrModal/qrModal.js @@ -70,12 +70,12 @@ class QRModal extends React.Component { } saveAsImage(e) { - const qrCanvas = document.getElementById('qrModalCanvas' + this.props.content); - const canvas = qrCanvas.getElementsByTagName('canvas'); - const dataURL = canvas[0].toDataURL(); - const a = document.getElementById('saveModalImage' + this.props.content); - a.href = dataURL; - a.download = this.props.content; + const qrCanvas = document.getElementById('qrModalCanvas' + this.props.content); + const canvas = qrCanvas.getElementsByTagName('canvas'); + const dataURL = canvas[0].toDataURL(); + const a = document.getElementById('saveModalImage' + this.props.content); + a.href = dataURL; + a.download = this.props.content; } render() { diff --git a/react/src/components/dashboard/qrModal/qrModal.render.js b/react/src/components/dashboard/qrModal/qrModal.render.js index a96f886e8..7aa8650df 100644 --- a/react/src/components/dashboard/qrModal/qrModal.render.js +++ b/react/src/components/dashboard/qrModal/qrModal.render.js @@ -5,10 +5,11 @@ import QRCode from 'qrcode.react'; export const QRModalRender = function() { return ( - - + generate QR-code
    -
    { + if (json.length && + json.length > 10) { + Store.dispatch(copyString(json, 'WIF address copied to clipboard')); + } + }); + } + handleClickOutside(e) { - if (e.srcElement.className.indexOf('dropdown') === -1 && + if (e && + e.srcElement && + e.srcElement.offsetParent && + e.srcElement.offsetParent.className.indexOf('dropdown') === -1 && (e.srcElement.offsetParent && e.srcElement.offsetParent.className.indexOf('dropdown') === -1)) { this.setState({ openDropMenu: false, + toggledAddressMenu: + e.srcElement.className.indexOf('receive-address-context-menu-trigger') === -1 && + e.srcElement.className.indexOf('fa-qrcode') === -1 && + e.srcElement.className.indexOf('receive-address-context-menu-get-qr') === -1 && + e.srcElement.className.indexOf('qrcode-modal') === -1 ? null : this.state.toggledAddressMenu, }); } } @@ -64,6 +93,7 @@ class ReceiveCoin extends React.Component { } _copyCoinAddress(address) { + this.toggleAddressMenu(address); Store.dispatch(copyCoinAddress(address)); } diff --git a/react/src/components/dashboard/receiveCoin/receiveCoin.render.js b/react/src/components/dashboard/receiveCoin/receiveCoin.render.js index 657de38a1..c8915b95e 100644 --- a/react/src/components/dashboard/receiveCoin/receiveCoin.render.js +++ b/react/src/components/dashboard/receiveCoin/receiveCoin.render.js @@ -7,15 +7,34 @@ export const AddressActionsNonBasiliskModeRender = function(address, type) { return ( - +   { type === 'public' ? translate('IAPI.PUBLIC_SM') : translate('KMD_NATIVE.PRIVATE') } - + { this.state.toggledAddressMenu && + this.state.toggledAddressMenu === address && +
    +
      +
    • this._copyCoinAddress(address) }> + { translate('INDEX.COPY') + ' pub key' } +
    • + { address[0] !== 'b' && +
    • this.dumpPrivKey(address) }> + { translate('INDEX.COPY') + ' priv key (WIF)' } +
    • + } +
    • + +
    • +
    +
    + } ); }; diff --git a/react/src/components/overrides.scss b/react/src/components/overrides.scss index d885da681..62ea340d4 100644 --- a/react/src/components/overrides.scss +++ b/react/src/components/overrides.scss @@ -546,4 +546,49 @@ select{ .settings-coind-stdout-textarea { border: none; background-image: none !important; +} + +.receive-address-context-menu { + box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.4); + background: #fff; + position: absolute; + z-index: 100; + margin-left: 65px; + margin-top: 5px; + + ul { + margin: 0; + list-style: none; + -webkit-margin-before: 0; + -webkit-margin-after: 0; + -webkit-margin-start: 0; + -webkit-margin-end: 0; + -webkit-padding-start: 0; + + li { + padding: 5px 15px; + + &:first-child { + margin-top: 5px; + } + &:last-child { + margin-bottom: 5px; + } + &:hover { + background: #f9f9f9; + cursor: pointer; + } + } + } + &.closed { + z-index: 1700; + position: absolute; + top: -100%; + left: -100%; + } + .receive-address-context-menu-get-qr { + .modal { + cursor: default; + } + } } \ No newline at end of file From 85a7d82640690f3db76de0d596eaf88f9cb704ae Mon Sep 17 00:00:00 2001 From: pbca26 Date: Thu, 16 Nov 2017 23:59:35 +0300 Subject: [PATCH 9/9] toaster duplicates handling fix; zcparams check refactor --- react/src/components/addcoin/addcoin.js | 76 +++++++++++++++---- .../components/dashboard/main/dashboard.js | 45 +++++++++++ .../zcparamsFetchModal/zcparamsFetchModal.js | 8 +- react/src/components/login/login.js | 4 +- react/src/components/login/login.render.js | 4 + react/src/components/main/main.js | 38 ---------- react/src/reducers/toaster.js | 11 ++- react/src/util/zcashParams.js | 29 +++++++ 8 files changed, 156 insertions(+), 59 deletions(-) create mode 100644 react/src/util/zcashParams.js diff --git a/react/src/components/addcoin/addcoin.js b/react/src/components/addcoin/addcoin.js index 43237f64c..1d42963f2 100644 --- a/react/src/components/addcoin/addcoin.js +++ b/react/src/components/addcoin/addcoin.js @@ -7,9 +7,11 @@ import { toggleAddcoinModal, triggerToaster, shepherdGetCoinList, - shepherdPostCoinList + shepherdPostCoinList, + toggleZcparamsFetchModal, } from '../../actions/actionCreators'; import Store from '../../store'; +import { zcashParamsCheckErrors } from '../../util/zcashParams'; import CoinSelectorsRender from './coin-selectors.render'; import AddCoinRender from './addcoin.render'; @@ -46,6 +48,43 @@ class AddCoin extends React.Component { this.toggleActionsMenu = this.toggleActionsMenu.bind(this); this.saveCoinSelection = this.saveCoinSelection.bind(this); this.loadCoinSelection = this.loadCoinSelection.bind(this); + this.verifyZcashParamsExist = this.verifyZcashParamsExist.bind(this); + } + + verifyZcashParamsExist(mode) { + return new Promise((resolve, reject) => { + if (Number(mode) === -1) { + const _res = window.require('electron').remote.getCurrentWindow().zcashParamsExist; + const __errors = zcashParamsCheckErrors(_res); + + if (__errors) { + window.require('electron').remote.getCurrentWindow().zcashParamsExistPromise() + .then((res) => { + const _errors = zcashParamsCheckErrors(res); + window.require('electron').remote.getCurrentWindow().zcashParamsExist = res; + + if (_errors) { + Store.dispatch( + triggerToaster( + _errors, + 'Komodod', + 'error', + false + ) + ); + Store.dispatch(toggleZcparamsFetchModal(true)); + resolve(false); + } else { + resolve(true); + } + }); + } else { + resolve(true); + } + } else { + resolve(true); + } + }); } saveCoinSelection() { @@ -206,23 +245,28 @@ class AddCoin extends React.Component { return; } - if (!_coin.daemonParam) { - Store.dispatch(addCoin( - coin, - _coin.mode, - )); - } else { - Store.dispatch(addCoin( - coin, - _coin.mode, - { type: _coin.daemonParam } - )); - } + this.verifyZcashParamsExist(_coin.mode) + .then((res) => { + if (res) { + if (!_coin.daemonParam) { + Store.dispatch(addCoin( + coin, + _coin.mode, + )); + } else { + Store.dispatch(addCoin( + coin, + _coin.mode, + { type: _coin.daemonParam } + )); + } - this.removeCoin(); - this.addNewItem(); + this.removeCoin(); + this.addNewItem(); - Store.dispatch(toggleAddcoinModal(false, false)); + Store.dispatch(toggleAddcoinModal(false, false)); + } + }); } dismiss() { diff --git a/react/src/components/dashboard/main/dashboard.js b/react/src/components/dashboard/main/dashboard.js index fda315b58..6645be75e 100755 --- a/react/src/components/dashboard/main/dashboard.js +++ b/react/src/components/dashboard/main/dashboard.js @@ -1,13 +1,58 @@ import React from 'react'; import { connect } from 'react-redux'; import DashboardRender from './dashboard.render'; +import { + toggleZcparamsFetchModal, + triggerToaster, +} from '../../../actions/actionCreators'; +import { zcashParamsCheckErrors } from '../../../util/zcashParams'; +import Store from '../../../store'; class Dashboard extends React.Component { constructor() { super(); this.state = { + zcashParamsVerifyTriggered: false, }; this.renderDashboard = this.renderDashboard.bind(this); + this.verifyZcashParams = this.verifyZcashParams.bind(this); + } + + verifyZcashParams() { + if (!this.state.zcashParamsVerifyTriggered) { + const _res = window.require('electron').remote.getCurrentWindow().zcashParamsExist; + const _errors = zcashParamsCheckErrors(_res); + + if (_errors) { + Store.dispatch( + triggerToaster( + _errors, + 'Komodo', + 'error', + false + ) + ); + + Store.dispatch(toggleZcparamsFetchModal(true)); + } + } else { + this.setState({ + zcashParamsVerifyTriggered: false, + }); + } + } + + componentWillReceiveProps() { + if (this.props.Main && + this.props.Main.coins && + this.props.Main.coins.native && + this.props.Main.coins.native.length && + !this.props.Dashboard.displayZcparamsModal) { + this.setState({ + zcashParamsVerifyTriggered: true, + }); + this.verifyZcashParams(); + } } isSectionActive(section) { diff --git a/react/src/components/dashboard/zcparamsFetchModal/zcparamsFetchModal.js b/react/src/components/dashboard/zcparamsFetchModal/zcparamsFetchModal.js index 7a28f79a3..9c77e3114 100644 --- a/react/src/components/dashboard/zcparamsFetchModal/zcparamsFetchModal.js +++ b/react/src/components/dashboard/zcparamsFetchModal/zcparamsFetchModal.js @@ -108,11 +108,17 @@ class ZcparamsFetchModal extends React.Component { if (data.msg.file === 'proving') { _updateLog = []; _updateLog.push(translate('ZCPARAMS_FETCH.BOTH_KEYS_VERIFIED')); - _updateLog.push(translate('ZCPARAMS_FETCH.PLEASE_RESTART')); + // _updateLog.push(translate('ZCPARAMS_FETCH.PLEASE_RESTART')); this.setState(Object.assign({}, this.state, { updateLog: _updateLog, done: true, })); + + window.require('electron').remote.getCurrentWindow().zcashParamsExistPromise() + .then((res) => { + const _errors = zcashParamsCheckErrors(res); + window.require('electron').remote.getCurrentWindow().zcashParamsExist = res; + }); } else { this.setState(Object.assign({}, this.state, { updateLog: _updateLog, diff --git a/react/src/components/login/login.js b/react/src/components/login/login.js index 8b655f8d9..1f991a8a0 100644 --- a/react/src/components/login/login.js +++ b/react/src/components/login/login.js @@ -499,9 +499,7 @@ class Login extends React.Component { const mapStateToProps = (state) => { return { Main: state.Main, - Dashboard: { - activeHandle: state.Dashboard.activeHandle, - }, + Dashboard: state.Dashboard, Interval: { interval: state.Interval.interval, }, diff --git a/react/src/components/login/login.render.js b/react/src/components/login/login.render.js index 3442a9e80..10b2d04ba 100644 --- a/react/src/components/login/login.render.js +++ b/react/src/components/login/login.render.js @@ -1,10 +1,14 @@ import React from 'react'; import { translate } from '../../translate/translate'; import LoginSettingsModal from '../dashboard/loginSettingsModal/loginSettingsModal'; +import ZcparamsFetchModal from '../dashboard/zcparamsFetchModal/zcparamsFetchModal'; const LoginRender = function () { return (
    + { this.props.Dashboard.displayZcparamsModal && + + } { this.renderSwallModal() }
    diff --git a/react/src/components/main/main.js b/react/src/components/main/main.js index 4ca80d70d..7126b67fa 100644 --- a/react/src/components/main/main.js +++ b/react/src/components/main/main.js @@ -1,13 +1,10 @@ import React from 'react'; import WalletMain from './walletMain'; import Store from '../../store'; -import { translate } from '../../translate/translate'; import { getDexCoins, activeHandle, - triggerToaster, shepherdElectrumCoins, - toggleZcparamsFetchModal, } from '../../actions/actionCreators'; class Main extends React.Component { @@ -20,51 +17,16 @@ class Main extends React.Component { componentDidMount() { let appVersion; - let zcashParamsExist; let appConfig; try { appVersion = window.require('electron').remote.getCurrentWindow().appBasicInfo; appConfig = window.require('electron').remote.getCurrentWindow().appConfig; - zcashParamsExist = window.require('electron').remote.getCurrentWindow().zcashParamsExist; } catch (e) {} if (appVersion) { document.title = `${appVersion.name} (v${appVersion.version.replace('version=', '')}-beta)`; } - - // TODO: isolate check only when komodod is detected - if (zcashParamsExist.errors) { - let _errors = [translate('KMD_NATIVE.ZCASH_PARAMS_MISSING'), '']; - - if (!zcashParamsExist.rootDir) { - _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_ROOT_DIR')); - } - if (!zcashParamsExist.provingKey) { - _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_PROVING_KEY')); - } - if (!zcashParamsExist.verifyingKey) { - _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_VERIFYING_KEY')); - } - if (!zcashParamsExist.provingKeySize && - zcashParamsExist.provingKey) { - _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_PROVING_KEY_SIZE')); - } - if (!zcashParamsExist.verifyingKeySize && - zcashParamsExist.verifyingKey) { - _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_VERIFYING_KEY_SIZE')); - } - - Store.dispatch( - triggerToaster( - _errors, - 'Komodo', - 'error', - false - ) - ); - Store.dispatch(toggleZcparamsFetchModal(true)); - } } componentWillMount() { diff --git a/react/src/reducers/toaster.js b/react/src/reducers/toaster.js index 0abc6c171..35a05b802 100644 --- a/react/src/reducers/toaster.js +++ b/react/src/reducers/toaster.js @@ -12,9 +12,18 @@ export function toaster(state = { case ADD_TOASTER_MESSAGE: let _isSameToastTwice = false; + function arrayToString(arr) { + if (typeof arr === 'object') { + return arr.join().toString(); + } else { + return arr; + } + } + for (let i = 0; i < state.toasts.length; i++) { if (state.toasts[i].title === action.title && - state.toasts[i].message === action.message && + (arrayToString(action.message) === arrayToString(state.toasts[i].message) || + state.toasts[i].message === action.message) && state.toasts[i]['_type'] === action['_type']) { _isSameToastTwice = true; break; diff --git a/react/src/util/zcashParams.js b/react/src/util/zcashParams.js new file mode 100644 index 000000000..7f41f867f --- /dev/null +++ b/react/src/util/zcashParams.js @@ -0,0 +1,29 @@ +import { translate } from '../translate/translate'; + +export function zcashParamsCheckErrors(zcashParamsExist) { + let _errors; + + if (zcashParamsExist.errors) { + _errors = [translate('KMD_NATIVE.ZCASH_PARAMS_MISSING'), '']; + + if (!zcashParamsExist.rootDir) { + _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_ROOT_DIR')); + } + if (!zcashParamsExist.provingKey) { + _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_PROVING_KEY')); + } + if (!zcashParamsExist.verifyingKey) { + _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_VERIFYING_KEY')); + } + if (!zcashParamsExist.provingKeySize && + zcashParamsExist.provingKey) { + _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_PROVING_KEY_SIZE')); + } + if (!zcashParamsExist.verifyingKeySize && + zcashParamsExist.verifyingKey) { + _errors.push(translate('KMD_NATIVE.ZCASH_PARAMS_MISSING_VERIFYING_KEY_SIZE')); + } + } + + return _errors; +} \ No newline at end of file