Browse Source
new version of the maintenance tool See merge request dojo/samourai-dojo!160use-env-var-docker
kenshin-samourai
4 years ago
41 changed files with 2622 additions and 10564 deletions
@ -0,0 +1,17 @@ |
|||
{ |
|||
// Use IntelliSense to learn about possible attributes. |
|||
// Hover to view descriptions of existing attributes. |
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
|||
"version": "0.2.0", |
|||
"configurations": [ |
|||
{ |
|||
"type": "node", |
|||
"request": "launch", |
|||
"name": "Launch Program", |
|||
"skipFiles": [ |
|||
"<node_internals>/**" |
|||
], |
|||
"program": "${workspaceFolder}/accounts/index.js" |
|||
} |
|||
] |
|||
} |
@ -1,587 +0,0 @@ |
|||
/*! |
|||
* Bootstrap v3.3.7 (http://getbootstrap.com) |
|||
* Copyright 2011-2016 Twitter, Inc. |
|||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) |
|||
*/ |
|||
.btn-default, |
|||
.btn-primary, |
|||
.btn-success, |
|||
.btn-info, |
|||
.btn-warning, |
|||
.btn-danger { |
|||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); |
|||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); |
|||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); |
|||
} |
|||
.btn-default:active, |
|||
.btn-primary:active, |
|||
.btn-success:active, |
|||
.btn-info:active, |
|||
.btn-warning:active, |
|||
.btn-danger:active, |
|||
.btn-default.active, |
|||
.btn-primary.active, |
|||
.btn-success.active, |
|||
.btn-info.active, |
|||
.btn-warning.active, |
|||
.btn-danger.active { |
|||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); |
|||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); |
|||
} |
|||
.btn-default.disabled, |
|||
.btn-primary.disabled, |
|||
.btn-success.disabled, |
|||
.btn-info.disabled, |
|||
.btn-warning.disabled, |
|||
.btn-danger.disabled, |
|||
.btn-default[disabled], |
|||
.btn-primary[disabled], |
|||
.btn-success[disabled], |
|||
.btn-info[disabled], |
|||
.btn-warning[disabled], |
|||
.btn-danger[disabled], |
|||
fieldset[disabled] .btn-default, |
|||
fieldset[disabled] .btn-primary, |
|||
fieldset[disabled] .btn-success, |
|||
fieldset[disabled] .btn-info, |
|||
fieldset[disabled] .btn-warning, |
|||
fieldset[disabled] .btn-danger { |
|||
-webkit-box-shadow: none; |
|||
box-shadow: none; |
|||
} |
|||
.btn-default .badge, |
|||
.btn-primary .badge, |
|||
.btn-success .badge, |
|||
.btn-info .badge, |
|||
.btn-warning .badge, |
|||
.btn-danger .badge { |
|||
text-shadow: none; |
|||
} |
|||
.btn:active, |
|||
.btn.active { |
|||
background-image: none; |
|||
} |
|||
.btn-default { |
|||
text-shadow: 0 1px 0 #fff; |
|||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); |
|||
background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); |
|||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #dbdbdb; |
|||
border-color: #ccc; |
|||
} |
|||
.btn-default:hover, |
|||
.btn-default:focus { |
|||
background-color: #e0e0e0; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-default:active, |
|||
.btn-default.active { |
|||
background-color: #e0e0e0; |
|||
border-color: #dbdbdb; |
|||
} |
|||
.btn-default.disabled, |
|||
.btn-default[disabled], |
|||
fieldset[disabled] .btn-default, |
|||
.btn-default.disabled:hover, |
|||
.btn-default[disabled]:hover, |
|||
fieldset[disabled] .btn-default:hover, |
|||
.btn-default.disabled:focus, |
|||
.btn-default[disabled]:focus, |
|||
fieldset[disabled] .btn-default:focus, |
|||
.btn-default.disabled.focus, |
|||
.btn-default[disabled].focus, |
|||
fieldset[disabled] .btn-default.focus, |
|||
.btn-default.disabled:active, |
|||
.btn-default[disabled]:active, |
|||
fieldset[disabled] .btn-default:active, |
|||
.btn-default.disabled.active, |
|||
.btn-default[disabled].active, |
|||
fieldset[disabled] .btn-default.active { |
|||
background-color: #e0e0e0; |
|||
background-image: none; |
|||
} |
|||
.btn-primary { |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #245580; |
|||
} |
|||
.btn-primary:hover, |
|||
.btn-primary:focus { |
|||
background-color: #265a88; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-primary:active, |
|||
.btn-primary.active { |
|||
background-color: #265a88; |
|||
border-color: #245580; |
|||
} |
|||
.btn-primary.disabled, |
|||
.btn-primary[disabled], |
|||
fieldset[disabled] .btn-primary, |
|||
.btn-primary.disabled:hover, |
|||
.btn-primary[disabled]:hover, |
|||
fieldset[disabled] .btn-primary:hover, |
|||
.btn-primary.disabled:focus, |
|||
.btn-primary[disabled]:focus, |
|||
fieldset[disabled] .btn-primary:focus, |
|||
.btn-primary.disabled.focus, |
|||
.btn-primary[disabled].focus, |
|||
fieldset[disabled] .btn-primary.focus, |
|||
.btn-primary.disabled:active, |
|||
.btn-primary[disabled]:active, |
|||
fieldset[disabled] .btn-primary:active, |
|||
.btn-primary.disabled.active, |
|||
.btn-primary[disabled].active, |
|||
fieldset[disabled] .btn-primary.active { |
|||
background-color: #265a88; |
|||
background-image: none; |
|||
} |
|||
.btn-success { |
|||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); |
|||
background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); |
|||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #3e8f3e; |
|||
} |
|||
.btn-success:hover, |
|||
.btn-success:focus { |
|||
background-color: #419641; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-success:active, |
|||
.btn-success.active { |
|||
background-color: #419641; |
|||
border-color: #3e8f3e; |
|||
} |
|||
.btn-success.disabled, |
|||
.btn-success[disabled], |
|||
fieldset[disabled] .btn-success, |
|||
.btn-success.disabled:hover, |
|||
.btn-success[disabled]:hover, |
|||
fieldset[disabled] .btn-success:hover, |
|||
.btn-success.disabled:focus, |
|||
.btn-success[disabled]:focus, |
|||
fieldset[disabled] .btn-success:focus, |
|||
.btn-success.disabled.focus, |
|||
.btn-success[disabled].focus, |
|||
fieldset[disabled] .btn-success.focus, |
|||
.btn-success.disabled:active, |
|||
.btn-success[disabled]:active, |
|||
fieldset[disabled] .btn-success:active, |
|||
.btn-success.disabled.active, |
|||
.btn-success[disabled].active, |
|||
fieldset[disabled] .btn-success.active { |
|||
background-color: #419641; |
|||
background-image: none; |
|||
} |
|||
.btn-info { |
|||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); |
|||
background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); |
|||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #28a4c9; |
|||
} |
|||
.btn-info:hover, |
|||
.btn-info:focus { |
|||
background-color: #2aabd2; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-info:active, |
|||
.btn-info.active { |
|||
background-color: #2aabd2; |
|||
border-color: #28a4c9; |
|||
} |
|||
.btn-info.disabled, |
|||
.btn-info[disabled], |
|||
fieldset[disabled] .btn-info, |
|||
.btn-info.disabled:hover, |
|||
.btn-info[disabled]:hover, |
|||
fieldset[disabled] .btn-info:hover, |
|||
.btn-info.disabled:focus, |
|||
.btn-info[disabled]:focus, |
|||
fieldset[disabled] .btn-info:focus, |
|||
.btn-info.disabled.focus, |
|||
.btn-info[disabled].focus, |
|||
fieldset[disabled] .btn-info.focus, |
|||
.btn-info.disabled:active, |
|||
.btn-info[disabled]:active, |
|||
fieldset[disabled] .btn-info:active, |
|||
.btn-info.disabled.active, |
|||
.btn-info[disabled].active, |
|||
fieldset[disabled] .btn-info.active { |
|||
background-color: #2aabd2; |
|||
background-image: none; |
|||
} |
|||
.btn-warning { |
|||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); |
|||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); |
|||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #e38d13; |
|||
} |
|||
.btn-warning:hover, |
|||
.btn-warning:focus { |
|||
background-color: #eb9316; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-warning:active, |
|||
.btn-warning.active { |
|||
background-color: #eb9316; |
|||
border-color: #e38d13; |
|||
} |
|||
.btn-warning.disabled, |
|||
.btn-warning[disabled], |
|||
fieldset[disabled] .btn-warning, |
|||
.btn-warning.disabled:hover, |
|||
.btn-warning[disabled]:hover, |
|||
fieldset[disabled] .btn-warning:hover, |
|||
.btn-warning.disabled:focus, |
|||
.btn-warning[disabled]:focus, |
|||
fieldset[disabled] .btn-warning:focus, |
|||
.btn-warning.disabled.focus, |
|||
.btn-warning[disabled].focus, |
|||
fieldset[disabled] .btn-warning.focus, |
|||
.btn-warning.disabled:active, |
|||
.btn-warning[disabled]:active, |
|||
fieldset[disabled] .btn-warning:active, |
|||
.btn-warning.disabled.active, |
|||
.btn-warning[disabled].active, |
|||
fieldset[disabled] .btn-warning.active { |
|||
background-color: #eb9316; |
|||
background-image: none; |
|||
} |
|||
.btn-danger { |
|||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); |
|||
background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); |
|||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-color: #b92c28; |
|||
} |
|||
.btn-danger:hover, |
|||
.btn-danger:focus { |
|||
background-color: #c12e2a; |
|||
background-position: 0 -15px; |
|||
} |
|||
.btn-danger:active, |
|||
.btn-danger.active { |
|||
background-color: #c12e2a; |
|||
border-color: #b92c28; |
|||
} |
|||
.btn-danger.disabled, |
|||
.btn-danger[disabled], |
|||
fieldset[disabled] .btn-danger, |
|||
.btn-danger.disabled:hover, |
|||
.btn-danger[disabled]:hover, |
|||
fieldset[disabled] .btn-danger:hover, |
|||
.btn-danger.disabled:focus, |
|||
.btn-danger[disabled]:focus, |
|||
fieldset[disabled] .btn-danger:focus, |
|||
.btn-danger.disabled.focus, |
|||
.btn-danger[disabled].focus, |
|||
fieldset[disabled] .btn-danger.focus, |
|||
.btn-danger.disabled:active, |
|||
.btn-danger[disabled]:active, |
|||
fieldset[disabled] .btn-danger:active, |
|||
.btn-danger.disabled.active, |
|||
.btn-danger[disabled].active, |
|||
fieldset[disabled] .btn-danger.active { |
|||
background-color: #c12e2a; |
|||
background-image: none; |
|||
} |
|||
.thumbnail, |
|||
.img-thumbnail { |
|||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); |
|||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075); |
|||
} |
|||
.dropdown-menu > li > a:hover, |
|||
.dropdown-menu > li > a:focus { |
|||
background-color: #e8e8e8; |
|||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); |
|||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); |
|||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.dropdown-menu > .active > a, |
|||
.dropdown-menu > .active > a:hover, |
|||
.dropdown-menu > .active > a:focus { |
|||
background-color: #2e6da4; |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.navbar-default { |
|||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); |
|||
background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); |
|||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-radius: 4px; |
|||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); |
|||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); |
|||
} |
|||
.navbar-default .navbar-nav > .open > a, |
|||
.navbar-default .navbar-nav > .active > a { |
|||
background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); |
|||
background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); |
|||
background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); |
|||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); |
|||
} |
|||
.navbar-brand, |
|||
.navbar-nav > li > a { |
|||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25); |
|||
} |
|||
.navbar-inverse { |
|||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); |
|||
background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); |
|||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); |
|||
background-repeat: repeat-x; |
|||
border-radius: 4px; |
|||
} |
|||
.navbar-inverse .navbar-nav > .open > a, |
|||
.navbar-inverse .navbar-nav > .active > a { |
|||
background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); |
|||
background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); |
|||
background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); |
|||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); |
|||
} |
|||
.navbar-inverse .navbar-brand, |
|||
.navbar-inverse .navbar-nav > li > a { |
|||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); |
|||
} |
|||
.navbar-static-top, |
|||
.navbar-fixed-top, |
|||
.navbar-fixed-bottom { |
|||
border-radius: 0; |
|||
} |
|||
@media (max-width: 767px) { |
|||
.navbar .navbar-nav .open .dropdown-menu > .active > a, |
|||
.navbar .navbar-nav .open .dropdown-menu > .active > a:hover, |
|||
.navbar .navbar-nav .open .dropdown-menu > .active > a:focus { |
|||
color: #fff; |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
} |
|||
.alert { |
|||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2); |
|||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); |
|||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); |
|||
} |
|||
.alert-success { |
|||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); |
|||
background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); |
|||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #b2dba1; |
|||
} |
|||
.alert-info { |
|||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); |
|||
background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); |
|||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #9acfea; |
|||
} |
|||
.alert-warning { |
|||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); |
|||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); |
|||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #f5e79e; |
|||
} |
|||
.alert-danger { |
|||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); |
|||
background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); |
|||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #dca7a7; |
|||
} |
|||
.progress { |
|||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); |
|||
background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); |
|||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar { |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar-success { |
|||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); |
|||
background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); |
|||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar-info { |
|||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); |
|||
background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); |
|||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar-warning { |
|||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); |
|||
background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); |
|||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar-danger { |
|||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); |
|||
background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); |
|||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.progress-bar-striped { |
|||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); |
|||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); |
|||
background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); |
|||
} |
|||
.list-group { |
|||
border-radius: 4px; |
|||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); |
|||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075); |
|||
} |
|||
.list-group-item.active, |
|||
.list-group-item.active:hover, |
|||
.list-group-item.active:focus { |
|||
text-shadow: 0 -1px 0 #286090; |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #2b669a; |
|||
} |
|||
.list-group-item.active .badge, |
|||
.list-group-item.active:hover .badge, |
|||
.list-group-item.active:focus .badge { |
|||
text-shadow: none; |
|||
} |
|||
.panel { |
|||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); |
|||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05); |
|||
} |
|||
.panel-default > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); |
|||
background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); |
|||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.panel-primary > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); |
|||
background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.panel-success > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); |
|||
background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); |
|||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.panel-info > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); |
|||
background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); |
|||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.panel-warning > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); |
|||
background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); |
|||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.panel-danger > .panel-heading { |
|||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); |
|||
background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); |
|||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
} |
|||
.well { |
|||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); |
|||
background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); |
|||
background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); |
|||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); |
|||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); |
|||
background-repeat: repeat-x; |
|||
border-color: #dcdcdc; |
|||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); |
|||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); |
|||
} |
|||
/*# sourceMappingURL=bootstrap-theme.css.map */ |
File diff suppressed because it is too large
@ -0,0 +1,147 @@ |
|||
<div id="addresses-tool"> |
|||
<h1>ADDRESSES TOOL</h1> |
|||
|
|||
<div class="box-context">Check if an address is tracked by your Dojo. Import and track a new address. Rescan the full history of an address.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<!-- ADDRESS SEARCH FORM --> |
|||
<div id="addresses-tool-search-form" class="fullwidth box"> |
|||
<div class="box-body"> |
|||
<span>Check if </span> |
|||
<input id="address" type="text" placeholder="address"> |
|||
<span> is tracked by your Dojo </span> |
|||
<button id="btn-address-search-go" class="btn btn-success" type="button">GO</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ADDRESS IMPORT --> |
|||
<div id="addresses-tool-import" class="fullwidth box"> |
|||
<div class="box-body"> |
|||
<div> |
|||
<span>This address isn't tracked by your Dojo.</span> |
|||
</div> |
|||
<div class="spacer20"></div> |
|||
<div> |
|||
<span>Do you want to import </span> |
|||
<span id="import-address"></span> |
|||
<span> and track its activity?</span> |
|||
<button id="btn-address-import-go" class="btn btn-success" type="button">IMPORT</button> |
|||
<button id="btn-address-import-cancel" class="btn btn-success" type="button">CANCEL</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- ADDRESS DETAILS --> |
|||
<div id="addresses-tool-details"> |
|||
<div id="addresses-tool-header" class="row box-main"> |
|||
<div class="fullwidth box"> |
|||
<div id="addr-value" class="box-body center"></div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="addresses-tool-actions" class="row box-main"> |
|||
<div class="center"> |
|||
<button id="btn-address-details-rescan" class="btn btn-success" type="button">RESCAN THIS ADDRESS</button> |
|||
<button id="btn-address-details-reset" class="btn btn-success" type="button">SEARCH ANOTHER ADDRESS</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="addresses-rescans-actions" class="row box-main"> |
|||
<div class="center"> |
|||
<span>Do you want to rescan this address?</span> |
|||
<button id="btn-address-rescan-go" class="btn btn-success" type="button">RESCAN</button> |
|||
<button id="btn-address-rescan-cancel" class="btn btn-success" type="button">CANCEL</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="addresses-tool-details-row1" class="row box-main"> |
|||
<!-- GENERAL INFO --> |
|||
<div id="box-general" class="fullwidth box"> |
|||
<div class="box-header">GENERAL INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Balance</td> |
|||
<td class="table-value" id="addr-balance"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of Txs</td> |
|||
<td class="table-value" id="addr-nb-txs"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of UTXOs</td> |
|||
<td class="table-value" id="addr-nb-utxos"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Segwit</td> |
|||
<td class="table-value" id="addr-segwit"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Address Type</td> |
|||
<td class="table-value" id="addr-type"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="addresses-tool-details-row2" class="row box-main"> |
|||
<!-- HD ADDRESS INFO --> |
|||
<div id="box-hd" class="fullwidth box"> |
|||
<div class="box-header">DERIVATION INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Derivation path</td> |
|||
<td class="table-value" id="addr-deriv-path"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label" colspan="2">Derived from</td> |
|||
</tr> |
|||
<tr> |
|||
<td id="addr-xpub" colspan="2"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="addresses-tool-details-row3" class="row box-main"> |
|||
<!-- TXS LIST --> |
|||
<div id="box-txs" class="halfwidth-left box"> |
|||
<div class="box-header">MOST RECENT TRANSACTIONS</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table id="addr-table-list-txs"> |
|||
<tbody> |
|||
<tr> |
|||
<td></td> |
|||
<td></td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<!-- UTXOS LIST --> |
|||
<div id="box-utxos" class="halfwidth-right box"> |
|||
<div class="box-header">UNSPENT TRANSACTION OUTPUTS</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table id="addr-table-list-utxos"> |
|||
<tbody> |
|||
<tr> |
|||
<td></td> |
|||
<td></td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script include-js="addresses-tools/addresses-tools.js"></script> |
@ -0,0 +1,228 @@ |
|||
const screenAddressesToolsScript = { |
|||
|
|||
explorerInfo: null, |
|||
currentAddress: null, |
|||
|
|||
initPage: function() { |
|||
this.getExplorerInfo() |
|||
// Sets the event handlers
|
|||
$('#btn-address-search-go').click(() => {this.searchAddress()}) |
|||
$('#btn-address-details-reset').click(() => {this.showSearchForm()}) |
|||
$('#btn-address-details-rescan').click(() => {this.showRescanForm()}) |
|||
$('#btn-address-rescan-go').click(() => {this.rescanAddress()}) |
|||
$('#btn-address-rescan-cancel').click(() => {this.hideRescanForm()}) |
|||
$('#btn-address-import-go').click(() => {this.importAddress()}) |
|||
$('#btn-address-import-cancel').click(() => {this.showSearchForm()}) |
|||
$('#addresses-tool').keyup(evt => { |
|||
if (evt.keyCode === 13) { |
|||
this.searchAddress() |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
this.hideRescanForm() |
|||
this.showSearchForm() |
|||
$("#address").focus() |
|||
}, |
|||
|
|||
getExplorerInfo: function() { |
|||
lib_api.getExplorerPairingInfo().then(explorerInfo => { |
|||
this.explorerInfo = explorerInfo |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
searchAddress: function() { |
|||
lib_msg.displayMessage('Search in progress...'); |
|||
const address = $('#address').val() |
|||
this.currentAddress = address |
|||
return this._searchAddress(address).then(() => { |
|||
lib_msg.cleanMessagesUi() |
|||
}) |
|||
}, |
|||
|
|||
_searchAddress: function(address) { |
|||
return lib_api.getAddressInfo(address).then(addressInfo => { |
|||
if (addressInfo && addressInfo['tracked']) { |
|||
this.setAddressDetails(addressInfo) |
|||
this.showAddressDetails() |
|||
const jsonData = {'active': address} |
|||
return lib_api.getWallet(jsonData).then(walletInfo => { |
|||
// Display the txs
|
|||
const txs = walletInfo['txs'] |
|||
for (let tx of txs) |
|||
this.setTxDetails(tx) |
|||
// Display the UTXOs
|
|||
const utxos = walletInfo['unspent_outputs'].sort((a,b) => { |
|||
return a['confirmations'] - b['confirmations'] |
|||
}) |
|||
$('#addr-nb-utxos').text(utxos.length) |
|||
for (let utxo of utxos) |
|||
this.setUtxoDetails(utxo) |
|||
}) |
|||
} else { |
|||
lib_msg.displayErrors('address not found') |
|||
this.showImportForm(false) |
|||
} |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
throw e |
|||
}) |
|||
}, |
|||
|
|||
importAddress: function() { |
|||
lib_msg.displayMessage('Processing address import...'); |
|||
const jsonData = {'active': this.currentAddress} |
|||
return lib_api.getWallet(jsonData) |
|||
.then(result => { |
|||
this._searchAddress(this.currentAddress).then(() => { |
|||
lib_msg.displayInfo('Import complete') |
|||
}) |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
rescanAddress: function() { |
|||
lib_msg.displayMessage('Processing address rescan...'); |
|||
return lib_api.getAddressRescan(this.currentAddress) |
|||
.then(result => { |
|||
this.hideRescanForm() |
|||
this._searchAddress(this.currentAddress).then(() => { |
|||
lib_msg.displayInfo('Rescan complete') |
|||
}) |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
setAddressDetails: function(addressInfo) { |
|||
$('tr.tx-row').remove() |
|||
$('tr.utxo-row').remove() |
|||
|
|||
$('#addr-value').text(this.currentAddress) |
|||
$('#addr-nb-txs').text(addressInfo['n_tx']) |
|||
$('#addr-nb-utxos').text('-') |
|||
|
|||
const balance = parseInt(addressInfo['balance']) / 100000000 |
|||
$('#addr-balance').text(`${balance} BTC`) |
|||
|
|||
const addrType = (addressInfo['type'] == 'hd') ? 'Derived from an XPUB' : 'Loose address' |
|||
$('#addr-type').text(addrType) |
|||
|
|||
if (addressInfo['segwit']) { |
|||
$('#addr-segwit').html('✓') |
|||
$('#addr-segwit').css('color', '#76d776') |
|||
} else { |
|||
$('#addr-segwit').text('-') |
|||
$('#addr-segwit').css('color', '#f77c7c') |
|||
} |
|||
|
|||
if (addressInfo['type'] == 'hd') { |
|||
$('#addr-xpub').text(addressInfo['xpub']) |
|||
$('#addr-deriv-path').text(addressInfo['path']) |
|||
$('#addresses-tool-details-row2').show() |
|||
} else { |
|||
$('#addresses-tool-details-row2').hide() |
|||
} |
|||
}, |
|||
|
|||
setTxDetails: function(tx) { |
|||
const txid = tx['hash'] |
|||
const txidDisplay = `${txid.substring(0,50)}...` |
|||
const amount = parseInt(tx['result']) / 100000000 |
|||
const amountLabel = amount < 0 ? amount : `+${amount}` |
|||
const amountStyle = amount < 0 ? 'amount-sent' : 'amount-received' |
|||
const date = lib_fmt.unixTsToLocaleString(tx['time']) |
|||
const txUrl = lib_cmn.getExplorerTxUrl(txid, this.explorerInfo) |
|||
|
|||
const newRow = `<tr class="tx-row"><td colspan="2"> </td></tr>
|
|||
<tr class="tx-row"> |
|||
<td class="table-label" colspan="2"> |
|||
<a href="${txUrl}" target="_blank">${txidDisplay}</a> |
|||
</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Amount</td> |
|||
<td class="table-value ${amountStyle}">${amountLabel} BTC</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Block height</td> |
|||
<td class="table-value">${tx['block_height']}</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Date</td> |
|||
<td class="table-value">${date}</td> |
|||
</tr>` |
|||
|
|||
$('#addr-table-list-txs tr:last').after(newRow) |
|||
}, |
|||
|
|||
setUtxoDetails: function(utxo) { |
|||
const txid = utxo['tx_hash'] |
|||
const txidVout = `${txid.substring(0,50)}...:${utxo['tx_output_n']}` |
|||
const amount = parseInt(utxo['value']) / 100000000 |
|||
const txUrl = lib_cmn.getExplorerTxUrl(txid, this.explorerInfo) |
|||
|
|||
const newRow = `<tr class="utxo-row"><td colspan="2"> </td></tr>
|
|||
<tr class="utxo-row"> |
|||
<td class="table-label" colspan="2"> |
|||
<a href="${txUrl}" target="_blank">${txidVout}</a> |
|||
</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Amount</td> |
|||
<td class="table-value">${amount} BTC</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Address</td> |
|||
<td class="table-value">${utxo['addr']}</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Confirmations</td> |
|||
<td class="table-value">${utxo['confirmations']}</td> |
|||
</tr>` |
|||
|
|||
$('#addr-table-list-utxos tr:last').after(newRow) |
|||
}, |
|||
|
|||
showSearchForm: function() { |
|||
$('#addresses-tool-details').hide() |
|||
$('#addresses-tool-import').hide() |
|||
$('#address').val('') |
|||
$('#addresses-tool-search-form').show() |
|||
lib_msg.cleanMessagesUi() |
|||
}, |
|||
|
|||
showImportForm: function() { |
|||
$('#addresses-tool-search-form').hide() |
|||
$('#addresses-tool-details').hide() |
|||
$('#import-address').text(this.currentAddress) |
|||
$('#addresses-tool-import').show() |
|||
}, |
|||
|
|||
showAddressDetails: function() { |
|||
$('#addresses-tool-search-form').hide() |
|||
$('#addresses-tool-import').hide() |
|||
$('#addresses-tool-details').show() |
|||
}, |
|||
|
|||
showRescanForm: function() { |
|||
$('#addresses-tool-actions').hide() |
|||
$('#addresses-rescans-actions').show() |
|||
lib_msg.cleanMessagesUi() |
|||
}, |
|||
|
|||
hideRescanForm: function() { |
|||
$('#addresses-rescans-actions').hide() |
|||
$('#addresses-tool-actions').show() |
|||
}, |
|||
} |
|||
|
|||
screenScripts.set('#screen-addresses-tools', screenAddressesToolsScript) |
@ -0,0 +1,22 @@ |
|||
<div id="blocks-rescan"> |
|||
<h1>BLOCKS RESCAN</h1> |
|||
|
|||
<div class="box-context">Force the Tracker to rescan a range of blocks.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<div id="blocks-rescan-form" class="box fullwidth"> |
|||
<div class="box-body"> |
|||
<span>Rescan blocks between</span> |
|||
<input id="rescan-from-height" type="text" placeholder="height"> |
|||
<span> and </span> |
|||
<input id="rescan-to-height" type="text" placeholder="height"> |
|||
<button id="btn-rescan-go" |
|||
class="btn btn-success" |
|||
type="button">GO</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<script include-js="blocks-rescan/blocks-rescan.js"></script> |
@ -0,0 +1,45 @@ |
|||
const screenBlocksRescanScript = { |
|||
|
|||
initPage: function() { |
|||
// Sets the event handlers
|
|||
$('#btn-rescan-go').click(() => { |
|||
this.processRescan() |
|||
}) |
|||
$('#blocks-rescan').keyup(evt => { |
|||
if (evt.keyCode === 13) { |
|||
this.processRescan() |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
$("#rescan-from-height").focus() |
|||
}, |
|||
|
|||
processRescan: function() { |
|||
lib_msg.displayMessage('Processing...'); |
|||
|
|||
let fromHeight = $("#rescan-from-height").val() |
|||
let toHeight = $("#rescan-to-height").val() |
|||
fromHeight = parseInt(fromHeight) |
|||
toHeight = (toHeight) ? parseInt(toHeight) : fromHeight; |
|||
|
|||
lib_api.getBlocksRescan(fromHeight, toHeight).then(result => { |
|||
if (!result) |
|||
return |
|||
const fromHeightRes = result['fromHeight'] |
|||
const toHeightRes = result['toHeight'] |
|||
const msg = `successfully rescanned blocks between height ${fromHeightRes} and height ${toHeightRes}` |
|||
lib_msg.displayInfo(msg) |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}).then(() => { |
|||
$('#rescan-from-height').val('') |
|||
$('#rescan-to-height').val('') |
|||
}) |
|||
}, |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-blocks-rescan', screenBlocksRescanScript) |
@ -0,0 +1,152 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<title>DOJO // MAINTENANCE TOOL</title> |
|||
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"> |
|||
<link rel="stylesheet" type="text/css" href="../css/bootstrap-theme.min.css"> |
|||
<link rel="stylesheet" type="text/css" href="../css/style.css"> |
|||
<script src="../lib/jquery-3.5.1.min.js"></script> |
|||
<script src="../lib/jquery.qrcode.min.js"></script> |
|||
<script src="../conf/index.js"></script> |
|||
<script src="../lib/common-script.js"></script> |
|||
<script src="../lib/api-wrapper.js"></script> |
|||
<script src="../lib/auth-utils.js"></script> |
|||
<script src="../lib/format-utils.js"></script> |
|||
<script src="../lib/messages.js"></script> |
|||
<script src="index.js"></script> |
|||
</head> |
|||
|
|||
<body class="dmt"> |
|||
<div id="top-container" class="container" style="display: none"> |
|||
<!-- HEADER --> |
|||
<div id="header" class="row"> |
|||
<div class="col-xs-9"> |
|||
<h1 class="title"><span>DOJO // MAINTENANCE TOOL</span> <span id="dojo-version" class="beta">beta</span></h1> |
|||
</div> |
|||
<div class="col-xs-3 login-box"> |
|||
<a id="btn-logout" style="display: inline;" href="#" title="DISCONNECT"> |
|||
<img src="../icons/ic_power_settings_new_white_24dp_1x.png" class="mini-icon"/> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="spacer30"></div> |
|||
|
|||
<!-- BODY --> |
|||
<div id="body" class="row"> |
|||
<!-- MENU --> |
|||
<div id="menu" class="col-xs-2"> |
|||
<div class="title"> |
|||
<h1>MONITORING</h1> |
|||
</div> |
|||
<ul id="tab-menu_list" class="nav nav-pills nav-stacked"> |
|||
<li id="link-welcome" style="display: none;"> |
|||
<a href="#">WELCOME</a> |
|||
</li> |
|||
<li id="link-status"> |
|||
<a href="#">DOJO STATUS</a> |
|||
</li> |
|||
<li id="link-pushtx"> |
|||
<a href="#">PUSHTX STATUS</a> |
|||
</li> |
|||
</ul> |
|||
<div class="spacer20"></div> |
|||
<div class="title"> |
|||
<h1>TOOLS</h1> |
|||
</div> |
|||
<ul id="tab-menu_list2" class="nav nav-pills nav-stacked"> |
|||
<li id="link-pairing"> |
|||
<a href="#">PAIRING</a> |
|||
</li> |
|||
<li id="link-xpubs-tools"> |
|||
<a href="#">XPUBS TOOL</a> |
|||
</li> |
|||
<li id="link-addresses-tools"> |
|||
<a href="#">ADDRESSES TOOL</a> |
|||
</li> |
|||
<li id="link-txs-tools"> |
|||
<a href="#">TRANSACTIONS TOOL</a> |
|||
</li> |
|||
<li id="link-blocks-rescan"> |
|||
<a href="#">BLOCKS RESCAN</a> |
|||
</li> |
|||
</ul> |
|||
<div class="spacer20"></div> |
|||
<div class="title"> |
|||
<h1>HELP</h1> |
|||
</div> |
|||
<ul id="tab-menu_list3" class="nav nav-pills nav-stacked"> |
|||
<li id="link-help-dmt"> |
|||
<a href="#">HELP DMT</a> |
|||
</li> |
|||
<li id="link-dojo-telegram"> |
|||
<a href="https://t.me/samourai_dojo" target="_blank">DOJO TELEGRAM CHAT</a> |
|||
</li> |
|||
<li id="link-wp-telegram"> |
|||
<a href="https://t.me/whirlpool_trollbox" target="_blank">WHIRLPOOL TELEGRAM CHAT</a> |
|||
</li> |
|||
<li id="link-sw-support"> |
|||
<a href="https://t.me/SamouraiWallet" target="_blank">SAMOURAI TELEGRAM CHAT</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
<div class="col-xs-1"></div> |
|||
<!-- MAIN AREA --> |
|||
<div id="main" class="col-xs-9"> |
|||
<!-- WELCOME --> |
|||
<div id="screen-welcome" |
|||
include-html="welcome/welcome.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- STATUS --> |
|||
<div id="screen-status" |
|||
include-html="status/status.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- PUSH TX --> |
|||
<div id="screen-pushtx" |
|||
include-html="pushtx/pushtx.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- PAIRING --> |
|||
<div id="screen-pairing" |
|||
include-html="pairing/pairing.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- XPUBS TOOLS --> |
|||
<div id="screen-xpubs-tools" |
|||
include-html="xpubs-tools/xpubs-tools.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- ADDRESSES TOOLS --> |
|||
<div id="screen-addresses-tools" |
|||
include-html="addresses-tools/addresses-tools.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- TRANSACTIONS TOOLS --> |
|||
<div id="screen-txs-tools" |
|||
include-html="txs-tools/txs-tools.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- BLOCKS RESCAN --> |
|||
<div id="screen-blocks-rescan" |
|||
include-html="blocks-rescan/blocks-rescan.html" |
|||
style="display: none"> |
|||
</div> |
|||
<!-- HELP DMT --> |
|||
<div id="screen-help-dmt" |
|||
include-html="welcome/welcome.html" |
|||
style="display: none"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- MSG BOX --> |
|||
<div id="box-msg" |
|||
include-html="msg-box/msg-box.html"> |
|||
</div> |
|||
</body> |
|||
|
|||
</html> |
@ -0,0 +1,116 @@ |
|||
/** |
|||
* Global obkjects |
|||
*/ |
|||
|
|||
// Ordered list of screens
|
|||
const screens = [ |
|||
'#screen-welcome', |
|||
'#screen-status', |
|||
'#screen-pushtx', |
|||
'#screen-pairing', |
|||
'#screen-xpubs-tools', |
|||
'#screen-addresses-tools', |
|||
'#screen-txs-tools', |
|||
'#screen-blocks-rescan', |
|||
'#screen-help-dmt' |
|||
] |
|||
|
|||
// Ordered list of menu items
|
|||
const tabs = [ |
|||
'#link-welcome', |
|||
'#link-status', |
|||
'#link-pushtx', |
|||
'#link-pairing', |
|||
'#link-xpubs-tools', |
|||
'#link-addresses-tools', |
|||
'#link-txs-tools', |
|||
'#link-blocks-rescan', |
|||
'#link-help-dmt' |
|||
] |
|||
|
|||
// Mapping of scripts associaed to screens
|
|||
const screenScripts = new Map() |
|||
|
|||
|
|||
/** |
|||
* UI initialization |
|||
*/ |
|||
function initTabs() { |
|||
// Activates the current tab
|
|||
let currentTab = sessionStorage.getItem('activeTab') |
|||
if (!currentTab) |
|||
currentTab = '#link-status' |
|||
$(currentTab).addClass('active') |
|||
|
|||
// Sets event handlers
|
|||
for (let tab of tabs) { |
|||
$(tab).click(function() { |
|||
$(sessionStorage.getItem('activeTab')).removeClass('active') |
|||
sessionStorage.setItem('activeTab', tab) |
|||
$(tab).addClass('active') |
|||
preparePage() |
|||
}) |
|||
} |
|||
} |
|||
|
|||
function initPages() { |
|||
// Dynamic loading of screens and scripts
|
|||
lib_cmn.includeHTML(_initPages) |
|||
// Dojo version
|
|||
let lblVersion = sessionStorage.getItem('lblVersion') |
|||
if (lblVersion == null) { |
|||
lib_api.getPairingInfo().then(apiInfo => { |
|||
lblVersion = 'v' + apiInfo['pairing']['version'] + ' beta' |
|||
sessionStorage.setItem('lblVersion', lblVersion) |
|||
$('#dojo-version').text(lblVersion) |
|||
}) |
|||
} else { |
|||
$('#dojo-version').text(lblVersion) |
|||
} |
|||
} |
|||
|
|||
function _initPages() { |
|||
for (let screen of screens) { |
|||
const screenScript = screenScripts.get(screen) |
|||
if (screenScript) |
|||
screenScript.initPage() |
|||
} |
|||
preparePage() |
|||
$('#top-container').show() |
|||
} |
|||
|
|||
function preparePage() { |
|||
lib_msg.cleanMessagesUi() |
|||
const activeTab = sessionStorage.getItem('activeTab') |
|||
for (let idxTab in tabs) { |
|||
const screen = screens[idxTab] |
|||
if (tabs[idxTab] == activeTab) { |
|||
$(screen).show() |
|||
if (screenScripts.has(screen)) |
|||
screenScripts.get(screen).preparePage() |
|||
} else { |
|||
$(screen).hide() |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* Processing on loading completed |
|||
*/ |
|||
$(document).ready(function() { |
|||
// Refresh the access token
|
|||
lib_auth.refreshAccessToken() |
|||
setInterval(() => { |
|||
lib_auth.refreshAccessToken() |
|||
}, 300000) |
|||
|
|||
// Inits menu and pages
|
|||
initTabs() |
|||
initPages() |
|||
|
|||
// Set event handlers
|
|||
$('#btn-logout').click(function() { |
|||
lib_auth.logout() |
|||
}) |
|||
}) |
@ -0,0 +1,7 @@ |
|||
<div class="row box-msg"> |
|||
<div class="col-xs-12"> |
|||
<div id="msg" class="msg"></div> |
|||
<div id="errors" class="msg-error"></div> |
|||
<div id="info" class="msg-info"></div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,33 @@ |
|||
<div id="pairing"> |
|||
<h1>PAIRING</h1> |
|||
|
|||
<div class="box-context">Pair your wallet to your Dojo and to your Block Explorer with a simple QRCode.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<div id="dojo-pairing" class="halfwidth-left box"> |
|||
<div class="box-header">DOJO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body" id="qr-container"> |
|||
<div class="center">Scan this QRCode with your wallet</div> |
|||
<div class="spacer10"></div> |
|||
<div id="qr-pairing"></div> |
|||
<div class="spacer10"></div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="explorer-pairing" class="halfwidth-right box"> |
|||
<div class="box-header">BLOCK EXPLORER</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body" id="qr-explorer-container"> |
|||
<div class="center">Scan this QRCode with your wallet</div> |
|||
<div class="spacer10"></div> |
|||
<div id="qr-explorer-pairing"></div> |
|||
<div class="spacer10"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
|
|||
<script include-js="pairing/pairing.js"></script> |
@ -0,0 +1,65 @@ |
|||
const screenPairingScript = { |
|||
|
|||
initPage: function() {}, |
|||
|
|||
preparePage: function() { |
|||
this.displayQRPairing() |
|||
}, |
|||
|
|||
loadPairingPayloads: function() { |
|||
let result = { |
|||
'api': null, |
|||
'explorer': null |
|||
} |
|||
|
|||
lib_msg.displayMessage('Loading pairing payloads...'); |
|||
|
|||
return lib_api.getPairingInfo().then(apiInfo => { |
|||
if (apiInfo) { |
|||
apiInfo['pairing']['url'] = window.location.protocol + '//' + window.location.host + conf['api']['baseUri'] |
|||
result['api'] = apiInfo |
|||
} |
|||
}).then(() => { |
|||
return lib_api.getExplorerPairingInfo() |
|||
}).then(explorerInfo => { |
|||
if (explorerInfo) |
|||
result['explorer'] = explorerInfo |
|||
lib_msg.cleanMessagesUi() |
|||
return result |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
return result |
|||
}) |
|||
}, |
|||
|
|||
displayQRPairing: function() { |
|||
this.loadPairingPayloads().then( |
|||
function (result) { |
|||
if (result) { |
|||
if (result['api']) { |
|||
const textJson = JSON.stringify(result['api'], null, 4) |
|||
$("#qr-pairing").html('') // clear qrcode first
|
|||
$('#qr-pairing').qrcode({width: 256, height: 256, text: textJson}) |
|||
} |
|||
if (result['explorer'] && result['explorer']['pairing']['url']) { |
|||
const textJson = JSON.stringify(result['explorer'], null, 4) |
|||
$("#qr-explorer-pairing").html('') // clear qrcode first
|
|||
$('#qr-explorer-pairing').qrcode({width: 256, height: 256, text: textJson}) |
|||
} else { |
|||
$("#qr-label").removeClass('halfwidth') |
|||
$("#qr-label").addClass('fullwidth') |
|||
$("#qr-container").removeClass('halfwidth') |
|||
$("#qr-container").addClass('fullwidth') |
|||
$("#qr-explorer-label").hide() |
|||
$("#qr-explorer-container").hide() |
|||
} |
|||
} |
|||
}, |
|||
function (jqxhr) {} |
|||
); |
|||
} |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-pairing', screenPairingScript) |
@ -0,0 +1,44 @@ |
|||
<div id="pushtx-status"> |
|||
<h1>PUSHTX STATUS</h1> |
|||
|
|||
<div class="box-context">Monitor the transactions pushed through your Dojo.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<div id="txs-pushed" class="box fullwidth"> |
|||
<div class="box-header">TRANSACTIONS PUSHED</div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Uptime</td> |
|||
<td class="table-value" id="pushed-uptime"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of Transactions</td> |
|||
<td class="table-value" id="pushed-count"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Total Amount</td> |
|||
<td class="table-value" id="pushed-amount"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row box-main"> |
|||
<div id="txs-scheduled" class="box fullwidth"> |
|||
<div class="box-header">TRANSACTIONS SCHEDULED</div> |
|||
<div class="box-body"> |
|||
<table id="table-scheduled-txs"> |
|||
<thead> |
|||
<td colspan="2"></td> |
|||
</thead> |
|||
<tbody></tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
<script include-js="pushtx/pushtx.js"></script> |
@ -0,0 +1,90 @@ |
|||
const pushtxScript = { |
|||
|
|||
processedSchedTxs: new Set(), |
|||
|
|||
initPage: function() { |
|||
// Refresh PushTx status
|
|||
setInterval(() => {this.refreshPushTxStatus()}, 60000) |
|||
// Refresh ScheduledTxs list
|
|||
setInterval(() => {this.refreshScheduledTxsList()}, 60000) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
this.refreshPushTxStatus() |
|||
this.refreshScheduledTxsList() |
|||
}, |
|||
|
|||
refreshPushTxStatus: function() { |
|||
lib_msg.displayMessage('Loading PushTx status info...'); |
|||
lib_api.getPushtxStatus().then(pushTxStatus => { |
|||
if (pushTxStatus) { |
|||
const data = pushTxStatus['data'] |
|||
const uptime = lib_cmn.timePeriod(data['uptime']) |
|||
$('#pushed-uptime').text(uptime) |
|||
$('#pushed-count').text(data['push']['count']) |
|||
$('#pushed-amount').text(data['push']['amount']) |
|||
lib_msg.cleanMessagesUi() |
|||
} |
|||
}).catch(e => { |
|||
$('#pushed-uptime').text('-') |
|||
$('#pushed-count').text('-') |
|||
$('#pushed-amount').text('-') |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
refreshScheduledTxsList: function() { |
|||
lib_msg.displayMessage('Loading PushTx orchestrator status info...'); |
|||
lib_api.getOrchestratorStatus().then(orchestrStatus => { |
|||
if(orchestrStatus) { |
|||
const data = orchestrStatus['data'] |
|||
for (let tx of data['txs']) { |
|||
if (!this.processedSchedTxs.has(tx['schTxid'])) { |
|||
this.displayScheduledTx(tx) |
|||
this.processedSchedTxs.add(tx['schTxid']) |
|||
} |
|||
} |
|||
lib_msg.cleanMessagesUi() |
|||
} |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
displayScheduledTx: function(tx) { |
|||
const newRow = `<tr><td colspan="2"> </td></tr>
|
|||
<tr class="table-value"> |
|||
<td class="table-label">TXID</td> |
|||
<td class="table-value" id="scheduled-txid">${tx['schTxid']}</td> |
|||
</tr> |
|||
<tr class="table-value"> |
|||
<td class="table-label">Schedule Id</td> |
|||
<td class="table-value" id="scheduled-txid">${tx['schID']}</td> |
|||
</tr> |
|||
<tr class="table-value"> |
|||
<td class="table-label">Scheduled for block</td> |
|||
<td class="table-value" id="scheduled-trigger">${tx['schTrigger']}</td> |
|||
</tr> |
|||
<tr class="table-value"> |
|||
<td class="table-label">Created on</td> |
|||
<td class="table-value" id="scheduled-created">${lib_fmt.unixTsToLocaleString(tx['schCreated'])}</td> |
|||
</tr> |
|||
<tr class="table-value"> |
|||
<td class="table-label">Parent TXID</td> |
|||
<td class="table-value" id="scheduled-parent-txid">${tx['schParentTxid']}</td> |
|||
</tr> |
|||
<tr class="table-value"> |
|||
<td class="table-label">Raw Transaction</td> |
|||
<td class="table-value" id="scheduled-tx"> |
|||
<pre class="raw-tx">${tx['schRaw']}</pre> |
|||
</td> |
|||
</tr>` |
|||
|
|||
$('#table-scheduled-txs tr:last').after(newRow) |
|||
}, |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-pushtx', pushtxScript) |
@ -0,0 +1,92 @@ |
|||
<div id="status"> |
|||
<h1>DOJO STATUS</h1> |
|||
|
|||
<div class="box-context">Monitor the health of some core components of your Dojo.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<div id="left-column" class="two-columns-left"> |
|||
<div id="bitcoind-status" class="fullwidth box"> |
|||
<div class="box-header">FULL NODE</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Status</td> |
|||
<td class="table-value" id="node-status-ind"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Uptime</td> |
|||
<td class="table-value" id="node-uptime"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Latest block</td> |
|||
<td class="table-value" id="node-chaintip"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Bitcoind version</td> |
|||
<td class="table-value" id="node-version"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Network</td> |
|||
<td class="table-value" id="node-network"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Connected nodes</td> |
|||
<td class="table-value" id="node-conn"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Network relay fee</td> |
|||
<td class="table-value" id="node-relay-fee"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div id="right-column" class="two-columns-right"> |
|||
<div id="tracker-status" class="fullwidth box"> |
|||
<div class="box-header">TRACKER</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Status</td> |
|||
<td class="table-value" id="tracker-status-ind"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Uptime</td> |
|||
<td class="table-value" id="tracker-uptime"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Latest block</td> |
|||
<td class="table-value" id="tracker-chaintip"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="web-status" class="fullwidth box"> |
|||
<div class="box-header">WEB</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Tor status</td> |
|||
<td class="table-value" id="tor-status-ind">✓</td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Nginx status</td> |
|||
<td class="table-value" id="nginx-status-ind">✓</td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Node.js status</td> |
|||
<td class="table-value" id="nodejs-status-ind">✓</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<script include-js="status/status.js"></script> |
@ -0,0 +1,68 @@ |
|||
const statusScript = { |
|||
|
|||
initPage: function() { |
|||
// Refresh API status
|
|||
setInterval(() => {this.refreshApiStatus()}, 60000) |
|||
// Refresh PushTx status
|
|||
setInterval(() => {this.refreshPushTxStatus()}, 60000) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
this.refreshApiStatus() |
|||
this.refreshPushTxStatus() |
|||
}, |
|||
|
|||
refreshApiStatus: function() { |
|||
lib_msg.displayMessage('Loading API status info...'); |
|||
return lib_api.getApiStatus().then(apiStatus => { |
|||
if (apiStatus) { |
|||
$('#tracker-status-ind').html('✓') |
|||
$('#tracker-status-ind').css('color', '#76d776') |
|||
$('#tracker-uptime').text(apiStatus['uptime']) |
|||
$('#tracker-chaintip').text(apiStatus['blocks']) |
|||
lib_msg.cleanMessagesUi() |
|||
} |
|||
}).catch(e => { |
|||
$('#tracker-status-ind').text('X') |
|||
$('#tracker-status-ind').css('color', '#f77c7c') |
|||
$('#tracker-uptime').text('-') |
|||
$('#tracker-chaintip').text('-') |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
refreshPushTxStatus: function() { |
|||
lib_msg.displayMessage('Loading Tracker status info...'); |
|||
lib_api.getPushtxStatus().then(pushTxStatus => { |
|||
if (pushTxStatus) { |
|||
const data = pushTxStatus['data'] |
|||
$('#node-status-ind').html('✓') |
|||
$('#node-status-ind').css('color', '#76d776') |
|||
const uptime = lib_cmn.timePeriod(data['uptime']) |
|||
$('#node-uptime').text(uptime) |
|||
$('#node-chaintip').text(data['bitcoind']['blocks']) |
|||
$('#node-version').text(data['bitcoind']['version']) |
|||
const network = data['bitcoind']['testnet'] == true ? 'testnet' : 'mainnet' |
|||
$('#node-network').text(network) |
|||
$('#node-conn').text(data['bitcoind']['conn']) |
|||
$('#node-relay-fee').text(data['bitcoind']['relayfee']) |
|||
lib_msg.cleanMessagesUi() |
|||
} |
|||
}).catch(e => { |
|||
$('#node-status-ind').text('-') |
|||
$('#node-status-ind').css('color', '#f77c7c') |
|||
$('#node-uptime').text('-') |
|||
$('#node-chaintip').text('-') |
|||
$('#node-version').text('-') |
|||
$('#node-network').text('-') |
|||
$('#node-conn').text('-') |
|||
$('#node-relay-fee').text('-') |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-status', statusScript) |
@ -0,0 +1,101 @@ |
|||
<div id="txs-tool"> |
|||
<h1>TRANSACTIONS TOOL</h1> |
|||
|
|||
<div class="box-context">Check if a transaction is found in a block or in the mempool of your full node.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<!-- TRANSACTION SEARCH FORM --> |
|||
<div id="txs-tool-search-form" class="fullwidth box"> |
|||
<div class="box-body"> |
|||
<span>Search transaction with this </span> |
|||
<input id="txid" type="text" placeholder="TXID"> |
|||
<button id="btn-tx-search-go" class="btn btn-success" type="button">GO</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- TRANSACTION DETAILS --> |
|||
<div id="txs-tool-details"> |
|||
<div id="txs-tool-header" class="row box-main"> |
|||
<div class="fullwidth box"> |
|||
<div class="box-body center"> |
|||
<a id="txid-value" href="" target="_blank"></a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="txs-tool-actions" class="row box-main"> |
|||
<div class="center"> |
|||
<button id="btn-txs-details-reset" class="btn btn-success" type="button">SEARCH ANOTHER TRANSACTION</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="txs-tool-details-row1" class="row box-main"> |
|||
<!-- GENERAL INFO --> |
|||
<div id="box-general" class="halfwidth-left box"> |
|||
<div class="box-header">GENERAL INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">First-seen date</td> |
|||
<td class="table-value" id="tx-firstseen"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Found in</td> |
|||
<td class="table-value" id="tx-location"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Amount</td> |
|||
<td class="table-value" id="tx-amount"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Fees</td> |
|||
<td class="table-value" id="tx-fees"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Feerate</td> |
|||
<td class="table-value" id="tx-vfeerate"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of inputs</td> |
|||
<td class="table-value" id="tx-nb-inputs"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of outputs</td> |
|||
<td class="table-value" id="tx-nb-outputs"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<!-- TECHNICAL INFO --> |
|||
<div id="box-technical" class="halfwidth-right box"> |
|||
<div class="box-header">TECHNICAL INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Virtual size</td> |
|||
<td class="table-value" id="tx-vsize"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Raw size</td> |
|||
<td class="table-value" id="tx-size"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Transaction version</td> |
|||
<td class="table-value" id="tx-version"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">nLockTime</td> |
|||
<td class="table-value" id="tx-nlocktime"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script include-js="txs-tools/txs-tools.js"></script> |
@ -0,0 +1,117 @@ |
|||
const screenTxsToolsScript = { |
|||
|
|||
explorerInfo: null, |
|||
currentTxid: null, |
|||
|
|||
initPage: function() { |
|||
this.getExplorerInfo() |
|||
// Sets the event handlers
|
|||
$('#btn-tx-search-go').click(() => {this.searchTx()}) |
|||
$('#btn-txs-details-reset').click(() => {this.showSearchForm()}) |
|||
$('#txs-tool').keyup(evt => { |
|||
if (evt.keyCode === 13) { |
|||
this.searchTx() |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
this.showSearchForm() |
|||
$("#txid").focus() |
|||
}, |
|||
|
|||
getExplorerInfo: function() { |
|||
lib_api.getExplorerPairingInfo().then(explorerInfo => { |
|||
this.explorerInfo = explorerInfo |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
searchTx: function() { |
|||
lib_msg.displayMessage('Search in progress...'); |
|||
const txid = $('#txid').val() |
|||
this.currentTxid = txid |
|||
return this._searchTx(txid).then(() => { |
|||
lib_msg.cleanMessagesUi() |
|||
}) |
|||
}, |
|||
|
|||
_searchTx: function(txid) { |
|||
return lib_api.getTransaction(txid).then(txInfo => { |
|||
if (txInfo) { |
|||
console.log(txInfo) |
|||
this.setTxDetails(txInfo) |
|||
this.showTxDetails() |
|||
} |
|||
}).catch(e => { |
|||
lib_msg.displayErrors('No transaction found') |
|||
console.log(e) |
|||
throw e |
|||
}) |
|||
}, |
|||
|
|||
setTxDetails: function(txInfo) { |
|||
$('tr.input-row').remove() |
|||
$('tr.output-row').remove() |
|||
|
|||
const txUrl = lib_cmn.getExplorerTxUrl(this.currentTxid, this.explorerInfo) |
|||
$('#txid-value').text(this.currentTxid) |
|||
$('#txid-value').attr('href', txUrl) |
|||
|
|||
const firstseen = lib_fmt.unixTsToLocaleString(txInfo['created']) |
|||
$('#tx-firstseen').text(firstseen) |
|||
|
|||
if (txInfo.hasOwnProperty('block')) |
|||
$('#tx-location').text(` Block ${txInfo['block']['height']}`) |
|||
else |
|||
$('#tx-location').text(' Mempool') |
|||
|
|||
|
|||
const nbInputs = txInfo['inputs'].length |
|||
$('#tx-nb-inputs').text(nbInputs) |
|||
|
|||
const nbOutputs = txInfo['outputs'].length |
|||
$('#tx-nb-outputs').text(nbOutputs) |
|||
|
|||
$('#tx-vfeerate').text(`${txInfo['vfeerate']} sats/vbyte`) |
|||
|
|||
const fees = parseInt(txInfo['fees']) |
|||
$('#tx-fees').text(`${fees} sats`) |
|||
|
|||
let amount = fees |
|||
for (let o of txInfo['outputs']) { |
|||
amount += parseInt(o['value']) |
|||
} |
|||
amount = amount / 100000000 |
|||
$('#tx-amount').text(`${amount} BTC`) |
|||
|
|||
$('#tx-size').text(`${txInfo['size']} bytes`) |
|||
$('#tx-vsize').text(`${txInfo['vsize']} vbytes`) |
|||
$('#tx-version').text(txInfo['version']) |
|||
|
|||
let nlocktime = parseInt(txInfo['locktime']) |
|||
if (nlocktime < 500000000) { |
|||
$('#tx-nlocktime').text(`Block ${nlocktime}`) |
|||
} else { |
|||
locktime = lib_fmt.unixTsToLocaleString(locktime) |
|||
$('#tx-nlocktime').text(locktime) |
|||
} |
|||
}, |
|||
|
|||
showSearchForm: function() { |
|||
$('#txs-tool-details').hide() |
|||
$('#txid').val('') |
|||
$('#txs-tool-search-form').show() |
|||
lib_msg.cleanMessagesUi() |
|||
}, |
|||
|
|||
showTxDetails: function() { |
|||
$('#txs-tool-search-form').hide() |
|||
$('#txs-tool-details').show() |
|||
}, |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-txs-tools', screenTxsToolsScript) |
@ -0,0 +1,42 @@ |
|||
<div id="welcome"> |
|||
<h1>WELCOME!</h1> |
|||
|
|||
<span>The Dojo's Maintenance Tool (DMT for short) provides a set of tools for monitoring and maintaining your Dojo.</span> |
|||
|
|||
<span class="items-category ">MONITORING</span> |
|||
|
|||
<span class="item">DOJO STATUS</span> |
|||
<span class="item-descr">A dashboard for monitoring the health of some components of your Dojo.</span> |
|||
|
|||
<span class="item">PUSHTX STATUS</span> |
|||
<span class="item-descr">A dashboard for monitoring the transactions pushed through your Dojo.</span> |
|||
|
|||
<span class="items-category ">TOOLS</span> |
|||
|
|||
<span class="item">PAIRING</span> |
|||
<span class="item-descr">Pair your wallet to your Dojo by scanning a QRCode.</span> |
|||
|
|||
<span class="item">XPUBS TOOL</span> |
|||
<span class="item-descr">Everything you need to manage your XPUBs manually.<br/>Check if a XPUB is tracked by your Dojo. Import and track a XPUB. Rescan the full history of a XPUB.</span> |
|||
|
|||
<span class="item">ADDRESSES TOOL</span> |
|||
<span class="item-descr">Everything you need to manage your addresses manually.<br/>Check if an address is tracked by your Dojo. Import and track an address. Rescan the full history of an address.</span> |
|||
|
|||
<span class="item">TRANSACTIONS TOOL</span> |
|||
<span class="item-descr">Check if a transaction is found in a block or in the mempool of your full node.</span> |
|||
|
|||
<span class="item">BLOCKS RESCAN</span> |
|||
<span class="item-descr">Rescan the transactions confirmed by the blocks in a given range.</span> |
|||
|
|||
<span class="items-category ">HELP</span> |
|||
|
|||
<span class="item">DOJO TELEGRAM CHAT</span> |
|||
<span class="item-descr">Get support from the community for all things related to your Dojo (requires Telegram).</span> |
|||
|
|||
<span class="item">WHIRLPOOL TELEGRAM CHAT</span> |
|||
<span class="item-descr">Get support from the community for all things related to Whirlpool (requires Telegram).</span> |
|||
|
|||
<span class="item">SW TELEGRAM CHAT</span> |
|||
<span class="item-descr">Get support from the community for all things related to your Samourai Wallet (requires Telegram).</span> |
|||
|
|||
</div> |
@ -0,0 +1,177 @@ |
|||
<div id="xpubs-tool"> |
|||
<h1>XPUBS TOOL</h1> |
|||
|
|||
<div class="box-context">Check if a XPUB is tracked by your Dojo. Import and track a new XPUB. Rescan the full history of a XPUB.</div> |
|||
|
|||
<div class="row box-main"> |
|||
<!-- XPUB SEARCH FORM --> |
|||
<div id="xpubs-tool-search-form" class="fullwidth box"> |
|||
<div class="box-body"> |
|||
<span>Check if </span> |
|||
<input id="xpub" type="text" placeholder="XPUB"> |
|||
<span> is tracked by your Dojo </span> |
|||
<button id="btn-xpub-search-go" |
|||
class="btn btn-success" |
|||
type="button">GO</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- XPUB IMPORT --> |
|||
<div id="xpubs-tool-import" class="fullwidth box"> |
|||
<div class="box-body"> |
|||
<div id="import-deriv-first-import-msg"> |
|||
<span>This XPUB isn't tracked by your Dojo. Do you want to import it and track its activity?</span> |
|||
</div> |
|||
<div id="import-deriv-reimport-msg"> |
|||
<span>This XPUB is already tracked by your Dojo. Do you want to reimport it with a new derivation type?</span> |
|||
</div> |
|||
<div class="spacer20"></div> |
|||
<div> |
|||
<span>Import </span> |
|||
<span id="import-xpub"></span> |
|||
<span> with a </span> |
|||
<select id="import-deriv-type" type="select" value="auto"> |
|||
<option value="auto" selected>auto</option> |
|||
<option value="bip44">BIP44</option> |
|||
<option value="bip49">BIP49</option> |
|||
<option value="bip84">BIP84</option> |
|||
</select> |
|||
<span> derivation</span> |
|||
<button id="btn-xpub-import-go" class="btn btn-success" type="button">IMPORT</button> |
|||
<button id="btn-xpub-import-cancel" class="btn btn-success" type="button">CANCEL</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- XPUB DETAILS --> |
|||
<div id="xpubs-tool-details"> |
|||
<div id="xpubs-tool-header" class="row box-main"> |
|||
<div class="fullwidth box"> |
|||
<div id="xpub-value" class="box-body center"></div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="xpubs-tool-actions" class="row box-main"> |
|||
<div class="center"> |
|||
<button id="btn-xpub-details-rescan" class="btn btn-success" type="button">RESCAN THIS XPUB</button> |
|||
<button id="btn-xpub-details-retype" class="btn btn-success" type="button">RETYPE THIS XPUB</button> |
|||
<button id="btn-xpub-details-reset" class="btn btn-success" type="button">SEARCH ANOTHER XPUB</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="xpubs-rescans-actions" class="row box-main"> |
|||
<div class="center"> |
|||
<span>Rescan this xpub starting at index</span> |
|||
<input id="rescan-start-idx" type="text" value="0" placeholder="index"> |
|||
<span> with a lookahead of </span> |
|||
<input id="rescan-lookahead" type="text" value="100" placeholder="#addresses"> |
|||
<span> addresses</span> |
|||
<button id="btn-xpub-rescan-go" class="btn btn-success" type="button">RESCAN</button> |
|||
<button id="btn-xpub-rescan-cancel" class="btn btn-success" type="button">CANCEL</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="xpubs-tool-details-row1" class="row box-main"> |
|||
<!-- GENERAL INFO --> |
|||
<div id="box-general" class="halfwidth-left box"> |
|||
<div class="box-header">GENERAL INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Derivation Type</td> |
|||
<td class="table-value" id="xpub-deriv-type"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Balance</td> |
|||
<td class="table-value" id="xpub-balance"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of Txs</td> |
|||
<td class="table-value" id="xpub-nb-txs"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Number of UTXOs</td> |
|||
<td class="table-value" id="xpub-nb-utxos"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Tracked since</td> |
|||
<td class="table-value" id="xpub-import-date"></td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<!-- DERIVATION INFO --> |
|||
<div id="box-derivation" class="halfwidth-right box"> |
|||
<div class="box-header">XPUB DERIVATION INFO</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table> |
|||
<tr> |
|||
<td class="table-label">Account</td> |
|||
<td class="table-value" id="xpub-deriv-account"></td> |
|||
<td class="table-label">Depth</td> |
|||
<td class="table-value" id="xpub-deriv-depth"></td> |
|||
</tr> |
|||
</table> |
|||
<div class="spacer10"></div> |
|||
<table id="table-deriv-idx"> |
|||
<tr> |
|||
<td class="table-label" colspan="2">First unused indices</td> |
|||
<td class="table-label" colspan="2">Last derived indices</td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">External</td> |
|||
<td class="table-value" id="xpub-idx-unused-ext"></td> |
|||
<td class="table-label">External</td> |
|||
<td class="table-value" id="xpub-idx-derived-ext"></td> |
|||
</tr> |
|||
<tr> |
|||
<td class="table-label">Internal</td> |
|||
<td class="table-value" id="xpub-idx-unused-int"></td> |
|||
<td class="table-label">Internal</td> |
|||
<td class="table-value" id="xpub-idx-derived-int"></td> |
|||
</tr> |
|||
</table> |
|||
<div class="spacer10"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="xpubs-tool-details-row2" class="row box-main"> |
|||
<!-- TXS LIST --> |
|||
<div id="box-txs" class="halfwidth-left box"> |
|||
<div class="box-header">MOST RECENT TRANSACTIONS</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table id="xpub-table-list-txs"> |
|||
<tbody> |
|||
<tr> |
|||
<td></td> |
|||
<td></td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
<!-- UTXOS LIST --> |
|||
<div id="box-utxos" class="halfwidth-right box"> |
|||
<div class="box-header">UNSPENT TRANSACTION OUTPUTS</div> |
|||
<div class="spacer10"></div> |
|||
<div class="box-body"> |
|||
<table id="xpub-table-list-utxos"> |
|||
<tbody> |
|||
<tr> |
|||
<td></td> |
|||
<td></td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script include-js="xpubs-tools/xpubs-tools.js"></script> |
@ -0,0 +1,249 @@ |
|||
const screenXpubsToolsScript = { |
|||
|
|||
explorerInfo: null, |
|||
currentXpub: null, |
|||
|
|||
initPage: function() { |
|||
this.getExplorerInfo() |
|||
// Sets the event handlers
|
|||
$('#btn-xpub-search-go').click(() => {this.searchXpub()}) |
|||
$('#btn-xpub-details-reset').click(() => {this.showSearchForm()}) |
|||
$('#btn-xpub-details-rescan').click(() => {this.showRescanForm()}) |
|||
$('#btn-xpub-rescan-go').click(() => {this.rescanXpub()}) |
|||
$('#btn-xpub-rescan-cancel').click(() => {this.hideRescanForm()}) |
|||
$('#btn-xpub-import-go').click(() => {this.importXpub()}) |
|||
$('#btn-xpub-details-retype').click(() => {this.showImportForm(true)}) |
|||
$('#btn-xpub-import-cancel').click(() => {this.showSearchForm()}) |
|||
$('#xpubs-tool').keyup(evt => { |
|||
if (evt.keyCode === 13) { |
|||
this.searchXpub() |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
preparePage: function() { |
|||
this.hideRescanForm() |
|||
this.showSearchForm() |
|||
$("#xpub").focus() |
|||
}, |
|||
|
|||
getExplorerInfo: function() { |
|||
lib_api.getExplorerPairingInfo().then(explorerInfo => { |
|||
this.explorerInfo = explorerInfo |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
searchXpub: function() { |
|||
lib_msg.displayMessage('Search in progress...'); |
|||
const xpub = $('#xpub').val() |
|||
this.currentXpub = xpub |
|||
return this._searchXpub(xpub).then(() => { |
|||
lib_msg.cleanMessagesUi() |
|||
}) |
|||
}, |
|||
|
|||
_searchXpub: function(xpub) { |
|||
return lib_api.getXpubInfo(xpub).then(xpubInfo => { |
|||
if (xpubInfo && xpubInfo['tracked']) { |
|||
this.setXpubDetails(xpubInfo) |
|||
this.showXpubDetails() |
|||
const jsonData = {'active': xpub} |
|||
return lib_api.getWallet(jsonData).then(walletInfo => { |
|||
// Display the txs
|
|||
const txs = walletInfo['txs'] |
|||
for (let tx of txs) |
|||
this.setTxDetails(tx) |
|||
// Display the UTXOs
|
|||
const utxos = walletInfo['unspent_outputs'].sort((a,b) => { |
|||
return a['confirmations'] - b['confirmations'] |
|||
}) |
|||
$('#xpub-nb-utxos').text(utxos.length) |
|||
for (let utxo of utxos) |
|||
this.setUtxoDetails(utxo) |
|||
}) |
|||
} else { |
|||
lib_msg.displayErrors('xpub not found') |
|||
this.showImportForm(false) |
|||
} |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
throw e |
|||
}) |
|||
}, |
|||
|
|||
importXpub: function() { |
|||
lib_msg.displayMessage('Processing xpub import...'); |
|||
|
|||
const jsonData = { |
|||
'xpub': this.currentXpub, |
|||
'type': 'restore', |
|||
'force': true |
|||
} |
|||
|
|||
const derivType = $('#import-deriv-type').val() |
|||
if (derivType == 'bip49' || derivType == 'bip84') { |
|||
jsonData['segwit'] = derivType |
|||
} else if (derivType == 'auto') { |
|||
if (this.currentXpub.startsWith('ypub')) |
|||
jsonData['segwit'] = 'bip49' |
|||
else if (this.currentXpub.startsWith('zpub')) |
|||
jsonData['segwit'] = 'bip84' |
|||
} |
|||
|
|||
return lib_api.postXpub(jsonData) |
|||
.then(result => { |
|||
this._searchXpub(this.currentXpub).then(() => { |
|||
lib_msg.displayInfo('Import complete') |
|||
}) |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
rescanXpub: function() { |
|||
lib_msg.displayMessage('Processing xpub rescan...'); |
|||
let startIdx = $('#rescan-start-idx').val() |
|||
startIdx = (startIdx == null) ? 0 : parseInt(startIdx) |
|||
let lookahead = $('#rescan-lookahead').val() |
|||
lookahead = (lookahead == null) ? 100 : parseInt(lookahead) |
|||
return lib_api.getXpubRescan(this.currentXpub, lookahead, startIdx) |
|||
.then(result => { |
|||
this.hideRescanForm() |
|||
this._searchXpub(this.currentXpub).then(() => { |
|||
lib_msg.displayInfo('Rescan complete') |
|||
}) |
|||
}).catch(e => { |
|||
lib_msg.displayErrors(lib_msg.extractJqxhrErrorMsg(e)) |
|||
console.log(e) |
|||
}) |
|||
}, |
|||
|
|||
setXpubDetails: function(xpubInfo) { |
|||
$('tr.tx-row').remove() |
|||
$('tr.utxo-row').remove() |
|||
|
|||
$('#xpub-value').text(this.currentXpub) |
|||
$('#xpub-import-date').text(xpubInfo['created']) |
|||
$('#xpub-deriv-type').text(xpubInfo['derivation']) |
|||
$('#xpub-nb-txs').text(xpubInfo['n_tx']) |
|||
$('#xpub-nb-utxos').text('-') |
|||
const balance = parseInt(xpubInfo['balance']) / 100000000 |
|||
$('#xpub-balance').text(`${balance} BTC`) |
|||
$('#xpub-deriv-account').text(xpubInfo['account']) |
|||
$('#xpub-deriv-depth').text(xpubInfo['depth']) |
|||
$('#xpub-idx-unused-ext').text(xpubInfo['unused']['external']) |
|||
$('#xpub-idx-derived-ext').text(xpubInfo['derived']['external']) |
|||
$('#xpub-idx-unused-int').text(xpubInfo['unused']['internal']) |
|||
$('#xpub-idx-derived-int').text(xpubInfo['derived']['internal']) |
|||
}, |
|||
|
|||
setTxDetails: function(tx) { |
|||
const txid = tx['hash'] |
|||
const txidDisplay = `${txid.substring(0,50)}...` |
|||
const amount = parseInt(tx['result']) / 100000000 |
|||
const amountLabel = amount < 0 ? amount : `+${amount}` |
|||
const amountStyle = amount < 0 ? 'amount-sent' : 'amount-received' |
|||
const date = lib_fmt.unixTsToLocaleString(tx['time']) |
|||
const txUrl = lib_cmn.getExplorerTxUrl(txid, this.explorerInfo) |
|||
|
|||
const newRow = `<tr class="tx-row"><td colspan="2"> </td></tr>
|
|||
<tr class="tx-row"> |
|||
<td class="table-label" colspan="2"> |
|||
<a href="${txUrl}" target="_blank">${txidDisplay}</a> |
|||
</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Amount</td> |
|||
<td class="table-value ${amountStyle}">${amountLabel} BTC</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Block height</td> |
|||
<td class="table-value">${tx['block_height']}</td> |
|||
</tr> |
|||
<tr class="tx-row"> |
|||
<td class="table-label">Date</td> |
|||
<td class="table-value">${date}</td> |
|||
</tr>` |
|||
|
|||
$('#xpub-table-list-txs tr:last').after(newRow) |
|||
}, |
|||
|
|||
setUtxoDetails: function(utxo) { |
|||
const txid = utxo['tx_hash'] |
|||
const txidVout = `${txid.substring(0,50)}...:${utxo['tx_output_n']}` |
|||
const amount = parseInt(utxo['value']) / 100000000 |
|||
const txUrl = lib_cmn.getExplorerTxUrl(txid, this.explorerInfo) |
|||
|
|||
const newRow = `<tr class="utxo-row"><td colspan="2"> </td></tr>
|
|||
<tr class="utxo-row"> |
|||
<td class="table-label" colspan="2"> |
|||
<a href="${txUrl}" target="_blank">${txidVout}</a> |
|||
</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Amount</td> |
|||
<td class="table-value">${amount} BTC</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Address</td> |
|||
<td class="table-value">${utxo['addr']}</td> |
|||
</tr> |
|||
<tr class="utxo-row"> |
|||
<td class="table-label">Confirmations</td> |
|||
<td class="table-value">${utxo['confirmations']}</td> |
|||
</tr>` |
|||
|
|||
$('#xpub-table-list-utxos tr:last').after(newRow) |
|||
}, |
|||
|
|||
showSearchForm: function() { |
|||
$('#xpubs-tool-details').hide() |
|||
$('#xpubs-tool-import').hide() |
|||
$('#xpub').val('') |
|||
$('#xpubs-tool-search-form').show() |
|||
lib_msg.cleanMessagesUi() |
|||
}, |
|||
|
|||
showImportForm: function(isReimport) { |
|||
$('#xpubs-tool-search-form').hide() |
|||
$('#xpubs-tool-details').hide() |
|||
|
|||
if (isReimport) { |
|||
$('#import-deriv-first-import-msg').hide() |
|||
$('#import-deriv-reimport-msg').show() |
|||
} else { |
|||
$('#import-deriv-reimport-msg').hide() |
|||
$('#import-deriv-first-import-msg').show() |
|||
} |
|||
|
|||
const xpubLen = this.currentXpub.length |
|||
const xpubShortLbl = `"${this.currentXpub.substring(0, 20)}...${this.currentXpub.substring(xpubLen-20, xpubLen)}"` |
|||
$('#import-xpub').text(xpubShortLbl) |
|||
$('#xpubs-tool-import').show() |
|||
}, |
|||
|
|||
showXpubDetails: function() { |
|||
$('#xpubs-tool-search-form').hide() |
|||
$('#xpubs-tool-import').hide() |
|||
$('#xpubs-tool-details').show() |
|||
}, |
|||
|
|||
showRescanForm: function() { |
|||
$('#xpubs-tool-actions').hide() |
|||
$('#xpubs-rescans-actions').show() |
|||
lib_msg.cleanMessagesUi() |
|||
}, |
|||
|
|||
hideRescanForm: function() { |
|||
$('#xpubs-rescans-actions').hide() |
|||
$('#xpubs-tool-actions').show() |
|||
}, |
|||
|
|||
} |
|||
|
|||
screenScripts.set('#screen-xpubs-tools', screenXpubsToolsScript) |
After Width: | Height: | Size: 17 KiB |
File diff suppressed because it is too large
@ -1,51 +1,125 @@ |
|||
lib_cmn = { |
|||
const lib_cmn = { |
|||
// Utils functions
|
|||
hasProperty: function(obj, propName) { |
|||
/* Checks if an object has a property with given name */ |
|||
if ( (obj == null) || (!propName) ) |
|||
return false; |
|||
return false |
|||
else if (obj.hasOwnProperty('propName') || propName in obj) |
|||
return true; |
|||
return true |
|||
else |
|||
return false; |
|||
return false |
|||
}, |
|||
|
|||
// Go to default page
|
|||
goToDefaultPage: function() { |
|||
const baseUri = conf['adminTool']['baseUri']; |
|||
sessionStorage.setItem('activeTab', '#link-pairing'); |
|||
window.location = baseUri + '/tool/'; |
|||
const baseUri = conf['adminTool']['baseUri'] |
|||
sessionStorage.setItem('activeTab', '#link-status') |
|||
window.location = baseUri + '/dmt/' |
|||
}, |
|||
|
|||
// Go to home page
|
|||
goToHomePage: function() { |
|||
sessionStorage.setItem('activeTab', null); |
|||
window.location = conf['adminTool']['baseUri'] + '/'; |
|||
sessionStorage.setItem('activeTab', null) |
|||
window.location = conf['adminTool']['baseUri'] + '/' |
|||
}, |
|||
|
|||
// Loads html snippet
|
|||
// Get Transaction url on selected explorer
|
|||
getExplorerTxUrl: function(txid, explorerInfo) { |
|||
if (explorerInfo == null) |
|||
return null |
|||
else if (explorerInfo['pairing']['type'] == 'explorer.oxt') |
|||
return `${explorerInfo['pairing']['url']}/transaction/${txid}` |
|||
else if (explorerInfo['pairing']['type'] == 'explorer.btc_rpc_explorer') |
|||
return `http://${explorerInfo['pairing']['url']}/tx/${txid}` |
|||
else |
|||
return null |
|||
}, |
|||
|
|||
// Loads html snippets
|
|||
includeHTML: function(cb) { |
|||
let self = this; |
|||
let z, i, elmnt, file, xhttp; |
|||
z = document.getElementsByTagName('*'); |
|||
let self = this |
|||
let z, i, elmnt, file, xhttp |
|||
z = document.getElementsByTagName('*') |
|||
for (i = 0; i < z.length; i++) { |
|||
elmnt = z[i] |
|||
file = elmnt.getAttribute('include-html') |
|||
if (file) { |
|||
xhttp = new XMLHttpRequest() |
|||
xhttp.onreadystatechange = function() { |
|||
if (this.readyState == 4 && this.status == 200) { |
|||
elmnt.innerHTML = this.responseText |
|||
elmnt.removeAttribute('include-html') |
|||
self.includeHTML(cb) |
|||
self.includeJs(elmnt) |
|||
} |
|||
} |
|||
xhttp.open('GET', file, true) |
|||
xhttp.send() |
|||
return |
|||
} |
|||
} |
|||
if (cb) cb() |
|||
}, |
|||
|
|||
// Loads js snippets
|
|||
includeJs: function(element) { |
|||
let self = this |
|||
let z, i, elmnt, file, xhttp |
|||
z = element.querySelectorAll('script') |
|||
for (i = 0; i < z.length; i++) { |
|||
elmnt = z[i]; |
|||
file = elmnt.getAttribute('include-html'); |
|||
elmnt = z[i] |
|||
file = elmnt.getAttribute('include-js') |
|||
if (file) { |
|||
xhttp = new XMLHttpRequest(); |
|||
xhttp = new XMLHttpRequest() |
|||
xhttp.onreadystatechange = function() { |
|||
if (this.readyState == 4 && this.status == 200) { |
|||
elmnt.innerHTML = this.responseText; |
|||
elmnt.removeAttribute('include-html'); |
|||
self.includeHTML(cb); |
|||
const newElmnt = document.createElement('script') |
|||
newElmnt.textContent = this.responseText |
|||
if (elmnt.parentNode) { |
|||
elmnt.parentNode.insertBefore(newElmnt, elmnt.nextSibling) |
|||
elmnt.parentNode.removeChild(elmnt) |
|||
} |
|||
} |
|||
xhttp.open('GET', file, true); |
|||
xhttp.send(); |
|||
return; |
|||
} |
|||
xhttp.open('GET', file, true) |
|||
xhttp.send() |
|||
return |
|||
} |
|||
} |
|||
}, |
|||
|
|||
pad10: function(v) { |
|||
return (v < 10) ? `0${v}` : `${v}` |
|||
}, |
|||
|
|||
pad100: function(v) { |
|||
if (v < 10) return `00${v}` |
|||
if (v < 100) return `0${v}` |
|||
return `${v}` |
|||
}, |
|||
|
|||
timePeriod: function(period, milliseconds) { |
|||
milliseconds = !!milliseconds |
|||
|
|||
const whole = Math.floor(period) |
|||
const ms = 1000*(period - whole) |
|||
const s = whole % 60 |
|||
const m = (whole >= 60) ? Math.floor(whole / 60) % 60 : 0 |
|||
const h = (whole >= 3600) ? Math.floor(whole / 3600) % 24 : 0 |
|||
const d = (whole >= 86400) ? Math.floor(whole / 86400) : 0 |
|||
|
|||
const parts = [this.pad10(h), this.pad10(m), this.pad10(s)] |
|||
|
|||
if (d > 0) |
|||
parts.splice(0, 0, this.pad100(d)) |
|||
|
|||
const str = parts.join(':') |
|||
|
|||
if (milliseconds) { |
|||
return str + '.' + this.pad100(ms) |
|||
} else { |
|||
return str |
|||
} |
|||
if (cb) cb(); |
|||
} |
|||
|
|||
} |
|||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,39 +1,41 @@ |
|||
var lib_msg = { |
|||
const lib_msg = { |
|||
|
|||
// Extracts jqxhr error message
|
|||
extractJqxhrErrorMsg: function(jqxhr) { |
|||
let hasErrorMsg = ('responseJSON' in jqxhr) && |
|||
(jqxhr['responseJSON'] != null) && |
|||
('message' in jqxhr['responseJSON']); |
|||
('error' in jqxhr['responseJSON']) |
|||
|
|||
return hasErrorMsg ? jqxhr['responseJSON']['message'] : jqxhr.statusText; |
|||
return hasErrorMsg ? jqxhr['responseJSON']['error'] : jqxhr.statusText |
|||
}, |
|||
|
|||
// UI functions
|
|||
addTextinID: function(text, id){ |
|||
$(id).html(text.toUpperCase()); |
|||
$(id).html(text.toUpperCase()) |
|||
}, |
|||
|
|||
displayMessage: function(text){ |
|||
this.addTextinID('', '#errors'); |
|||
this.addTextinID('', '#info'); |
|||
this.addTextinID(text, '#msg'); |
|||
this.addTextinID('', '#errors') |
|||
this.addTextinID('', '#info') |
|||
this.addTextinID(text, '#msg') |
|||
}, |
|||
|
|||
displayErrors: function(text){ |
|||
this.addTextinID('', '#msg'); |
|||
this.addTextinID('', '#info'); |
|||
this.addTextinID(text, '#errors'); |
|||
this.addTextinID('', '#msg') |
|||
this.addTextinID('', '#info') |
|||
this.addTextinID(text, '#errors') |
|||
}, |
|||
|
|||
displayInfo: function(text){ |
|||
this.addTextinID('', '#msg'); |
|||
this.addTextinID('', '#errors'); |
|||
this.addTextinID(text, '#info'); |
|||
this.addTextinID('', '#msg') |
|||
this.addTextinID('', '#errors') |
|||
this.addTextinID(text, '#info') |
|||
}, |
|||
|
|||
cleanMessagesUi: function() { |
|||
this.addTextinID('', '#msg'); |
|||
this.addTextinID('', '#errors'); |
|||
this.addTextinID('', '#info'); |
|||
this.addTextinID('', '#msg') |
|||
this.addTextinID('', '#errors') |
|||
this.addTextinID('', '#info') |
|||
} |
|||
|
|||
} |
@ -1,132 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
|
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<title>DOJO // MAINTENANCE TOOL</title> |
|||
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css"> |
|||
<link rel="stylesheet" type="text/css" href="../css/bootstrap-theme.min.css"> |
|||
<link rel="stylesheet" type="text/css" href="../css/style.css"> |
|||
<script src="../lib/jquery-3.2.1.min.js"></script> |
|||
<script src="../lib/jquery.qrcode.min.js"></script> |
|||
<script src="../conf/index.js"></script> |
|||
<script src="../lib/common-script.js"></script> |
|||
<script src="../lib/api-wrapper.js"></script> |
|||
<script src="../lib/auth-utils.js"></script> |
|||
<script src="../lib/format-utils.js"></script> |
|||
<script src="index.js"></script> |
|||
</head> |
|||
|
|||
<body> |
|||
<div id="info-xpub" class="container"> |
|||
<!-- HEADER --> |
|||
<div id="header" class="row"> |
|||
<div class="col-xs-9"> |
|||
<h1 class="title"><span>DOJO // MAINTENANCE TOOL</span> <span id="dojo-version" class="beta">beta</span></h1> |
|||
</div> |
|||
<div class="col-xs-3 login-box"> |
|||
<a id="btn-logout" style="display: inline;" href="#" title="DISCONNECT"> |
|||
<img src="../icons/ic_power_settings_new_white_24dp_1x.png" class="mini-icon"/> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="spacer60"></div> |
|||
|
|||
<!-- TAB MENU --> |
|||
<div id="tab-menu" class="row"> |
|||
<div class="col-xs-12" > |
|||
<ul id="tab-menu_list" class="nav nav-pills"> |
|||
<li id="link-pairing"> |
|||
<a href="#">PAIRING</a> |
|||
</li> |
|||
<li id="link-status-api"> |
|||
<a href="#">API</a> |
|||
</li> |
|||
<li id="link-status-pushtx"> |
|||
<a href="#">PUSHTX</a> |
|||
</li> |
|||
<li id="link-orchestrator"> |
|||
<a href="#">ORCHESTRATOR</a> |
|||
</li> |
|||
<li id="link-info-xpub"> |
|||
<a href="#">XPUB INFO</a> |
|||
</li> |
|||
<li id="link-rescan-xpub"> |
|||
<a href="#">XPUB RESCAN</a> |
|||
</li> |
|||
<li id="link-xpub"> |
|||
<a href="#">XPUB</a> |
|||
</li> |
|||
<li id="link-info-address"> |
|||
<a href="#">ADDR. INFO</a> |
|||
</li> |
|||
<li id="link-rescan-address"> |
|||
<a href="#">ADDR. RESCAN</a> |
|||
</li> |
|||
<li id="link-wallet"> |
|||
<a href="#">WALLET</a> |
|||
</li> |
|||
<li id="link-tx"> |
|||
<a href="#">TX</a> |
|||
</li> |
|||
<li id="link-rescan-blocks"> |
|||
<a href="#">BLOCKS RESCAN</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- BODY --> |
|||
<div id="body" class="row"> |
|||
<div class="col-xs-1"></div> |
|||
<div class="col-xs-10 json-data-container"> |
|||
<!-- PAIRING --> |
|||
<div id="screen-pairing"> |
|||
<div class="row"> |
|||
<div id="qr-label" class="halfwidth"> |
|||
PAIR YOUR WALLET WITH YOUR DOJO |
|||
</div> |
|||
<div id="qr-explorer-label" class="halfwidth"> |
|||
PAIR YOUR WALLET WITH YOUR BLOCK EXPLORER |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div id="qr-container" class="halfwidth"> |
|||
<div id="qr-pairing"></div> |
|||
</div> |
|||
<div id="qr-explorer-container" class="halfwidth"> |
|||
<div id="qr-explorer-pairing"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- MAINTENANCE --> |
|||
<div id="form-maintenance"> |
|||
<div id="row-form-field"> |
|||
<div id="cell-args"> |
|||
<input type="text" id="args" placeholder=""> |
|||
</div> |
|||
<div id="cell-args2"> |
|||
<input type="text" id="args2" placeholder=""> |
|||
</div> |
|||
<div id="cell-args3"> |
|||
<input type="text" id="args3" placeholder=""> |
|||
</div> |
|||
</div> |
|||
<div id="row-form-button" class="center"> |
|||
<button id="btn-go" |
|||
class="btn btn-success" |
|||
type="button">GO</button> |
|||
</div> |
|||
<div class="center"> |
|||
<pre id="json-data" style="min-height: 300px"></pre> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-xs-1"></div> |
|||
</div> |
|||
|
|||
</div> |
|||
</body> |
|||
|
|||
</html> |
@ -1,295 +0,0 @@ |
|||
/** |
|||
* Display Messages |
|||
*/ |
|||
|
|||
function displayInfoMsg(msg) { |
|||
const htmlMsg = '<span class="info">' + msg + '</span>'; |
|||
$('#json-data').html(htmlMsg); |
|||
} |
|||
|
|||
function displayErrorMsg(msg) { |
|||
const htmlMsg = '<span class="error">' + msg + '</span>'; |
|||
$('#json-data').html(htmlMsg); |
|||
} |
|||
|
|||
function displayQRPairing() { |
|||
const activeTab = sessionStorage.getItem('activeTab'); |
|||
processAction(activeTab).then( |
|||
function (result) { |
|||
if (result) { |
|||
if (result['api']) { |
|||
const textJson = JSON.stringify(result['api'], null, 4); |
|||
$("#qr-pairing").html('') // clear qrcode first
|
|||
$('#qr-pairing').qrcode({width: 256, height: 256, text: textJson}); |
|||
} |
|||
if (result['explorer'] && result['explorer']['pairing']['url']) { |
|||
const textJson = JSON.stringify(result['explorer'], null, 4); |
|||
$("#qr-explorer-pairing").html('') // clear qrcode first
|
|||
$('#qr-explorer-pairing').qrcode({width: 256, height: 256, text: textJson}); |
|||
} else { |
|||
$("#qr-label").removeClass('halfwidth'); |
|||
$("#qr-label").addClass('fullwidth'); |
|||
$("#qr-container").removeClass('halfwidth'); |
|||
$("#qr-container").addClass('fullwidth'); |
|||
$("#qr-explorer-label").hide(); |
|||
$("#qr-explorer-container").hide(); |
|||
} |
|||
} |
|||
}, |
|||
function (jqxhr) {} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* On tab switched |
|||
*/ |
|||
function initTabs() { |
|||
// Activates the current tab
|
|||
let currentTab = sessionStorage.getItem('activeTab'); |
|||
if (!currentTab) { |
|||
currentTab = '#link-pairing'; |
|||
} |
|||
$(currentTab).addClass('active'); |
|||
|
|||
const tabs = [ |
|||
'#link-pairing', |
|||
'#link-status-api', |
|||
'#link-status-pushtx', |
|||
'#link-orchestrator', |
|||
'#link-info-xpub', |
|||
'#link-rescan-xpub', |
|||
'#link-xpub', |
|||
'#link-info-address', |
|||
'#link-rescan-address', |
|||
'#link-rescan-blocks', |
|||
'#link-wallet', |
|||
'#link-tx' |
|||
]; |
|||
|
|||
// Sets event handlers
|
|||
for (let tab of tabs) { |
|||
$(tab).click(function() { |
|||
$(sessionStorage.getItem('activeTab')).removeClass('active'); |
|||
sessionStorage.setItem('activeTab', tab); |
|||
$(tab).addClass('active'); |
|||
preparePage(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Prepares the page content |
|||
*/ |
|||
function preparePage() { |
|||
const activeTab = sessionStorage.getItem('activeTab'); |
|||
|
|||
// Dojo version
|
|||
let lblVersion = sessionStorage.getItem('lblVersion'); |
|||
if (lblVersion == null) { |
|||
lib_api.getPairingInfo().then(apiInfo => { |
|||
lblVersion = 'v' + apiInfo['pairing']['version'] + ' beta'; |
|||
sessionStorage.setItem('lblVersion', lblVersion); |
|||
$('#dojo-version').text(lblVersion); |
|||
}); |
|||
} else { |
|||
$('#dojo-version').text(lblVersion); |
|||
} |
|||
|
|||
// Pairing
|
|||
if (activeTab == '#link-pairing') { |
|||
$('#screen-pairing').show(); |
|||
$('#form-maintenance').hide(); |
|||
displayQRPairing(); |
|||
|
|||
// Maintenance screens
|
|||
} else { |
|||
$('#form-maintenance').show(); |
|||
$('#screen-pairing').hide(); |
|||
|
|||
let placeholder = '', |
|||
placeholder2 = '', |
|||
placeholder3 = ''; |
|||
|
|||
$("#cell-args").removeClass('halfwidth'); |
|||
$("#cell-args").addClass('fullwidth'); |
|||
$("#cell-args2").hide(); |
|||
$("#cell-args3").hide(); |
|||
|
|||
if (activeTab == '#link-status-api' || |
|||
activeTab == '#link-status-pushtx' || |
|||
activeTab == '#link-orchestrator' |
|||
) { |
|||
$("#row-form-field").hide(); |
|||
$("#row-form-button").hide(); |
|||
processGo(); |
|||
} else { |
|||
$("#row-form-field").show(); |
|||
$("#row-form-button").show(); |
|||
} |
|||
|
|||
if (activeTab == '#link-info-xpub') { |
|||
placeholder = 'ENTER A XPUB, YPUB OR ZPUB'; |
|||
} else if (activeTab == '#link-xpub') { |
|||
placeholder = 'ENTER /XPUB URL ARGUMENTS (e.g.: xpub=xpub0123456789&segwit=bip84&type=restore&force=true)'; |
|||
} else if (activeTab == '#link-info-address') { |
|||
placeholder = 'ENTER A BITCOIN ADDRESS'; |
|||
} else if (activeTab == '#link-rescan-address') { |
|||
placeholder = 'ENTER A BITCOIN ADDRESS'; |
|||
} else if (activeTab == '#link-rescan-blocks') { |
|||
$("#cell-args").removeClass('fullwidth'); |
|||
$("#cell-args").addClass('halfwidth'); |
|||
$("#cell-args2").show(); |
|||
placeholder = 'RESCAN BLOCKS FROM HEIGHT...'; |
|||
placeholder2 = '...TO HEIGHT (OPTIONAL)'; |
|||
} else if (activeTab == '#link-wallet') { |
|||
placeholder = 'ENTER /WALLET URL ARGUMENTS (e.g.: active=xpub0123456789&new=address2|address3&pubkey=pubkey4)'; |
|||
} else if (activeTab == '#link-tx') { |
|||
placeholder = 'ENTER A TRANSACTION TXID'; |
|||
} else if (activeTab == '#link-rescan-xpub') { |
|||
$("#cell-args").removeClass('fullwidth'); |
|||
$("#cell-args").addClass('halfwidth'); |
|||
$("#cell-args2").show(); |
|||
$("#cell-args3").show(); |
|||
placeholder = 'ENTER A XPUB, YPUB OR ZPUB'; |
|||
placeholder2 = 'ENTER #ADDR. (DEFAULT=100)'; |
|||
placeholder3 = 'ENTER START INDEX (DEFAULT=0)'; |
|||
} |
|||
|
|||
$("#args").attr('placeholder', placeholder); |
|||
$('#args').val(''); |
|||
$("#args2").attr('placeholder', placeholder2); |
|||
$('#args2').val(''); |
|||
$("#args3").attr('placeholder', placeholder3); |
|||
$('#args3').val(''); |
|||
$('#json-data').html(''); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Process action (api calls) |
|||
*/ |
|||
function processAction(activeTab, args, args2, args3) { |
|||
if (activeTab == '#link-pairing') { |
|||
//return lib_api.getPairingInfo();
|
|||
let result = { |
|||
'api': null, |
|||
'explorer': null |
|||
}; |
|||
return lib_api.getPairingInfo().then(apiInfo => { |
|||
if (apiInfo) { |
|||
apiInfo['pairing']['url'] = window.location.protocol + '//' + window.location.host + conf['api']['baseUri']; |
|||
result['api'] = apiInfo; |
|||
} |
|||
}).then(() => { |
|||
return lib_api.getExplorerPairingInfo(); |
|||
}).then(explorerInfo => { |
|||
if (explorerInfo) |
|||
result['explorer'] = explorerInfo; |
|||
return result |
|||
}).catch(e => { |
|||
console.log(e); |
|||
return result; |
|||
}); |
|||
} else if (activeTab == '#link-status-api') { |
|||
return lib_api.getApiStatus(); |
|||
} else if (activeTab == '#link-status-pushtx') { |
|||
return lib_api.getPushtxStatus(); |
|||
} else if (activeTab == '#link-orchestrator') { |
|||
return lib_api.getOrchestratorStatus(); |
|||
} |
|||
|
|||
if (args == '') { |
|||
alert('Argument is mandatory'); |
|||
return; |
|||
} |
|||
|
|||
if (activeTab == '#link-info-xpub') { |
|||
return lib_api.getXpubInfo(args); |
|||
} else if (activeTab == '#link-rescan-xpub') { |
|||
const nbAddr = (!args2) ? 100 : parseInt(args2); |
|||
const startIdx = (!args3) ? 0 : parseInt(args3); |
|||
return lib_api.getXpubRescan(args, nbAddr, startIdx); |
|||
} else if (activeTab == '#link-info-address') { |
|||
return lib_api.getAddressInfo(args); |
|||
} else if (activeTab == '#link-rescan-address') { |
|||
return lib_api.getAddressRescan(args); |
|||
} else if (activeTab == '#link-rescan-blocks') { |
|||
const fromHeight = parseInt(args); |
|||
const toHeight = (args2) ? parseInt(args2) : fromHeight; |
|||
return lib_api.getBlocksRescan(fromHeight, toHeight); |
|||
} else if (activeTab == '#link-tx') { |
|||
return lib_api.getTransaction(args); |
|||
} |
|||
|
|||
const jsonData = {}; |
|||
const aArgs = args.split('&'); |
|||
for (let arg of aArgs) { |
|||
const aArg = arg.split('='); |
|||
jsonData[aArg[0]] = aArg[1]; |
|||
} |
|||
|
|||
if (activeTab == '#link-wallet') |
|||
return lib_api.getWallet(jsonData); |
|||
else if (activeTab == '#link-xpub') |
|||
return lib_api.postXpub(jsonData); |
|||
} |
|||
|
|||
/** |
|||
* Retrieve information about the xpub |
|||
*/ |
|||
function processGo() { |
|||
const activeTab = sessionStorage.getItem('activeTab'); |
|||
const args = $("#args").val(); |
|||
const args2 = $("#args2").val(); |
|||
const args3 = $("#args3").val(); |
|||
|
|||
displayInfoMsg('Processing...'); |
|||
|
|||
let deferred = processAction(activeTab, args, args2, args3); |
|||
|
|||
deferred.then( |
|||
function (result) { |
|||
if (!result) |
|||
return; |
|||
let textJson = lib_fmt.cleanJson(result); |
|||
textJson = JSON.stringify(JSON.parse(textJson), null, 4); |
|||
textJson = lib_fmt.jsonSyntaxHighlight(textJson); |
|||
$('#json-data').html(textJson); |
|||
}, |
|||
function (jqxhr) { |
|||
let hasErrorMsg = |
|||
('responseJSON' in jqxhr) && |
|||
(jqxhr['responseJSON'] != null) && |
|||
('message' in jqxhr['responseJSON']); |
|||
|
|||
const msg = hasErrorMsg ? jqxhr['responseJSON']['message'] : jqxhr.statusText; |
|||
displayErrorMsg(msg); |
|||
} |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* Processing on loading completed |
|||
*/ |
|||
$(document).ready(function() { |
|||
// Refresh the access token if needed
|
|||
setInterval(() => { |
|||
lib_auth.refreshAccessToken(); |
|||
}, 300000); |
|||
|
|||
initTabs(); |
|||
preparePage(); |
|||
|
|||
// Sets the event handlers
|
|||
$('#args').keyup(function(evt) { |
|||
if (evt.keyCode === 13) { |
|||
processGo(); |
|||
} |
|||
}); |
|||
$('#btn-go').click(function() { |
|||
processGo(); |
|||
}); |
|||
$('#btn-logout').click(function() { |
|||
lib_auth.logout(); |
|||
}); |
|||
}); |
Loading…
Reference in new issue