Browse Source

Merge branch 'redux' of https://github.com/SuperNETorg/EasyDEX-GUI into feature/qr-invoice

all-modes^2^2
pbca26 7 years ago
parent
commit
f0717568c0
  1. 359
      assets/mainWindow/css/loading.css
  2. BIN
      assets/mainWindow/img/fa-caret-down.png
  3. BIN
      assets/mainWindow/img/fa-caret-up.png
  4. BIN
      assets/mainWindow/img/fa-close.png
  5. BIN
      assets/mainWindow/img/fa-cogs.png
  6. BIN
      assets/mainWindow/img/fa-cube.png
  7. BIN
      assets/mainWindow/img/fa-cubes.png
  8. BIN
      assets/mainWindow/img/fa-question.png
  9. 6
      assets/mainWindow/js/init.js
  10. 301
      assets/mainWindow/js/loading.js
  11. 3
      react/change.log
  12. 61
      react/src/actions/actionCreators.js
  13. 34
      react/src/actions/actions/addCoin.js
  14. 113
      react/src/actions/actions/addressBalance.js
  15. 30
      react/src/actions/actions/atomic.js
  16. 4
      react/src/actions/actions/basiliskCache.js
  17. 56
      react/src/actions/actions/basiliskProcessAddress.js
  18. 4
      react/src/actions/actions/basiliskTxHistory.js
  19. 4
      react/src/actions/actions/cli.js
  20. 4
      react/src/actions/actions/coinList.js
  21. 30
      react/src/actions/actions/createWallet.js
  22. 30
      react/src/actions/actions/dexCoins.js
  23. 49
      react/src/actions/actions/edexBalance.js
  24. 30
      react/src/actions/actions/edexGetTx.js
  25. 30
      react/src/actions/actions/fullTxHistory.js
  26. 30
      react/src/actions/actions/getAddrByAccount.js
  27. 30
      react/src/actions/actions/iguanaHelpers.js
  28. 20
      react/src/actions/actions/iguanaInstance.js
  29. 4
      react/src/actions/actions/interest.js
  30. 8
      react/src/actions/actions/jumblr.js
  31. 61
      react/src/actions/actions/log.js
  32. 30
      react/src/actions/actions/logout.js
  33. 30
      react/src/actions/actions/nativeBalance.js
  34. 86
      react/src/actions/actions/nativeDashboardUpdate.js
  35. 30
      react/src/actions/actions/nativeNewAddress.js
  36. 61
      react/src/actions/actions/nativeSend.js
  37. 235
      react/src/actions/actions/nativeSyncInfo.js
  38. 30
      react/src/actions/actions/nativeTxHistory.js
  39. 223
      react/src/actions/actions/notary.js
  40. 4
      react/src/actions/actions/openAlias.js
  41. 110
      react/src/actions/actions/sendFullBasilisk.js
  42. 86
      react/src/actions/actions/settings.js
  43. 30
      react/src/actions/actions/syncInfo.js
  44. 4
      react/src/actions/actions/syncOnly.js
  45. 4
      react/src/actions/actions/sysInfo.js
  46. 4
      react/src/actions/actions/update.js
  47. 127
      react/src/actions/actions/walletAuth.js
  48. 14
      react/src/actions/storeType.js
  49. 14
      react/src/components/addcoin/addcoin.js
  50. 59
      react/src/components/addcoin/addcoin.scss
  51. 46
      react/src/components/addcoin/addcoinOptionsAC.js
  52. 77
      react/src/components/addcoin/addcoinOptionsACFiat.js
  53. 44
      react/src/components/addcoin/addcoinOptionsCrypto.js
  54. 8
      react/src/components/addcoin/coin-selectors.render.js
  55. 3
      react/src/components/addcoin/payload.js
  56. 1
      react/src/components/app/app.js
  57. 3
      react/src/components/dashboard/atomic/atomic.js
  58. 12
      react/src/components/dashboard/claimInterestModal/claimInterestModal.js
  59. 53
      react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js
  60. 47
      react/src/components/dashboard/claimInterestModal/claimInterestModal.scss
  61. 4
      react/src/components/dashboard/coinTile/coinTile.js
  62. 182
      react/src/components/dashboard/coinTile/coinTileItem.js
  63. 2
      react/src/components/dashboard/coinTile/coinTileItem.render.js
  64. 28
      react/src/components/dashboard/coindDownModal/coindDownModal.js
  65. 2
      react/src/components/dashboard/coindDownModal/coindDownModal.render.js
  66. 24
      react/src/components/dashboard/coindDownModal/coindDownModal.scss
  67. 243
      react/src/components/dashboard/importKeyModal/importKeyModal.js
  68. 136
      react/src/components/dashboard/importKeyModal/importKeyModal.render.js
  69. 33
      react/src/components/dashboard/importKeyModal/importKeyModal.scss
  70. 17
      react/src/components/dashboard/jumblr/jumblr.js
  71. 92
      react/src/components/dashboard/jumblr/jumblr.scss
  72. 2
      react/src/components/dashboard/loginModal/loginModal.render.js
  73. 3
      react/src/components/dashboard/loginSettingsModal/loginSettingsModal.js
  74. 7
      react/src/components/dashboard/loginSettingsModal/loginSettingsModal.scss
  75. 5
      react/src/components/dashboard/main/dashboard.js
  76. 6
      react/src/components/dashboard/main/dashboard.render.js
  77. 20
      react/src/components/dashboard/navbar/navbar.js
  78. 13
      react/src/components/dashboard/navbar/navbar.render.js
  79. 122
      react/src/components/dashboard/notifications/notifications.js
  80. 116
      react/src/components/dashboard/notifications/notifications.render.js
  81. 4
      react/src/components/dashboard/qrModal/qrModal.js
  82. 76
      react/src/components/dashboard/qrModal/qrModal.render.js
  83. 11
      react/src/components/dashboard/qrModal/qrModal.scss
  84. 17
      react/src/components/dashboard/receiveCoin/receiveCoin.js
  85. 30
      react/src/components/dashboard/sendCoin/sendCoin.js
  86. 180
      react/src/components/dashboard/settings/settings.addNodePanel.js
  87. 90
      react/src/components/dashboard/settings/settings.appInfoPanel.js
  88. 321
      react/src/components/dashboard/settings/settings.appSettingsPanel.js
  89. 151
      react/src/components/dashboard/settings/settings.appUpdatePanel.js
  90. 206
      react/src/components/dashboard/settings/settings.cliPanel.js
  91. 180
      react/src/components/dashboard/settings/settings.debugLogPanel.js
  92. 235
      react/src/components/dashboard/settings/settings.exportKeysPanel.js
  93. 23
      react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js
  94. 67
      react/src/components/dashboard/settings/settings.importKeysPanel.js
  95. 799
      react/src/components/dashboard/settings/settings.js
  96. 575
      react/src/components/dashboard/settings/settings.render.js
  97. 121
      react/src/components/dashboard/settings/settings.scss
  98. 82
      react/src/components/dashboard/settings/settings.supportPanel.js
  99. 23
      react/src/components/dashboard/settings/settings.walletBackupPanel.js
  100. 60
      react/src/components/dashboard/settings/settings.walletInfoPanel.js

359
assets/mainWindow/css/loading.css

@ -1,7 +1,7 @@
body {
overflow: hidden !important;
border: solid 1px #ccc;
height: 300px;
user-select: none;
cursor: default;
}
.text-center {
@ -19,30 +19,41 @@ body {
margin: auto;
}
.pulse-loader {
position: absolute;
top: 10px;
left: -100px;
margin: 80px 50px;
width: 400px !important;
}
body.agamaMode {
background-color: rgba(33, 33, 33, 0.85);
padding-top: 40px;
color: #fff;
}
body.loading-window,
body.agama-default-window-height {
height: 355px;
}
body.agama-app-settings-window {
height: 700px;
}
.agama-logo {
padding-bottom: 20px;
}
#agamaModeStatus {
padding-bottom: 25px;
padding-bottom: 35px;
font-weight: bold;
font-size: 16px;
}
.btn-info {
color: #fff;
background-color: #25b4c5 !important;
border-color: #25b4c5 !important;
}
.btn-info:hover {
background-color: #6cd2de !important;
border-color: #6cd2de !important;
}
.btn-primary.focus,
.btn-primary:focus,
.btn-primary:hover,
@ -67,8 +78,8 @@ body.agamaMode {
font-size: 14px;
line-height: 1.57142857;
border-radius: 3px;
-webkit-box-shadow: 0 1px 4px 0 rgba(0,0,0,.1);
box-shadow: 0 1px 4px 0 rgba(0,0,0,.1);
-webkit-box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.1);
-webkit-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
-o-transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
transition: border .2s linear,color .2s linear,width .2s linear,background-color .2s linear;
@ -114,4 +125,326 @@ body.agamaMode {
.app-closing {
position: relative;
top: 50px;
}
.height--auto {
height: auto;
}
.settings-title {
font-weight: bold;
margin-bottom: 30px;
}
.margin-right-5 {
margin-right: 5px;
}
.margin-right-10 {
margin-right: 10px;
}
.margin-right-20 {
margin-right: 20px;
}
.margin-top-15 {
margin-top: 15px;
}
.margin-top-20 {
margin-top: 20px;
}
.pull-left {
float: left;
margin-left: 50px;
}
.btn-close {
border-bottom-left-radius: 50%;
background: #fff;
color: rgba(33, 33, 33, 0.85);
padding: 8px 10px;
font-weight: bold;
font-size: 20px;
position: absolute;
top: 0;
right: 0;
cursor: pointer;
}
.btn-close img {
height: 12px;
position: relative;
top: -1px;
right: -1px;
}
.btn-mode img {
height: 20px;
position: relative;
top: -1px;
left: -4px;
padding-right: 5px;
}
/* settings */
.settings-help {
position: relative;
top: -2px;
left: 10px;
color: #fff;
border-radius: 50%;
background: #5683ad;
display: inline-block;
padding: 4px 4px;
line-height: 30px;
cursor: default;
}
.settings-help img {
height: 13px;
}
.settings-buttons-block {
margin-top: 50px;
margin-right: 50px;
text-align: right;
}
.settings-table {
margin: 0 auto;
width: 650px;
text-align: left;
}
.settings-table input[type="number"] {
width: 100px;
padding: 0 4px;
}
.settings-table input[type="text"] {
width: 100%;
padding: 0 4px;
}
.settings-table td {
padding-bottom: 35px;
}
.settings-table tr:last-child td {
padding: 0;
}
.settings-table .left {
width: 50%;
}
.settings-table .right {
width: 50%;
text-align: left;
}
.agama-app-settings-window #agamaModeStatus {
padding-bottom: 50px;
}
/* toggle */
.slider {
border-radius: 20px;
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #fff;
transition: .4s;
}
.switch input {
display: none;
}
input[type=checkbox],
input[type=radio] {
margin: 4px 0 0;
margin-top: 1px\9;
line-height: normal;
}
input[type=checkbox],
input[type=radio] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
.switch {
position: relative;
display: inline-block;
width: 40px;
height: 24px;
}
label {
font-weight: 300;
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 700;
}
input:checked + .slider {
background: #36ab7a;
}
input:checked + .slider:before {
background: #fff;
}
input:checked + .slider:before {
-ms-transform: translateX(16px);
transform: translateX(16px);
}
.slider:before {
content: '';
display: inline-block;
border-radius: 50%;
position: absolute;
height: 20px;
width: 20px;
left: 2px;
bottom: 2px;
background-color: #ccc;
transition: .4s;
}
input[type="text"],
input[type="number"] {
color: rgb(33, 33, 33);
}
/* toastr */
#toast-container {
position: fixed;
z-index: 999999;
}
.toast-bottom-right {
right: 12px;
bottom: 12px;
}
#toast-container > .toast-success {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==) !important;
}
#toast-container > .toast-error {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=) !important;
}
#toast-container > div {
margin: 0 0 6px;
padding: 15px 15px 15px 50px;
width: 300px;
-moz-border-radius: 3px 3px 3px 3px;
-webkit-border-radius: 3px 3px 3px 3px;
border-radius: 3px 3px 3px 3px;
background-position: 15px center;
background-repeat: no-repeat;
color: #fff;
}
.toast-success {
background-color: #51a351;
}
.toast-error {
background-color: #bd362f;
}
.toast-title {
font-weight: bold;
text-align: left;
margin-left: 10px;
}
button.toast-close-button {
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
}
.toast-close-button {
position: relative;
right: -0.3em;
top: -0.3em;
float: right;
font-size: 20px;
font-weight: bold;
color: #fff;
-webkit-text-shadow: 0 1px 0 #fff;
text-shadow: 0 1px 0 #fff;
opacity: .8;
-ms-filter: alpha(opacity=80);
filter: alpha(opacity=80);
}
.toast-message {
text-align: left;
margin-left: 10px;
-ms-word-wrap: break-word;
word-wrap: break-word;
}
.test-bins {
text-align: left;
margin-top: 10px;
margin-left: 30px;
}
.btn-caret {
display: inline-block;
position: relative;
left: -4px;
height: 36px;
border-bottom-left-radius: 0;
border-top-left-radius: 0;
box-shadow: none;
width: 38px;
}
.btn-caret:before {
content: '';
display: inline-block;
position: absolute;
height: 25px;
background: #fff;
width: 1px;
left: -2px;
top: 4px;
}
.btn-caret img {
height: 14px;
position: absolute;
top: 10px;
left: 10px;
}
.btn-native {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.btn-native:hover + .btn-caret:before {
display: none;
}
.btn-caret:hover:before {
display: none;
}
.dropdown-menu {
display: inherit;
top: inherit;
left: inherit;
right: 48%;
padding: 2px 0;
}
.dropdown-menu li {
cursor: pointer;
margin: 5px 0;
}
body.iguana-less {
height: 570px;
}
.iguana-less #iguanaCorePort,
.iguana-less #useBasiliskInstance {
display: none;
}

BIN
assets/mainWindow/img/fa-caret-down.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/mainWindow/img/fa-caret-up.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/mainWindow/img/fa-close.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/mainWindow/img/fa-cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
assets/mainWindow/img/fa-cube.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
assets/mainWindow/img/fa-cubes.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
assets/mainWindow/img/fa-question.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

6
assets/mainWindow/js/init.js

@ -3,6 +3,12 @@ $(document).ready(function() {
var window = remote.getCurrentWindow();
var appConf = remote.getCurrentWindow().appConfig;
if (!appConf.experimentalFeatures) {
$('#normalStartBtn').hide();
$('.dropdown-menu').css('right', '34.8%');
$('#nativeOnlyBtnCarret').css('margin-right', '0');
}
$('#pulse').jRoll({
radius: 100,
animation: 'pulse'

301
assets/mainWindow/js/loading.js

@ -1,59 +1,284 @@
function closeMainWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
let _configCopy;
window.createWindow('open');
window.hide();
function toggleDropdown() {
const _dropdown = $('.dropdown-menu');
if (_dropdown.hasClass('hide')) {
_dropdown.removeClass('hide');
} else {
_dropdown.addClass('hide');
}
}
function quitApp() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
function initSettingsForm() {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
let appConfSchema = remote.getCurrentWindow().appConfigSchema;
_configCopy = Object.assign({}, appConf);
if (!appConf.experimentalFeatures) {
$('.agama-app-settings-window').addClass('iguana-less');
}
let _htmlOut = '<table class="settings-table">';
for (let key in appConf) {
if (appConfSchema[key] &&
appConfSchema[key].initDisplay) {
_htmlOut = `
${_htmlOut}
<tr id="${key}">
<td class="left">
${appConfSchema[key].displayName}`;
window.forseCloseApp();
if (appConfSchema[key].info) {
_htmlOut = `
${_htmlOut}
<div
class="settings-help"
title="${appConfSchema[key].info}">
<img src="../EasyDEX-GUI/assets/mainWindow/img/fa-question.png" />
</div>`;
}
if (appConfSchema[key].type === 'number') {
_htmlOut = `
${_htmlOut}
</td>
<td class="right">
<input
type="number"
id="${key}"
pattern="[0-9]*"
onKeyup="handleInput('${key}')"
value="${_configCopy[key]}" />
</td>
</tr>`;
} else if (appConfSchema[key].type === 'string' || appConfSchema[key].type === 'folder') {
_htmlOut = `
${_htmlOut}
</td>
<td class="right">
<input
type="text"
id="${key}"
onKeyup="handleInput('${key}')"
value="${_configCopy[key]}" />
</td>
</tr>`;
} else if (appConfSchema[key].type === 'boolean') {
_htmlOut = `${_htmlOut}
</td>
<td class="right">
<label
class="switch"
id="${key}"
onClick="settingsToggle(\'${key}\')">
${(appConf[key] ? '<input type="checkbox" class="cb" checked />' : '<input type="checkbox" class="cb" />')}
<div class="slider"></div>
</label>
</td>
</tr>`;
}
}
}
function normalStart() {
_htmlOut = `
${_htmlOut}
</table>`;
$('#agamaConfigBlock').html(_htmlOut);
}
function hideToastImmediate() {
$('#toast-container').addClass('hide');
}
function hideToast() {
setTimeout(function() {
$('#toast-container').addClass('hide');
}, 5000);
}
function showToast(type, message) {
$('#toast-container .toast').removeClass('toast-success').removeClass('toast-error');
$('#toast-container .toast').addClass(`toast-${type}`);
$('#toast-container .toast-message').html(message);
$('#toast-container').removeClass('hide');
hideToast();
}
function setDefaultAppSettings() {
const remote = require('electron').remote;
remote.getCurrentWindow().setDefaultAppSettings();
remote.getCurrentWindow().appConfig = remote.getCurrentWindow().defaultAppSettings;
initSettingsForm();
showToast('success', 'App settings are reset to default');
}
function testBins(binName) {
const remote = require('electron').remote;
remote.getCurrentWindow().testBins(binName).
then(function(res) {
$('#debugOut').html(JSON.stringify(res, null, '\t'));
});
}
function handleSaveSettings() {
if (_configCopy.dataDir &&
_configCopy.dataDir.length) {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
appConf.iguanaLessMode = false;
// run iguana-less mode with no daemons startup
if (appConf && appConf.iguanaLessMode) {
// do something
} else { // run normal mode with 2 iguana instances started prior loading GUI
if (appConf && !appConf.manualIguanaStart) {
StartIguana();
remote.getCurrentWindow().testLocation(_configCopy.dataDir)
.then(function(res) {
$('#debugOut').html(res + ' | ' + _configCopy.dataDir);
if (res === -1) {
showToast('error', 'Komodo datadir path is invalid');
} else if (res === false) {
showToast('error', 'Komodo datadir path is not a directory');
} else {
// save settings
remote.getCurrentWindow().updateAppSettings(_configCopy);
remote.getCurrentWindow().appConfig = _configCopy;
showToast('success', 'Settings saved');
}
});
} else {
// save settings
const remote = require('electron').remote;
var portcheck;
remote.getCurrentWindow().updateAppSettings(_configCopy);
remote.getCurrentWindow().appConfig = _configCopy;
showToast('success', 'Settings saved');
}
}
function startcheck() {
portcheck = setInterval(function() {
Iguana_activehandle(appConf).then(function(result){
console.log(result);
function handleInput(key) {
const _value = $(`#${key}`).val();
_configCopy[key] = _value;
}
if (result !== 'error') {
stopcheck();
function settingsToggle(key) {
const _value = $(`#${key} .cb`).prop('checked');
_configCopy[key] = _value;
}
if (appConf && appConf.useBasiliskInstance) {
StartIguana_Cache();
}
function closeSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
toggleDropdown();
window.destroyAppSettingsWindow();
}
function reloadSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('#loading_status_text').text('Connecting to Basilisk Network...');
EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf);
window.reloadSettingsWindow();
}
function openSettingsWindow() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
window.createAppSettingsWindow();
}
function startKMDPassive() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
disableModeButtons();
window.startKMDNative('KMD', true);
window.createWindow('open');
window.hide();
}
function closeMainWindow(isKmdOnly, isCustom) {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
$('.dropdown-menu').addClass('hide');
disableModeButtons();
if (!isCustom) {
window.startKMDNative(isKmdOnly ? 'KMD' : null);
setTimeout(function() {
window.createWindow('open');
window.hide();
}, 3000);
} else {
window.createWindow('open');
window.hide();
}
}
function quitApp() {
const remote = require('electron').remote;
const window = remote.getCurrentWindow();
window.forseCloseApp();
}
function disableModeButtons() {
$('#nativeOnlyBtn').attr('disabled', true);
$('#normalStartBtn').attr('disabled', true);
$('#settingsBtn').attr('disabled', true);
$('#nativeOnlyBtnCarret').attr('disabled', true);
}
function normalStart() {
const remote = require('electron').remote;
let appConf = remote.getCurrentWindow().appConfig;
appConf.iguanaLessMode = false;
$('.dropdown-menu').addClass('hide');
disableModeButtons();
// run iguana-less mode with no daemons startup
if (appConf &&
appConf.iguanaLessMode) {
// do something
} else { // run normal mode with 2 iguana instances started prior loading GUI
if (appConf &&
!appConf.manualIguanaStart) {
StartIguana();
}
var portcheck;
function startcheck() {
portcheck = setInterval(function() {
Iguana_activehandle(appConf).then(function(result){
console.log(result);
if (result !== 'error') {
stopcheck();
if (appConf && appConf.useBasiliskInstance) {
StartIguana_Cache();
}
})
}, 2000);
}
function stopcheck() {
clearInterval(portcheck);
}
$('#loading_status_text').text('Connecting to Basilisk Network...');
EDEX_DEXgetinfoAll(appConf.skipBasiliskNetworkCheck, appConf.minNotaries, appConf);
}
})
}, 2000);
}
startcheck();
function stopcheck() {
clearInterval(portcheck);
}
startcheck();
}
}
function IguanaAJAX(url, ajax_data, timeout) {
return $.ajax({

3
react/change.log

@ -8,7 +8,7 @@ UI:
- minor placeholders fixes
- hide address dropdown if wallet has only one address
- komodod crash report modal
- values rounding (up to 6 decimals)
- values clipping
- add coin multi ui reflow fix
- reset app setting to default
- manual balance / transactions list refresh
@ -26,6 +26,7 @@ UI:
- coin daemon port check on addcoin
- updated application settings
- komodo datadir
- windows bins path fix
v0.2.0.21a-beta
--------------

61
react/src/actions/actionCreators.js

@ -6,7 +6,6 @@ import {
GET_ACTIVE_COINS,
DASHBOARD_ACTIVE_ADDRESS,
VIEW_CACHE_DATA,
DASHBOARD_DISPLAY_NOTARIES_MODAL,
DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR,
DASHBOARD_ACTIVE_SECTION,
DASHBOARD_ACTIVE_TXINFO_MODAL,
@ -29,13 +28,10 @@ import {
DISPLAY_COIND_DOWN_MODAL,
DISPLAY_CLAIM_INTEREST_MODAL,
START_INTERVAL,
STOP_INTERVAL
STOP_INTERVAL,
DASHBOARD_SYNC_ONLY_UPDATE,
DISPLAY_IMPORT_KEY_MODAL,
} from './storeType';
import {
logGuiHttp,
getAgamaLog,
guiLogState
} from './actions/log';
export * from './actions/nativeSyncInfo';
export * from './actions/basiliskCache';
@ -52,7 +48,6 @@ export * from './actions/sendFullBasilisk';
export * from './actions/settings';
export * from './actions/syncOnly';
export * from './actions/iguanaInstance';
export * from './actions/notary';
export * from './actions/edexBalance';
export * from './actions/addCoin';
export * from './actions/addressBalance';
@ -71,6 +66,7 @@ export * from './actions/cli';
export * from './actions/update';
export * from './actions/jumblr';
export * from './actions/interest';
export * from './actions/nativeDashboardUpdate';
export function changeActiveAddress(address) {
return {
@ -92,13 +88,6 @@ export function toggleViewCacheModal(display) {
}
}
export function displayNotariesModal(display) {
return {
type: DASHBOARD_DISPLAY_NOTARIES_MODAL,
display,
}
}
export function changeMainBasiliskAddress(address) {
return {
type: DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR,
@ -121,34 +110,6 @@ export function toggleDashboardTxInfoModal(display, txIndex) {
}
}
export function basiliskConnectionState(display, json) {
return {
type: BASILISK_CONNECTION,
basiliskConnection: display,
progress: json,
}
}
export function basiliskRefreshState(display, json) {
return {
type: BASILISK_REFRESH,
basiliskRefresh: display,
progress: json,
}
}
export function basiliskRefresh(display) {
return dispatch => {
dispatch(basiliskRefreshState(display));
}
}
export function basiliskConnection(display) {
return dispatch => {
dispatch(basiliskConnectionState(display));
}
}
export function syncingNativeModeState(display, json) {
return {
type: SYNCING_NATIVE_MODE,
@ -382,4 +343,18 @@ export function toggleClaimInterestModal(display) {
type: DISPLAY_CLAIM_INTEREST_MODAL,
displayClaimInterestModal: display,
}
}
export function skipFullDashboardUpdate(skip) {
return {
type: DASHBOARD_SYNC_ONLY_UPDATE,
skipFullDashboardUpdate: skip,
}
}
export function displayImportKeyModal(display) {
return {
type: DISPLAY_IMPORT_KEY_MODAL,
displayImportKeyModal: display,
}
}

34
react/src/actions/actions/addCoin.js

@ -7,10 +7,6 @@ import {
startIguanaInstance,
iguanaWalletPassphraseState,
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import {
startCurrencyAssetChain,
startAssetChain,
@ -96,31 +92,12 @@ export function addCoin(coin, mode, syncOnly, port, startupParams) {
export function iguanaAddCoin(coin, mode, acData, port) {
function _iguanaAddCoin(dispatch) {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaAddCoin',
type: 'post',
url: `http://127.0.0.1:${(port ? port : Config.iguanaCorePort)}`,
payload: acData,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${(port ? port : Config.iguanaCorePort)}`, {
method: 'POST',
body: JSON.stringify(acData),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
translate('TOASTR.FAILED_TO_ADDCOIN'),
@ -131,13 +108,6 @@ export function iguanaAddCoin(coin, mode, acData, port) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
addCoinResult(
coin,
@ -287,7 +257,7 @@ export function shepherdHerd(coin, mode, path, startupParams) {
console.warn(acData);
dispatch(
triggerToaster(
`Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`,
`Error starting ${coin} daemon. Port ${acData.rpc} is already taken!`, // translate
translate('TOASTR.SERVICE_NOTIFICATION'),
'error',
false
@ -372,7 +342,7 @@ export function iguanaActiveHandleBypass() {
.then(response => response.json())
.then(
json => dispatch(
iguanaWalletPassphraseState(json, dispatch)
iguanaWalletPassphraseState(json, dispatch, true)
)
)
}

113
react/src/actions/actions/addressBalance.js

@ -5,10 +5,6 @@ import {
getPassthruAgent,
iguanaHashHex
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function getKMDAddressesNativeState(json) {
@ -105,18 +101,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -139,13 +123,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative',
@ -156,13 +133,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(Config.cli.default && mode === 'native' ? json.result : json);
})
}
@ -307,16 +277,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
hex: hashHexJson,
};
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+ZBalance',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
@ -349,13 +309,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+ZBalance',
@ -369,13 +322,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
if (json &&
json.error) {
resolve(0);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: json,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+ZBalance',
@ -394,13 +340,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
amount: json,
type: 'private',
};
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
}
});
});
@ -448,31 +387,12 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
if (json[coin][currentAddress].refresh) {
calcBalance(result, json[coin][currentAddress].refresh.data, dispatch, mode);
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+Balance',
type: 'post',
url: `http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+Balance',
@ -483,13 +403,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
})
.then(response => response.json())
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
updatedCache.basilisk[coin][currentAddress].refresh = {
data: json,
status: 'done',
@ -506,18 +419,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
}
})
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDAddressesNative+Balance',
type: 'post',
url: `http://127.0.0.1:${(Config.useBasiliskInstance && mode === 'basilisk' ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -547,13 +448,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDAddressesNative+Balance',
@ -568,13 +462,6 @@ export function getKMDAddressesNative(coin, mode, currentAddress) {
mode === 'native') {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
calcBalance(
result,
json,

30
react/src/actions/actions/atomic.js

@ -1,38 +1,15 @@
import { ATOMIC } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function atomic(payload) {
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'atomic',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
payload.method,
@ -43,13 +20,6 @@ export function atomic(payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(atomicState(json));
});
}

4
react/src/actions/actions/basiliskCache.js

@ -1,9 +1,5 @@
import { DASHBOARD_ACTIVE_COIN_GET_CACHE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
// TODO: rewrite cache API to use POST

56
react/src/actions/actions/basiliskProcessAddress.js

@ -1,9 +1,5 @@
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function checkAddressBasilisk(coin, address) {
@ -16,31 +12,12 @@ export function checkAddressBasilisk(coin, address) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'checkAddressBasilisk',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'checkAddressBasilisk',
@ -51,13 +28,6 @@ export function checkAddressBasilisk(coin, address) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(checkAddressBasiliskHandle(json));
})
}
@ -102,31 +72,12 @@ export function validateAddressBasilisk(coin, address) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'validateAddressBasilisk',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'validateAddressBasilisk',
@ -137,13 +88,6 @@ export function validateAddressBasilisk(coin, address) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(validateAddressBasiliskHandle(json));
})
}

4
react/src/actions/actions/basiliskTxHistory.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNativeTxHistoryState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getBasiliskTransactionsList(coin, address) {

4
react/src/actions/actions/cli.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import { CLI } from '../storeType';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function shepherdCliPromise(mode, chain, cmd) {

4
react/src/actions/actions/coinList.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function shepherdGetCoinList() {

30
react/src/actions/actions/createWallet.js

@ -1,9 +1,5 @@
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function createNewWalletState(json) {
@ -41,31 +37,12 @@ export function createNewWallet(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'createNewWallet',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'createNewWallet',
@ -76,13 +53,6 @@ export function createNewWallet(_passphrase) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(createNewWalletState(json));
})
}

30
react/src/actions/actions/dexCoins.js

@ -2,10 +2,6 @@ import {
triggerToaster,
dashboardCoinsState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
// TODO: find out why it errors on slow systems
@ -17,18 +13,6 @@ export function getDexCoins() {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexCoins',
type: 'post',
url: Config.iguanaLessMode ? `http://127.0.0.1:${Config.agamaPort}/shepherd/InstantDEX/allcoins` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(_payload),
@ -49,13 +33,6 @@ export function getDexCoins() {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error getDexCoins',
@ -66,13 +43,6 @@ export function getDexCoins() {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(dashboardCoinsState(json));
});
}

49
react/src/actions/actions/edexBalance.js

@ -1,9 +1,5 @@
import { DASHBOARD_ACTIVE_COIN_BALANCE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function iguanaEdexBalance(coin) {
@ -16,31 +12,12 @@ export function iguanaEdexBalance(coin) {
return dispatch => {
if (coin) {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaEdexBalance',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(_payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error iguanaEdexBalance',
@ -73,31 +50,12 @@ export function getDexBalance(coin, mode, addr) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexBalance',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getDexBalance',
@ -109,13 +67,6 @@ export function getDexBalance(coin, mode, addr) {
.then(response => response.json())
.then(json => {
console.log(json);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
})
resolve(index);

30
react/src/actions/actions/edexGetTx.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function edexGetTransaction(data, dispatch) {
@ -16,31 +12,12 @@ export function edexGetTransaction(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'edexGetTransaction',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'edexGetTransaction',
@ -51,13 +28,6 @@ export function edexGetTransaction(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});

30
react/src/actions/actions/fullTxHistory.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNativeTxHistoryState
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getFullTransactionsList(coin) {
@ -21,31 +17,12 @@ export function getFullTransactionsList(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getFullTransactionsList',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getFullTransactionsList',
@ -56,13 +33,6 @@ export function getFullTransactionsList(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getNativeTxHistoryState(json));
})
}

30
react/src/actions/actions/getAddrByAccount.js

@ -1,8 +1,4 @@
import { ACTIVE_COIN_GET_ADDRESSES } from '../storeType';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getAddressesByAccountState(json, coin, mode) {
@ -36,31 +32,12 @@ export function getAddressesByAccount(coin, mode) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getAddressesByAccount',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(updateErrosStack('activeHandle'));
dispatch(
triggerToaster(
@ -72,13 +49,6 @@ export function getAddressesByAccount(coin, mode) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
getAddressesByAccountState(
json,

30
react/src/actions/actions/iguanaHelpers.js

@ -1,7 +1,3 @@
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
import { checkAC } from '../../components/addcoin/payload';
@ -29,31 +25,12 @@ export function iguanaHashHex(data, dispatch) {
if (Config.cli.default) {
resolve(true);
} else {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaHashHex',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'iguanaHashHex',
@ -64,13 +41,6 @@ export function iguanaHashHex(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json.hex);
})
}

20
react/src/actions/actions/iguanaInstance.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function restartIguanaInstance(pmid) {
@ -28,22 +24,6 @@ export function restartIguanaInstance(pmid) {
});
}
export function restartBasiliskInstance() {
return dispatch => {
getIguanaInstancesList()
.then(function(json) {
for (let port in json.result) {
if (json.result[port].mode === 'basilisk') {
restartIguanaInstance(json.result[port].pmid)
.then(function(json) {
console.log('restartBasiliskInstance', json);
});
}
}
});
}
}
export function startIguanaInstance(mode, coin) {
return new Promise((resolve, reject) => {
fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/forks`, {

4
react/src/actions/actions/interest.js

@ -1,10 +1,6 @@
import {
triggerToaster
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getListUnspent(coin) {

8
react/src/actions/actions/jumblr.js

@ -2,10 +2,6 @@ import {
triggerToaster,
getNewKMDAddresses
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
function getNewAddress(coin) { // TODO: remove(?)
@ -121,7 +117,7 @@ function dumpPrivkey(coin, key) {
});
}
export function importPrivkey(coin, key) {
export function importPrivkey(coin, key, rescan = false) {
return new Promise((resolve, reject) => {
const payload = {
mode: null,
@ -130,7 +126,7 @@ export function importPrivkey(coin, key) {
params: [
key,
'',
false
rescan
],
};

61
react/src/actions/actions/log.js

@ -1,61 +0,0 @@
import { LOG_GUI_HTTP } from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
export function logGuiHttp(payload) {
return dispatch => {
dispatch(guiLogState(payload));
// disabled for now
/*return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/guilog`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(triggerToaster('logGuiHttp', 'Error', 'error'));
})
.then(response => response.json())*/
}
}
export function getAgamaLog(type) {
return dispatch => {
return fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/getlog?type=${type}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getAgamaLog',
'Error',
'error'
)
);
})
.then(response => response.json())
}
}
export function guiLogState(logData) {
return {
type: LOG_GUI_HTTP,
timestamp: logData.timestamp,
log: {
timestamp: logData.timestamp,
function: logData.function,
httpMethod: logData.type,
url: logData.url,
payload: logData.payload,
status: logData.status,
response: logData.response,
}
}
}

30
react/src/actions/actions/logout.js

@ -4,10 +4,6 @@ import {
} from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function logoutState(json) {
sessionStorage.removeItem('IguanaActiveAccount');
@ -38,31 +34,12 @@ function walletLock() {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'walletLock',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'walletLock',
@ -73,13 +50,6 @@ function walletLock() {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(logoutState(json));
dispatch(logoutResetAppState());
})

30
react/src/actions/actions/nativeBalance.js

@ -4,10 +4,6 @@ import {
getPassthruAgent
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getKMDBalanceTotal(coin) {
let payload;
@ -41,18 +37,6 @@ export function getKMDBalanceTotal(coin) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDBalanceTotal',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -74,13 +58,6 @@ export function getKMDBalanceTotal(coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDBalanceTotal',
@ -91,13 +68,6 @@ export function getKMDBalanceTotal(coin) {
})
.then(response => response.json())
.then(function(json) { // TODO: figure out why komodod spits out "parse error"
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json &&
!json.error) {
dispatch(getNativeBalancesState(json));

86
react/src/actions/actions/nativeDashboardUpdate.js

@ -0,0 +1,86 @@
import {
triggerToaster,
} from '../actionCreators';
import Config from '../../config';
import { DASHBOARD_UPDATE } from '../storeType';
export function getDashboardUpdate(coin, activeCoinProps) {
return dispatch => {
const _fetchConfig = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ coin: coin }),
};
return fetch(
`http://127.0.0.1:${Config.agamaPort}/shepherd/native/dashboard/update`,
_fetchConfig
)
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'getDashboardUpdate',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
dispatch(getDashboardUpdateState(json, coin));
// dirty hack to trigger dashboard render
if (!activeCoinProps.balance &&
!activeCoinProps.addresses) {
setTimeout(() => {
dispatch(getDashboardUpdateState(json, coin));
}, 100);
}
})
}
}
export function getDashboardUpdateState(json, coin, fakeResponse) {
// rescan or similar resource heavy process
if (fakeResponse ||
((json.result['getinfo'].error && json.result['getinfo'].error === 'daemon is busy') &&
(json.result['z_getoperationstatus'].error && json.result['z_getoperationstatus'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy') &&
(json.result['listtransactions'].error && json.result['listtransactions'].error === 'daemon is busy'))) {
return {
type: DASHBOARD_UPDATE,
progress: null,
opids: null,
txhistory: null,
balance: null,
addresses: null,
coin: coin,
rescanInProgress: true,
};
} else {
let _listtransactions = json.result['listtransactions'];
if (_listtransactions &&
_listtransactions.error) {
_listtransactions = null;
} else if (_listtransactions && _listtransactions.result && _listtransactions.result.length) {
_listtransactions = _listtransactions.result;
} else if (!_listtransactions || (!_listtransactions.result || !_listtransactions.result.length)) {
_listtransactions = 'no data';
}
return {
type: DASHBOARD_UPDATE,
progress: json.result['getinfo'].result,
opids: json.result['z_getoperationstatus'].result,
txhistory: _listtransactions,
balance: json.result['z_gettotalbalance'].result,
addresses: json.result['addresses'],
coin: coin,
rescanInProgress: false,
};
}
}

30
react/src/actions/actions/nativeNewAddress.js

@ -5,10 +5,6 @@ import {
getKMDAddressesNative
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getNewKMDAddresses(coin, pubpriv, mode) {
let payload;
@ -34,18 +30,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getNewKMDAddresses',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -73,13 +57,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getNewKMDAddresses',
@ -93,13 +70,6 @@ export function getNewKMDAddresses(coin, pubpriv, mode) {
if (Config.cli.default) {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
triggerToaster(
json.result ? json.result : json,

61
react/src/actions/actions/nativeSend.js

@ -5,10 +5,6 @@ import {
getPassthruAgent,
iguanaHashHex
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function sendNativeTx(coin, _payload) {
@ -47,18 +43,6 @@ export function sendNativeTx(coin, _payload) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendNativeTx',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -110,13 +94,6 @@ export function sendNativeTx(coin, _payload) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendNativeTx',
@ -130,14 +107,6 @@ export function sendNativeTx(coin, _payload) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json.indexOf('"code":') > -1) {
const _message = json.substring(
`${json.indexOf('"message":"')}11`,
@ -230,18 +199,6 @@ export function getKMDOPID(opid, coin) {
};
}
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getKMDOPID',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -251,7 +208,7 @@ export function getKMDOPID(opid, coin) {
payload = {
mode: null,
chain: coin,
cmd: 'z_getoperationstatus'
cmd: 'z_getoperationstatus',
};
_fetchConfig = {
@ -269,13 +226,6 @@ export function getKMDOPID(opid, coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getKMDOPID',
@ -289,13 +239,6 @@ export function getKMDOPID(opid, coin) {
if (Config.cli.default) {
json = json.result;
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getKMDOPIDState(json));
})
})
@ -342,6 +285,6 @@ export function sendToAddressPromise(coin, address, amount) {
.then(response => response.json())
.then(json => {
resolve(json);
})
});
});
}

235
react/src/actions/actions/nativeSyncInfo.js

@ -1,98 +1,105 @@
import { SYNCING_NATIVE_MODE } from '../storeType';
import {
SYNCING_NATIVE_MODE,
DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE
} from '../storeType';
import {
triggerToaster,
getPassthruAgent,
getDebugLog,
toggleCoindDownModal
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
import Config from '../../config';
export function getSyncInfoNativeKMD(skipDebug, json) {
const coin = 'KMD';
// https://www.kmd.host/
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfoNativeKMD',
type: 'post',
url: Config.iguanaLessMode ? 'http://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`,
payload: '',
status: 'pending',
}));
}
export function nativeGetinfoFailureState() {
return {
type: DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE,
}
}
// TODO: use debug.log instead
export function getSyncInfoNativeKMD(skipDebug, json, skipRemote) {
let _json = json;
if (skipRemote) {
return dispatch => {
dispatch(getSyncInfoNativeState(Config.iguanaLessMode ? json.info : json ));
return fetch(
Config.iguanaLessMode ? 'http://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
/*dispatch(
triggerToaster(
'getSyncInfoNativeKMD',
'Error',
'error'
)
);*/
console.warn('remote kmd node fetch failed', true);
dispatch(getSyncInfoNativeState({ remoteKMDNode: null }));
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: Config.iguanaLessMode ? json.info : json,
}));
}
dispatch(getSyncInfoNativeState({ remoteKMDNode: Config.iguanaLessMode ? json.info : json }));
})
.then(function() {
if (!skipDebug) {
dispatch(getDebugLog('komodo', 1));
}
})
}
} else {
const coin = 'KMD';
// https://www.kmd.host/
return dispatch => {
return fetch(
Config.iguanaLessMode ? 'https://kmd.explorer.supernet.org/api/status?q=getInfo' : `http://127.0.0.1:${Config.iguanaCorePort}/api/dex/getinfo?userpass=tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}&symbol=${coin}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
/*dispatch(
triggerToaster(
'getSyncInfoNativeKMD',
'Error',
'error'
)
);*/
console.warn('remote kmd node fetch failed', true);
_json = _json.error;
_json['remoteKMDNode'] = null;
dispatch(getSyncInfoNativeState(_json));
})
.then(response => response.json())
.then(json => {
_json = _json.error;
_json['remoteKMDNode'] = json.info;
dispatch(getSyncInfoNativeState(_json));
})
.then(function() {
if (!skipDebug) {
dispatch(getDebugLog('komodo', 1));
}
})
}
}
}
function getSyncInfoNativeState(json, coin, skipDebug) {
if (coin === 'KMD' &&
json &&
json.error &&
json.error.message.indexOf('Activating best') === -1) {
return getSyncInfoNativeKMD(skipDebug, json);
function getSyncInfoNativeState(json, coin, skipDebug, skipRemote) {
/*if (!json.remoteKMDNode) {
json = { error: { code: -28, message: 'Activating best chain...' } };
}*/
if (json.remoteKMDNode) {
return {
type: SYNCING_NATIVE_MODE,
progress: json,
}
} else {
if (json &&
if (coin === 'KMD' &&
json &&
json.error &&
Config.cli.default) {
return {
type: SYNCING_NATIVE_MODE,
progress: json.error,
}
json.error.message.indexOf('Activating best') > -1) {
return getSyncInfoNativeKMD(skipDebug, json, skipRemote);
} else {
return {
type: SYNCING_NATIVE_MODE,
progress: json.result ? json.result : json,
if (json &&
json.error &&
Config.cli.default) {
return {
type: SYNCING_NATIVE_MODE,
progress: json.error,
}
} else {
return {
type: SYNCING_NATIVE_MODE,
progress: json.result ? json.result : json,
}
}
}
}
}
export function getSyncInfoNative(coin, skipDebug) {
export function getSyncInfoNative(coin, skipDebug, skipRemote, suppressErrors) {
let payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: getPassthruAgent(coin),
@ -111,17 +118,6 @@ export function getSyncInfoNative(coin, skipDebug) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfo',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -143,20 +139,15 @@ export function getSyncInfoNative(coin, skipDebug) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
if (!suppressErrors) { // rescan case
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
}
dispatch(
triggerToaster(
'getSyncInfo',
'Error',
'error'
)
);
})
.then(function(response) {
const _response = response.text().then(function(text) { return text; });
@ -164,6 +155,11 @@ export function getSyncInfoNative(coin, skipDebug) {
})
.then(json => {
if (json === 'Work queue depth exceeded') {
if (coin === 'KMD') {
dispatch(getDebugLog('komodo', 100));
} else {
dispatch(getDebugLog('komodo', 100, coin));
}
dispatch(
getSyncInfoNativeState(
{
@ -172,20 +168,39 @@ export function getSyncInfoNative(coin, skipDebug) {
id: null
},
coin,
skipDebug
true,
skipRemote
)
);
} else {
if (!json &&
Config.cli.default) {
dispatch(
triggerToaster(
'Komodod is down',
'Critical Error',
'error',
true
)
);
let _kmdMainPassiveMode;
try {
_kmdMainPassiveMode = window.require('electron').remote.getCurrentWindow().kmdMainPassiveMode;
} catch (e) {}
if (!_kmdMainPassiveMode) {
dispatch(nativeGetinfoFailureState());
/* dispatch(
triggerToaster(
'Komodod is down',
'Critical Error',
'error',
true
)
); */
} else {
dispatch(
triggerToaster(
'Please make sure to run komodod manually',
'Connection error',
'warning',
true
)
);
}
if (coin === 'KMD') {
dispatch(getDebugLog('komodo', 50));
@ -206,18 +221,12 @@ export function getSyncInfoNative(coin, skipDebug) {
}
}
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
getSyncInfoNativeState(
json,
coin,
skipDebug
skipDebug,
skipRemote
)
);
}

30
react/src/actions/actions/nativeTxHistory.js

@ -4,10 +4,6 @@ import {
getNativeTxHistoryState
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function getNativeTxHistory(coin) {
let payload;
@ -32,18 +28,6 @@ export function getNativeTxHistory(coin) {
}
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getNativeTxHistory',
type: 'post',
url: Config.cli.default ? `http://127.0.0.1:${Config.agamaPort}/shepherd/cli` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(payload),
@ -71,13 +55,6 @@ export function getNativeTxHistory(coin) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getNativeTxHistory',
@ -88,13 +65,6 @@ export function getNativeTxHistory(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getNativeTxHistoryState(json));
})
}

223
react/src/actions/actions/notary.js

@ -1,223 +0,0 @@
import {
DASHBOARD_CONNECT_NOTARIES,
DASHBOARD_GET_NOTARIES_LIST
} from '../storeType';
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function initNotaryNodesConSequence(nodes) {
return dispatch => {
Promise.all(nodes.map((node, index) => {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dex',
method: 'getinfo',
symbol: node,
timeout: 10000,
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: `initNotaryNodesConSequence+${node}`,
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${(Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort)}/api/dex/getinfo?userpass=${('tmpIgRPCUser@' + sessionStorage.getItem('IguanaRPCAuth'))}&symbol=${node}`, {
method: 'GET',
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
`getInfoDexNode+${node}`,
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
updateNotaryNodeConState(
json,
nodes.length,
index,
node
)
);
})
});
}));
}
}
function updateNotaryNodeConState(json, totalNodes, currentNodeIndex, currentNodeName) {
if (currentNodeIndex === totalNodes - 1) {
return dispatch => {
dispatch(basiliskConnectionState(false));
};
} else {
if (json &&
json.error === 'less than required responses') {
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: totalNodes - 1,
current: currentNodeIndex,
name: currentNodeName,
failedNode: currentNodeName,
}
} else {
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: totalNodes - 1,
current: currentNodeIndex,
name: currentNodeName,
}
}
}
}
function connectAllNotaryNodes(json, dispatch) {
if (json &&
json.length) {
dispatch(initNotaryNodesConSequence(json));
return {
type: DASHBOARD_CONNECT_NOTARIES,
total: json.length - 1,
current: 0,
name: json[0],
}
}
}
export function connectNotaries() {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dpow',
method: 'notarychains',
};
return dispatch => {
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
dispatch(
triggerToaster(
'connectNotaries',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(
json => dispatch(
connectAllNotaryNodes(json, dispatch)
)
)
}
}
function getDexNotariesState(json) {
if (json.error === 'less than required responses') {
return dispatch => {
dispatch(
triggerToaster(
translate('TOASTR.LESS_RESPONSES_REQ'),
translate('TOASTR.BASILISK_NOTIFICATION'),
'error'
)
);
}
} else {
return {
type: DASHBOARD_GET_NOTARIES_LIST,
notaries: json,
}
}
}
export function getDexNotaries(coin) {
const payload = {
userpass: `tmpIgRPCUser@${sessionStorage.getItem('IguanaRPCAuth')}`,
agent: 'dex',
method: 'getnotaries',
symbol: coin,
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getDexNotaries',
type: 'post',
url: `http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.useBasiliskInstance ? Config.iguanaCorePort + 1 : Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getDexNotaries',
'Error',
'error'
)
);
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getDexNotariesState(json));
})
}
}

4
react/src/actions/actions/openAlias.js

@ -1,8 +1,4 @@
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function resolveOpenAliasAddress(email) {
const url = email.replace('@', '.');

110
react/src/actions/actions/sendFullBasilisk.js

@ -5,10 +5,6 @@ import {
getDispatch
} from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function sendToAddress(coin, _payload) {
const payload = {
@ -24,31 +20,12 @@ export function sendToAddress(coin, _payload) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendToAddress',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendToAddress',
@ -59,13 +36,6 @@ export function sendToAddress(coin, _payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(sendToAddressState(json, dispatch));
})
}
@ -86,31 +56,12 @@ export function sendFromAddress(coin, _payload) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'sendFromAddress',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'sendFromAddress',
@ -121,13 +72,6 @@ export function sendFromAddress(coin, _payload) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(sendToAddressState(json, dispatch));
})
}
@ -151,31 +95,12 @@ export function iguanaUTXORawTX(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaUTXORawTX',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch => dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'iguanaUTXORawTX',
@ -186,13 +111,6 @@ export function iguanaUTXORawTX(data, dispatch) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});
@ -208,31 +126,12 @@ export function dexSendRawTX(data, dispatch) {
};
return new Promise((resolve, reject) => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'dexSendRawTX',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
fetch('http://127.0.0.1:' + Config.iguanaCorePort, {
fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'dexSendRawTX',
@ -247,13 +146,6 @@ export function dexSendRawTX(data, dispatch) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
resolve(json);
})
});

86
react/src/actions/actions/settings.js

@ -8,10 +8,6 @@ import {
import { translate } from '../../translate/translate';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
function getAppInfoState(json) {
return {
@ -56,7 +52,7 @@ function parseImportPrivKeyResponse(json, dispatch) {
return dispatch => {
dispatch(
triggerToaster(
transalte('API.ILLEGAL_PRIVKEY'),
translate('API.ILLEGAL_PRIVKEY'),
translate('TOASTR.SETTINGS_NOTIFICATION'),
'error'
)
@ -67,7 +63,7 @@ function parseImportPrivKeyResponse(json, dispatch) {
return dispatch => {
dispatch(
triggerToaster(
transalte('API.PRIVKEY_IN_WALLET'),
translate('API.PRIVKEY_IN_WALLET'),
translate('TOASTR.SETTINGS_NOTIFICATION'),
'warning'
)
@ -100,31 +96,12 @@ export function importPrivKey(wifKey) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'importPrivKey',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'importPrivKey',
@ -135,13 +112,6 @@ export function importPrivKey(wifKey) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
parseImportPrivKeyResponse(
json,
@ -209,31 +179,12 @@ export function getPeersList(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getPeersList',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getPeersList',
@ -244,13 +195,6 @@ export function getPeersList(coin) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(getPeersListState(json, dispatch));
})
}
@ -331,31 +275,12 @@ export function addPeerNode(coin, ip) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'addPeerNode',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'addPeerNode',
@ -366,13 +291,6 @@ export function addPeerNode(coin, ip) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(addPeerNodeState(json, dispatch));
})
}

30
react/src/actions/actions/syncInfo.js

@ -1,10 +1,6 @@
import { SYNCING_FULL_MODE } from '../storeType';
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
// TODO: add custom json parser
function getSyncInfoState(json) {
@ -30,31 +26,12 @@ export function getSyncInfo(coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'getSyncInfo',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'getSyncInfo',
@ -69,13 +46,6 @@ export function getSyncInfo(coin) {
return _response;
})
.then(function(json) {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (json.indexOf('coin is busy processing') === -1) {
dispatch(getSyncInfoState(json, dispatch));
}

4
react/src/actions/actions/syncOnly.js

@ -5,10 +5,6 @@ import {
import { translate } from '../../translate/translate';
import Config from '../../config';
import { triggerToaster } from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function toggleSyncOnlyModal(display) {
return {

4
react/src/actions/actions/sysInfo.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function shepherdGetSysInfo() {
return dispatch => {

4
react/src/actions/actions/update.js

@ -1,9 +1,5 @@
import { triggerToaster } from '../actionCreators';
import Config from '../../config';
import {
logGuiHttp,
guiLogState
} from './log';
export function checkForUpdateUIPromise() {
return new Promise((resolve, reject) => {

127
react/src/actions/actions/walletAuth.js

@ -9,10 +9,6 @@ import {
getMainAddressState,
updateErrosStack
} from '../actionCreators';
import {
logGuiHttp,
guiLogState
} from './log';
export function encryptWallet(_passphrase, cb, coin) {
const payload = {
@ -23,31 +19,12 @@ export function encryptWallet(_passphrase, cb, coin) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'encryptWallet',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'encryptWallet',
@ -59,13 +36,6 @@ export function encryptWallet(_passphrase, cb, coin) {
.then(dispatch(walletPassphrase(_passphrase)))
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(
cb.call(
this,
@ -87,31 +57,12 @@ export function walletPassphrase(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'walletpassphrase',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'walletPassphrase',
@ -121,13 +72,6 @@ export function walletPassphrase(_passphrase) {
);
})
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
})
}
}
@ -143,31 +87,12 @@ export function iguanaWalletPassphrase(_passphrase) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaWalletPassphrase',
type: 'post',
url: `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
return fetch(`http://127.0.0.1:${Config.iguanaCorePort}`, {
method: 'POST',
body: JSON.stringify(_payload),
})
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(
triggerToaster(
'Error iguanaWalletPassphrase',
@ -178,13 +103,6 @@ export function iguanaWalletPassphrase(_passphrase) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
dispatch(iguanaWalletPassphraseState(json, dispatch));
});
}
@ -198,18 +116,6 @@ export function iguanaActiveHandle(getMainAddress) {
};
return dispatch => {
const _timestamp = Date.now();
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
function: 'iguanaActiveHandle',
type: 'post',
url: Config.iguanaLessMode ? `http://127.0.0.1:${Config.agamaPort}/shepherd/SuperNET/activehandle` : `http://127.0.0.1:${Config.iguanaCorePort}`,
payload: _payload,
status: 'pending',
}));
}
let _fetchConfig = {
method: 'POST',
body: JSON.stringify(_payload),
@ -230,13 +136,6 @@ export function iguanaActiveHandle(getMainAddress) {
)
.catch(function(error) {
console.log(error);
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'error',
response: error,
}));
}
dispatch(updateErrosStack('activeHandle'));
dispatch(
triggerToaster(
@ -248,13 +147,6 @@ export function iguanaActiveHandle(getMainAddress) {
})
.then(response => response.json())
.then(json => {
if (Config.debug) {
dispatch(logGuiHttp({
timestamp: _timestamp,
status: 'success',
response: json,
}));
}
if (!Config.iguanaLessMode &&
sessionStorage.getItem('IguanaActiveAccount') &&
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey === json.pubkey &&
@ -266,15 +158,18 @@ export function iguanaActiveHandle(getMainAddress) {
}
}
export function iguanaWalletPassphraseState(json, dispatch) {
export function iguanaWalletPassphraseState(json, dispatch, skipToastr) {
sessionStorage.setItem('IguanaActiveAccount', JSON.stringify(json));
dispatch(
triggerToaster(
translate('TOASTR.LOGIN_SUCCESSFULL'),
translate('TOASTR.ACCOUNT_NOTIFICATION'),
'success'
)
);
if (!skipToastr) {
dispatch(
triggerToaster(
translate('TOASTR.LOGIN_SUCCESSFULL'),
translate('TOASTR.ACCOUNT_NOTIFICATION'),
'success'
)
);
}
dispatch(getMainAddressState(json));
dispatch(iguanaActiveHandleState(json));

14
react/src/actions/storeType.js

@ -20,8 +20,8 @@ export const BASILISK_CONNECTION = 'BASILISK_CONNECTION';
export const SYNCING_FULL_MODE = 'SYNCING_FULL_MODE';
export const SYNCING_NATIVE_MODE = 'SYNCING_NATIVE_MODE';
export const ACTIVE_COIN_GET_ADDRESSES = 'ACTIVE_COIN_GET_ADDRESSES';
export const START_INTERVAL= 'START_INTERVAL';
export const STOP_INTERVAL= 'STOP_INTERVAL';
export const START_INTERVAL = 'START_INTERVAL';
export const STOP_INTERVAL = 'STOP_INTERVAL';
export const DASHBOARD_ACTIVE_SECTION = 'DASHBOARD_ACTIVE_SECTION';
export const DASHBOARD_ACTIVE_TXINFO_MODAL = 'DASHBOARD_ACTIVE_TXINFO_MODAL';
export const DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE = 'DASHBOARD_ACTIVE_COIN_NATIVE_BALANCE';
@ -30,9 +30,9 @@ export const DASHBOARD_ACTIVE_COIN_NATIVE_OPIDS = 'DASHBOARD_ACTIVE_COIN_NATIVE_
export const DASHBOARD_ACTIVE_COIN_SENDTO = 'DASHBOARD_ACTIVE_COIN_SENDTO';
export const DASHBOARD_ACTIVE_COIN_GET_CACHE = 'DASHBOARD_ACTIVE_COIN_GET_CACHE';
export const DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR = 'DASHBOARD_ACTIVE_COIN_MAIN_BASILISK_ADDR';
export const DASHBOARD_GET_NOTARIES_LIST = 'DASHBOARD_GET_NOTARIES_LIST';
export const DASHBOARD_DISPLAY_NOTARIES_MODAL = 'DASHBOARD_DISPLAY_NOTARIES_MODAL';
export const DASHBOARD_CONNECT_NOTARIES = 'DASHBOARD_CONNECT_NOTARIES';
export const DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE = 'DASHBOARD_ACTIVE_COIN_GETINFO_FAILURE';
export const DASHBOARD_UPDATE = 'DASHBOARD_UPDATE';
export const DASHBOARD_SYNC_ONLY_UPDATE = 'DASHBOARD_SYNC_ONLY_UPDATE';
export const VIEW_CACHE_DATA = 'VIEW_CACHE_DATA';
export const SYNC_ONLY_MODAL_TOGGLE = 'SYNC_ONLY_MODAL_TOGGLE';
export const SYNC_ONLY_DATA = 'SYNC_ONLY_DATA';
@ -41,9 +41,9 @@ export const SAVE_APP_CONFIG = 'SAVE_APP_CONFIG';
export const SERVICE_ERROR = 'SERVICE_ERROR';
export const DASHBOARD_ACTIVE_ADDRESS = 'DASHBOARD_ACTIVE_ADDRESS';
export const LOAD_APP_INFO = 'LOAD_APP_INFO';
export const LOG_GUI_HTTP = 'LOG_GUI_HTTP';
export const CLI = 'CLI';
export const LOGOUT = 'LOGOUT';
export const DISPLAY_COIND_DOWN_MODAL = 'DISPLAY_COIND_DOWN_MODAL';
export const DISPLAY_LOGIN_SETTINGS_MODAL = 'DISPLAY_LOGIN_SETTINGS_MODAL';
export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL';
export const DISPLAY_CLAIM_INTEREST_MODAL = 'DISPLAY_CLAIM_INTEREST_MODAL';
export const DISPLAY_IMPORT_KEY_MODAL = 'DISPLAY_IMPORT_KEY_MODAL';

14
react/src/components/addcoin/addcoin.js

@ -43,6 +43,7 @@ class AddCoin extends React.Component {
display: false,
actionsMenu: false,
modalClassName: 'hide',
isExperimentalOn: false,
};
this.existingCoins = null;
this.activateCoin = this.activateCoin.bind(this);
@ -113,6 +114,16 @@ class AddCoin extends React.Component {
componentWillMount() {
this.addNewItem();
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
this.setState({
isExperimentalOn: appConfig.experimentalFeatures,
});
}
componentWillReceiveProps(props) {
@ -363,9 +374,8 @@ const mapStateToProps = (state) => {
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
AddCoin: state.AddCoin,
AddCoin: state.AddCoin,
};
};
export default connect(mapStateToProps)(AddCoin);

59
react/src/components/addcoin/addcoin.scss

@ -1,5 +1,43 @@
.add-coin-modal {
color: #757575;
.modal-body {
max-height: 590px;
overflow-y: auto;
}
.multi {
.col-sm-8 {
width: 30%;
}
.col-sm-12 {
&.text-center {
width: 60%;
padding: 0;
.col-lg-4 {
width: 25%;
margin-right: 8%;
padding: 0;
.input{
&.to-labelauty+label {
max-width: 136px;
}
}
}
.col-lg-4 {
&:last-child {
margin-right: 0;
}
}
.col-sm-1 {
width: 44px;
padding: 0;
}
}
}
}
}
.vertical-margin-20 {
@ -24,4 +62,25 @@
margin: 0;
}
}
}
.btn-add-coin-item,
.btn-add-coin-item-options,
.btn-save-coin-selection,
.btn-load-coin-selection {
position: absolute;
right: 32px;
z-index: 50;
}
.btn-add-coin-item {
right: 60px;
}
.btn-add-coin-item-options {
padding: 6px;
}
.btn-save-coin-selection {
top: 60px;
}
.btn-load-coin-selection {
top: 95px;
}

46
react/src/components/addcoin/addcoinOptionsAC.js

@ -3,25 +3,37 @@ import { translate } from '../../translate/translate';
class AddCoinOptionsAC extends React.Component {
render() {
const _assetChains = [
'bet',
'bots',
'ceal',
'coqui',
'crypto',
'hodl',
'dex',
'jumblr',
'kv',
'mgw',
//'mvp',
'pangea',
'revs',
'shark',
'supernet',
'wlc',
];
let _items = [];
for (let i = 0; i < _assetChains.length; i++) {
_items.push(
<option
key={ _assetChains[i] }
value={ `${_assetChains[i].toUpperCase()}|basilisk|native` }>{ translate(`ASSETCHAINS.${_assetChains[i].toUpperCase()}`) }</option>
);
}
return (
<optgroup label={ translate('ADD_COIN.ASSETCHAINS') }>
<option value="BET|basilisk|native">BET (BET)</option>
<option value="BOTS|basilisk|native">BOTS (BOTS)</option>
<option value="CEAL|basilisk|native">CEAL NET (CEAL)</option>
<option value="COQUI|basilisk|native">COQUI (COQUI)</option>
<option value="CRYPTO|basilisk|native">CRYPTO (CRYPTO)</option>
<option value="HODL|basilisk|native">HODL (HODL)</option>
<option value="DEX|basilisk|native">InstantDEX (DEX)</option>
<option value="JUMBLR|basilisk|native">JUMBLR (JUMBLR)</option>
<option value="KV|basilisk|native">KV (KV)</option>
<option value="MGW|basilisk|native">MultiGateway (MGW)</option>
<option value="MVP|basilisk|native" className="hide">MVP Lineup (MVP)</option>
<option value="PANGEA|basilisk|native">PANGEA (PANGEA)</option>
<option value="REVS|basilisk|native">REVS (REVS)</option>
<option value="SHARK|basilisk|native">SHARK (SHARK)</option>
<option value="MESH|basilisk|native">SpaceMesh (MESH)</option>
<option value="SUPERNET|basilisk|native">SUPERNET (SUPERNET)</option>
<option value="WLC|basilisk|native">WIRELESS (WIRELESS)</option>
{ _items }
</optgroup>
);
}

77
react/src/components/addcoin/addcoinOptionsACFiat.js

@ -3,40 +3,53 @@ import { translate } from '../../translate/translate';
class AddCoinOptionsACFiat extends React.Component {
render() {
const _fiat = [
'aud',
'brl',
'gbp',
'bgn',
'cad',
'hrk',
'czk',
'cny',
'dkk',
'eur',
'hkd',
'huf',
'inr',
'idr',
'ils',
'jpy',
'krw',
'myr',
'mxn',
'nzd',
'nok',
'php',
'pln',
'ron',
'rub',
'sgd',
'zar',
'sek',
'chf',
'thb',
'try',
'usd'
];
let _items = [];
for (let i = 0; i < _fiat.length; i++) {
_items.push(
<option
key={ _fiat[i] }
value={ `${_fiat[i].toUpperCase()}|basilisk|native` }>{ translate(`FIAT_CURRENCIES.${_fiat[i].toUpperCase()}`) }</option>
);
}
return (
<optgroup label={ translate('ADD_COIN.FIAT_CURRENCIES') }>
<option value="AUD|basilisk|native">Australian Dollar (AUD)</option>
<option value="BRL|basilisk|native">Brazilian Real (BRL)</option>
<option value="GBP|basilisk|native">British Pound (GBP)</option>
<option value="BGN|basilisk|native">Bulgarian Lev (BGN)</option>
<option value="CAD|basilisk|native">Canadian Dollar (CAD)</option>
<option value="HRK|basilisk|native">Croatian Kuna (HRK)</option>
<option value="CZK|basilisk|native">Czech Koruna (CZK)</option>
<option value="CNY|basilisk|native">Chinese Yuan (CNY)</option>
<option value="DKK|basilisk|native">Danish Krone (DKK)</option>
<option value="EUR|basilisk|native">Euro (EUR)</option>
<option value="HKD|basilisk|native">Hong Kong Dollar (HKD)</option>
<option value="HUF|basilisk|native">Hungarian Forint (HUF)</option>
<option value="INR|basilisk|native">Indian Rupee (INR)</option>
<option value="IDR|basilisk|native">Indonesian Rupiah (IDR)</option>
<option value="ILS|basilisk|native">Israeli Shekel (ILS)</option>
<option value="JPY|basilisk|native">Japanese Yen (JPY)</option>
<option value="KRW|basilisk|native">Korean Won (KRW)</option>
<option value="MYR|basilisk|native">Malaysian Ringgit (MYR)</option>
<option value="MXN|basilisk|native">Mexican peso (MXN)</option>
<option value="NZD|basilisk|native">New Zealand Dollar (NZD)</option>
<option value="NOK|basilisk|native">Norwegian Krone (NOK)</option>
<option value="PHP|basilisk|native">Philippine Peso (PHP)</option>
<option value="PLN|basilisk|native">Polish Zloty (PLN)</option>
<option value="RON|basilisk|native">Romanian Leu (RON)</option>
<option value="RUB|basilisk|native">Russian Ruble (RUB)</option>
<option value="SGD|basilisk|native">Singapore Dollar (SGD)</option>
<option value="ZAR|basilisk|native">South African Rand (ZAR)</option>
<option value="SEK|basilisk|native">Swedish Krona (SEK)</option>
<option value="CHF|basilisk|native">Swiss Franc (CHF)</option>
<option value="THB|basilisk|native">Thai Baht (THB)</option>
<option value="TRY|basilisk|native">Turkish Lira (TRY)</option>
<option value="USD|basilisk|native">US Dollar (USD)</option>
{ _items }
</optgroup>
);
}

44
react/src/components/addcoin/addcoinOptionsCrypto.js

@ -12,50 +12,61 @@ class AddCoinOptionsCrypto extends React.Component {
}
render() {
const isWindows = this.props.appSettings && this.props.appSettings.appInfo && this.props.appSettings.appInfo.sysInfo && this.props.appSettings.appInfo.sysInfo.platform === 'win32';
// const isWindows = this.props.appSettings && this.props.appSettings.appInfo && this.props.appSettings.appInfo.sysInfo && this.props.appSettings.appInfo.sysInfo.platform === 'win32';
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
//<option value="ANC|full">AnonCoin (ANC)</option>
//<option value="MZC|full">MazaCoin (MZC)</option>
//<option value="SYS|full">SysCoin (SYS)</option>
return (
<optgroup label={ translate('ADD_COIN.CRYPTO_CURRENCIES') }>
<option
value="ANC|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>AnonCoin (ANC)</option>
<option
value="BTCD|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>BitcoinDark (BTCD)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>BitcoinDark (BTCD)</option>
<option
value="BTC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Bitcoin (BTC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Bitcoin (BTC)</option>
<option
value="BTM|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Bitmark (BTM)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Bitmark (BTM)</option>
<option
value="CARB|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Carboncoin (CARB)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Carboncoin (CARB)</option>
<option
value="DGB|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Digibyte (DGB)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Digibyte (DGB)</option>
<option
value="DOGE|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Dogecoin (DOGE)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Dogecoin (DOGE)</option>
<option
value="FRK|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Franko (FRK)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Franko (FRK)</option>
<option
value="GAME|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Gamecredits (GAME)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Gamecredits (GAME)</option>
<option value="KMD|basilisk|native">Komodo (KMD)</option>
<option
value="MZC|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>MazaCoin (MZC)</option>
<option
value="LTC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Litecoin (LTC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Litecoin (LTC)</option>
<option
value="SYS|full"
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>SysCoin (SYS)</option>
<option
value="UNO|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Unobtanium (UNO)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Unobtanium (UNO)</option>
<option
value="ZEC|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Zcash (ZEC)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Zcash (ZEC)</option>
<option
value="ZET|full"
className={ this.state.nativeOnly || isWindows ? 'hide' : '' }>Zetacoin (ZET)</option>
className={ this.state.nativeOnly || !appConfig.experimentalFeatures ? 'hide' : '' }>Zetacoin (ZET)</option>
</optgroup>
);
}
@ -65,7 +76,6 @@ const mapStateToProps = (state) => {
return {
appSettings: state.appSettings,
};
};
export default connect(mapStateToProps)(AddCoinOptionsCrypto);

8
react/src/components/addcoin/coin-selectors.render.js

@ -5,7 +5,8 @@ import AddCoinOptionsAC from '../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../addcoin/addcoinOptionsACFiat';
const CoinSelectorsRender = function(item, coin, i) {
const isWindows = this.props.Settings && this.props.Settings.appInfo && this.props.Settings.appInfo.sysInfo && this.props.Settings.appInfo.sysInfo.platform === 'win32';
// const isWindows = this.props.Settings && this.props.Settings.appInfo && this.props.Settings.appInfo.sysInfo && this.props.Settings.appInfo.sysInfo.platform === 'win32';
const hideFullModeBtn = item && item.selectedCoin && item.selectedCoin.indexOf('|full') === -1 || !this.state.isExperimentalOn ? true : false;
return (
<div
@ -54,7 +55,7 @@ const CoinSelectorsRender = function(item, coin, i) {
</button>
</div>
<div className="col-sm-11 text-center add-coin-modes">
<div className={ this.state.nativeOnly || isWindows ? 'hide' : 'form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login' }>
<div className={ this.state.nativeOnly || hideFullModeBtn ? 'hide' : 'form-group col-lg-4 col-md-4 col-sm-6 col-xs-6 style-addcoin-lbl-mdl-login' }>
<input
type="radio"
className="to-labelauty labelauty"
@ -169,7 +170,7 @@ const CoinSelectorsRender = function(item, coin, i) {
</select>
</div>
</div>
<div className={ item.mode === '1' || item.mode === 1 ? 'col-sm-12' : 'hide' }>
<div className={ (item.mode === '1' || item.mode === 1) && this.state.isExperimentalOn ? 'col-sm-12' : 'hide' }>
<div className="toggle-box padding-top-3 padding-bottom-10">
<span className="pointer">
<label className="switch">
@ -191,4 +192,5 @@ const CoinSelectorsRender = function(item, coin, i) {
</div>
)
};
export default CoinSelectorsRender;

3
react/src/components/addcoin/payload.js

@ -688,6 +688,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'seedipaddr': '78.47.196.146'
};
// TODO: move netmagic to node
const acConfig = {
'SUPERNET': {
'name': 'SUPERNET',
@ -790,7 +791,7 @@ export function startAssetChain(confpath, coin, mode, getSuppyOnly) {
'supply': 72000000,
'AddCoinData': confpath ? Object.assign({}, _acPayloadOrigin, {'coin':'COQUI','conf':'COQUI.conf','path':confpath,'RELAY':-1,'VALIDATE':1,'startpend':4,'endpend':4,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI}) : {},
'AddCoinDataVar': Object.assign({}, _acPayloadOrigin, {'userpass':tmpIguanaRPCAuth,'RELAY':mode,'VALIDATE':mode,'startpend':tmpPendValue,'endpend':tmpPendValue,'maxpeers':8,'newcoin':'COQUI','name':'COQUI','netmagic':'4cbd5ef4','p2p':assetChainPorts.COQUI - 1,'rpc':assetChainPorts.COQUI})
}
},
};
if (mode === '-1') {

1
react/src/components/app/app.js

@ -14,7 +14,6 @@ function mapStateToProps(state) {
Settings: state.Settings,
Interval: state.Interval,
SyncOnly: state.SyncOnly,
Errors: state.Errors,
};
}

3
react/src/components/dashboard/atomic/atomic.js

@ -502,9 +502,8 @@ const mapStateToProps = (state) => {
return {
Atomic: {
response: state.Atomic.response,
}
},
};
};
export default connect(mapStateToProps)(Atomic);

12
react/src/components/dashboard/claimInterestModal/claimInterestModal.js

@ -24,6 +24,7 @@ class ClaimInterestModal extends React.Component {
isLoading: true,
transactionsList: [],
showZeroInterest: true,
totalInterest: 0,
};
this.claimInterestTableRender = this.claimInterestTableRender.bind(this);
this.toggleZeroInterest = this.toggleZeroInterest.bind(this);
@ -37,6 +38,7 @@ class ClaimInterestModal extends React.Component {
loadListUnspent() {
let _transactionsList = [];
let _totalInterest = 0;
getListUnspent(this.props.ActiveCoin.coin)
.then((json) => {
@ -52,11 +54,13 @@ class ClaimInterestModal extends React.Component {
interest: json[i].interest,
txid: json[i].txid,
});
_totalInterest += Number(json[i].interest);
if (i === json.length - 1) {
this.setState({
transactionsList: _transactionsList,
isLoading: false,
totalInterest: _totalInterest,
});
}
});
@ -80,7 +84,7 @@ class ClaimInterestModal extends React.Component {
} else if (json.result && json.result.length && json.result.length === 64) {
Store.dispatch(
triggerToaster(
`translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1') ${this.state.transactionsList[0].address}. translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')`,
`${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P1')} ${this.state.transactionsList[0].address}. ${translate('TOASTR.CLAIM_INTEREST_BALANCE_SENT_P2')}`,
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
@ -134,6 +138,7 @@ class ClaimInterestModal extends React.Component {
return ClaimInterestModalRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
@ -142,10 +147,9 @@ const mapStateToProps = (state) => {
activeSection: state.ActiveCoin.activeSection,
},
Dashboard: {
displayClaimInterestModal: state.Dashboard.displayClaimInterestModal
}
displayClaimInterestModal: state.Dashboard.displayClaimInterestModal,
},
};
};
export default connect(mapStateToProps)(ClaimInterestModal);

53
react/src/components/dashboard/claimInterestModal/claimInterestModal.render.js

@ -39,29 +39,36 @@ export const _ClaimInterestTableRender = function() {
return (
<span>
<div className="padding-bottom-20">
<strong>{ translate('CLAIM_INTEREST.REQ_P1') }:</strong> { translate('CLAIM_INTEREST.REQ_P2') } <strong>10 KMD</strong>
<p>
<strong>{ translate('CLAIM_INTEREST.REQ_P1') }:</strong> { translate('CLAIM_INTEREST.REQ_P2') } <strong>10 KMD</strong>
</p>
<p>
<strong>{ translate('CLAIM_INTEREST.TIP') }:</strong> { translate('CLAIM_INTEREST.TIP_DESC') }
</p>
</div>
<div className="text-left padding-top-10 padding-bottom-10">
<label className="switch">
<input
type="checkbox"
checked={ this.state.showZeroInterest } />
{ this.state.totalInterest > 0 &&
<div className="text-left padding-top-10 padding-bottom-10">
<label className="switch">
<input
type="checkbox"
checked={ this.state.showZeroInterest } />
<div
className="slider"
onClick={ this.toggleZeroInterest }></div>
</label>
<div
className="slider"
onClick={ this.toggleZeroInterest }></div>
</label>
<div
className="toggle-label margin-right-15 pointer"
onClick={ this.toggleZeroInterest }>
Show zero interest
className="toggle-label margin-right-15 pointer"
onClick={ this.toggleZeroInterest }>
Show zero interest
</div>
<button
type="button"
className="btn btn-success waves-effect waves-light claim-btn"
onClick={ () => this.claimInterest() }>
<i className="icon fa-dollar"></i> { translate('CLAIM_INTEREST.CLAIM_INTEREST', `${this.state.totalInterest} KMD `) }
</button>
</div>
</div>
<button
type="button"
className="btn btn-success waves-effect waves-light claim-btn"
onClick={ () => this.claimInterest() }>
<i className="icon fa-dollar"></i> { translate('CLAIM_INTEREST.CLAIM_INTEREST') }
</button>
}
<div className="table-scroll">
<table className="table table-hover dataTable table-striped">
<thead>
@ -69,7 +76,7 @@ export const _ClaimInterestTableRender = function() {
<th></th>
<th>{ translate('INDEX.ADDRESS') }</th>
<th>{ translate('INDEX.AMOUNT') }</th>
<th>{ translate('INDEX.Address') }</th>
<th>{ translate('INDEX.INTEREST') }</th>
<th>Locktime</th>
</tr>
</thead>
@ -81,7 +88,7 @@ export const _ClaimInterestTableRender = function() {
<th></th>
<th>{ translate('INDEX.ADDRESS') }</th>
<th>{ translate('INDEX.AMOUNT') }</th>
<th>{ translate('INDEX.Address') }</th>
<th>{ translate('INDEX.INTEREST') }</th>
<th>Locktime</th>
</tr>
</tfoot>
@ -104,7 +111,7 @@ export const ClaimInterestModalRender = function() {
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.CLAIM_INTEREST') }</h4>
<h4 className="modal-title white text-left">{ translate('CLAIM_INTEREST.CLAIM_INTEREST', ' ') }</h4>
</div>
<div className="modal-body">
<i

47
react/src/components/dashboard/claimInterestModal/claimInterestModal.scss

@ -0,0 +1,47 @@
.modal-claim-interest {
.modal-dialog {
width: 70%;
.table > tbody > tr > td,
.table > tbody > tr > th,
.table > tfoot > tr > td,
.table > tfoot > tr > th,
.table > thead > tr > td,
.table > thead > tr > th {
padding: 8px 30px 8px 0;
}
.claim-btn {
float: right;
margin-bottom: 30px;
}
.table-scroll {
height: 366px;
overflow-y: auto;
overflow-x: hidden;
width: 100%;
}
.bold {
font-weight: bold;
}
.green {
color: #66bb6a;
}
.red {
color: #f96868;
}
.locktime {
i {
font-size: 20px;
line-height: 1.1;
}
}
.refresh-icon {
position: absolute;
right: 20px;
font-size: 20px;
z-index: 100;
}
}
}

4
react/src/components/dashboard/coinTile/coinTile.js

@ -53,8 +53,7 @@ class CoinTile extends React.Component {
<CoinTileItem
key={ i }
i={ i }
item={ item }
/>)
item={ item } />)
);
}
@ -66,7 +65,6 @@ const mapStateToProps = (state) => {
return {
allCoins: state.Main.coins,
};
};
export default connect(mapStateToProps)(CoinTile);

182
react/src/components/dashboard/coinTile/coinTileItem.js

@ -18,7 +18,8 @@ import {
getNativeTxHistory,
getKMDBalanceTotal,
getSyncInfoNative,
getDebugLog
getDebugLog,
getDashboardUpdate
} from '../../../actions/actionCreators';
import Store from '../../../store';
import Config from '../../../config';
@ -39,72 +40,133 @@ class CoinTileItem extends React.Component {
// 2) limit amount of req per update e.g. list of addresses don't change too often
// 3) limit req in basilisk as much as possible incl. activehandle
dispatchCoinActions(coin, mode) {
if (mode === 'native') {
Store.dispatch(iguanaActiveHandle(true));
const _propsDashboard = this.props.Dashboard;
const syncPercentage = _propsDashboard && _propsDashboard.progress && (parseFloat(parseInt(_propsDashboard.progress.blocks, 10) * 100 / parseInt(this.props.Dashboard.progress.longestchain, 10)).toFixed(2)).replace('NaN', 0);
if (syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) {
Store.dispatch(getDebugLog('komodo', 10));
}
if (!this.props.Dashboard.displayCoindDownModal &&
_propsDashboard.progress &&
_propsDashboard.progress.blocks &&
_propsDashboard.progress.longestchain &&
syncPercentage &&
(Config.iguanaLessMode || syncPercentage >= NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD)) {
Store.dispatch(getSyncInfoNative(coin, true));
Store.dispatch(getKMDBalanceTotal(coin));
Store.dispatch(getNativeTxHistory(coin));
Store.dispatch(getKMDAddressesNative(coin, mode));
Store.dispatch(getKMDOPID(null, coin));
} else {
Store.dispatch(getSyncInfoNative(coin));
componentWillMount() {
if (!this.props.ActiveCoin.coin) {
let _coinSelected = false;
let _mode;
let _coin;
let _coinMode = {};
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
if (allCoins) {
modes.map((mode) => {
allCoins[mode].map((coin) => {
if (!_coinSelected) {
_coinSelected = true;
_coin = coin;
_mode = mode;
}
_coinMode[coin] = mode;
});
if (_coinMode['KMD'] &&
_coinMode['KMD'] === 'native') {
_coin = 'KMD';
_mode = 'native';
}
});
setTimeout(() => {
this._dashboardChangeActiveCoin(_coin, _mode);
}, 100);
}
}
if (mode === 'full') {
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(getSyncInfo(coin));
Store.dispatch(iguanaEdexBalance(coin, mode));
Store.dispatch(getAddressesByAccount(coin, mode));
Store.dispatch(getFullTransactionsList(coin));
}
if (mode === 'basilisk') {
const useAddress = this.props.ActiveCoin.mainBasiliskAddress ? this.props.ActiveCoin.mainBasiliskAddress : this.props.Dashboard.activeHandle[coin];
}
Store.dispatch(iguanaActiveHandle(true));
dispatchCoinActions(coin, mode) {
if (this.props.Dashboard &&
this.props.Dashboard.activeSection === 'wallets') {
if (mode === 'native') {
Store.dispatch(iguanaActiveHandle(true));
const _propsDashboard = this.props.ActiveCoin;
const syncPercentage = _propsDashboard && _propsDashboard.progress && (parseFloat(parseInt(_propsDashboard.progress.blocks, 10) * 100 / parseInt(_propsDashboard.progress.longestchain, 10)).toFixed(2)).replace('NaN', 0);
Store.dispatch(
getKMDAddressesNative(
coin,
mode,
useAddress
)
);
if ((syncPercentage < 100 &&
!this.props.Dashboard.displayCoindDownModal) ||
this.props.ActiveCoin.rescanInProgress) {
if (coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 50));
} else {
Store.dispatch(getDebugLog('komodo', 50, coin));
}
}
Store.dispatch(
getShepherdCache(
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey,
coin
)
);
if (!this.props.Dashboard.displayCoindDownModal &&
_propsDashboard.progress &&
_propsDashboard.progress.blocks &&
_propsDashboard.progress.longestchain &&
syncPercentage &&
(Config.iguanaLessMode || syncPercentage >= NATIVE_MIN_SYNC_PERCENTAGE_THRESHOLD)) {
Store.dispatch(
getSyncInfoNative(
coin,
true,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
if (this.props &&
this.props.Dashboard &&
this.props.Dashboard.activeHandle &&
this.props.Dashboard.activeHandle[coin]) {
if (!this.props.ActiveCoin.addresses) {
Store.dispatch(getAddressesByAccount(coin, mode));
if (!this.props.Dashboard.skipFullDashboardUpdate) {
Store.dispatch(getDashboardUpdate(coin, _propsDashboard));
}
} else {
Store.dispatch(
getSyncInfoNative(
coin,
null,
this.props.Dashboard.skipFullDashboardUpdate,
this.props.ActiveCoin.rescanInProgress
)
);
}
}
if (mode === 'full') {
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(getSyncInfo(coin));
Store.dispatch(iguanaEdexBalance(coin, mode));
Store.dispatch(getAddressesByAccount(coin, mode));
Store.dispatch(getFullTransactionsList(coin));
}
if (mode === 'basilisk') {
const useAddress = this.props.ActiveCoin.mainBasiliskAddress ? this.props.ActiveCoin.mainBasiliskAddress : this.props.Dashboard.activeHandle[coin];
Store.dispatch(iguanaActiveHandle(true));
Store.dispatch(
getKMDAddressesNative(
coin,
mode,
useAddress
)
);
Store.dispatch(
getShepherdCache(
JSON.parse(sessionStorage.getItem('IguanaActiveAccount')).pubkey,
coin
)
);
if (this.props &&
this.props.Dashboard &&
this.props.Dashboard.activeHandle &&
this.props.Dashboard.activeHandle[coin]) {
if (!this.props.ActiveCoin.addresses) {
Store.dispatch(getAddressesByAccount(coin, mode));
}
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
Store.dispatch(getBasiliskTransactionsList(coin, useAddress));
}
}
}
}
dashboardChangeActiveCoin(coin, mode) {
_dashboardChangeActiveCoin(coin, mode) {
if (coin !== this.props.ActiveCoin.coin) {
Store.dispatch(dashboardChangeActiveCoin(coin, mode));
setTimeout(() => {
@ -205,14 +267,16 @@ const mapStateToProps = (state) => {
ActiveCoin: {
coin: state.ActiveCoin.coin,
addresses: state.ActiveCoin.addresses,
mainBasiliskAddress: state.ActiveCoin.mainBasiliskAddress
mainBasiliskAddress: state.ActiveCoin.mainBasiliskAddress,
progress: state.ActiveCoin.progress,
rescanInProgress: state.ActiveCoin.rescanInProgress,
},
Dashboard: state.Dashboard,
Interval: {
interval: state.Interval.interval
}
interval: state.Interval.interval,
},
Main: state.Main,
};
};
export default connect(mapStateToProps)(CoinTileItem);

2
react/src/components/dashboard/coinTile/coinTileItem.render.js

@ -8,7 +8,7 @@ const CoinTileItemRender = function() {
<div className={ 'widget widget-shadow' + (this.props.ActiveCoin.coin === item.coin ? ' active' : '') }>
<div
className="widget-content text-center bg-white padding-20"
onClick={ () => this.dashboardChangeActiveCoin(item.coin, item.mode) }>
onClick={ () => this._dashboardChangeActiveCoin(item.coin, item.mode) }>
<a className="avatar margin-bottom-5">
<img
className="img-responsive"

28
react/src/components/dashboard/coindDownModal/coindDownModal.js

@ -5,12 +5,15 @@ import Store from '../../../store';
import CoindDownModalRender from './coindDownModal.render';
const COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD = 5;
class CoindDownModal extends React.Component {
constructor() {
super();
this.state = {
display: false,
debugLogCrash: null,
kmdMainPassiveMode: false,
};
this.dismiss = this.dismiss.bind(this);
}
@ -19,6 +22,18 @@ class CoindDownModal extends React.Component {
Store.dispatch(toggleCoindDownModal(false));
}
componentWillMount() {
let _kmdMainPassiveMode;
try {
_kmdMainPassiveMode = window.require('electron').remote.getCurrentWindow().kmdMainPassiveMode;
} catch (e) {}
this.setState(Object.assign({}, this.state, {
kmdMainPassiveMode: _kmdMainPassiveMode,
}));
}
componentWillReceiveProps(nextProps) {
if (this.props.displayCoindDownModal !== nextProps.displayCoindDownModal) {
this.setState(Object.assign({}, this.state, {
@ -28,19 +43,26 @@ class CoindDownModal extends React.Component {
}
render() {
if (this.state.display) {
if (this.state.display &&
!this.state.kmdMainPassiveMode &&
this.props.ActiveCoin.getinfoFetchFailures >= COIND_DOWN_MODAL_FETCH_FAILURES_THRESHOLD) {
return CoindDownModalRender.call(this);
}
return null;
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
mode: state.ActiveCoin.mode,
coin: state.ActiveCoin.coin,
getinfoFetchFailures: state.ActiveCoin.getinfoFetchFailures,
},
displayCoindDownModal: state.Dashboard.displayCoindDownModal,
debugLog: state.Settings.debugLog
debugLog: state.Settings.debugLog,
};
};
export default connect(mapStateToProps)(CoindDownModal);

2
react/src/components/dashboard/coindDownModal/coindDownModal.render.js

@ -1,7 +1,7 @@
import React from 'react';
import { translate } from '../../../translate/translate';
const CoindDownModalRender = function () {
const CoindDownModalRender = function() {
return (
<div>
<div

24
react/src/components/dashboard/coindDownModal/coindDownModal.scss

@ -0,0 +1,24 @@
.coind-down-modal {
.modal-body {
height: 60vh;
> div {
height: 100%;
}
.form-group {
&.form-material {
&.floating {
height: 80%;
}
}
}
.page-content {
width: 90%;
height: 100%;
textarea {
height: 100%;
}
}
}
}

243
react/src/components/dashboard/importKeyModal/importKeyModal.js

@ -0,0 +1,243 @@
import React from 'react';
import { connect } from 'react-redux';
import ReactDOM from 'react-dom';
import Store from '../../../store';
import {
displayImportKeyModal,
importPrivkey,
triggerToaster,
copyCoinAddress,
getDebugLog,
getDashboardUpdateState
} from '../../../actions/actionCreators';
import { translate } from '../../../translate/translate';
import {
ImportKeyModalRender,
} from './importKeyModal.render';
// import gen komodo keys utils
import '../../../util/crypto/gen/array.map.js';
import '../../../util/crypto/gen/cryptojs.js';
import '../../../util/crypto/gen/cryptojs.sha256.js';
import '../../../util/crypto/gen/cryptojs.pbkdf2.js';
import '../../../util/crypto/gen/cryptojs.hmac.js';
import '../../../util/crypto/gen/cryptojs.aes.js';
import '../../../util/crypto/gen/cryptojs.blockmodes.js';
import '../../../util/crypto/gen/cryptojs.ripemd160.js';
import '../../../util/crypto/gen/securerandom.js';
import '../../../util/crypto/gen/ellipticcurve.js';
import '../../../util/crypto/gen/biginteger.js';
import '../../../util/crypto/gen/crypto-scrypt.js';
import { Bitcoin } from '../../../util/crypto/gen/bitcoin.js';
class ImportKeyModal extends React.Component {
constructor() {
super();
this.state = {
open: false,
wif: '',
wifkeysPassphrase: '',
passphraseWif: null,
passphraseAddress: null,
keyImportResult: null,
importWithRescan: false,
seedInputVisibility: false,
toggleSeedInputVisibility: false,
trimPassphraseTimer: null,
};
this.generateKeysFromPassphrase = this.generateKeysFromPassphrase.bind(this);
this.toggleImportWithRescan = this.toggleImportWithRescan.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
this.showPassphraseAddress = this.showPassphraseAddress.bind(this);
this.importWifAddress = this.importWifAddress.bind(this);
this.updateInput = this.updateInput.bind(this);
this.importFromPassphrase = this.importFromPassphrase.bind(this);
this.importFromWif = this.importFromWif.bind(this);
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
showPassphraseAddress() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.setState({
passphraseAddress: _address.address,
passphraseWif: _address.wif,
});
}
}
importFromPassphrase() {
const _address = this.generateKeysFromPassphrase();
if (_address) {
this.importWifAddress(_address.wif, true);
}
}
importFromWif() {
this.importWifAddress(this.state.wif, this.state.importWithRescan);
}
importWifAddress(wif, rescan) {
let _rescanInProgress = true;
if (rescan) {
setTimeout(() => {
if (_rescanInProgress) {
setTimeout(() => {
if (this.props.ActiveCoin.coin === 'KMD') {
Store.dispatch(getDebugLog('komodo', 100));
} else {
Store.dispatch(getDebugLog('komodo', 100, this.props.ActiveCoin.coin));
}
}, 2000);
Store.dispatch(getDashboardUpdateState(null, this.props.ActiveCoin.coin, true));
Store.dispatch(
triggerToaster(
'Address imported. Wallet rescan is in progress. Please wait until it is finished.',
translate('TOASTR.WALLET_NOTIFICATION'),
'info',
false
)
);
this.closeModal();
}
}, 2000);
}
importPrivkey(
this.props.ActiveCoin.coin,
wif,
rescan
).then((json) => {
_rescanInProgress = false;
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
Store.dispatch(
triggerToaster(
rescan ? 'Wallet rescan finished' : 'Address imported',
translate('TOASTR.WALLET_NOTIFICATION'),
'success',
false
)
);
} else {
Store.dispatch(
triggerToaster(
json.error.message,
'Error',
'error'
)
);
}
});
}
generateKeysFromPassphrase() {
if (this.state.wifkeysPassphrase &&
this.state.wifkeysPassphrase.length) {
const bytes = Crypto.SHA256(this.state.wifkeysPassphrase, { asBytes: true });
// byte flipping to make it compat with iguana core
bytes[0] &= 248;
bytes[31] &= 127;
bytes[31] |= 64;
const btcKey = new Bitcoin.ECKey(bytes).setCompressed(true);
const kmdAddress = btcKey.getBitcoinAddress();
const wifAddress = btcKey.getBitcoinWalletImportFormat();
return {
address: kmdAddress,
wif: wifAddress,
};
} else {
Store.dispatch(
triggerToaster(
'Empty passphrase field',
'Error',
'error'
)
);
return null;
}
}
toggleImportWithRescan() {
this.setState({
importWithRescan: !this.state.importWithRescan,
});
}
closeModal() {
Store.dispatch(displayImportKeyModal(false));
}
render() {
return ImportKeyModalRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
balance: state.ActiveCoin.balance,
},
Dashboard: {
displayImportKeyModal: state.Dashboard.displayImportKeyModal,
},
};
};
export default connect(mapStateToProps)(ImportKeyModal);

136
react/src/components/dashboard/importKeyModal/importKeyModal.render.js

@ -0,0 +1,136 @@
import React from 'react';
import { translate } from '../../../translate/translate';
/*export const _ClaimInterestTableRender = function() {
};*/
export const ImportKeyModalRender = function() {
return (
<span>
<div className={ 'modal modal-import-key modal-3d-sign ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }>
<div className="modal-dialog modal-center modal-sm">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">Import key</h4>
</div>
<div className="modal-body">
<div className="padding-bottom-40">
Two forms below allow you to import either <strong>Iguana Core / ICO</strong> passphrase (seed) or <strong>WIF (Wallet Import Format)</strong> key.
</div>
<div>
<strong>Passphrase / seed</strong>
<p className="margin-top-10">
<strong>Notice:</strong> importing a passphrase will trigger a full wallet rescan.&nbsp;
<span className={ this.props.ActiveCoin.coin === 'KMD' ? '' : 'hide' }>This process can take hours to rescan the whole blockchain.</span>
</p>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-right-20"
onClick={ this.importFromPassphrase }>Import</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.showPassphraseAddress }>Show address and WIF</button>
</div>
</form>
{ this.state.passphraseAddress && this.state.passphraseWif &&
<div className="margin-top-60">
<p>
<strong>Address: </strong> { this.state.passphraseAddress }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseAddress) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
<p>
<strong>WIF: </strong> { this.state.passphraseWif }
<button
className="btn btn-default btn-xs clipboard-edexaddr copy-string-btn"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(this.state.passphraseWif) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</p>
</div>
}
</div>
<div className="line">or</div>
<div>
<strong>WIF (Wallet Import Format)</strong>
<div className="toggle-box padding-top-20">
<span className="pointer">
<label className="switch">
<input
type="checkbox"
checked={ this.state.importWithRescan } />
<div
className="slider"
onClick={ this.toggleImportWithRescan }></div>
</label>
<div
className="toggle-label"
onClick={ this.toggleImportWithRescan }>
Trigger rescan
<i
className="icon fa-question-circle settings-help"
title="Use this option if you want to trigger rescan after WIF is imported. If you have several addresses that you want to import add them one by one and toggle this option on the last address import."></i>
</div>
</span>
</div>
<div className="margin-top-20">
<label htmlFor="wif" className="bold">Wif key</label>
<input
type="text"
className="form-control"
name="wif"
onChange={ this.updateInput }
value={ this.state.wif } />
</div>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-top-10"
onClick={ this.importFromWif }>{ this.state.importWithRescan ? 'Import and rescan' : 'Import' }</button>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.props.Dashboard.displayImportKeyModal ? 'show in' : 'fade hide') }></div>
</span>
);
};

33
react/src/components/dashboard/importKeyModal/importKeyModal.scss

@ -0,0 +1,33 @@
.modal-import-key {
.modal-dialog {
width: 70%;
max-height: 90vh;
overflow-y: auto;
overflow-x: hidden;
}
.line {
padding: 50px 0 40px 0;
text-transform: uppercase;
font-weight: bold;
}
.line:before {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-right: 10px;
position: relative;
top: -4px;
}
.line:after {
content: '';
display: inline-block;
height: 1px;
width: 47%;
background: #ccc;
margin-left: 10px;
position: relative;
top: -4px;
}
}

17
react/src/components/dashboard/jumblr/jumblr.js

@ -128,12 +128,6 @@ class Jumblr extends React.Component {
});
}
/*toggleAddressGenMod() {
this.setState({
jumblrDepositAddressPBased: !this.state.jumblrDepositAddressPBased,
});
}*/
generateJumblrSecretAddress() {
let _jumblrSecretAddress = [];
let _apiSuccessCount = 0;
@ -285,7 +279,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
_jumblrSecretAddress.push(_genKeys);
this.setState(Object.assign({}, this.state, {
jumblrSecretAddressImport: _jumblrSecretAddress,
@ -344,7 +340,9 @@ class Jumblr extends React.Component {
importPrivkey(this.props.ActiveCoin.coin, _genKeys.wif)
.then((json) => {
if (!json.id && !json.result && !json.error) {
if (!json.id &&
!json.result &&
!json.error) {
// console.warn('importPrivkey', json);
setJumblrAddress(
this.props.ActiveCoin.coin,
@ -429,9 +427,8 @@ const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
}
},
};
};
export default connect(mapStateToProps)(Jumblr);

92
react/src/components/dashboard/jumblr/jumblr.scss

@ -0,0 +1,92 @@
.jumblr {
.alert-info {
width: 100%;
}
p {
width: calc(100% - 100px);
}
.breadcrumb {
padding: 8px 30px;
position: relative;
top: 0;
}
.img-responsive {
position: absolute;
top: -28px;
right: 18px;
.coin {
font-size: 30px;
position: relative;
left: -18px;
top: 4px;
}
.image {
width: 60px;
}
}
.header-easydex-section {
img {
max-width: inherit;
}
}
.copy-string-btn {
position: absolute;
right: 36px;
margin-top: -68px;
}
.btn-next {
position: absolute;
top: 60px;
right: 32px;
}
input.labelauty+label,
input.labelauty+label {
background: #d6d5d5;
color: #504e4e;
}
input.labelauty:checked+label {
color: #fff;
background-color: #3949ab;
}
input.labelauty + label:hover .labelauty-unchecked,
input.labelauty + label .labelauty-unchecked {
color: #504e4e;
}
.nofloat {
float: none;
display: inline-block;
padding-left: 0;
}
}
.jumblr-mode-selector {
.nav-tabs {
li {
cursor: pointer;
&.active {
> a {
cursor: pointer;
color: #fff;
background-color: #62a8ea;
border-color: transparent;
border-bottom-color: #62a8ea;
}
}
}
}
.panel-heading {
background: #f3f3f3;
cursor: pointer;
}
.panel-title {
color: #676767;
}
.jumblr-addresses-list {
.col-xs-3 {
padding: 0;
}
}
}

2
react/src/components/dashboard/loginModal/loginModal.render.js

@ -1,7 +1,7 @@
import React from 'react';
import { translate } from '../../../translate/translate';
const LoginModalRender = function () {
const LoginModalRender = function() {
return (
<div>
<div

3
react/src/components/dashboard/loginSettingsModal/loginSettingsModal.js

@ -32,9 +32,8 @@ class LoginSettingsModal extends React.Component {
const mapStateToProps = (state) => {
return {
Main: state.Main
Main: state.Main,
};
};
export default connect(mapStateToProps)(LoginSettingsModal);

7
react/src/components/dashboard/loginSettingsModal/loginSettingsModal.scss

@ -0,0 +1,7 @@
.login-settings-modal {
form {
width: 100%;
margin: 0;
margin-top: 25px;
}
}

5
react/src/components/dashboard/main/dashboard.js

@ -45,11 +45,8 @@ const mapStateToProps = (state) => {
ActiveCoin: {
mode: state.ActiveCoin.mode,
},
Dashboard: {
activeSection: state.Dashboard.activeSection,
}
Dashboard: state.Dashboard,
};
};
export default connect(mapStateToProps)(Dashboard);

6
react/src/components/dashboard/main/dashboard.render.js

@ -16,6 +16,7 @@ import About from '../about/about';
import WalletsNative from '../walletsNative/walletsNative';
import WalletsTxInfo from '../walletsTxInfo/walletsTxInfo';
import CoindDownModal from '../coindDownModal/coindDownModal';
import ImportKeyModal from '../importKeyModal/importKeyModal';
const DashboardRender = function() {
return (
@ -25,6 +26,9 @@ const DashboardRender = function() {
id="section-dashboard">
<Navbar />
<CoindDownModal />
{ this.props.Dashboard.displayImportKeyModal &&
<ImportKeyModal />
}
<div className={ this.isSectionActive('wallets') ? 'show' : 'hide' }>
<CoinTile />
<WalletsNav />
@ -46,7 +50,7 @@ const DashboardRender = function() {
<Jumblr />
}
{ this.isSectionActive('settings') &&
<Settings />
<Settings disableWalletSpecificUI={false} />
}
{ this.isSectionActive('about') &&
<About />

20
react/src/components/dashboard/navbar/navbar.js

@ -7,6 +7,7 @@ import {
startInterval,
toggleSyncOnlyModal,
getSyncOnlyForks,
displayImportKeyModal,
logout,
} from '../../../actions/actionCreators';
import Store from '../../../store';
@ -21,6 +22,7 @@ class Navbar extends React.Component {
this.state = {
openDropMenu: false,
nativeOnly: Config.iguanaLessMode,
isExperimentalOn: false,
};
this.openDropMenu = this.openDropMenu.bind(this);
this.logout = this.logout.bind(this);
@ -34,6 +36,16 @@ class Navbar extends React.Component {
this.handleClickOutside,
false
);
let appConfig;
try {
appConfig = window.require('electron').remote.getCurrentWindow().appConfig;
} catch (e) {}
this.setState({
isExperimentalOn: appConfig.experimentalFeatures,
});
}
componentWillUnmount() {
@ -56,6 +68,10 @@ class Navbar extends React.Component {
}
}
openImportKeyModal() {
Store.dispatch(displayImportKeyModal(true));
}
openDropMenu() {
this.setState(Object.assign({}, this.state, {
openDropMenu: !this.state.openDropMenu,
@ -115,6 +131,7 @@ class Navbar extends React.Component {
return NavbarRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
@ -127,9 +144,8 @@ const mapStateToProps = (state) => {
Interval: {
interval: state.Interval.interval,
},
nativeOnly: Config.iguanaLessMode
nativeOnly: Config.iguanaLessMode,
};
};
export default connect(mapStateToProps)(Navbar);

13
react/src/components/dashboard/navbar/navbar.render.js

@ -57,13 +57,20 @@ const NavbarRender = function() {
<i className="site-menu-icon"></i> BarterDEX
</a>
</li>
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (this._checkAC() || this.props.ActiveCoin.coin === 'KMD') &&
{ this.props.ActiveCoin && this.props.ActiveCoin.mode === 'native' && (/*this._checkAC() || */this.props.ActiveCoin.coin === 'KMD') &&
<li className={ this.isSectionActive('jumblr') ? 'active nav-top-menu' : 'nav-top-menu' }>
<a onClick={ () => this.dashboardChangeSection('jumblr') }>
<i className="site-menu-icon"></i> Jumblr
</a>
</li>
}
{ this.state.nativeOnly &&
<li className="nav-top-menu">
<a onClick={ this.openImportKeyModal }>
<i className="site-menu-icon"></i> Import key
</a>
</li>
}
<li className={ this.state.nativeOnly ? 'hide' : (this.isSectionActive('atomic') ? 'active nav-top-menu' : 'nav-top-menu') }>
<a onClick={ () => this.dashboardChangeSection('atomic') }>
<i className="site-menu-icon"></i> Atomic Explorer
@ -99,14 +106,14 @@ const NavbarRender = function() {
<i className="icon md-settings"></i> { translate('INDEX.SETTINGS') }
</a>
</li>
<li className={ this.state.nativeOnly ? 'hide' : '' }>
<li className={ this.state.nativeOnly || !this.state.isExperimentalOn ? 'hide' : '' }>
<a onClick={ () => this.openSyncOnlyModal() }>
<i className="icon fa-cubes"></i> { translate('ADD_COIN.SYNC_ONLY') }
</a>
</li>
<li>
<a onClick={ () => this.dashboardChangeSection('about') }>
<i className="icon fa-users"></i> { translate('INDEX.ABOUT_IGUANA') }
<i className="icon fa-users"></i> { translate('ABOUT.ABOUT_AGAMA') }
</a>
</li>
<li className={ this.state.nativeOnly ? 'hide' : 'divider' }></li>

122
react/src/components/dashboard/notifications/notifications.js

@ -1,122 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import { sortByDate } from '../../../util/sort';
import Config from '../../../config';
import {
NotificationsByTypeRender,
NotificationsModalRender,
NotificationsRender
} from './notifications.render';
class Notifications extends React.Component {
constructor() {
super();
this.state = {
displayModal: false,
calls: {
total: 0,
error: 0,
success: 0,
pending: 0,
},
activeTab: 2,
guiLog: null,
debug: Config.debug,
};
this.toggleNotificationsModal = this.toggleNotificationsModal.bind(this);
}
openTab(tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
}));
}
componentWillReceiveProps(props) {
// get total number of calls per type
if (this.props.Dashboard &&
this.props.Dashboard.guiLog) {
const _guiLog = this.props.Dashboard.guiLog;
let _callsLength = {
total: Object.keys(_guiLog).length,
error: 0,
success: 0,
pending: 0,
}
let guiLogToArray = [];
for (let timestamp in _guiLog) {
guiLogToArray.push(_guiLog[timestamp]);
_callsLength[_guiLog[timestamp].status]++;
}
this.setState(Object.assign({}, this.state, {
calls: {
total: _callsLength.total,
error: _callsLength.error,
success: _callsLength.success,
pending: _callsLength.pending,
},
guiLog: guiLogToArray,
}));
}
}
renderNotificationsByType(type) {
// get total number of calls per type
if (this.state.guiLog &&
this.state.guiLog.length) {
let _guiLog = this.state.guiLog;
let items = [];
_guiLog = sortByDate(_guiLog);
for (let i = 0; i < _guiLog.length; i++) {
if (_guiLog[i].status === type) {
const _logItem = _guiLog[i];
items.push(
NotificationsByTypeRender.call(
this,
_logItem,
type,
i
)
);
}
}
return items;
}
}
renderNotificationsModal() {
if (this.state.displayModal) {
return NotificationsModalRender.call(this);
}
return null;
}
toggleNotificationsModal() {
this.setState(Object.assign({}, this.state, {
displayModal: !this.state.displayModal,
}));
}
render() {
return NotificationsRender.call(this);
}
}
const mapStateToProps = (state) => {
return {
Dashboard: {
guiLog: state.Dashboard.guiLog,
activeHandle: state.Dashboard.activeHandle,
}
};
};
export default connect(mapStateToProps)(Notifications);

116
react/src/components/dashboard/notifications/notifications.render.js

@ -1,116 +0,0 @@
import React from 'react';
import {
secondsToString
} from '../../../util/time';
import { translate } from '../../../translate/translate';
export const NotificationsByTypeRender = function(logItem, type, index) {
return (
<div key={ logItem.timestamp }>
<div>{ index + 1 }.</div>
<div>
<strong>Time:</strong> { secondsToString(logItem.timestamp, true, true) }
</div>
<div>
<strong>GUI Function:</strong> { logItem.function }
</div>
<div>
<strong>HTTP:</strong> { logItem.httpMethod.toUpperCase() }
</div>
<div>
<strong>URL:</strong> { logItem.url }
</div>
<div>
<strong>Payload:</strong> { JSON.stringify(logItem.payload, null, '\t') }
</div>
<div className={ type !== 'pending' ? '' : 'hide' }>
<strong>Response:</strong> { JSON.stringify(logItem.response, null, '\t') }
</div>
<hr />
</div>
);
}
export const NotificationsModalRender = function() {
return (
<div onKeyDown={ (event) => this.handleKeydown(event) }>
<div className="modal show notifications-modal">
<div className="modal-dialog modal-center modal-lg">
<div className="modal-content">
<div className="modal-body modal-body-container">
<div className="panel nav-tabs-horizontal">
<ul className="nav nav-tabs nav-tabs-line">
<li className={ this.state.activeTab === 0 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(0) }>
<i className="icon fa fa-thumbs-o-up"></i> Success ({ this.state.calls.success })
</a>
</li>
<li className={ this.state.activeTab === 1 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(1) }>
<i className="icon fa fa-exclamation-triangle"></i> Error ({ this.state.calls.error })
</a>
</li>
<li className={ this.state.activeTab === 2 ? 'active' : 'pointer' }>
<a onClick={ () => this.openTab(2) }>
<i className="icon fa fa-clock-o"></i> Pending ({ this.state.calls.pending })
</a>
</li>
</ul>
<div className="panel-body panel-body-container">
<div className="tab-content">
<div className={ 'tab-pane' + (this.state.activeTab === 0 ? ' active' : '') }>
{ this.renderNotificationsByType('success') }
</div>
<div className={ 'tab-pane' + (this.state.activeTab === 1 ? ' active' : '') }>
{ this.renderNotificationsByType('error') }
</div>
<div className={ 'tab-pane' + (this.state.activeTab === 2 ? ' active' : '') }>
{ this.renderNotificationsByType('pending') }
</div>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-default"
onClick={ this.toggleNotificationsModal }>
{ translate('INDEX.CLOSE') }
</button>
</div>
</div>
</div>
</div>
<div className="modal-backdrop show in"></div>
</div>
);
};
export const NotificationsRender = function() {
return (
<div>
<div
className={ 'notifications-badge' + (this.props.Dashboard.activeHandle && this.props.Dashboard.activeHandle.status === 'unlocked' ? ' stick-to-top' : '') }
onClick={ this.state.debug ? this.toggleNotificationsModal : null }>
<span className={ this.state.debug ? 'badge success' : 'hide' }>
{ this.state.calls.success }
</span>
<span className={ this.state.debug ? 'badge error' : 'hide' }>
{ this.state.calls.error }
</span>
<span className={ this.state.debug ? 'badge pending' : 'hide' }>
{ this.state.calls.pending }
</span>
<div className={ 'spinner' + (this.state.calls.pending === 0 ? ' spinner-hide' : '') }>
<div className="rect1"></div>
<div className="rect2"></div>
<div className="rect3"></div>
<div className="rect4"></div>
<div className="rect5"></div>
</div>
</div>
{ this.renderNotificationsModal() }
</div>
);
};

4
react/src/components/dashboard/qrModal/qrModal.js

@ -14,6 +14,7 @@ class QRModal extends React.Component {
this.state = {
modalIsOpen: false,
error: null,
errorShown: false,
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
@ -45,7 +46,7 @@ class QRModal extends React.Component {
openModal() {
this.setState({
modalIsOpen: true
modalIsOpen: true,
});
if (this.props.mode === 'scan') {
@ -65,6 +66,7 @@ class QRModal extends React.Component {
closeModal() {
this.setState({
modalIsOpen: false,
errorShown: this.state.error ? true : false,
});
}

76
react/src/components/dashboard/qrModal/qrModal.render.js

@ -2,7 +2,7 @@ import React from 'react';
import { translate } from '../../../translate/translate';
import QRCode from 'qrcode.react';
export const QRModalRender = function () {
export const QRModalRender = function() {
return (
<span>
<span className="label label-default margin-left-10 action"
@ -41,48 +41,46 @@ export const QRModalRender = function () {
);
};
export const QRModalReaderRender = function () {
return (
<span>
<button type="button"
className="btn btn-default"
onClick={ this.openModal }>
<i className="icon fa-qrcode"></i>
{ translate('INDEX.SCAN_QRCODE_WEBCAM') }
</button>
<div
className={ 'modal modal-3d-sign ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }
id="QRReadModal">
<div className="modal-dialog modal-center modal-md">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.SCAN_QRCODE_WEBCAM') }</h4>
</div>
<div className="modal-body">
<div className="animsition vertical-align fade-in">
<div
className="page-content vertical-align-middle"
style={{
width: '100%',
textAlign: 'center',
fontSize: '16px'
}}>
<div id="webcam">
{ this.state.error }
export const QRModalReaderRender = function() {
if (!this.state.errorShown) {
return (
<span>
<button type="button"
className="btn btn-default"
onClick={ this.openModal }>
<i className="icon fa-qrcode"></i>
{ translate('INDEX.SCAN_QRCODE_WEBCAM') }
</button>
<div
className={ 'modal modal-3d-sign ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }
id="QRReadModal">
<div className="modal-dialog modal-center modal-md">
<div className="modal-content">
<div className="modal-header bg-orange-a400 wallet-send-header">
<button
type="button"
className="close white"
onClick={ this.closeModal }>
<span>×</span>
</button>
<h4 className="modal-title white text-left">{ translate('INDEX.SCAN_QRCODE_WEBCAM') }</h4>
</div>
<div className="modal-body">
<div className="animsition vertical-align fade-in">
<div className="page-content vertical-align-middle webcam-frame">
<div id="webcam">
{ this.state.error }
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div className={ 'modal-backdrop ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }></div>
</span>
);
<div className={ 'modal-backdrop ' + (this.state.modalIsOpen ? 'show in' : 'fade hide') }></div>
</span>
);
} else {
return null;
}
};

11
react/src/components/dashboard/qrModal/qrModal.scss

@ -0,0 +1,11 @@
.qr-modal-send-block {
position: absolute;
top: 15px;
right: 30px;
}
.webcam-frame {
width: 100%;
text-align: center;
font-size: 16px;
}

17
react/src/components/dashboard/receiveCoin/receiveCoin.js

@ -217,8 +217,9 @@ class ReceiveCoin extends React.Component {
return null;
}
}
const mapStateToProps = (state) => {
return {
const mapStateToProps = (state, props) => {
let _mappedProps = {
coin: state.ActiveCoin.coin,
mode: state.ActiveCoin.mode,
receive: state.ActiveCoin.receive,
@ -226,9 +227,17 @@ const mapStateToProps = (state) => {
cache: state.ActiveCoin.cache,
activeSection: state.ActiveCoin.activeSection,
activeAddress: state.ActiveCoin.activeAddress,
addresses: state.ActiveCoin.addresses
addresses: state.ActiveCoin.addresses,
};
if (props &&
props.activeSection &&
props.renderTableOnly) {
_mappedProps.activeSection = props.activeSection;
_mappedProps.renderTableOnly = props.renderTableOnly;
}
return _mappedProps;
};
export default connect(mapStateToProps)(ReceiveCoin);

30
react/src/components/dashboard/sendCoin/sendCoin.js

@ -10,7 +10,6 @@ import {
import {
resolveOpenAliasAddress,
triggerToaster,
basiliskRefresh,
shepherdGroomPostPromise,
edexGetTransaction,
getCacheFile,
@ -128,13 +127,6 @@ class SendCoin extends React.Component {
currentStackLength: data.message.shepherd.iguanaAPI.currentStackLength,
}));
}
if (data &&
data.message &&
data.message.shepherd.method &&
data.message.shepherd.method === 'cache-one' &&
data.message.shepherd.status === 'done') {
Store.dispatch(basiliskRefresh(false));
}
}
_fetchNewUTXOData() {
@ -765,7 +757,7 @@ class SendCoin extends React.Component {
}
// TODO same as in walletsNav and receiveCoin, find a way to reuse it?
checkTotalBalance() {
checkBalance() {
let _balance = '0';
const _mode = this.props.ActiveCoin.mode;
@ -785,21 +777,16 @@ class SendCoin extends React.Component {
(_cache[_coin][_address].getbalance.data.balance ||
_cache[_coin][_address].getbalance.data.interest)) {
const _regBalance = _cache[_coin][_address].getbalance.data.balance ? _cache[_coin][_address].getbalance.data.balance : 0;
const _regInterest = _cache[_coin][_address].getbalance.data.interest ? _cache[_coin][_address].getbalance.data.interest : 0;
_balance = _regBalance + _regInterest;
_balance = _regBalance;
}
}
} else if (_mode === 'native') {
if (this.props.ActiveCoin.balance &&
this.props.ActiveCoin.balance.total) {
_balance = this.props.ActiveCoin.balance.total;
}
}
return +_balance;
return _balance;
}
// TODO: reduce to a single toast
validateSendFormData() {
let valid = true;
if (!this.state.sendTo || this.state.sendTo.length < 34) {
@ -846,7 +833,8 @@ class SendCoin extends React.Component {
valid = false;
}
if (this.state.amount > this.checkTotalBalance()) {
/*if ((this.props.ActiveCoin.mode === 'basilisk' && Number(this.state.amount) > Number(this.state.sendFromAmount)) ||
(this.props.ActiveCoin.mode === 'full' && Number(this.state.amount) > Number(this.checkBalance()))) {
Store.dispatch(
triggerToaster(
translate('SEND.INSUFFICIENT_FUNDS'),
@ -855,7 +843,7 @@ class SendCoin extends React.Component {
)
);
valid = false;
}
}*/
return valid;
}
@ -890,10 +878,8 @@ const mapStateToProps = (state) => {
},
Dashboard: {
activeHandle: state.Dashboard.activeHandle,
}
},
};
};
export default connect(mapStateToProps)(SendCoin);

180
react/src/components/dashboard/settings/settings.addNodePanel.js

@ -0,0 +1,180 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import {
addPeerNode,
getPeersList,
getPeersListState,
} from '../../../actions/actionCreators';
import Store from '../../../store';
import AddCoinOptionsCrypto from '../../addcoin/addcoinOptionsCrypto';
import AddCoinOptionsAC from '../../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../../addcoin/addcoinOptionsACFiat';
class AddNodePanel extends React.Component {
constructor() {
super();
this.state = {
addNodeCoin: null,
addPeerIP: null,
getPeersCoin: null,
trimPassphraseTimer: null,
wifkeysPassphrase:'',
};
this.renderSNPeersList = this.renderSNPeersList.bind(this);
this.renderPeersList = this.renderPeersList.bind(this);
this.checkNodes = this.checkNodes.bind(this);
this.addNode = this.addNode.bind(this);
this.updateInput = this.updateInput.bind(this);
}
renderSNPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _supernetPeers = this.props.Settings.supernetPeers;
const coin = _getPeersCoin.split('|')[0];
if (_supernetPeers &&
_getPeersCoin &&
_supernetPeers[coin]) {
return _supernetPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
renderPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _rawPeers = this.props.Settings.rawPeers;
const coin = _getPeersCoin.split('|')[0];
if (_rawPeers &&
_getPeersCoin &&
_rawPeers[coin]) {
return _rawPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
checkNodes() {
if (this.state.getPeersCoin) {
console.warn(this.state.getPeersCoin.split('|')[0]);
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
addNode() {
if (this.state.addNodeCoin && this.state.addPeerIP) {
Store.dispatch(
addPeerNode(
this.state.addNodeCoin.split('|')[0],
this.state.addPeerIP
)
);
}
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="getPeersCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.checkNodes }>{ translate('INDEX.CHECK_NODES') }</button>
</div>
<div className="col-sm-12">
<h5>
SuperNET Peers:
</h5>
<div>{ this.renderSNPeersList() }</div>
<h5>
Raw Peers:
</h5>
<div>{ this.renderPeersList() }</div>
</div>
</div>
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION_PEER') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="addNodeCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
<div className="form-group">
<input
type="text"
className="form-control"
name="addPeerIP"
placeholder={ translate('SETTINGS.ADD_PEER_IP') }
onChange={ this.updateInput } />
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.addNode }>{ translate('INDEX.ADD_NODE') }</button>
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AddNodePanel);

90
react/src/components/dashboard/settings/settings.appInfoPanel.js

@ -0,0 +1,90 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class AppInfoPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">
<div className="col-sm-12 padding-top-15">
<div className="row">
<h5>{ translate('SETTINGS.APP_RELEASE') }</h5>
<div>
{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name }
</div>
<div>
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` }
</div>
<div>
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.SYS_INFO') }</h5>
<div>
{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch }
</div>
<div>
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type }
</div>
<div>
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform }
</div>
<div>
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release }
</div>
<div>
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu }
</div>
<div>
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores }
</div>
<div>
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.LOCATIONS') }</h5>
<div>
{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation }
</div>
<div>
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation }
</div>
<div>
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin }
</div>
<div>
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir }
</div>
<div>
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin }
</div>
<div>
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
<div>
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AppInfoPanel);

321
react/src/components/dashboard/settings/settings.appSettingsPanel.js

@ -0,0 +1,321 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import {
iguanaActiveHandle,
getAppConfig,
getAppInfo,
resetAppConfig,
saveAppConfig,
skipFullDashboardUpdate,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class AppSettingsPanel extends React.Component {
constructor() {
super();
this.state = {
appSettings: {},
appConfigSchema: {},
};
this._saveAppConfig = this._saveAppConfig.bind(this);
this._resetAppConfig = this._resetAppConfig.bind(this);
this._skipFullDashboardUpdate = this._skipFullDashboardUpdate.bind(this);
this.updateInput = this.updateInput.bind(this);
}
componentWillMount() {
try {
const _appConfigSchema = window.require('electron').remote.getCurrentWindow().appConfigSchema;
const _appSettings = this.props.Settings.appSettings ? this.props.Settings.appSettings : Object.assign({}, window.require('electron').remote.getCurrentWindow().appConfig);
this.setState(Object.assign({}, this.state, {
appConfigSchema: _appConfigSchema,
appSettings: _appSettings,
}));
} catch(e) {}
}
componentDidMount(props) {
if (!this.props.disableWalletSpecificUI) {
Store.dispatch(iguanaActiveHandle());
}
Store.dispatch(getAppConfig());
Store.dispatch(getAppInfo());
}
_skipFullDashboardUpdate() {
Store.dispatch(skipFullDashboardUpdate(!this.props.Dashboard.skipFullDashboardUpdate));
}
_resetAppConfig() {
Store.dispatch(resetAppConfig());
}
_saveAppConfig() {
const _appSettings = this.state.appSettings;
let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings);
let isError = false;
let saveAfterPathCheck = false;
for (let key in _appSettings) {
if (key.indexOf('__') === -1) {
_appSettingsPristine[key] = this.state.appConfigSchema[key] && this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
if (this.state.appConfigSchema[key] && this.state.appConfigSchema[key].type === 'folder' &&
_appSettings[key] &&
_appSettings[key].length) {
const _testLocation = window.require('electron').remote.getCurrentWindow().testLocation;
saveAfterPathCheck = true;
_testLocation(_appSettings[key])
.then((res) => {
if (res === -1) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_INVALID'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else if (res === false) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_NOT_DIR'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
});
}
} else {
const _nestedKey = key.split('__');
_appSettingsPristine[_nestedKey[0]][_nestedKey[1]] = this.state.appConfigSchema[_nestedKey[0]][_nestedKey[1]].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
}
}
if (!saveAfterPathCheck) {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
}
renderConfigEditForm() {
let items = [];
const _appConfig = this.state.appSettings;
for (let key in _appConfig) {
if (this.state.appConfigSchema[key] && typeof _appConfig[key] === 'object') {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15"></td>
</tr>
);
for (let _key in _appConfig[key]) {
items.push(
<tr key={ `app-settings-${key}-${_key}` }>
<td className="padding-15 padding-left-30">
{ this.state.appConfigSchema[key][_key].displayName ? this.state.appConfigSchema[key][_key].displayName : _key }
{ this.state.appConfigSchema[key][_key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key][_key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key][_key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ (this.state.appConfigSchema[key][_key].type === 'string' || this.state.appConfigSchema[key][_key].type === 'folder') &&
<input
type="text"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
className={ this.state.appConfigSchema[key][_key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ this.state.appConfigSchema[key][_key].type === 'boolean' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}__${_key}` }
value={ _appConfig[key] }
checked={ _appConfig[key][_key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key, _key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
} else {
if (this.state.appConfigSchema[key] && this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}` }
value={ _appConfig[key] }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ (this.state.appConfigSchema[key].type === 'string' || this.state.appConfigSchema[key].type === 'folder') &&
<input
type="text"
name={ `${key}` }
value={ _appConfig[key] }
className={ this.state.appConfigSchema[key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ this.state.appConfigSchema[key].type === 'boolean' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}` }
value={ _appConfig[key] }
checked={ _appConfig[key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
}
items.push(
<tr key={ `kmd-main-sync-only` }>
<td className="padding-15">
KMD main sync only
<i
className="icon fa-question-circle settings-help"
title="Fetch block synchronization data only. Skip any other requests that can deteriorate sync speed."></i>
</td>
<td className="padding-15">
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `kmd-main-sync-only` }
value={ this.props.Dashboard.skipFullDashboardUpdate }
checked={ this.props.Dashboard.skipFullDashboardUpdate } />
<div
className="slider"
onClick={ this._skipFullDashboardUpdate }></div>
</label>
</span>
</td>
</tr>
);
return items;
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
updateInputSettings(e, parentKey, childKey) {
let _appSettings = this.state.appSettings;
let _appSettingsPrev = Object.assign({}, _appSettings);
if (!childKey && this.state.appConfigSchema[parentKey].type === 'boolean') {
_appSettings[parentKey] = typeof _appSettings[parentKey] !== undefined ? !_appSettings[parentKey] : !this.state.appSettings[parentKey];
} else if (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'boolean') {
_appSettings[parentKey][childKey] = typeof _appSettings[parentKey][childKey] !== undefined ? !_appSettings[parentKey][childKey] : !this.state.appSettings[parentKey][childKey];
} else if ((!childKey && this.state.appConfigSchema[parentKey].type === 'number') || (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'number')) {
if (e.target.value === '') {
_appSettings[e.target.name] = _appSettingsPrev[e.target.name];
} else {
_appSettings[e.target.name] = e.target.value.replace(/[^0-9]+/g, '');
}
} else {
_appSettings[e.target.name] = e.target.value;
}
this.setState({
appSettings: _appSettings,
});
}
render() {
return (
<div className="panel-body">
<p>
<strong>{ translate('SETTINGS.CONFIG_RESTART_REQUIRED') }</strong>
</p>
<div className="col-sm-12 padding-top-15">
<table>
<tbody>
{ this.renderConfigEditForm() }
</tbody>
</table>
</div>
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this._saveAppConfig }>{ translate('SETTINGS.SAVE_APP_CONFIG') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-30"
onClick={ this._resetAppConfig }>Reset to default</button>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
Dashboard: {
skipFullDashboardUpdate: state.Dashboard.skipFullDashboardUpdate,
},
};
};
export default connect(mapStateToProps)(AppSettingsPanel);

151
react/src/components/dashboard/settings/settings.appUpdatePanel.js

@ -0,0 +1,151 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import Config from '../../../config';
import {
getPeersList,
checkForUpdateUIPromise,
updateUIPromise,
} from '../../../actions/actionCreators';
import { SocketProvider } from 'socket.io-react';
import io from 'socket.io-client';
const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
let updateProgressBar = {
patch: -1,
};
class AppUpdatePanel extends React.Component {
constructor() {
super();
this.state = {
updatePatch: null,
updateLog: [],
updateProgressPatch: null,
updatePatch: null,
updateBins: null,
};
this._checkForUpdateUIPromise = this._checkForUpdateUIPromise.bind(this);
this._updateUIPromise = this._updateUIPromise.bind(this);
this.checkNodes = this.checkNodes.bind(this);
}
componentWillMount() {
socket.on('patch', msg => this.updateSocketsData = (msg) => {});
}
componentWillUnmount() {
socket.removeAllListeners('patch', msg => this.updateSocketsData(msg));
}
checkNodes() {
if (this.state.getPeersCoin) {
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
_updateUIPromise() {
updateProgressBar.patch = 0;
let _updateLog = [];
_updateLog.push(`${translate('INDEX.DOWNLOADING_UI_UPDATE')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateUIPromise();
}
_checkForUpdateUIPromise() {
let _updateLog = [];
_updateLog.push(translate('INDEX.CHECKING_UI_UPDATE'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
checkForUpdateUIPromise()
.then((res) => {
let _updateLog = this.state.updateLog;
_updateLog.push(res.result === 'update' ? (`${translate('INDEX.NEW_UI_UPDATE')} ${res.version.remote}`) : translate('INDEX.YOU_HAVE_LATEST_UI'));
this.setState(Object.assign({}, this.state, {
updatePatch: res.result === 'update' ? true : false,
updateLog: _updateLog,
}));
});
}
renderUpdateStatus() {
let items = [];
let patchProgressBar = null;
const _updateLogLength = this.state.updateLog.length;
for (let i = 0; i < _updateLogLength; i++) {
items.push(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
);
}
if (_updateLogLength) {
return (
<div style={{ minHeight: '200px' }}>
<hr />
<h5>{ translate('SETTINGS.PROGRESS') }:</h5>
<div className="padding-bottom-15">{ items }</div>
<div className={ updateProgressBar.patch > -1 ? 'progress progress-sm' : 'hide' }>
<div
className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent"
style={{ width: `${updateProgressBar.patch}%` }}>
</div>
</div>
</div>
);
} else {
return null;
}
}
render() {
return (
<div className="panel-body">
<div className="col-sm-4 padding-top-15">
<h5>{ translate('INDEX.UI_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this._updateUIPromise }
disabled={ !this.state.updatePatch }>{ translate('INDEX.UPDATE_UI_NOW') }</button>
</div>
</div>
<div className="col-sm-4 padding-top-15 hide">
<h5>{ translate('INDEX.BINS_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this.checkNodes }>{ translate('INDEX.UPDATE_BINS_NOW') }</button>
</div>
</div>
<div className="col-sm-12 padding-top-15">
{ this.renderUpdateStatus() }
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(AppUpdatePanel);

206
react/src/components/dashboard/settings/settings.cliPanel.js

@ -0,0 +1,206 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import {
shepherdCli,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class CliPanel extends React.Component {
constructor() {
super();
this.state = {
cliCmdString: '',
cliCoin: null,
cliResponse: null,
};
}
renderActiveCoinsList(mode) {
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
let items = [];
if (allCoins) {
if (mode === 'all') {
modes.map(function(mode) {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
});
} else {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
}
return items;
} else {
return null;
}
}
// TODO: rerender only if prop is changed
renderCliResponse() {
const _cliResponse = this.props.Settings.cli;
let _items = [];
if (_cliResponse) {
let _cliResponseParsed;
let responseType;
try {
_cliResponseParsed = JSON.parse(_cliResponse.result);
} catch(e) {
_cliResponseParsed = _cliResponse.result;
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object Array]') {
responseType = 'array';
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed[i], null, '\t') }</div>
);
}
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object]' ||
typeof _cliResponseParsed === 'object') {
responseType = 'object';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed, null, '\t') }</div>
);
}
if (Object.prototype.toString.call(_cliResponseParsed) === 'number' ||
typeof _cliResponseParsed === 'boolean' ||
_cliResponseParsed === 'wrong cli string format') {
responseType = 'number';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed.toString() }</div>
);
}
if (responseType !== 'number' &&
responseType !== 'array' &&
responseType !== 'object' &&
_cliResponseParsed.indexOf('\n') > -1) {
_cliResponseParsed = _cliResponseParsed.split('\n');
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed[i] }</div>
);
}
}
return (
<div>
<div>
<strong>{ translate('SETTINGS.CLI_RESPONSE') }:</strong>
</div>
{ _items }
</div>
);
} else {
return null;
}
}
execCliCmd() {
Store.dispatch(
shepherdCli(
'passthru',
this.state.cliCoin,
this.state.cliCmdString
)
);
}
updateInput = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p>
<div className="col-sm-12"></div>
<form
className="execute-cli-cmd-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="cliCoin"
id="settingsCliOptions"
onChange={ this.updateInput }>
<option>{ translate('INDEX.CLI_NATIVE_COIN') }</option>
{ this.renderActiveCoinsList('native') }
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.COIN') }</label>
</div>
<div className="form-group form-material floating">
<textarea
type="text"
className="form-control"
name="cliCmdString"
id="cliCmd"
value={ this.state.cliCmdString }
onChange={ this.updateInput }></textarea>
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.TYPE_CLI_CMD') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
disabled={ !this.state.cliCoin || !this.state.cliCmdString }
onClick={ () => this.execCliCmd() }>{ translate('INDEX.EXECUTE') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">
{ this.renderCliResponse() }
</div>
</div>
</form>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Main: {
coins: state.Main.coins,
},
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(CliPanel);

180
react/src/components/dashboard/settings/settings.debugLogPanel.js

@ -0,0 +1,180 @@
import React from 'react';
import { connect } from 'react-redux';
import { translate } from '../../../translate/translate';
import Config from '../../../config';
import { secondsToString } from '../../../util/time';
import {
getDebugLog,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class DebugLogPanel extends React.Component {
constructor() {
super();
this.state = {
appRuntimeLog: [],
debugLinesCount: 10,
debugTarget: 'iguana',
nativeOnly: Config.iguanaLessMode,
toggleAppRuntimeLog: false,
};
this.readDebugLog = this.readDebugLog.bind(this);
this.updateInput = this.updateInput.bind(this);
this.getAppRuntimeLog = this.getAppRuntimeLog.bind(this);
this.toggleAppRuntimeLog = this.toggleAppRuntimeLog.bind(this);
this.renderAppRuntimeLog = this.renderAppRuntimeLog.bind(this);
}
readDebugLog() {
Store.dispatch(
getDebugLog(
this.state.debugTarget,
this.state.debugLinesCount
)
);
}
renderAppRuntimeLog() {
let _items = [];
const _appRuntimeLog = this.state.appRuntimeLog;
for (let i = 0; i < _appRuntimeLog.length; i++) {
_items.push(
<p key={ `app-runtime-log-entry-${i}` }>
<span>{ secondsToString(_appRuntimeLog[i].time, true) }</span>
<span className="padding-left-30">{ JSON.stringify(_appRuntimeLog[i].msg, null, '') }</span>
</p>
);
}
return _items;
}
toggleAppRuntimeLog() {
this.setState(Object.assign({}, this.state, {
toggleAppRuntimeLog: !this.state.toggleAppRuntimeLog,
}));
this.getAppRuntimeLog();
}
getAppRuntimeLog() {
let _appRuntimeLog;
try {
_appRuntimeLog = window.require('electron').remote.getCurrentWindow().getAppRuntimeLog;
} catch (e) {}
_appRuntimeLog()
.then((json) => {
this.setState(Object.assign({}, this.state, {
appRuntimeLog: json,
}));
});
}
renderDebugLogData() {
if (this.props.Settings.debugLog) {
const _debugLogDataRows = this.props.Settings.debugLog.split('\n');
if (_debugLogDataRows &&
_debugLogDataRows.length) {
return _debugLogDataRows.map((_row) =>
<div
key={ `settings-debuglog-${Math.random(0, 9) * 10}` }
className="padding-bottom-5">{ _row }</div>
);
} else {
return (
<span>{ translate('INDEX.EMPTY_DEBUG_LOG') }</span>
);
}
} else {
return null;
}
}
updateInput(e) {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p>
<div className="margin-top-30">
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name="settings-app-debug-toggle"
value={ this.state.toggleAppRuntimeLog }
checked={ this.state.toggleAppRuntimeLog } />
<div
className="slider"
onClick={ this.toggleAppRuntimeLog }></div>
</label>
<span
className="title"
onClick={ this.toggleAppRuntimeLog }>Show app runtime log</span>
</span>
</div>
{ !this.state.toggleAppRuntimeLog &&
<form
className="read-debug-log-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="debugLinesCount"
id="readDebugLogLines"
value={ this.state.debugLinesCount }
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.DEBUG_LOG_LINES') }</label>
</div>
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="debugTarget"
id="settingsDelectDebugLogOptions"
onChange={ this.updateInput }>
<option value="iguana" className={ this.state.nativeOnly ? 'hide' : '' }>Iguana</option>
<option value="komodo">Komodo</option>
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.TARGET') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">{ this.renderDebugLogData() }</div>
</div>
</form>
}
{ this.state.toggleAppRuntimeLog &&
<div className="margin-top-20">{ this.renderAppRuntimeLog() }</div>
}
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(DebugLogPanel);

235
react/src/components/dashboard/settings/settings.exportKeysPanel.js

@ -0,0 +1,235 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
import {
encryptWallet,
settingsWifkeyState,
copyCoinAddress,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class ExportKeysPanel extends React.Component {
constructor() {
super();
this.state = {
exportWifKeysRaw: false,
seedInputVisibility: false,
trimPassphraseTimer: null,
wifkeysPassphrase: '',
};
this.exportWifKeys = this.exportWifKeys.bind(this);
this.exportWifKeysRaw = this.exportWifKeysRaw.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._copyCoinAddress = this._copyCoinAddress.bind(this);
this.updateInput = this.updateInput.bind(this);
}
exportWifKeys() {
Store.dispatch(
encryptWallet(
this.state.wifkeysPassphrase,
settingsWifkeyState,
this.props.ActiveCoin.coin
)
);
}
exportWifKeysRaw() {
this.setState(Object.assign({}, this.state, {
exportWifKeysRaw: !this.state.exportWifKeysRaw,
}));
}
toggleSeedInputVisibility() {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
});
}
renderExportWifKeysRaw() {
const _wifKeysResponse = this.props.Settings.wifkey;
if (_wifKeysResponse &&
this.state.exportWifKeysRaw) {
return (
<div className="padding-bottom-30 padding-top-30">
{ JSON.stringify(_wifKeysResponse, null, '\t') }
</div>
);
} else {
return null;
}
}
_copyCoinAddress(address) {
Store.dispatch(copyCoinAddress(address));
}
renderWifKeys() {
let items = [];
if (this.props.Settings.wifkey) {
const _wifKeys = this.props.Settings.wifkey;
for (let i = 0; i < 2; i++) {
items.push(
<tr key={ `wif-export-table-header-${i}` }>
<td className="padding-bottom-10 padding-top-10">
<strong>{ i === 0 ? translate('SETTINGS.ADDRESS_LIST') : translate('SETTINGS.WIF_KEY_LIST') }</strong>
</td>
<td className="padding-bottom-10 padding-top-10"></td>
</tr>
);
for (let _key in _wifKeys) {
if ((i === 0 && _key.length === 3 && _key !== 'tag') ||
(i === 1 && _key.indexOf('wif') > -1)) {
items.push(
<tr key={ _key }>
<td className="padding-bottom-20">{ _key.replace('wif', ' WIF') }</td>
<td className="padding-bottom-20 padding-left-15">
{ _wifKeys[_key] }
<button
className="btn btn-default btn-xs clipboard-edexaddr margin-left-10"
title={ translate('INDEX.COPY_TO_CLIPBOARD') }
onClick={ () => this._copyCoinAddress(_wifKeys[_key]) }>
<i className="icon wb-copy"></i> { translate('INDEX.COPY') }
</button>
</td>
</tr>
);
}
}
}
return items;
} else {
return null;
}
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
renderLB(_translationID) {
const _translationComponents = translate(_translationID).split('<br>');
return _translationComponents.map((_translation) =>
<span key={ `settings-label-${Math.random(0, 9) * 10}` }>
{ _translation }
<br />
</span>
);
}
render() {
return (
<div className="panel-body">
<div>
<div className="padding-bottom-20">{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }</div>
<div className="padding-bottom-20">
<i>{ this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') }</i>
</div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeys }>{ translate('INDEX.GET_WIF_KEYS') }</button>
</div>
</form>
<div className="col-sm-12 padding-top-15">
<div className="row">
<table className="table">
{ this.renderWifKeys() }
</table>
<div className={ this.props.wifkey ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeysRaw }>{ this.state.exportWifKeysRaw ? 'Hide' : 'Show' } raw data</button>
</div>
<div className={ this.state.exportWifKeysRaw ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
{ this.renderExportWifKeysRaw() }
</div>
</div>
</div>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(ExportKeysPanel);

23
react/src/components/dashboard/settings/settings.fiatCurrencyPanel.js

@ -0,0 +1,23 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class FiatCurrencyPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(FiatCurrencyPanel);

67
react/src/components/dashboard/settings/settings.importKeysPanel.js

@ -0,0 +1,67 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import {
importPrivKey,
} from '../../../actions/actionCreators';
import Store from '../../../store';
class ImportKeysPanel extends React.Component {
constructor() {
super();
this.state = {
importWifKey: '',
};
this.importWifKey = this.importWifKey.bind(this);
}
importWifKey() {
Store.dispatch(importPrivKey(this.state.importWifKey));
}
updateInput = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
}
render() {
return (
<div className="panel-body">
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P1') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P2') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P3') }</div><br/>
<div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="importWifKey"
id="importWifkey"
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="importWifkey">{ translate('INDEX.INPUT_PRIV_KEY') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.importWifKey }>{ translate('INDEX.IMPORT_PRIV_KEY') }</button>
</div>
</form>
</div>
);
}
}
export default ImportKeysPanel;

799
react/src/components/dashboard/settings/settings.js

@ -4,36 +4,31 @@ import { translate } from '../../../translate/translate';
import Config from '../../../config';
import {
iguanaActiveHandle,
encryptWallet,
settingsWifkeyState,
importPrivKey,
getDebugLog,
getAppConfig,
getPeersList,
addPeerNode,
getAppConfig,
saveAppConfig,
resetAppConfig,
getAppInfo,
shepherdCli,
checkForUpdateUIPromise,
updateUIPromise,
triggerToaster,
} from '../../../actions/actionCreators';
import Store from '../../../store';
import {
AppInfoTabRender,
SettingsRender,
AppUpdateTabRender,
} from './settings.render';
import { SocketProvider } from 'socket.io-react';
import io from 'socket.io-client';
const socket = io.connect(`http://127.0.0.1:${Config.agamaPort}`);
let updateProgressBar = {
patch: -1,
};
import AppUpdatePanel from './settings.appUpdatePanel';
import AppInfoPanel from './settings.appInfoPanel';
import AddNodePanel from './settings.addNodePanel';
import AppSettingsPanel from './settings.appSettingsPanel';
import CliPanel from './settings.cliPanel';
import DebugLogPanel from './settings.debugLogPanel';
import FiatCurrencyPanel from './settings.fiatCurrencyPanel';
import ExportKeysPanel from './settings.exportKeysPanel';
import ImportKeysPanel from './settings.importKeysPanel';
import SupportPanel from './settings.supportPanel';
import WalletInfoPanel from './settings.walletInfoPanel';
import WalletBackupPanel from './settings.walletBackupPanel';
/*
TODO:
@ -47,77 +42,12 @@ class Settings extends React.Component {
super();
this.state = {
activeTab: 0,
debugLinesCount: 10,
debugTarget: 'iguana',
activeTabHeight: '0',
appSettings: {},
appConfigSchema: {},
tabElId: null,
cliCmdString: '',
cliCoin: null,
cliResponse: null,
exportWifKeysRaw: false,
seedInputVisibility: false,
nativeOnly: Config.iguanaLessMode,
updatePatch: null,
updateBins: null,
updateLog: [],
updateProgressPatch: null,
wifkeysPassphrase: '',
trimPassphraseTimer: null,
disableWalletSpecificUI: null,
disableWalletSpecificUI: false,
};
this.exportWifKeys = this.exportWifKeys.bind(this);
this.updateInput = this.updateInput.bind(this);
// this.updateInputSettings = this.updateInputSettings.bind(this);
this.importWifKey = this.importWifKey.bind(this);
this.readDebugLog = this.readDebugLog.bind(this);
this.checkNodes = this.checkNodes.bind(this);
this.addNode = this.addNode.bind(this);
this.renderPeersList = this.renderPeersList.bind(this);
this.renderSNPeersList = this.renderSNPeersList.bind(this);
this._saveAppConfig = this._saveAppConfig.bind(this);
this._resetAppConfig = this._resetAppConfig.bind(this);
this.exportWifKeysRaw = this.exportWifKeysRaw.bind(this);
this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this);
this._checkForUpdateUIPromise = this._checkForUpdateUIPromise.bind(this);
this._updateUIPromise = this._updateUIPromise.bind(this);
this.updateTabDimensions = this.updateTabDimensions.bind(this);
}
updateTabDimensions() {
setTimeout(() => {
const _height = document.querySelector(`#${this.state.tabElId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTabHeight: _height,
}));
}, 100);
}
componentWillMount() {
socket.on('patch', msg => this.updateSocketsData(msg));
window.addEventListener('resize', this.updateTabDimensions);
try {
const _appConfigSchema = window.require('electron').remote.getCurrentWindow().appConfigSchema;
const _appSettings = this.props.Settings.appSettings ? this.props.Settings.appSettings : Object.assign({}, window.require('electron').remote.getCurrentWindow().appConfig);
this.setState(Object.assign({}, this.state, {
appConfigSchema: _appConfigSchema,
appSettings: _appSettings,
}));
} catch(e) {}
}
componentWillUnmount() {
socket.removeAllListeners('patch', msg => this.updateSocketsData(msg));
window.removeEventListener('resize', this.updateTabDimensions);
if (!this.state.disableWalletSpecificUI) {
document.documentElement.style.height = '100%';
document.body.style.height = '100%';
}
}
componentDidMount(props) {
@ -127,719 +57,84 @@ class Settings extends React.Component {
Store.dispatch(getAppConfig());
Store.dispatch(getAppInfo());
document.getElementById('section-iguana-wallet-settings').setAttribute('style', 'height:auto; min-height: 100%');
}
componentWillReceiveProps(props) {
if (this.state.tabElId) {
const _height = document.querySelector(`#${this.state.tabElId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTab: this.state.activeTab,
activeTabHeight: _height,
tabElId: this.state.tabElId,
disableWalletSpecificUI: props.disableWalletSpecificUI,
disableWalletSpecificUI: this.props.disableWalletSpecificUI,
}));
}
}
openExternalWindow(url) {
const remote = window.require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
const externalWindow = new BrowserWindow({
width: 1280,
height: 800,
title: `${translate('INDEX.LOADING')}...`,
icon: remote.getCurrentWindow().iguanaIcon,
});
externalWindow.loadURL(url);
externalWindow.webContents.on('did-finish-load', function() {
setTimeout(function() {
externalWindow.show();
}, 40);
});
}
_resetAppConfig() {
Store.dispatch(resetAppConfig());
}
resizeLoginTextarea() {
// auto-size textarea
setTimeout(() => {
if (this.state.seedInputVisibility) {
document.querySelector('#wifkeysPassphraseTextarea').style.height = '1px';
document.querySelector('#wifkeysPassphraseTextarea').style.height = `${(15 + document.querySelector('#wifkeysPassphraseTextarea').scrollHeight)}px`;
}
}, 100);
}
updateSocketsData(data) {
if (data &&
data.msg &&
data.msg.type === 'ui') {
if (data.msg.status === 'progress' &&
data.msg.progress &&
data.msg.progress < 100) {
this.setState(Object.assign({}, this.state, {
updateProgressPatch: data.msg.progress,
}));
updateProgressBar.patch = data.msg.progress;
} else {
if (data.msg.status === 'progress' &&
data.msg.progress &&
data.msg.progress === 100) {
let _updateLog = [];
_updateLog.push(`${translate('INDEX.UI_UPDATE_DOWNLOADED')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateProgressBar.patch = 100;
}
if (data.msg.status === 'done') {
let _updateLog = [];
_updateLog.push(translate('INDEX.UI_UPDATED'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
updatePatch: null,
}));
updateProgressBar.patch = -1;
}
if (data.msg.status === 'error') {
let _updateLog = [];
_updateLog.push(translate('INDEX.UI_UPDATE_ERROR'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
updateProgressBar.patch = -1;
}
}
} else {
if (data &&
data.msg) {
let _updateLog = this.state.updateLog;
_updateLog.push(data.msg);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
}
}
}
_checkForUpdateUIPromise() {
let _updateLog = [];
_updateLog.push(translate('INDEX.CHECKING_UI_UPDATE'));
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
}));
checkForUpdateUIPromise()
.then((res) => {
let _updateLog = this.state.updateLog;
_updateLog.push(res.result === 'update' ? (`${translate('INDEX.NEW_UI_UPDATE')} ${res.version.remote}`) : translate('INDEX.YOU_HAVE_LATEST_UI'));
this.setState(Object.assign({}, this.state, {
updatePatch: res.result === 'update' ? true : false,
updateLog: _updateLog,
}));
});
}
_updateUIPromise() {
updateProgressBar.patch = 0;
let _updateLog = [];
_updateLog.push(`${translate('INDEX.DOWNLOADING_UI_UPDATE')}...`);
this.setState(Object.assign({}, this.state, {
updateLog: _updateLog,
openTab(elemId, tab) {
this.setState(Object.assign({}, this.state, {
activeTab: tab,
tabElId: elemId,
}));
updateUIPromise();
}
renderUpdateStatus() {
let items = [];
let patchProgressBar = null;
const _updateLogLength = this.state.updateLog.length;
for (let i = 0; i < _updateLogLength; i++) {
items.push(
<div key={ `settings-update-log-${i}` }>{ this.state.updateLog[i] }</div>
);
}
if (_updateLogLength) {
return (
<div style={{ minHeight: '200px' }}>
<hr />
<h5>{ translate('SETTINGS.PROGRESS') }:</h5>
<div className="padding-bottom-15">{ items }</div>
<div className={ updateProgressBar.patch > -1 ? 'progress progress-sm' : 'hide' }>
<div
className="progress-bar progress-bar-striped active progress-bar-indicating progress-bar-success font-size-80-percent"
style={{ width: `${updateProgressBar.patch}%` }}>
</div>
</div>
</div>
);
} else {
return null;
}
}
toggleSeedInputVisibility() {
updateInput(e) {
this.setState({
seedInputVisibility: !this.state.seedInputVisibility,
[e.target.name]: e.target.value,
});
}
execCliCmd() {
Store.dispatch(
shepherdCli(
'passthru',
this.state.cliCoin,
this.state.cliCmdString
)
);
}
openTab(elemId, tab) {
setTimeout(() => {
const _height = document.querySelector(`#${elemId} .panel-collapse .panel-body`).offsetHeight;
this.setState(Object.assign({}, this.state, {
activeTab: tab,
activeTabHeight: _height,
tabElId: elemId,
}));
// body size hack
if (!this.state.disableWalletSpecificUI) {
document.documentElement.style.height = '100%';
document.body.style.height = '100%';
setTimeout(() => {
document.documentElement.style.height = _height <= 200 ? '100%' : 'inherit';
document.body.style.height = _height <= 200 ? '100%' : 'inherit';
}, 100);
}
}, 100);
}
exportWifKeys() {
Store.dispatch(
encryptWallet(
this.state.wifkeysPassphrase,
settingsWifkeyState,
this.props.ActiveCoin.coin
)
);
}
importWifKey() {
Store.dispatch(importPrivKey(this.state.importWifKey));
}
readDebugLog() {
Store.dispatch(
getDebugLog(
this.state.debugTarget,
this.state.debugLinesCount
)
);
}
checkNodes() {
if (this.state.getPeersCoin) {
Store.dispatch(getPeersList(this.state.getPeersCoin.split('|')[0]));
}
}
addNode() {
if (this.state.addNodeCoin) {
Store.dispatch(
addPeerNode(
this.state.addNodeCoin.split('|')[0],
this.state.addPeerIP
)
);
}
}
renderPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _rawPeers = this.props.Settings.rawPeers;
const coin = _getPeersCoin.split('|')[0];
if (_rawPeers &&
_getPeersCoin &&
_rawPeers[coin]) {
return _rawPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
}
renderAppInfoTab() {
const releaseInfo = this.props.Settings.appInfo && this.props.Settings.appInfo.releaseInfo;
if (releaseInfo) {
return AppInfoTabRender.call(this);
return <AppInfoPanel />
}
return null;
}
renderAppUpdateTab() {
return AppUpdateTabRender.call(this);
return <AppUpdatePanel />
}
renderSNPeersList() {
if (this.state.getPeersCoin) {
const _getPeersCoin = this.state.getPeersCoin;
const _supernetPeers = this.props.Settings.supernetPeers;
const coin = _getPeersCoin.split('|')[0];
if (_supernetPeers &&
_getPeersCoin &&
_supernetPeers[coin]) {
return _supernetPeers[coin].map((ip) =>
<div key={ ip }>{ ip }</div>
);
} else {
return null;
}
} else {
return null;
}
renderWalletInfo() {
return <WalletInfoPanel />
}
updateInputSettings(e, parentKey, childKey) {
let _appSettings = this.state.appSettings;
let _appSettingsPrev = Object.assign({}, _appSettings);
if (!childKey && this.state.appConfigSchema[parentKey].type === 'boolean') {
_appSettings[parentKey] = typeof _appSettings[parentKey] !== undefined ? !_appSettings[parentKey] : !this.state.appSettings[parentKey];
} else if (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'boolean') {
_appSettings[parentKey][childKey] = typeof _appSettings[parentKey][childKey] !== undefined ? !_appSettings[parentKey][childKey] : !this.state.appSettings[parentKey][childKey];
} else if ((!childKey && this.state.appConfigSchema[parentKey].type === 'number') || (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'number')) {
if (e.target.value === '') {
_appSettings[e.target.name] = _appSettingsPrev[e.target.name];
} else {
_appSettings[e.target.name] = e.target.value.replace(/[^0-9]+/g, '');
}
} else {
_appSettings[e.target.name] = e.target.value;
}
this.setState({
appSettings: _appSettings,
});
}
_saveAppConfig() {
const _appSettings = this.state.appSettings;
let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings);
let isError = false;
let saveAfterPathCheck = false;
for (let key in _appSettings) {
if (key.indexOf('__') === -1) {
_appSettingsPristine[key] = this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
if (this.state.appConfigSchema[key].type === 'folder' &&
_appSettings[key] &&
_appSettings[key].length) {
const _testLocation = window.require('electron').remote.getCurrentWindow().testLocation;
saveAfterPathCheck = true;
_testLocation(_appSettings[key])
.then((res) => {
if (res === -1) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_INVALID'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else if (res === false) {
isError = true;
Store.dispatch(
triggerToaster(
translate('TOASTR.KOMODO_DATADIR_NOT_DIR'),
translate('INDEX.SETTINGS'),
'error'
)
);
} else {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
});
}
} else {
const _nestedKey = key.split('__');
_appSettingsPristine[_nestedKey[0]][_nestedKey[1]] = this.state.appConfigSchema[_nestedKey[0]][_nestedKey[1]].type === 'number' ? Number(_appSettings[key]) : _appSettings[key];
}
}
if (!saveAfterPathCheck) {
Store.dispatch(saveAppConfig(_appSettingsPristine));
}
}
renderConfigEditForm() {
let items = [];
const _appConfig = this.state.appSettings;
for (let key in _appConfig) {
if (typeof _appConfig[key] === 'object') {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15"></td>
</tr>
);
for (let _key in _appConfig[key]) {
items.push(
<tr key={ `app-settings-${key}-${_key}` }>
<td className="padding-15 padding-left-30">
{ this.state.appConfigSchema[key][_key].displayName ? this.state.appConfigSchema[key][_key].displayName : _key }
{ this.state.appConfigSchema[key][_key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key][_key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key][_key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
type="text"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ (this.state.appConfigSchema[key][_key].type === 'string' || this.state.appConfigSchema[key][_key].type === 'folder') &&
<input
type="text"
name={ `${key}__${_key}` }
value={ _appConfig[key][_key] }
className={ this.state.appConfigSchema[key][_key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key, _key) } />
}
{ this.state.appConfigSchema[key][_key].type === 'boolean' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}__${_key}` }
value={ _appConfig[key] }
checked={ _appConfig[key][_key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key, _key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
} else {
if (this.state.appConfigSchema[key].display) {
items.push(
<tr key={ `app-settings-${key}` }>
<td className="padding-15">
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key }
{ this.state.appConfigSchema[key].info &&
<i
className="icon fa-question-circle settings-help"
title={ this.state.appConfigSchema[key].info }></i>
}
</td>
<td className="padding-15">
{ this.state.appConfigSchema[key].type === 'number' &&
<input
type="number"
pattern="[0-9]*"
name={ `${key}` }
value={ _appConfig[key] }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ (this.state.appConfigSchema[key].type === 'string' || this.state.appConfigSchema[key].type === 'folder') &&
<input
type="text"
name={ `${key}` }
value={ _appConfig[key] }
className={ this.state.appConfigSchema[key].type === 'folder' ? 'full-width': '' }
onChange={ (event) => this.updateInputSettings(event, key) } />
}
{ this.state.appConfigSchema[key].type === 'boolean' &&
<span className="pointer toggle">
<label className="switch">
<input
type="checkbox"
name={ `${key}` }
value={ _appConfig[key] }
checked={ _appConfig[key] } />
<div
className="slider"
onClick={ (event) => this.updateInputSettings(event, key) }></div>
</label>
</span>
}
</td>
</tr>
);
}
}
}
return items;
renderAddNode() {
return <AddNodePanel />
}
updateInput(e) {
if (e.target.name === 'wifkeysPassphrase') {
// remove any empty chars from the start/end of the string
const newValue = e.target.value;
clearTimeout(this.state.trimPassphraseTimer);
const _trimPassphraseTimer = setTimeout(() => {
this.setState({
wifkeysPassphrase: newValue ? newValue.trim() : '', // hardcoded field name
});
}, 2000);
this.resizeLoginTextarea();
this.setState({
trimPassphraseTimer: _trimPassphraseTimer,
[e.target.name]: newValue,
});
} else {
this.setState({
[e.target.name]: e.target.value,
});
}
renderWalletBackup() {
return <WalletBackupPanel />
}
renderDebugLogData() {
if (this.props.Settings.debugLog) {
const _debugLogDataRows = this.props.Settings.debugLog.split('\n');
if (_debugLogDataRows &&
_debugLogDataRows.length) {
return _debugLogDataRows.map((_row) =>
<div
key={ `settings-debuglog-${Math.random(0, 9) * 10}` }
className="padding-bottom-5">{ _row }</div>
);
} else {
return (
<span>{ translate('INDEX.EMPTY_DEBUG_LOG') }</span>
);
}
} else {
return null;
}
renderFiatCurrency() {
return <FiatCurrencyPanel />
}
renderLB(_translationID) {
const _translationComponents = translate(_translationID).split('<br>');
return _translationComponents.map((_translation) =>
<span key={ `settings-label-${Math.random(0, 9) * 10}` }>
{ _translation }
<br />
</span>
);
renderExportKeys() {
return <ExportKeysPanel />
}
// TODO: rerender only if prop is changed
renderCliResponse() {
const _cliResponse = this.props.Settings.cli;
let _items = [];
if (_cliResponse) {
let _cliResponseParsed;
let responseType;
try {
_cliResponseParsed = JSON.parse(_cliResponse.result);
} catch(e) {
_cliResponseParsed = _cliResponse.result;
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object Array]') {
responseType = 'array';
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed[i], null, '\t') }</div>
);
}
}
if (Object.prototype.toString.call(_cliResponseParsed) === '[object]' ||
typeof _cliResponseParsed === 'object') {
responseType = 'object';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed, null, '\t') }</div>
);
}
if (Object.prototype.toString.call(_cliResponseParsed) === 'number' ||
typeof _cliResponseParsed === 'boolean' ||
_cliResponseParsed === 'wrong cli string format') {
responseType = 'number';
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed.toString() }</div>
);
}
if (responseType !== 'number' &&
responseType !== 'array' &&
responseType !== 'object' &&
_cliResponseParsed.indexOf('\n') > -1) {
_cliResponseParsed = _cliResponseParsed.split('\n');
for (let i = 0; i < _cliResponseParsed.length; i++) {
_items.push(
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed[i] }</div>
);
}
}
return (
<div>
<div>
<strong>{ translate('SETTINGS.CLI_RESPONSE') }:</strong>
</div>
{ _items }
</div>
);
} else {
return null;
}
renderImportKeys() {
return <ImportKeysPanel />
}
renderActiveCoinsList(mode) {
const modes = [
'native',
'basilisk',
'full'
];
const allCoins = this.props.Main.coins;
let items = [];
if (allCoins) {
if (mode === 'all') {
modes.map(function(mode) {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
});
} else {
allCoins[mode].map(function(coin) {
items.push(
<option
value={ coin }
key={ coin }>
{ coin } ({ mode })
</option>
);
});
}
return items;
} else {
return null;
}
renderDebugLog() {
return <DebugLogPanel />
}
renderExportWifKeysRaw() {
const _wifKeysResponse = this.props.Settings.wifkey;
if (_wifKeysResponse &&
this.state.exportWifKeysRaw) {
return (
<div className="padding-bottom-30 padding-top-30">
{ JSON.stringify(_wifKeysResponse, null, '\t') }
</div>
);
} else {
return null;
}
renderAppSettings() {
return <AppSettingsPanel />
}
renderWifKeys() {
let items = [];
if (this.props.Settings.wifkey) {
const _wifKeys = this.props.Settings.wifkey;
for (let i = 0; i < 2; i++) {
items.push(
<tr key={ `wif-export-table-header-${i}` }>
<td className="padding-bottom-10 padding-top-10">
<strong>{ i === 0 ? translate('SETTINGS.ADDRESS_LIST') : translate('SETTINGS.WIF_KEY_LIST') }</strong>
</td>
<td className="padding-bottom-10 padding-top-10"></td>
</tr>
);
for (let _key in _wifKeys) {
if ((i === 0 && _key.length === 3 && _key !== 'tag') ||
(i === 1 && _key.indexOf('wif') > -1)) {
items.push(
<tr key={ _key }>
<td>{ _key }</td>
<td className="padding-left-15">{ _wifKeys[_key] }</td>
</tr>
);
}
}
}
return items;
} else {
return null;
}
renderCliPanel() {
return <CliPanel />
}
exportWifKeysRaw() {
this.setState(Object.assign({}, this.state, {
exportWifKeysRaw: !this.state.exportWifKeysRaw,
}));
renderSupportPanel() {
return <SupportPanel />
}
render() {
@ -856,9 +151,9 @@ const mapStateToProps = (state) => {
ActiveCoin: {
coin: state.ActiveCoin.coin,
},
Settings: state.Settings,
Settings: state.Settings,
Dashboard: state.Dashboard,
};
};
export default connect(mapStateToProps)(Settings);

575
react/src/components/dashboard/settings/settings.render.js

@ -1,146 +1,5 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import AddCoinOptionsCrypto from '../../addcoin/addcoinOptionsCrypto';
import AddCoinOptionsAC from '../../addcoin/addcoinOptionsAC';
import AddCoinOptionsACFiat from '../../addcoin/addcoinOptionsACFiat';
export const AppUpdateTabRender = function() {
return (
<div
className="panel"
id="AppUpdate"
onClick={ () => this.openTab('AppUpdate', 10) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 10 ? '' : ' collapsed') }>
<i className="icon fa fa-cloud-download"></i> { translate('INDEX.UPDATE') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 10 ? ' in' : '') }
style={{ height: this.state.activeTab === 10 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-4 padding-top-15">
<h5>{ translate('INDEX.UI_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this._updateUIPromise }
disabled={ !this.state.updatePatch }>{ translate('INDEX.UPDATE_UI_NOW') }</button>
</div>
</div>
<div className="col-sm-4 padding-top-15 hide">
<h5>{ translate('INDEX.BINS_UPDATE') }</h5>
<div className="padding-top-15">
<button
type="button"
className="btn btn-info waves-effect waves-light"
onClick={ this._checkForUpdateUIPromise }>{ translate('INDEX.CHECK_FOR_UPDATE') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-20"
onClick={ this.checkNodes }>{ translate('INDEX.UPDATE_BINS_NOW') }</button>
</div>
</div>
<div className="col-sm-12 padding-top-15">
{ this.renderUpdateStatus() }
</div>
</div>
</div>
</div>
);
};
export const AppInfoTabRender = function() {
return (
<div
className="panel"
id="AppInfo"
onClick={ () => this.openTab('AppInfo', 8) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 8 ? '' : ' collapsed') }>
<i className="icon md-info"></i>{ translate('SETTINGS.APP_INFO') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 8 ? ' in' : '') }
style={{ height: this.state.activeTab === 8 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-12 padding-top-15">
<div className="row">
<h5>{ translate('SETTINGS.APP_RELEASE') }</h5>
<div>
{ translate('SETTINGS.NAME') }: { this.props.Settings.appInfo.releaseInfo.name }
</div>
<div>
{ translate('SETTINGS.VERSION') }: { `${this.props.Settings.appInfo.releaseInfo.version.replace('version=', '')}-beta` }
</div>
<div>
{ translate('SETTINGS.APP_SESSION') }: { this.props.Settings.appInfo.appSession }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.SYS_INFO') }</h5>
<div>
{ translate('SETTINGS.ARCH') }: { this.props.Settings.appInfo.sysInfo.arch }
</div>
<div>
{ translate('SETTINGS.OS_TYPE') }: { this.props.Settings.appInfo.sysInfo.os_type }
</div>
<div>
{ translate('SETTINGS.OS_PLATFORM') }: { this.props.Settings.appInfo.sysInfo.platform }
</div>
<div>
{ translate('SETTINGS.OS_RELEASE') }: { this.props.Settings.appInfo.sysInfo.os_release }
</div>
<div>
{ translate('SETTINGS.CPU') }: { this.props.Settings.appInfo.sysInfo.cpu }
</div>
<div>
{ translate('SETTINGS.CPU_CORES') }: { this.props.Settings.appInfo.sysInfo.cpu_cores }
</div>
<div>
{ translate('SETTINGS.MEM') }: { this.props.Settings.appInfo.sysInfo.totalmem_readable }
</div>
</div>
</div>
<div className="col-sm-12 padding-top-20">
<div className="row">
<h5>{ translate('SETTINGS.LOCATIONS') }</h5>
<div>
{ translate('SETTINGS.CACHE') }: { this.props.Settings.appInfo.dirs.cacheLocation }
</div>
<div>
{ translate('SETTINGS.CONFIG') }: { this.props.Settings.appInfo.dirs.configLocation }
</div>
<div>
Iguana { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.iguanaBin }
</div>
<div>
Iguana { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.iguanaDir }
</div>
<div>
Komodo { translate('SETTINGS.BIN') }: { this.props.Settings.appInfo.dirs.komododBin }
</div>
<div>
Komodo { translate('SETTINGS.DIR') }: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
<div>
Komodo wallet.dat: { this.props.Settings.appInfo.dirs.komodoDir }
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export const SettingsRender = function() {
return (
@ -156,6 +15,7 @@ export const SettingsRender = function() {
<div
className="panel-group"
id="SettingsAccordion">
{ !this.props.disableWalletSpecificUI &&
<div
id="WalletInfo"
@ -168,43 +28,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 0 ? ' in' : '') }
style={{ height: this.state.activeTab === 0 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<table className="table">
<thead>
<tr>
<th width="10%">{ translate('INDEX.KEY') }</th>
<th>{ translate('INDEX.VALUE') }</th>
</tr>
</thead>
<tbody>
<tr>
<td className="wallet-info-key">pubkey</td>
<td>{ this.props.Main.activeHandle.pubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">btcpubkey</td>
<td>{ this.props.Main.activeHandle.btcpubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">rmd160</td>
<td>{ this.props.Main.activeHandle.rmd160 }</td>
</tr>
<tr>
<td className="wallet-info-key">NXT</td>
<td>{ this.props.Main.activeHandle.NXT }</td>
</tr>
<tr>
<td className="wallet-info-key">notary</td>
<td>{ this.props.Main.activeHandle.notary }</td>
</tr>
<tr>
<td className="wallet-info-key">status</td>
<td>{ this.props.Main.activeHandle.status }</td>
</tr>
</tbody>
</table>
</div>
style={{ height: this.state.activeTab === 0 ? `auto` : '0' }}>
{ this.renderWalletInfo() }
</div>
</div>
}
@ -220,78 +45,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 1 ? ' in' : '') }
style={{ height: this.state.activeTab === 1 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="row">
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="getPeersCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.checkNodes }>{ translate('INDEX.CHECK_NODES') }</button>
</div>
<div className="col-sm-12">
<h5>
SuperNET Peers:
</h5>
<p>{ this.renderSNPeersList() }</p>
<h5>
Raw Peers:
</h5>
<p>{ this.renderPeersList() }</p>
</div>
</div>
<div className="col-sm-6">
<div className="col-sm-12">
<p>{ translate('INDEX.USE_THIS_SECTION_PEER') }</p>
</div>
<div className="col-sm-8 col-xs-12">
<div className="form-group">
<select
className="form-control form-material"
name="addNodeCoin"
onChange={ this.updateInput }>
<option>{ translate('INDEX.SELECT_COIN') }</option>
<AddCoinOptionsCrypto />
<AddCoinOptionsAC />
<AddCoinOptionsACFiat />
</select>
</div>
<div className="form-group">
<input
type="text"
className="form-control"
name="addPeerIP"
placeholder={ translate('SETTINGS.ADD_PEER_IP') }
onChange={ this.updateInput } />
</div>
</div>
<div className="col-sm-4 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.addNode }>{ translate('INDEX.ADD_NODE') }</button>
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 1 ? `auto` : '0' }}>
{ this.renderAddNode() }
</div>
</div>
}
@ -299,7 +54,7 @@ export const SettingsRender = function() {
<div
id="DumpWallet"
onClick={ () => this.openTab('DumpWallet', 2) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 2 ? '' : ' collapsed') }>
<i className="icon wb-briefcase"></i>{ translate('INDEX.WALLET_BACKUP') }
@ -307,8 +62,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 2 ? ' in' : '') }
style={{ height: this.state.activeTab === 2 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">Wallet Backup section to be updated soon.</div>
style={{ height: this.state.activeTab === 2 ? `auto` : '0' }}>
{ this.renderWalletBackup() }
</div>
</div>
}
@ -316,7 +71,7 @@ export const SettingsRender = function() {
<div
id="FiatCurrencySettings"
onClick={ () => this.openTab('FiatCurrencySettings', 3) }
className={ 'panel' + (this.state.nativeOnly ? ' hide' : '') }>
className={ 'hide panel' + (this.state.nativeOnly ? ' hide' : '') }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 3 ? '' : ' collapsed') }>
<i className="icon fa-money"></i>{ translate('INDEX.FIAT_CURRENCY') }
@ -324,8 +79,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 3 ? ' in' : '') }
style={{ height: this.state.activeTab === 3 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">Fiat currency settings section to be updated soon.</div>
style={{ height: this.state.activeTab === 3 ? `auto` : '0' }}>
{ this.renderFiatCurrency() }
</div>
</div>
}
@ -341,69 +96,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 4 ? ' in' : '') }
style={{ height: this.state.activeTab === 4 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div>
<div className="padding-bottom-20">{ this.renderLB('INDEX.ONLY_ACTIVE_WIF_KEYS') }</div>
<div className="padding-bottom-20">
<i>{ this.renderLB('SETTINGS.EXPORT_KEYS_NOTE') }</i>
</div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="password"
className={ !this.state.seedInputVisibility ? 'form-control' : 'hide' }
name="wifkeysPassphrase"
id="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase } />
<textarea
className={ this.state.seedInputVisibility ? 'form-control' : 'hide' }
id="wifkeysPassphraseTextarea"
name="wifkeysPassphrase"
onChange={ this.updateInput }
value={ this.state.wifkeysPassphrase }></textarea>
<i
className={ 'seed-toggle fa fa-eye' + (!this.state.seedInputVisibility ? '-slash' : '') }
onClick={ this.toggleSeedInputVisibility }></i>
<label
className="floating-label"
htmlFor="wifkeysPassphrase">{ translate('INDEX.PASSPHRASE') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeys }>{ translate('INDEX.GET_WIF_KEYS') }</button>
</div>
</form>
<div className="col-sm-12 padding-top-15">
<div className="row">
<table className="table">
{ this.renderWifKeys() }
</table>
<div className={ this.props.Settings.wifkey ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.exportWifKeysRaw }>{ this.state.exportWifKeysRaw ? 'Hide' : 'Show' } raw data</button>
</div>
<div className={ this.state.exportWifKeysRaw ? 'col-sm-12 col-xs-12 text-align-center' : 'hide' }>
{ this.renderExportWifKeysRaw() }
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 4 ? `auto` : '0' }}>
{ this.renderExportKeys() }
</div>
</div>
}
@ -419,41 +113,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 5 ? ' in' : '') }
style={{ height: this.state.activeTab === 5 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P1') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P2') }</div><br/>
<div>{ translate('INDEX.IMPORT_KEYS_DESC_P3') }</div><br/>
<div>
<strong>
<i>{ translate('INDEX.PLEASE_KEEP_KEYS_SAFE') }</i>
</strong>
</div>
<div className="col-sm-12"></div>
<form
className="wifkeys-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="importWifKey"
id="importWifkey"
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="importWifkey">{ translate('INDEX.INPUT_PRIV_KEY') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.importWifKey }>{ translate('INDEX.IMPORT_PRIV_KEY') }</button>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 5 ? `auto` : '0' }}>
{ this.renderImportKeys() }
</div>
</div>
}
@ -469,51 +130,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 6 ? ' in' : '') }
style={{ height: this.state.activeTab === 6 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p>
<div className="col-sm-12"></div>
<form
className="read-debug-log-import-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<input
type="text"
className="form-control"
name="debugLinesCount"
id="readDebugLogLines"
value={ this.state.debugLinesCount }
onChange={ this.updateInput } />
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.DEBUG_LOG_LINES') }</label>
</div>
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="debugTarget"
id="settingsDelectDebugLogOptions"
onChange={ this.updateInput }>
<option value="iguana" className={ this.state.nativeOnly ? 'hide' : '' }>Iguana</option>
<option value="komodo">Komodo</option>
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.TARGET') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">{ this.renderDebugLogData() }</div>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 6 ? `auto` : '0' }}>
{ this.renderDebugLog() }
</div>
</div>
@ -528,32 +146,26 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 7 ? ' in' : '') }
style={{ height: this.state.activeTab === 7 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>
<strong>{ translate('SETTINGS.CONFIG_RESTART_REQUIRED') }</strong>
</p>
<div className="col-sm-12 padding-top-15">
<table>
<tbody>
{ this.renderConfigEditForm() }
</tbody>
</table>
</div>
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
onClick={ this._saveAppConfig }>{ translate('SETTINGS.SAVE_APP_CONFIG') }</button>
<button
type="button"
className="btn btn-primary waves-effect waves-light margin-left-30"
onClick={ this._resetAppConfig }>Reset to default</button>
</div>
</div>
style={{ height: this.state.activeTab === 7 ? `auto` : '0' }}>
{ this.renderAppSettings() }
</div>
</div>
<div
className="panel"
id="AppInfo"
onClick={ () => this.openTab('AppInfo', 8) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 8 ? '' : ' collapsed') }>
<i className="icon md-info"></i>{ translate('SETTINGS.APP_INFO') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 8 ? ' in' : '') }
style={{ height: this.state.activeTab === 8 ? `auto` : '0' }}>
{ this.renderAppInfoTab() }
</div>
</div>
{ this.renderAppInfoTab() }
{ this.props.Main && this.props.Main.coins.native &&
<div
@ -567,59 +179,27 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 9 ? ' in' : '') }
style={{ height: this.state.activeTab === 9 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p>
<div className="col-sm-12"></div>
<form
className="execute-cli-cmd-form"
method="post"
action="javascript:"
autoComplete="off">
<div className="form-group form-material floating">
<select
className="form-control form-material"
name="cliCoin"
id="settingsCliOptions"
onChange={ this.updateInput }>
<option>{ translate('INDEX.CLI_NATIVE_COIN') }</option>
{ this.renderActiveCoinsList('native') }
</select>
<label
className="floating-label"
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.COIN') }</label>
</div>
<div className="form-group form-material floating">
<textarea
type="text"
className="form-control"
name="cliCmdString"
id="cliCmd"
value={ this.state.cliCmdString }
onChange={ this.updateInput }></textarea>
<label
className="floating-label"
htmlFor="readDebugLogLines">{ translate('INDEX.TYPE_CLI_CMD') }</label>
</div>
<div className="col-sm-12 col-xs-12 text-align-center">
<button
type="button"
className="btn btn-primary waves-effect waves-light"
disabled={ !this.state.cliCoin || !this.state.cliCmdString }
onClick={ () => this.execCliCmd() }>{ translate('INDEX.EXECUTE') }</button>
</div>
<div className="col-sm-12 col-xs-12 text-align-left">
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">
{ this.renderCliResponse() }
</div>
</div>
</form>
</div>
style={{ height: this.state.activeTab === 9 ? `auto` : '0' }}>
{ this.renderCliPanel() }
</div>
</div>
}
{ this.renderAppUpdateTab() }
<div
className="panel"
id="AppUpdate"
onClick={ () => this.openTab('AppUpdate', 10) }>
<div className="panel-heading">
<a className={ 'panel-title' + (this.state.activeTab === 10 ? '' : ' collapsed') }>
<i className="icon fa fa-cloud-download"></i> { translate('INDEX.UPDATE') }
</a>
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 10 ? ' in' : '') }
style={{ height: this.state.activeTab === 10 ? `auto` : '0' }}>
{ this.renderAppUpdateTab() }
</div>
</div>
<div
className="panel"
@ -632,55 +212,8 @@ export const SettingsRender = function() {
</div>
<div
className={ 'panel-collapse collapse' + (this.state.activeTab === 11 ? ' in' : '') }
style={{ height: this.state.activeTab === 11 ? `${this.state.activeTabHeight}px` : '0' }}>
<div className="panel-body">
<div className="col-sm-12 no-padding-left">
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://support.supernet.org') }>
<img
src="assets/images/cryptologo/supernet.png"
alt="Support tickets" />
<div className="support-box-title">{ translate('SETTINGS.SUPPORT_TICKETS') }</div>
<div className="support-box-link">support.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://sprnt.slack.com') }>
<img
src="assets/images/support/slack-icon.png"
alt="Slack" />
<div className="support-box-title">Slack</div>
<div className="support-box-link">sprnt.slack.com</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://slackinvite.supernet.org') }>
<img
src="assets/images/support/slack-invite-icon.png"
alt="Slack invite" />
<div className="support-box-title">{ translate('SETTINGS.GET_SLACK_INVITE') }</div>
<div className="support-box-link">slackinvite.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://github.com/SuperNETorg/Agama') }>
<img
src="assets/images/support/github-icon.png"
alt="Github" />
<div className="support-box-title">Github</div>
<div className="support-box-link">github.com/SuperNETorg/Agama</div>
</div>
</div>
</div>
</div>
style={{ height: this.state.activeTab === 11 ? `auto` : '0' }}>
{ this.renderSupportPanel() }
</div>
</div>
</div>

121
react/src/components/dashboard/settings/settings.scss

@ -0,0 +1,121 @@
.support-box {
padding: 15px 20px;
width: 220px;
display: inline-block;
cursor: pointer;
&-title {
font-weight: bold;
padding-top: 12px;
padding-bottom: 3px;
}
img {
height: 50px;
}
}
.support-box-wrapper {
display: inline-block;
margin-right: 50px;
&:last-child, {
margin-right: 0;
}
}
.support-box:hover {
.support-box-link {
color: #5683ad;
font-weight: 500;
}
}
.login-settings-modal {
#AppUpdate {
.col-sm-4 {
width: 100%;
}
}
.modal-dialog {
width: 80%;
}
.modal-body {
background: #f3f4f5;
border-radius: 4px;
}
.modal-footer {
margin-top: 15px;
}
.page-content {
padding-top: 0;
}
.support-box-wrapper {
.support-box {
margin: 0;
margin-bottom: 20px;
}
}
}
.settings-help {
font-size: 20px;
position: relative;
top: 2px;
left: 10px;
color: #5683ad;
}
#SettingsAccordion {
.toggle {
position: relative;
top: 4px;
.title {
position: relative;
top: -12px;
left: 12px;
}
}
table {
width: 100%;
td {
&:first-child {
width: 40%;
}
&:last-child {
width: 60%;
}
}
}
}
#SettingsAccordion {
.panel {
.panel-collapse {
transition: all .3s;
&.collapse {
height: 0;
}
}
}
}
#section-iguana-wallet-settings {
background: #f3f4f5;
.panel-title {
cursor: pointer;
cursor: hand;
&:before {
content: '\F273';
}
&.collapsed {
&:before {
content: '\F278';
}
}
}
}

82
react/src/components/dashboard/settings/settings.supportPanel.js

@ -0,0 +1,82 @@
import React from 'react';
import { translate } from '../../../translate/translate';
class SupportPanel extends React.Component {
constructor() {
super();
}
openExternalWindow(url) {
const remote = window.require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
const externalWindow = new BrowserWindow({
width: 1280,
height: 800,
title: `${translate('INDEX.LOADING')}...`,
icon: remote.getCurrentWindow().iguanaIcon,
});
externalWindow.loadURL(url);
externalWindow.webContents.on('did-finish-load', function() {
setTimeout(function() {
externalWindow.show();
}, 40);
});
}
render() {
return (
<div className="panel-body">
<div className="col-sm-12 no-padding-left">
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://support.supernet.org') }>
<img
src="assets/images/cryptologo/supernet.png"
alt="Support tickets" />
<div className="support-box-title">{ translate('SETTINGS.SUPPORT_TICKETS') }</div>
<div className="support-box-link">support.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://sprnt.slack.com') }>
<img
src="assets/images/support/slack-icon.png"
alt="Slack" />
<div className="support-box-title">Slack</div>
<div className="support-box-link">sprnt.slack.com</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('http://slackinvite.supernet.org') }>
<img
src="assets/images/support/slack-invite-icon.png"
alt="Slack invite" />
<div className="support-box-title">{ translate('SETTINGS.GET_SLACK_INVITE') }</div>
<div className="support-box-link">slackinvite.supernet.org</div>
</div>
</div>
<div className="support-box-wrapper">
<div
className="support-box"
onClick={ () => this.openExternalWindow('https://github.com/SuperNETorg/Agama') }>
<img
src="assets/images/support/github-icon.png"
alt="Github" />
<div className="support-box-title">Github</div>
<div className="support-box-link">github.com/SuperNETorg/Agama</div>
</div>
</div>
</div>
</div>
);
};
}
export default SupportPanel;

23
react/src/components/dashboard/settings/settings.walletBackupPanel.js

@ -0,0 +1,23 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class WalletBackupPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">Wallet Backup section to be updated soon.</div>
);
};
}
const mapStateToProps = (state) => {
return {
Settings: state.Settings,
};
};
export default connect(mapStateToProps)(WalletBackupPanel);

60
react/src/components/dashboard/settings/settings.walletInfoPanel.js

@ -0,0 +1,60 @@
import React from 'react';
import { translate } from '../../../translate/translate';
import { connect } from 'react-redux';
class WalletInfoPanel extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="panel-body">
<table className="table">
<thead>
<tr>
<th width="10%">{ translate('INDEX.KEY') }</th>
<th>{ translate('INDEX.VALUE') }</th>
</tr>
</thead>
<tbody>
<tr>
<td className="wallet-info-key">pubkey</td>
<td>{ this.props.Main.activeHandle.pubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">btcpubkey</td>
<td>{ this.props.Main.activeHandle.btcpubkey }</td>
</tr>
<tr>
<td className="wallet-info-key">rmd160</td>
<td>{ this.props.Main.activeHandle.rmd160 }</td>
</tr>
<tr>
<td className="wallet-info-key">NXT</td>
<td>{ this.props.Main.activeHandle.NXT }</td>
</tr>
<tr>
<td className="wallet-info-key">notary</td>
<td>{ this.props.Main.activeHandle.notary }</td>
</tr>
<tr>
<td className="wallet-info-key">status</td>
<td>{ this.props.Main.activeHandle.status }</td>
</tr>
</tbody>
</table>
</div>
);
};
}
const mapStateToProps = (state) => {
return {
Main: {
activeHandle: state.Main.activeHandle,
},
};
};
export default connect(mapStateToProps)(WalletInfoPanel);

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save