parent
d05b0b36ce
commit
e3668d2a37
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
!function(e){function r(r){for(var n,a,i=r[0],c=r[1],f=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={0:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+""+({}[e]||e)+"-es2015."+{1:"7e9111b7c3b5e28be38c",5:"eba8765707aa8a3bfc1f",6:"f1092df1bd789fbce299"}[e]+".js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:i})},12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,(function(r){return e[r]}).bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var f=0;f<i.length;f++)r(i[f]);var l=c;t()}([]);
|
@ -1 +0,0 @@
|
||||
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)o[i=a[p]]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es5."+{1:"25aced163e24b1852e25",4:"20db81847c2dde69946d",5:"e5a5e954e6d78b52fbf7"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);
|
@ -0,0 +1 @@
|
||||
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)o[i=a[p]]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"."+{1:"54859a9ed4dbe675e082",6:"10cd8607c932f8229120",7:"2becbc02aff346bd8d1e"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);
|
@ -0,0 +1,88 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.getInvoice = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/invoice/' + req.params.rHashStr;
|
||||
request(options).then((body) => {
|
||||
logger.info({fileName: 'Invoice', msg: 'Invoice Info Received: ' + JSON.stringify(body)});
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Fetching Invoice Info Failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
}
|
||||
res.status(200).json(body);
|
||||
})
|
||||
.catch((err) => {
|
||||
return res.status(500).json({
|
||||
message: "Fetching Invoice Info Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.listInvoices = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/invoices?num_max_invoices=' + req.query.num_max_invoices + '&index_offset=' + req.query.index_offset +
|
||||
'&reversed=' + req.query.reversed;
|
||||
request(options).then((body) => {
|
||||
const body_str = (undefined === body) ? '' : JSON.stringify(body);
|
||||
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
|
||||
logger.info({fileName: 'Invoice', msg: 'Invoices List Received: ' + body_str});
|
||||
if(undefined === body || search_idx > -1 || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Fetching Invoice Info failed!",
|
||||
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
if (undefined !== body.invoices) {
|
||||
body.invoices.forEach(invoice => {
|
||||
invoice.creation_date_str = (undefined === invoice.creation_date) ? '' : common.convertTimestampToDate(invoice.creation_date);
|
||||
invoice.settle_date_str = (undefined === invoice.settle_date) ? '' : common.convertTimestampToDate(invoice.settle_date);
|
||||
invoice.btc_value = (undefined === invoice.value) ? 0 : common.convertToBTC(invoice.value);
|
||||
invoice.btc_amt_paid_sat = (undefined === invoice.amt_paid_sat) ? 0 : common.convertToBTC(invoice.amt_paid_sat);
|
||||
});
|
||||
body.invoices = common.sortDescByKey(body.invoices, 'creation_date');
|
||||
}
|
||||
logger.info({fileName: 'Invoice', msg: 'Invoices List Received: ' + JSON.stringify(body)});
|
||||
res.status(200).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Fetching Invoice Info failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.addInvoice = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/invoices';
|
||||
options.form = JSON.stringify({
|
||||
memo: req.body.memo,
|
||||
value: req.body.amount,
|
||||
private: req.body.private,
|
||||
expiry: req.body.expiry
|
||||
});
|
||||
request.post(options).then((body) => {
|
||||
logger.info({fileName: 'Invoice', msg: 'Add Invoice Responce: ' + JSON.stringify(body)});
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Add Invoice Failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
res.status(201).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Add Invoice Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,17 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var options = {};
|
||||
|
||||
exports.getNewAddress = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/newaddr?addrType=' + req.query.type;
|
||||
request(options).then((body) => {
|
||||
res.status(200).json(body);
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Fetching new address failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,30 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.decodePayment = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/payreq/' + req.params.payRequest;
|
||||
request(options).then((body) => {
|
||||
const body_str = (undefined === body) ? '' : JSON.stringify(body);
|
||||
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
|
||||
logger.info({fileName: 'PayReq', msg: 'Payment Decodd Received: ' + body_str});
|
||||
if(undefined === body || search_idx > -1 || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Payment Request Decode Failed!",
|
||||
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
body.btc_num_satoshis = (undefined === body.num_satoshis) ? 0 : common.convertToBTC(body.num_satoshis);
|
||||
body.timestamp_str = (undefined === body.timestamp) ? '' : common.convertTimestampToDate(body.timestamp);
|
||||
res.status(200).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Payment Request Decode Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.getPayments = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/payments';
|
||||
request(options).then((body) => {
|
||||
const body_str = (undefined === body) ? '' : JSON.stringify(body);
|
||||
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
|
||||
logger.info({fileName: 'Payments', msg: 'Payment Decoded Received: ' + body_str});
|
||||
if(undefined === body || search_idx > -1 || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Payments List Failed!",
|
||||
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
if (undefined !== body.payments) {
|
||||
body.payments.forEach(payment => {
|
||||
payment.creation_date_str = (undefined === payment.creation_date) ? '' : common.convertTimestampToDate(payment.creation_date);
|
||||
});
|
||||
body.payments = common.sortDescByKey(body.payments, 'creation_date');
|
||||
}
|
||||
res.status(200).json(body.payments);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Payments List Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,72 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.getPeers = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/peer/listPeers';
|
||||
request(options).then(function (body) {
|
||||
let peers = (undefined !== body) ? common.sortDescByKey(body, 'alias') : [];
|
||||
logger.info({fileName: 'Peers', msg: 'Peers with Alias: ' + JSON.stringify(peers)});
|
||||
res.status(200).json(peers);
|
||||
})
|
||||
.catch((err) => {
|
||||
return res.status(500).json({
|
||||
message: "Peers Fetch Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.postPeer = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/peer/connect';
|
||||
options.body = req.body;
|
||||
request.post(options, (error, response, body) => {
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Adding peer failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
logger.info({fileName: 'Peers', msg: 'Peer Added: ' + JSON.stringify(body)});
|
||||
options.url = common.getSelLNServerUrl() + '/peer/listPeers';
|
||||
request(options).then(function (body) {
|
||||
let peers = (undefined !== body) ? common.sortDescByKey(body, 'alias') : [];
|
||||
peers = common.newestOnTop(peers, 'id', req.body.id);
|
||||
logger.info({fileName: 'Peers', msg: 'Peer with Newest On Top: ' + JSON.stringify(peers)});
|
||||
logger.info({fileName: 'Peers', msg: 'Peer Added Successfully'});
|
||||
res.status(201).json(peers);
|
||||
}).catch((err) => {
|
||||
return res.status(500).json({
|
||||
message: "Peer Add Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.deletePeer = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/peer/disconnect/' + req.params.peerId + '?force=' + req.query.force;
|
||||
request.delete(options).then((body) => {
|
||||
logger.info({fileName: 'Peers', msg: 'Detach Peer Response: ' + JSON.stringify(body)});
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Detach peer failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
logger.info({fileName: 'Peers', msg: 'Peer Detached: ' + req.params.peerId});
|
||||
res.status(204).json({});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
return res.status(500).json({
|
||||
message: "Detach Peer Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,50 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.forwardingHistory = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/switch';
|
||||
options.form = {};
|
||||
if (undefined !== req.body.num_max_events) {
|
||||
options.form.num_max_events = req.body.num_max_events;
|
||||
}
|
||||
if (undefined !== req.body.index_offset) {
|
||||
options.form.index_offset = req.body.index_offset;
|
||||
}
|
||||
if (undefined !== req.body.end_time) {
|
||||
options.form.end_time = req.body.end_time;
|
||||
}
|
||||
if (undefined !== req.body.start_time) {
|
||||
options.form.start_time = req.body.start_time;
|
||||
}
|
||||
options.form = JSON.stringify(options.form);
|
||||
logger.info({fileName: 'Switch', msg: 'Switch Post Options: ' + JSON.stringify(options)});
|
||||
request.post(options).then((body) => {
|
||||
logger.info({fileName: 'Switch', msg: 'Switch Post Response: ' + JSON.stringify(body)});
|
||||
if(undefined === body || body.error) {
|
||||
logger.error({fileName: 'Switch', lineNum: 27, msg: 'Switch Post Erroe: ' + JSON.stringify((undefined === body) ? 'Error From Server!' : body.error)});
|
||||
res.status(500).json({
|
||||
message: "Switch post failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
if (undefined !== body.forwarding_events) {
|
||||
body.forwarding_events.forEach(event => {
|
||||
event.timestamp_str = (undefined === event.timestamp) ? '' : common.convertTimestampToDate(event.timestamp);
|
||||
});
|
||||
body.forwarding_events = common.sortDescByKey(body.forwarding_events, 'timestamp');
|
||||
}
|
||||
logger.info({fileName: 'Switch', msg: 'Forwarding History Received: ' + JSON.stringify(body)});
|
||||
res.status(201).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
logger.error({fileName: 'Switch', lineNum: 44, msg: 'Switch Post Error: ' + JSON.stringify(err)});
|
||||
return res.status(500).json({
|
||||
message: "Switch post failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.getTransactions = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/transactions';
|
||||
request(options).then((body) => {
|
||||
const body_str = (undefined === body) ? '' : JSON.stringify(body);
|
||||
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
|
||||
logger.info({fileName: 'Transactions', msg: 'Transaction Received: ' + body_str});
|
||||
if(undefined === body || search_idx > -1 || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Fetching Transactions Failed!",
|
||||
error: (undefined === body || search_idx > -1) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
if (undefined !== body.transactions) {
|
||||
body.transactions.forEach(transaction => {
|
||||
transaction.time_stamp_str = (undefined === transaction.time_stamp) ? '' : common.convertTimestampToDate(transaction.time_stamp);
|
||||
});
|
||||
body.transactions = common.sortDescByKey(body.transactions, 'time_stamp');
|
||||
}
|
||||
res.status(200).json(body.transactions);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Fetching Transactions Failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
exports.postTransactions = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/transactions';
|
||||
options.form = {
|
||||
amount: req.body.amount,
|
||||
addr: req.body.address,
|
||||
sat_per_byte: req.body.fees,
|
||||
target_conf: req.body.blocks
|
||||
};
|
||||
if (req.body.sendAll) {
|
||||
options.form.send_all = req.body.sendAll;
|
||||
}
|
||||
options.form = JSON.stringify(options.form);
|
||||
request.post(options).then((body) => {
|
||||
logger.info({fileName: 'Transactions', msg: 'Transaction Post Response: ' + JSON.stringify(body)});
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Transactions post failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
res.status(201).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Transactions post failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
};
|
@ -0,0 +1,93 @@
|
||||
var request = require('request-promise');
|
||||
var common = require('../../common');
|
||||
var atob = require('atob');
|
||||
var logger = require('../logger');
|
||||
var options = {};
|
||||
|
||||
exports.genSeed = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.url = common.getSelLNServerUrl() + '/genseed';
|
||||
if (undefined !== req.params.passphrase) {
|
||||
options.form = JSON.stringify({aezeed_passphrase: atob(req.params.passphrase)});
|
||||
}
|
||||
request(options).then((body) => {
|
||||
if(undefined === body || body.error) {
|
||||
res.status(500).json({
|
||||
message: "Genseed failed!",
|
||||
error: (undefined === body) ? 'Error From Server!' : body.error
|
||||
});
|
||||
} else {
|
||||
res.status(200).json(body);
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
return res.status(500).json({
|
||||
message: "Genseed failed!",
|
||||
error: err.error
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
exports.operateWallet = (req, res, next) => {
|
||||
options = common.getOptions();
|
||||
options.method = 'POST';
|
||||
if (undefined === req.params.operation || req.params.operation === 'unlockwallet') {
|
||||
options.url = common.getSelLNServerUrl() + '/unlockwallet';
|
||||
options.form = JSON.stringify({
|
||||
wallet_password: Buffer.from(atob(req.body.wallet_password)).toString('base64')
|
||||
});
|
||||
err_message = 'Unlocking wallet failed! Verify that lnd is running and the wallet is locked!';
|
||||
} else {
|
||||
options.url = common.getSelLNServerUrl() + '/initwallet';
|
||||
if (undefined !== req.body.aezeed_passphrase && req.body.aezeed_passphrase !== '') {
|
||||
options.form = JSON.stringify({
|
||||
wallet_password: Buffer.from(atob(req.body.wallet_password)).toString('base64'),
|
||||
cipher_seed_mnemonic: req.body.cipher_seed_mnemonic,
|
||||
aezeed_passphrase: Buffer.from(atob(req.body.aezeed_passphrase)).toString('base64')
|
||||
});
|
||||
} else {
|
||||
options.form = JSON.stringify({
|
||||
wallet_password: Buffer.from(atob(req.body.wallet_password)).toString('base64'),
|
||||
cipher_seed_mnemonic: req.body.cipher_seed_mnemonic
|
||||
});
|
||||
}
|
||||
err_message = 'Initializing wallet failed!';
|
||||
}
|
||||
request(options).then((body) => {
|
||||
logger.info({fileName: 'Wallet', msg: 'Wallet Response: ' + JSON.stringify(body)});
|
||||
const body_str = (undefined === body) ? '' : JSON.stringify(body);
|
||||
const search_idx = (undefined === body) ? -1 : body_str.search('Not Found');
|
||||
if(undefined === body) {
|
||||
res.status(500).json({
|
||||
message: err_message,
|
||||
error: (error) ? error : err_message
|
||||
});
|
||||
} else if(search_idx > -1) {
|
||||
res.status(500).json({
|
||||
message: err_message,
|
||||
error: err_message
|
||||
});
|
||||
} else if(body.error) {
|
||||
if((body.code === 1 && body.error === 'context canceled') || (body.code === 14 && body.error === 'transport is closing')) {
|
||||
res.status(201).json('Successful');
|
||||
} else {
|
||||
res.status(500).json({
|
||||
message: err_message,
|
||||
error: body.error
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(201).json('Successful');
|
||||
}
|
||||
}).catch(error => {
|
||||
logger.error({fileName: 'Wallet', lineNum: 83, msg: 'Wallet Response: ' + JSON.stringify(error.error)});
|
||||
if((error.error.code === 1 && error.error.error === 'context canceled') || (error.error.code === 14 && error.error.error === 'transport is closing')) {
|
||||
res.status(201).json('Successful');
|
||||
} else {
|
||||
res.status(500).json({
|
||||
message: err_message,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
const invoicesController = require("../../controllers/c-lightning/invoices");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/", authCheck, invoicesController.listInvoices);
|
||||
router.get("/:rHashStr", authCheck, invoicesController.getInvoice);
|
||||
router.post("/", authCheck, invoicesController.addInvoice);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,8 @@
|
||||
const NewAddressController = require("../../controllers/c-lightning/newAddress");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/", authCheck, NewAddressController.getNewAddress);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,8 @@
|
||||
const PayRequestController = require("../../controllers/c-lightning/payReq");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/:payRequest", authCheck, PayRequestController.decodePayment);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,8 @@
|
||||
const PaymentsController = require("../../controllers/c-lightning/payments");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/", authCheck, PaymentsController.getPayments);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,10 @@
|
||||
const PeersController = require("../../controllers/c-lightning/peers");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/", authCheck, PeersController.getPeers);
|
||||
router.post("/", authCheck, PeersController.postPeer);
|
||||
router.delete("/:peerId", authCheck, PeersController.deletePeer);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,8 @@
|
||||
const SwitchController = require("../../controllers/c-lightning/switch");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.post("/", authCheck, SwitchController.forwardingHistory);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,9 @@
|
||||
const TransactionsController = require("../../controllers/c-lightning/transactions");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/", authCheck, TransactionsController.getTransactions);
|
||||
router.post("/", authCheck, TransactionsController.postTransactions);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,9 @@
|
||||
const WalletController = require("../../controllers/c-lightning/wallet");
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const authCheck = require("../authCheck");
|
||||
|
||||
router.get("/genseed/:passphrase?", authCheck, WalletController.genSeed);
|
||||
router.post("/:operation", authCheck, WalletController.operateWallet);
|
||||
|
||||
module.exports = router;
|
@ -0,0 +1,131 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card [ngClass]="{'flip': redirectedWithPeer}">
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Open Channel</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayout.gt-sm="row wrap" (ngSubmit)="openChannelForm.form.valid && onOpenChannel(openChannelForm)" #openChannelForm="ngForm">
|
||||
<mat-form-field fxFlex="40" fxLayoutAlign="start end">
|
||||
<mat-select [(ngModel)]="selectedPeer" placeholder="Alias" name="peer_alias" tabindex="1" required name="selPeer" #selPeer="ngModel">
|
||||
<mat-option *ngFor="let peer of peers" [value]="peer.pub_key">
|
||||
{{peer.alias}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25" fxLayoutAlign="start end">
|
||||
<input matInput [(ngModel)]="fundingAmount" placeholder="Amount ({{information?.smaller_currency_unit}})" type="number" step="1000" min="1" tabindex="2" required name="amount" #amount="ngModel">
|
||||
<mat-hint>(Wallet Bal: {{totalBalance}}, Remaining Bal: {{totalBalance - ((fundingAmount) ? fundingAmount : 0)}})</mat-hint>
|
||||
</mat-form-field>
|
||||
<div fxFlex="15" tabindex="3" fxLayoutAlign="start center" class="chkbox-options">
|
||||
<mat-checkbox [(ngModel)]="moreOptions" name="moreOptions" (change)="onMoreOptionsChange($event)">Options</mat-checkbox>
|
||||
</div>
|
||||
<span *ngIf="moreOptions" fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="80" fxLayoutAlign.gt-sm="space-between center">
|
||||
<mat-form-field fxFlex="25" fxLayoutAlign="start end">
|
||||
<mat-select tabindex="4" [(value)]="selTransType">
|
||||
<mat-option *ngFor="let transType of transTypes" [value]="transType.id">
|
||||
{{transType.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25" *ngIf="selTransType=='0'">
|
||||
<input matInput placeholder="Channel Opening Priority" disabled>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25" *ngIf="selTransType=='1'">
|
||||
<input matInput [(ngModel)]="transTypeValue.blocks" placeholder="Target Confirmation Blocks" type="number" name="blocks" step="1" min="0" required tabindex="5" #blocks="ngModel">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="25" *ngIf="selTransType=='2'">
|
||||
<input matInput [(ngModel)]="transTypeValue.fees" placeholder="Fee ({{information?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1" min="0" required tabindex="6" #fees="ngModel">
|
||||
</mat-form-field>
|
||||
<mat-checkbox fxFlex="25" fxFlex.lt-lg="35" tabindex="7" [(ngModel)]="spendUnconfirmed" name="spendUnconfirmed">Spend Unconfirmed Output</mat-checkbox>
|
||||
<mat-checkbox fxFlex="20" fxFlex.lt-lg="15" tabindex="8" [(ngModel)]="isPrivate" name="isPrivate">Private</mat-checkbox>
|
||||
</span>
|
||||
<div fxFlex="10" fxLayoutAlign="end start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="selectedPeer === '' || fundingAmount == null || (totalBalance - ((fundingAmount) ? fundingAmount : 0) < 0)" type="submit" tabindex="8">
|
||||
<p *ngIf="(selectedPeer === '' || fundingAmount == null) && (selPeer.touched || selPeer.dirty) && (amount.touched || amount.dirty); else openText">Invalid Values</p>
|
||||
<ng-template #openText><p>Open</p></ng-template>
|
||||
</button>
|
||||
</div>
|
||||
<div fxFlex="10" fxLayoutAlign="end start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="9" type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content fxFlex="100" fxLayout="column">
|
||||
<div fxLayout="row" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="channels" matSort [ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
|
||||
<ng-container matColumnDef="close">
|
||||
<th mat-header-cell *matHeaderCellDef> Close Channel </th>
|
||||
<td mat-cell *matCellDef="let channel"><mat-icon color="accent" (click)="onChannelClose(channel)">link_off</mat-icon></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="update">
|
||||
<th mat-header-cell *matHeaderCellDef><mat-icon color="accent" (click)="onChannelUpdate('all')">edit</mat-icon></th>
|
||||
<td mat-cell *matCellDef="let channel"><mat-icon color="accent" (click)="onChannelUpdate(channel)">edit</mat-icon></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="active">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Status </th>
|
||||
<td mat-cell *matCellDef="let channel"> {{(channel.active) ? 'Active' : 'Inactive'}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chan_id">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
|
||||
<td mat-cell *matCellDef="let channel"> {{channel.chan_id}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="remote_pubkey">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Pub Key </th>
|
||||
<td mat-cell *matCellDef="let channel">
|
||||
<div>{{channel.remote_pubkey | slice:0:10}}...</div></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="remote_alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Alias </th>
|
||||
<td mat-cell *matCellDef="let channel">{{channel.remote_alias}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="capacity">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Capacity </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.capacity | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="local_balance">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Local Bal </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.local_balance | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="remote_balance">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Remote Bal </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.remote_balance | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="total_satoshis_sent">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> {{information?.smaller_currency_unit}} Sent </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.total_satoshis_sent | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="total_satoshis_received">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> {{information?.smaller_currency_unit}} Recv </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.total_satoshis_received | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="commit_fee">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Fee </th>
|
||||
<td mat-cell *matCellDef="let channel"><span fxLayoutAlign="end center"> {{channel.commit_fee | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="private">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Private </th>
|
||||
<td mat-cell *matCellDef="let channel"> {{(channel.private ? 'Private' : 'Public')}} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onChannelClick(row, $event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<h3>CHANNELS</h3>
|
@ -0,0 +1,67 @@
|
||||
.mat-column-close, .mat-column-update, .mat-column-active, .mat-column-private {
|
||||
flex: 0 0 6%;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.mat-column-private {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.mat-cell.mat-column-close, .mat-column-update {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mat-column-chan_id {
|
||||
flex: 0 0 16%;
|
||||
min-width: 160px;
|
||||
}
|
||||
|
||||
.mat-checkbox-inner-container:focus, .mat-checkbox-input:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.size-40 {
|
||||
font-size: 40px;
|
||||
margin-left: -30%;
|
||||
}
|
||||
|
||||
.mat-button-text {
|
||||
font-size: 24px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.flex-ellipsis {
|
||||
padding-right: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.chkbox-options:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.flip {
|
||||
position: relative;
|
||||
backface-visibility: hidden;
|
||||
animation: spin 1.5s cubic-bezier(.175, .885, .32, 1.275) 2;
|
||||
transform-style: preserve-3d;
|
||||
transform: rotateX(0deg);
|
||||
}
|
||||
|
||||
@-moz-keyframes spin {
|
||||
from { -moz-transform: rotateX(0deg); }
|
||||
to { -moz-transform: rotateX(360deg); }
|
||||
}
|
||||
@-webkit-keyframes spin {
|
||||
from { -webkit-transform: rotateX(0deg); }
|
||||
to { -webkit-transform: rotateX(360deg); }
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform:rotateX(0deg); }
|
||||
to { transform:rotateX(360deg); }
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLChannelsComponent } from './channels.component';
|
||||
|
||||
describe('CLChannelsComponent', () => {
|
||||
let component: CLChannelsComponent;
|
||||
let fixture: ComponentFixture<CLChannelsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLChannelsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLChannelsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,266 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Router, NavigationStart, ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { Subject, Observable } from 'rxjs';
|
||||
import { takeUntil, filter, map, subscribeOn } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { ChannelCL, PeerCL, GetInfoCL } from '../../shared/models/clModels';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
|
||||
import { CLEffects } from '../store/cl.effects';
|
||||
import { RTLEffects } from '../../store/rtl.effects';
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-channels',
|
||||
templateUrl: './channels.component.html',
|
||||
styleUrls: ['./channels.component.scss']
|
||||
})
|
||||
export class CLChannelsComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
public totalBalance = 0;
|
||||
public selectedPeer = '';
|
||||
public fundingAmount: number;
|
||||
public displayedColumns = [];
|
||||
public channels: any;
|
||||
public peers: PeerCL[] = [];
|
||||
public information: GetInfoCL = {};
|
||||
public flgLoading: Array<Boolean | 'error'> = [true];
|
||||
public selectedFilter = '';
|
||||
public myChanPolicy: any = {};
|
||||
public selFilter = '';
|
||||
public transTypes = [{id: '0', name: 'Default Priority'}, {id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
|
||||
public selTransType = '0';
|
||||
public transTypeValue = {blocks: '', fees: ''};
|
||||
public spendUnconfirmed = false;
|
||||
public isPrivate = false;
|
||||
public moreOptions = false;
|
||||
public flgSticky = false;
|
||||
public redirectedWithPeer = false;
|
||||
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
ngOnInit() {}
|
||||
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private clEffects: CLEffects, private activatedRoute: ActivatedRoute) {
|
||||
// switch (true) {
|
||||
// case (window.innerWidth <= 415):
|
||||
// this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias'];
|
||||
// break;
|
||||
// case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
// this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias', 'capacity'];
|
||||
// break;
|
||||
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
// this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias', 'capacity', 'local_balance', 'remote_balance'];
|
||||
// break;
|
||||
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias', 'capacity', 'local_balance', 'remote_balance', 'total_satoshis_sent',
|
||||
// 'total_satoshis_received', 'commit_fee', 'private'];
|
||||
// break;
|
||||
// default:
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_pubkey', 'remote_alias', 'capacity', 'local_balance', 'remote_balance',
|
||||
// 'total_satoshis_sent', 'total_satoshis_received', 'commit_fee', 'private'];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ngOnInit() {
|
||||
// this.store.select('cl')
|
||||
// .pipe(takeUntil(this.unsub[0]))
|
||||
// .subscribe((rtlStore) => {
|
||||
// rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
// if (effectsErr.action === 'FetchChannels/all') {
|
||||
// this.flgLoading[0] = 'error';
|
||||
// }
|
||||
// });
|
||||
// this.information = rtlStore.information;
|
||||
// this.peers = rtlStore.peers;
|
||||
// this.peers.forEach(peer => {
|
||||
// if (undefined === peer.alias || peer.alias === '') {
|
||||
// peer.alias = peer.pub_key.substring(0, 15) + '...';
|
||||
// }
|
||||
// });
|
||||
|
||||
// this.totalBalance = +rtlStore.blockchainBalance.total_balance;
|
||||
// if (undefined !== rtlStore.allChannels) {
|
||||
// this.loadChannelsTable(rtlStore.allChannels);
|
||||
// }
|
||||
// if (this.flgLoading[0] !== 'error') {
|
||||
// this.flgLoading[0] = (undefined !== rtlStore.allChannels) ? false : true;
|
||||
// }
|
||||
// this.logger.info(rtlStore);
|
||||
// });
|
||||
// this.activatedRoute.paramMap.subscribe(() => {
|
||||
// this.selectedPeer = window.history.state.peer;
|
||||
// this.redirectedWithPeer = (window.history.state.peer) ? true : false;
|
||||
// });
|
||||
// }
|
||||
|
||||
// onOpenChannel(form: any) {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Opening Channel...'));
|
||||
// let transTypeValue = '0';
|
||||
// if (this.selTransType === '1') {
|
||||
// transTypeValue = this.transTypeValue.blocks;
|
||||
// } else if (this.selTransType === '2') {
|
||||
// transTypeValue = this.transTypeValue.fees;
|
||||
// }
|
||||
// this.store.dispatch(new RTLActions.SaveNewChannel({
|
||||
// selectedPeerPubkey: this.selectedPeer, fundingAmount: this.fundingAmount, private: this.isPrivate,
|
||||
// transType: this.selTransType, transTypeValue: transTypeValue, spendUnconfirmed: this.spendUnconfirmed
|
||||
// }));
|
||||
// }
|
||||
|
||||
// onChannelUpdate(channelToUpdate: any) {
|
||||
// if (channelToUpdate === 'all') {
|
||||
// const titleMsg = 'Updated Values for ALL Channels';
|
||||
// const confirmationMsg = {};
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data: {
|
||||
// type: 'CONFIRM', titleMessage: titleMsg, noBtnText: 'Cancel', yesBtnText: 'Update', message: JSON.stringify(confirmationMsg), flgShowInput: true, getInputs: [
|
||||
// {placeholder: 'Base Fee msat', inputType: 'number', inputValue: 1000},
|
||||
// {placeholder: 'Fee Rate mili msat', inputType: 'number', inputValue: 1, min: 1},
|
||||
// {placeholder: 'Time Lock Delta', inputType: 'number', inputValue: 144}
|
||||
// ]
|
||||
// }}));
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(takeUntil(this.unsub[2]))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// const base_fee = confirmRes[0].inputValue;
|
||||
// const fee_rate = confirmRes[1].inputValue;
|
||||
// const time_lock_delta = confirmRes[2].inputValue;
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Updating Channel Policy...'));
|
||||
// this.store.dispatch(new RTLActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: 'all'}));
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// this.myChanPolicy = {fee_base_msat: 0, fee_rate_milli_msat: 0, time_lock_delta: 0};
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Fetching Channel Policy...'));
|
||||
// this.store.dispatch(new RTLActions.ChannelLookup(channelToUpdate.chan_id.toString()));
|
||||
// this.clEffects.setLookup
|
||||
// .pipe(takeUntil(this.unsub[3]))
|
||||
// .subscribe(resLookup => {
|
||||
// this.logger.info(resLookup);
|
||||
// if (resLookup.node1_pub === this.information.id) {
|
||||
// this.myChanPolicy = resLookup.node1_policy;
|
||||
// } else if (resLookup.node2_pub === this.information.id) {
|
||||
// this.myChanPolicy = resLookup.node2_policy;
|
||||
// } else {
|
||||
// this.myChanPolicy = {fee_base_msat: 0, fee_rate_milli_msat: 0, time_lock_delta: 0};
|
||||
// }
|
||||
// this.logger.info(this.myChanPolicy);
|
||||
// this.store.dispatch(new RTLActions.CloseSpinner());
|
||||
// const titleMsg = 'Updated Values for Channel Point: ' + channelToUpdate.channel_point;
|
||||
// const confirmationMsg = {};
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data: {
|
||||
// type: 'CONFIRM', titleMessage: titleMsg, noBtnText: 'Cancel', yesBtnText: 'Update', message: JSON.stringify(confirmationMsg), flgShowInput: true, getInputs: [
|
||||
// {placeholder: 'Base Fee msat', inputType: 'number', inputValue: (this.myChanPolicy.fee_base_msat === '') ? 0 : this.myChanPolicy.fee_base_msat},
|
||||
// {placeholder: 'Fee Rate mili msat', inputType: 'number', inputValue: this.myChanPolicy.fee_rate_milli_msat, min: 1},
|
||||
// {placeholder: 'Time Lock Delta', inputType: 'number', inputValue: this.myChanPolicy.time_lock_delta}
|
||||
// ]
|
||||
// }}));
|
||||
// });
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(takeUntil(this.unsub[2]))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// const base_fee = confirmRes[0].inputValue;
|
||||
// const fee_rate = confirmRes[1].inputValue;
|
||||
// const time_lock_delta = confirmRes[2].inputValue;
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Updating Channel Policy...'));
|
||||
// this.store.dispatch(new RTLActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: channelToUpdate.channel_point}));
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// this.applyFilter();
|
||||
// }
|
||||
|
||||
// onChannelClose(channelToClose: ChannelCL) {
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({
|
||||
// width: '70%', data: { type: 'CONFIRM', titleMessage: 'Closing channel: ' + channelToClose.chan_id, noBtnText: 'Cancel', yesBtnText: 'Close Channel'
|
||||
// }}));
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(takeUntil(this.unsub[1]))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Closing Channel...'));
|
||||
// this.store.dispatch(new RTLActions.CloseChannel({channelPoint: channelToClose.channel_point, forcibly: !channelToClose.active}));
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// applyFilter() {
|
||||
// this.selectedFilter = this.selFilter;
|
||||
// this.channels.filter = this.selFilter;
|
||||
// }
|
||||
|
||||
// onChannelClick(selRow: ChannelCL, event: any) {
|
||||
// const flgCloseClicked =
|
||||
// event.target.className.includes('mat-column-close')
|
||||
// || event.target.className.includes('mat-column-update')
|
||||
// || event.target.className.includes('mat-icon');
|
||||
// if (flgCloseClicked) {
|
||||
// return;
|
||||
// }
|
||||
// const selChannel = this.channels.data.filter(channel => {
|
||||
// return channel.chan_id === selRow.chan_id;
|
||||
// })[0];
|
||||
// const reorderedChannel = JSON.parse(JSON.stringify(selChannel, [
|
||||
// 'active', 'remote_pubkey', 'remote_alias', 'channel_point', 'chan_id', 'capacity', 'local_balance', 'remote_balance', 'commit_fee', 'commit_weight',
|
||||
// 'fee_per_kw', 'unsettled_balance', 'total_satoshis_sent', 'total_satoshis_received', 'num_updates', 'pending_htlcs', 'csv_delay', 'private'
|
||||
// ] , 2));
|
||||
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
|
||||
// type: 'INFO',
|
||||
// message: JSON.stringify(reorderedChannel)
|
||||
// }}));
|
||||
// }
|
||||
|
||||
// loadChannelsTable(channels) {
|
||||
// channels.sort(function(a, b) {
|
||||
// return (a.active === b.active) ? 0 : ((b.active) ? 1 : -1);
|
||||
// });
|
||||
// this.channels = new MatTableDataSource<ChannelCL>([...channels]);
|
||||
// this.channels.sort = this.sort;
|
||||
// this.channels.filterPredicate = (channel: ChannelCL, fltr: string) => {
|
||||
// const newChannel = ((channel.active) ? 'active' : 'inactive') + (channel.chan_id ? channel.chan_id : '') +
|
||||
// (channel.remote_pubkey ? channel.remote_pubkey : '') + (channel.remote_alias ? channel.remote_alias : '') +
|
||||
// (channel.capacity ? channel.capacity : '') + (channel.local_balance ? channel.local_balance : '') +
|
||||
// (channel.remote_balance ? channel.remote_balance : '') + (channel.total_satoshis_sent ? channel.total_satoshis_sent : '') +
|
||||
// (channel.total_satoshis_received ? channel.total_satoshis_received : '') + (channel.commit_fee ? channel.commit_fee : '') +
|
||||
// (channel.private ? 'private' : 'public');
|
||||
// return newChannel.includes(fltr);
|
||||
// };
|
||||
// this.logger.info(this.channels);
|
||||
// }
|
||||
|
||||
// resetData() {
|
||||
// this.selectedPeer = '';
|
||||
// this.fundingAmount = 0;
|
||||
// this.moreOptions = false;
|
||||
// this.spendUnconfirmed = false;
|
||||
// this.isPrivate = false;
|
||||
// this.selTransType = '0';
|
||||
// this.transTypeValue = {blocks: '', fees: ''};
|
||||
// this.redirectedWithPeer = false;
|
||||
// }
|
||||
|
||||
// onMoreOptionsChange(event: any) {
|
||||
// if (!event.checked) {
|
||||
// this.spendUnconfirmed = false;
|
||||
// this.isPrivate = false;
|
||||
// this.selTransType = '0';
|
||||
// this.transTypeValue = {blocks: '', fees: ''};
|
||||
// }
|
||||
// }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsub.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Invoices</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign.gt-sm="space-between center" (ngSubmit)="addInvoiceForm.form.valid && onAddInvoice(addInvoiceForm)" #addInvoiceForm="ngForm">
|
||||
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
|
||||
<input matInput [(ngModel)]="memo" placeholder="Memo" tabindex="1" name="memo">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="15" fxLayoutAlign="start end">
|
||||
<input matInput [(ngModel)]="invoiceValue" placeholder="Invoice Value ({{information?.smaller_currency_unit}})" type="number" step="100" min="1" tabindex="2" name="invoiceValue">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="15" fxLayoutAlign="start end">
|
||||
<input matInput [(ngModel)]="expiry" placeholder="Expiry (Sec)" type="number" step="100" min="1" tabindex="3" name="expiry">
|
||||
</mat-form-field>
|
||||
<div fxFlex="15" tabindex="4" fxLayoutAlign="start center" class="chkbox-private">
|
||||
<mat-checkbox [(ngModel)]="private" matTooltip="Include routing hints for private channels" [matTooltipPosition]="'above'" name="private">Private</mat-checkbox>
|
||||
</div>
|
||||
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit" tabindex="5">Add</button>
|
||||
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="6" type="reset" (click)="resetData()">Clear</button>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content class="table-card-content">
|
||||
<div fxLayout="row" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="invoices" matSort [ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
|
||||
<ng-container matColumnDef="settled">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Settled </th>
|
||||
<td mat-cell *matCellDef="let invoice">
|
||||
<span *ngIf="invoice.settled"><i class="material-icons primary">done_all</i></span>
|
||||
<span *ngIf="!invoice.settled"><i class="material-icons accent">done</i></span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="creation_date">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Creation Date </th>
|
||||
<td mat-cell *matCellDef="let invoice">{{invoice.creation_date_str}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="settle_date">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Settle Date </th>
|
||||
<td mat-cell *matCellDef="let invoice">{{invoice.settle_date_str}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="memo">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Memo </th>
|
||||
<td mat-cell *matCellDef="let invoice">{{invoice.memo}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Value ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}}) </th>
|
||||
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{(selNode?.satsToBTC) ? (invoice?.btc_value | number:'1.0-3') : (invoice?.value | number)}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="expiry">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Expiry (Sec)</th>
|
||||
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.expiry | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="cltv_expiry">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> CLTV Expiry </th>
|
||||
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{invoice.cltv_expiry | number}} </span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="amt_paid_sat">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount Paid ({{(selNode?.satsToBTC) ? information?.currency_unit : information?.smaller_currency_unit}})</th>
|
||||
<td mat-cell *matCellDef="let invoice"><span fxLayoutAlign="end center"> {{(selNode?.satsToBTC) ? (invoice?.btc_amt_paid_sat | number:'1.0-3') : (invoice?.amt_paid_sat | number)}} </span></td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.memo == newlyAddedInvoiceMemo && row.value == newlyAddedInvoiceValue && flgAnimate) ? 'added' : 'notAdded'" (click)="onInvoiceClick(row, $event)" class="row-invoices"
|
||||
[ngClass]="{'settled': row.settled, 'unsettled': !row.settled}"></tr>
|
||||
</table>
|
||||
<mat-paginator [length]="totalInvoices" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" (page)="onPageChange($event)"></mat-paginator>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>INVOICES</h3>
|
@ -0,0 +1,16 @@
|
||||
.mat-column-value {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.mat-column-settled {
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.chkbox-private:focus {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
border-collapse: collapse;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLInvoicesComponent } from './invoices.component';
|
||||
|
||||
describe('CLInvoicesComponent', () => {
|
||||
let component: CLInvoicesComponent;
|
||||
let fixture: ComponentFixture<CLInvoicesComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLInvoicesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLInvoicesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,165 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { SelNodeChild } from '../../shared/models/RTLconfig';
|
||||
import { GetInfoCL, InvoiceCL } from '../../shared/models/clModels';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
|
||||
import { newlyAddedRowAnimation } from '../../shared/animation/row-animation';
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-invoices',
|
||||
templateUrl: './invoices.component.html',
|
||||
styleUrls: ['./invoices.component.scss'],
|
||||
animations: [newlyAddedRowAnimation]
|
||||
})
|
||||
export class CLInvoicesComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
public selNode: SelNodeChild = {};
|
||||
public newlyAddedInvoiceMemo = '';
|
||||
public newlyAddedInvoiceValue = 0;
|
||||
public flgAnimate = true;
|
||||
public memo = '';
|
||||
public expiry: number;
|
||||
public invoiceValue: number;
|
||||
public displayedColumns = [];
|
||||
public invoicePaymentReq = '';
|
||||
public invoices: any;
|
||||
public information: GetInfoCL = {};
|
||||
public flgLoading: Array<Boolean | 'error'> = [true];
|
||||
public flgSticky = false;
|
||||
public private = false;
|
||||
public totalInvoices = 100;
|
||||
public pageSize = 25;
|
||||
public pageSizeOptions = [5, 10, 25, 100];
|
||||
private firstOffset = -1;
|
||||
private lastOffset = -1;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
ngOnInit() {}
|
||||
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
|
||||
// switch (true) {
|
||||
// case (window.innerWidth <= 415):
|
||||
// this.displayedColumns = ['settled', 'creation_date', 'memo', 'value'];
|
||||
// break;
|
||||
// case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat'];
|
||||
// break;
|
||||
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat'];
|
||||
// break;
|
||||
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat', 'expiry', 'cltv_expiry'];
|
||||
// break;
|
||||
// default:
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['settled', 'creation_date', 'settle_date', 'memo', 'value', 'amt_paid_sat', 'expiry', 'cltv_expiry'];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ngOnInit() {
|
||||
// this.store.select('cl')
|
||||
// .pipe(takeUntil(this.unSubs[0]))
|
||||
// .subscribe((rtlStore) => {
|
||||
// rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
// if (effectsErr.action === 'FetchInvoices') {
|
||||
// this.flgLoading[0] = 'error';
|
||||
// }
|
||||
// });
|
||||
// this.selNode = rtlStore.nodeSettings;
|
||||
// this.information = rtlStore.information;
|
||||
// this.totalInvoices = rtlStore.totalInvoices;
|
||||
// this.firstOffset = +rtlStore.invoices.first_index_offset;
|
||||
// this.lastOffset = +rtlStore.invoices.last_index_offset;
|
||||
// this.logger.info(rtlStore);
|
||||
// this.loadInvoicesTable(rtlStore.invoices.invoices);
|
||||
// if (this.flgLoading[0] !== 'error') {
|
||||
// this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
|
||||
// }
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// onAddInvoice(form: any) {
|
||||
// this.flgAnimate = true;
|
||||
// this.newlyAddedInvoiceMemo = this.memo;
|
||||
// this.newlyAddedInvoiceValue = this.invoiceValue;
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Adding Invoice...'));
|
||||
// this.store.dispatch(new RTLActions.SaveNewInvoice({
|
||||
// memo: this.memo, invoiceValue: this.invoiceValue, private: this.private, expiry: (this.expiry ? this.expiry : 3600), pageSize: this.pageSize
|
||||
// }));
|
||||
// this.resetData();
|
||||
// }
|
||||
|
||||
// onInvoiceClick(selRow: Invoice, event: any) {
|
||||
// const selInvoice = this.invoices.data.filter(invoice => {
|
||||
// return invoice.payment_request === selRow.payment_request;
|
||||
// })[0];
|
||||
// const reorderedInvoice = JSON.parse(JSON.stringify(selInvoice, [
|
||||
// 'settled', 'creation_date_str', 'settle_date_str', 'memo', 'receipt', 'r_preimage', 'r_hash', 'value', 'payment_request',
|
||||
// 'description_hash', 'expiry', 'fallback_addr', 'cltv_expiry', 'route_hints', 'private', 'add_index', 'settle_index',
|
||||
// 'amt_paid', 'amt_paid_sat', 'amt_paid_msat'
|
||||
// ] , 2));
|
||||
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
|
||||
// type: 'INFO',
|
||||
// message: JSON.stringify(reorderedInvoice)
|
||||
// }}));
|
||||
// }
|
||||
|
||||
// loadInvoicesTable(invoices) {
|
||||
// this.invoices = new MatTableDataSource<Invoice>([...invoices]);
|
||||
// this.invoices.sort = this.sort;
|
||||
// this.invoices.data.forEach(invoice => {
|
||||
// if (undefined !== invoice.creation_date_str) {
|
||||
// invoice.creation_date_str = (invoice.creation_date_str === '') ? '' : formatDate(invoice.creation_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// }
|
||||
// if (undefined !== invoice.settle_date_str) {
|
||||
// invoice.settle_date_str = (invoice.settle_date_str === '') ? '' : formatDate(invoice.settle_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// }
|
||||
// });
|
||||
// setTimeout(() => { this.flgAnimate = false; }, 30000);
|
||||
// this.logger.info(this.invoices);
|
||||
// }
|
||||
|
||||
// resetData() {
|
||||
// this.memo = '';
|
||||
// this.invoiceValue = 0;
|
||||
// this.private = false;
|
||||
// this.expiry = undefined;
|
||||
// }
|
||||
|
||||
// applyFilter(selFilter: string) {
|
||||
// this.invoices.filter = selFilter;
|
||||
// }
|
||||
|
||||
// onPageChange(event: any) {
|
||||
// let reversed = true;
|
||||
// let index_offset = this.firstOffset;
|
||||
// if (event.pageIndex < event.previousPageIndex) {
|
||||
// reversed = false;
|
||||
// index_offset = this.lastOffset;
|
||||
// }
|
||||
// if (event.pageIndex === event.previousPageIndex) {
|
||||
// reversed = true;
|
||||
// index_offset = 0;
|
||||
// }
|
||||
// this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: event.pageSize, index_offset: index_offset, reversed: reversed}));
|
||||
// }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
.mat-list-base .mat-list-item, .mat-list-base .mat-list-option {
|
||||
height: 38px !important;
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
<!-- <div fxLayout="column" fxLayout.gt-sm="row wrap">
|
||||
<mat-card fxFlex="100" fxLayoutAlign="start start">
|
||||
<mat-card-content fxFlex="100" *ngIf="lookupResult">
|
||||
<mat-list fxLayoutAlign="space-between start">
|
||||
<mat-list-item fxFlex="30" fxLayoutAlign="start start">Channel Id</mat-list-item>
|
||||
<mat-list-item fxFlex="68" fxLayoutAlign="start start">{{lookupResult.channel_id}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="space-between start">
|
||||
<mat-list-item fxFlex="30" fxLayoutAlign="start start">Channel Point</mat-list-item>
|
||||
<mat-list-item fxFlex="68" fxLayoutAlign="start start" class="word-break">{{lookupResult.chan_point}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="space-between start">
|
||||
<mat-list-item fxFlex="30" fxLayoutAlign="start start">Last Update</mat-list-item>
|
||||
<mat-list-item fxFlex="68" fxLayoutAlign="start start">{{lookupResult.last_update_str}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="space-between start">
|
||||
<mat-list-item fxFlex="30" fxLayoutAlign="start start">Capacity (Sats)</mat-list-item>
|
||||
<mat-list-item fxFlex="68" fxLayoutAlign="start start">{{lookupResult.capacity | number}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayoutAlign="space-between start" fxLayout.gt-sm="row wrap" class="mt-2">
|
||||
<div fxFlex="48">
|
||||
<mat-card class="custom-card mat-elevation-z12">
|
||||
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
|
||||
<mat-card-title class="m-0 pt-2">
|
||||
<h5 *ngIf="!node1_match">Node 1</h5>
|
||||
<h5 *ngIf="node1_match">Node 1 (Your Node)</h5>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="px-2">
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="100" fxLayoutAlign="start start" class="word-break">{{lookupResult.node1_pub}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Time Lock Delta</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node1_policy.time_lock_delta}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Min HTLC</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node1_policy.min_htlc}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Fee Base Msat</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node1_policy.fee_base_msat}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Fee Rate Milli Msat</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node1_policy.fee_rate_milli_msat}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Disabled</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node1_policy.disabled}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxFlex="48">
|
||||
<mat-card class="custom-card mat-elevation-z12">
|
||||
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
|
||||
<mat-card-title class="m-0 pt-2">
|
||||
<h5 *ngIf="!node2_match">Node 2</h5>
|
||||
<h5 *ngIf="node2_match">Node 2 (Your Node)</h5>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content class="px-2">
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="100" fxLayoutAlign="start start" class="word-break">{{lookupResult.node2_pub}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Time Lock Delta</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node2_policy.time_lock_delta}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Min HTLC</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node2_policy.min_htlc}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Fee Base Msat</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node2_policy.fee_base_msat}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Fee Rate Milli Msat</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node2_policy.fee_rate_milli_msat}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Disabled</mat-list-item>
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">{{lookupResult.node2_policy.disabled}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div> -->
|
||||
<h3>CHANNEL LOOKUP</h3>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLChannelLookupComponent } from './channel-lookup.component';
|
||||
|
||||
describe('CLChannelLookupComponent', () => {
|
||||
let component: CLChannelLookupComponent;
|
||||
let fixture: ComponentFixture<CLChannelLookupComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLChannelLookupComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLChannelLookupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,40 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { ChannelEdgeCL } from '../../../shared/models/clModels';
|
||||
import * as fromRTLReducer from '../../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-channel-lookup',
|
||||
templateUrl: './channel-lookup.component.html',
|
||||
styleUrls: ['./channel-lookup.component.css']
|
||||
})
|
||||
export class CLChannelLookupComponent implements OnInit {
|
||||
@Input() lookupResult: ChannelEdgeCL;
|
||||
public node1_match = false;
|
||||
public node2_match = false;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private store: Store<fromRTLReducer.RTLState>) { }
|
||||
|
||||
ngOnInit() {
|
||||
if (undefined !== this.lookupResult && undefined !== this.lookupResult.last_update_str) {
|
||||
this.lookupResult.last_update_str = (this.lookupResult.last_update_str === '') ?
|
||||
'' : formatDate(this.lookupResult.last_update_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
}
|
||||
this.store.select('cl')
|
||||
.pipe(takeUntil(this.unSubs[0]))
|
||||
.subscribe((rtlStore) => {
|
||||
if (this.lookupResult.node1_pub === rtlStore.information.id) {
|
||||
this.node1_match = true;
|
||||
}
|
||||
if (this.lookupResult.node2_pub === rtlStore.information.id) {
|
||||
this.node2_match = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Lookups</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayout.gt-sm="row wrap" #form="ngForm">
|
||||
<mat-form-field fxFlex="20" fxLayoutAlign="start end">
|
||||
<mat-select [(ngModel)]="selectedField" placeholder="Lookup Field" (selectionChange)="onSelectChange($event)" tabindex="1" required name="lookupField">
|
||||
<mat-option *ngFor="let lookupField of lookupFields" [value]="lookupField">
|
||||
{{lookupField.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="50" fxLayoutAlign="start end">
|
||||
<input matInput name="lookupKey" [placeholder]="selectedField?.placeholder || 'Lookup Key'" (change)="clearLookupValue()" [(ngModel)]="lookupKey" tabindex="2" required>
|
||||
</mat-form-field>
|
||||
<div fxFlex="12" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="3" type="submit" (click)="onLookup()" [disabled]="!form.valid">Lookup</button>
|
||||
</div>
|
||||
<div fxFlex="12" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="4" type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap" *ngIf="lookupValue && flgSetLookupValue">
|
||||
<mat-card [ngClass]="{'error-border': flgLoading[0]==='error'}">
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>{{selectedField.name}} Details</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div [ngSwitch]="selectedField.id">
|
||||
<span *ngSwitchCase="0"><rtl-node-lookup [lookupResult]="lookupValue"></rtl-node-lookup></span>
|
||||
<span *ngSwitchCase="1"><rtl-channel-lookup [lookupResult]="lookupValue"></rtl-channel-lookup></span>
|
||||
<span *ngSwitchDefault><h3>Error! Unable to find details!</h3></span>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>LOOKUP</h3>
|
@ -0,0 +1,14 @@
|
||||
.tree-invisible {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lookup-tree ul,
|
||||
.lookup-tree li {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.pl-3 {
|
||||
padding-left: 3rem;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLLookupsComponent } from './lookups.component';
|
||||
|
||||
describe('CLLookupsComponent', () => {
|
||||
let component: CLLookupsComponent;
|
||||
let fixture: ComponentFixture<CLLookupsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLLookupsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLLookupsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,94 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, filter } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-lookups',
|
||||
templateUrl: './lookups.component.html',
|
||||
styleUrls: ['./lookups.component.scss']
|
||||
})
|
||||
export class CLLookupsComponent implements OnInit, OnDestroy {
|
||||
public lookupKey = '';
|
||||
public lookupValue = {};
|
||||
public flgSetLookupValue = false;
|
||||
public temp: any;
|
||||
public messageObj = [];
|
||||
public selectedField = { id: '0', name: 'Node', placeholder: 'Pubkey'};
|
||||
public lookupFields = [
|
||||
{ id: '0', name: 'Node', placeholder: 'Pubkey'},
|
||||
{ id: '1', name: 'Channel', placeholder: 'Channel ID'}
|
||||
];
|
||||
public flgLoading: Array<Boolean | 'error'> = [true];
|
||||
private unSubs: Array<Subject<void>> = [new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.actions$
|
||||
.pipe(
|
||||
takeUntil(this.unSubs[0]),
|
||||
filter((action) => (action.type === RTLActions.SET_LOOKUP || action.type === RTLActions.EFFECT_ERROR_CL))
|
||||
).subscribe((resLookup: RTLActions.SetLookup) => {
|
||||
if (resLookup.payload.action === 'Lookup') {
|
||||
this.flgLoading[0] = 'error';
|
||||
} else {
|
||||
this.flgLoading[0] = true;
|
||||
this.lookupValue = JSON.parse(JSON.stringify(resLookup.payload));
|
||||
this.flgSetLookupValue = true;
|
||||
this.logger.info(this.lookupValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onLookup() {
|
||||
this.flgSetLookupValue = false;
|
||||
this.lookupValue = {};
|
||||
this.store.dispatch(new RTLActions.OpenSpinner('Searching ' + this.selectedField.name + '...'));
|
||||
switch (this.selectedField.id) {
|
||||
case '0':
|
||||
this.store.dispatch(new RTLActions.PeerLookup(this.lookupKey.trim()));
|
||||
break;
|
||||
case '1':
|
||||
this.store.dispatch(new RTLActions.ChannelLookup(this.lookupKey.trim()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onSelectChange(event: any) {
|
||||
this.flgSetLookupValue = false;
|
||||
this.lookupKey = '';
|
||||
this.lookupValue = {};
|
||||
}
|
||||
|
||||
resetData() {
|
||||
this.flgSetLookupValue = false;
|
||||
this.lookupKey = '';
|
||||
this.selectedField = { id: '0', name: 'Node', placeholder: 'Pubkey'};
|
||||
this.lookupValue = {};
|
||||
this.flgLoading.forEach((flg, i) => {
|
||||
this.flgLoading[i] = true;
|
||||
});
|
||||
}
|
||||
|
||||
clearLookupValue() {
|
||||
this.lookupValue = {};
|
||||
this.flgSetLookupValue = false;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
.mat-table {
|
||||
width:99%;
|
||||
}
|
||||
|
||||
.mat-list-base .mat-list-item, .mat-list-base .mat-list-option {
|
||||
height: 38px !important;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content *ngIf="lookupResult">
|
||||
<div fxLayout="column">
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Alias</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start">{{lookupResult.node.alias}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Pub Key</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start">{{lookupResult.node.pub_key}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Color</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start"><span [ngStyle]="{'background-color': lookupResult.node?.color}">{{lookupResult.node?.color}}</span></mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Last Update</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start">{{lookupResult.node.last_update_str}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Total Capacity (Sats)</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start">{{lookupResult.total_capacity | number}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayoutAlign="start start">
|
||||
<mat-list-item fxFlex="50" fxLayoutAlign="start start">Number of Channels</mat-list-item>
|
||||
<mat-list-item fxFlex="40" fxLayoutAlign="start start">{{lookupResult.num_channels | number}}</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-list>
|
||||
<mat-list fxLayout="column" fxLayoutAlign="start start">
|
||||
<mat-divider></mat-divider>
|
||||
<mat-list-item fxFlex="100" fxLayoutAlign="start start">Addresses</mat-list-item>
|
||||
<mat-table [dataSource]="lookupResult.node.addresses" matSort class="mat-elevation-z8 overflow-auto">
|
||||
<ng-container matColumnDef="network">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Network</mat-header-cell>
|
||||
<mat-cell *matCellDef="let address"><div>{{address?.network}}</div></mat-cell>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="addr">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Address</mat-header-cell>
|
||||
<mat-cell *matCellDef="let address"><div>{{address?.addr}}</div></mat-cell>
|
||||
</ng-container>
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns;"></mat-header-row>
|
||||
<mat-row fxLayoutAlign="stretch stretch" *matRowDef="let row; columns: displayedColumns;"></mat-row>
|
||||
</mat-table>
|
||||
</mat-list>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>NODE LOOKUP</h3>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLNodeLookupComponent } from './node-lookup.component';
|
||||
|
||||
describe('CLNodeLookupComponent', () => {
|
||||
let component: CLNodeLookupComponent;
|
||||
let fixture: ComponentFixture<CLNodeLookupComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLNodeLookupComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLNodeLookupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,24 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
|
||||
import { GraphNodeCL } from '../../../shared/models/clModels';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-node-lookup',
|
||||
templateUrl: './node-lookup.component.html',
|
||||
styleUrls: ['./node-lookup.component.css']
|
||||
})
|
||||
export class CLNodeLookupComponent implements OnInit {
|
||||
@Input() lookupResult: GraphNodeCL;
|
||||
public displayedColumns = ['network', 'addr'];
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
if (undefined !== this.lookupResult && undefined !== this.lookupResult.node && undefined !== this.lookupResult.node.last_update_str) {
|
||||
this.lookupResult.node.last_update_str = (this.lookupResult.node.last_update_str === '') ?
|
||||
'' : formatDate(this.lookupResult.node.last_update_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
<div fxLayout="column" fxLayoutAlign="center center" class="test-banner mx-1">
|
||||
<h5>Don't be #reckless. #craefulgang #craefulgang #craefulgang.</h5>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayout.gt-sm="row wrap">
|
||||
<div fxFlex="34" class="padding-gap">
|
||||
<mat-card [ngClass]="{'custom-card error-border': flgLoadingWallet==='error','custom-card': true}">
|
||||
<mat-card-header class="bg-primary p-1" fxLayoutAlign="center center">
|
||||
<mat-card-title class="m-0 pt-1">
|
||||
<h5>Total Balance</h5>
|
||||
<mat-progress-bar *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
|
||||
<mat-card-content class="mt-1">
|
||||
<svg style="width:70px;height:70px" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V19A2,2 0 0,1 20,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2M14,6V4H10V6H14Z" />
|
||||
</svg>
|
||||
</mat-card-content>
|
||||
<span *ngIf="information?.currency_unit; else withoutData">
|
||||
<h3 *ngIf="selNode?.satsToBTC; else smallerUnit1">{{balance?.btc_totalBalance | number}} {{information?.currency_unit}}</h3>
|
||||
<ng-template #smallerUnit1><h3>{{balance?.totalBalance | number}} {{information?.smaller_currency_unit}}</h3></ng-template>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxFlex="33" class="padding-gap">
|
||||
<mat-card [ngClass]="{'custom-card error-border': flgLoadingWallet==='error','custom-card': true}">
|
||||
<mat-card-header class="bg-primary p-1" fxLayoutAlign="center center">
|
||||
<mat-card-title class="m-0 pt-1">
|
||||
<h5>Confirmed Balance</h5>
|
||||
<mat-progress-bar *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
|
||||
<mat-card-content class="mt-1">
|
||||
<svg style="width:70px;height:70px" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M10,2H14A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V8A2,2 0 0,1 4,6H8V4A2,2 0 0,1 10,2M14,6V4H10V6H14M10.5,17.5L17.09,10.91L15.68,9.5L10.5,14.67L8.41,12.59L7,14L10.5,17.5Z" />
|
||||
</svg>
|
||||
</mat-card-content>
|
||||
<span *ngIf="information?.currency_unit; else withoutData">
|
||||
<h3 *ngIf="selNode?.satsToBTC; else smallerUnit2">{{balance?.btc_confBalance | number}} {{information?.currency_unit}}</h3>
|
||||
<ng-template #smallerUnit2><h3>{{balance?.confBalance | number}} {{information?.smaller_currency_unit}}</h3></ng-template>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxFlex="33" class="padding-gap">
|
||||
<mat-card [ngClass]="{'custom-card error-border': flgLoadingWallet==='error','custom-card': true}">
|
||||
<mat-card-header class="bg-primary p-1" fxLayoutAlign="center center">
|
||||
<mat-card-title class="m-0 pt-1">
|
||||
<h5>Unconfirmed Balance</h5>
|
||||
<mat-progress-bar *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
|
||||
<mat-card-content class="mt-1">
|
||||
<svg style="width:70px;height:70px" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M14,2A2,2 0 0,1 16,4V6H20A2,2 0 0,1 22,8L10.85,19C10.85,20.1 10.85,19.5 10.85,21H4C2.89,21 2,20.1 2,19V8C2,6.89 2.89,6 4,6H8V4C8,2.89 8.89,2 10,2H14M14,6V4H10V6H14M21.04,12.13C20.9,12.13 20.76,12.19 20.65,12.3L19.65,13.3L21.7,15.35L22.7,14.35C22.92,14.14 22.92,13.79 22.7,13.58L21.42,12.3C21.31,12.19 21.18,12.13 21.04,12.13M19.07,13.88L13,19.94V22H15.06L21.12,15.93L19.07,13.88Z" />
|
||||
</svg>
|
||||
</mat-card-content>
|
||||
<span *ngIf="information?.currency_unit; else withoutData">
|
||||
<h3 *ngIf="selNode?.satsToBTC; else smallerUnit3">{{balance?.btc_unconfBalance | number}} {{information?.currency_unit}}</h3>
|
||||
<ng-template #smallerUnit3><h3>{{balance?.unconfBalance | number}} {{information?.smaller_currency_unit}}</h3></ng-template>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoadingWallet===true" mode="indeterminate"></mat-progress-bar>
|
||||
<mat-divider></mat-divider>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxFlex="100" class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Receive Funds</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div fxLayout="column" fxFlex="100" fxLayout.lt-md="top-minus-25px">
|
||||
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap">
|
||||
<div fxFlex="15" fxLayoutAlign="start end">
|
||||
<mat-form-field fxFlex="99">
|
||||
<mat-select [(ngModel)]="selectedAddress" placeholder="Address Type" name="address_type" tabindex="1">
|
||||
<mat-option *ngFor="let addressType of addressTypes" [value]="addressType">
|
||||
{{addressType.addressTp}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="25" fxLayoutAlign="space-between end">
|
||||
<div fxFlex.gt-md="65" fxFlex.lt-lg="49" fxLayoutAlign="start end">
|
||||
<button fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="undefined === selectedAddress.addressId" (click)="onGenerateAddress()" tabindex="2" class="top-minus-15px">Generate Address</button>
|
||||
</div>
|
||||
<div fxFlex.gt-md="30" fxFlex.lt-lg="49" fxLayoutAlign="start end">
|
||||
<button fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="3" (click)="resetReceiveData()" class="top-minus-15px">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
<div fxFlex="42" fxLayoutAlign="start end">
|
||||
<mat-form-field fxFlex="100">
|
||||
<input matInput [value]="newAddress" placeholder="Generated Address" readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex.lt-lg="40" fxFlex.gt-md="14" fxLayoutAlign="center center">
|
||||
<qrcode [qrdata]="newAddress" [size]="120" [level]="'L'" [allowEmptyString]="true" [ngStyle]="{'visibility': (newAddress === '') ? 'hidden' : 'visible'}" class="top-minus-5px qr-border"></qrcode>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div fxFlex="100" class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Send Funds</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div fxLayout="column" fxLayout.gt-sm="row wrap">
|
||||
<div fxFlex="62" fxLayoutAlign="start end">
|
||||
<mat-form-field fxFlex="99">
|
||||
<input matInput [(ngModel)]="transaction.address" placeholder="{{information?.currency_unit}} Address" tabindex="4" name="address" #address="ngModel">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="38" fxLayoutAlign="start end">
|
||||
<mat-radio-group fxFlex="100" fxLayoutAlign="space-between center" (change)="onOptionChange($event)" [(ngModel)]="flgCustomAmount">
|
||||
<mat-radio-button fxFlex="35" value="0">Sweep All</mat-radio-button>
|
||||
<mat-radio-button fxFlex="60" value="1">
|
||||
<mat-form-field fxFlex="70"><input matInput [(ngModel)]="transaction.amount" (click)="onCustomClicked()" placeholder="Amount ({{information?.smaller_currency_unit}})" name="amount" type="number" step="100" min="0" tabindex="5" #amount="ngModel"></mat-form-field>
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayout.gt-sm="row wrap">
|
||||
<div fxFlex="30" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="99">
|
||||
<mat-select [(value)]="selTransType">
|
||||
<mat-option *ngFor="let transType of transTypes" [value]="transType.id">
|
||||
{{transType.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="30" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="99" *ngIf="selTransType=='1'">
|
||||
<input matInput [(ngModel)]="transaction.blocks" placeholder="Target Confirmation Blocks" type="number" name="blocks" step="1" min="0" required tabindex="6" #blocks="ngModel">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="99" *ngIf="selTransType=='2'">
|
||||
<input matInput [(ngModel)]="transaction.fees" placeholder="Fee ({{information?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1" min="0" required tabindex="7" #fees="ngModel">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="40" fxLayoutAlign="space-between start">
|
||||
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="invalidValues" type="submit" tabindex="8" (click)="onSendFunds()">
|
||||
<p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">Invalid Values</p>
|
||||
<ng-template #sendText><p>Send</p></ng-template>
|
||||
</button>
|
||||
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="9" type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
<ng-template #withoutData><h3>Sats</h3></ng-template>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLOnChainComponent } from './on-chain.component';
|
||||
|
||||
describe('CLOnChainComponent', () => {
|
||||
let component: CLOnChainComponent;
|
||||
let fixture: ComponentFixture<CLOnChainComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLOnChainComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLOnChainComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,183 @@
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, take } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { SelNodeChild } from '../../shared/models/RTLconfig';
|
||||
import { GetInfoCL, BalanceCL, OnChainCL, AddressTypeCL } from '../../shared/models/clModels';
|
||||
import { RTLConfiguration } from '../../shared/models/RTLconfig';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
import * as sha256 from 'sha256';
|
||||
|
||||
import { CLEffects } from '../store/cl.effects';
|
||||
import { RTLEffects } from '../../store/rtl.effects';
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-on-chain',
|
||||
templateUrl: './on-chain.component.html',
|
||||
styleUrls: ['./on-chain.component.scss']
|
||||
})
|
||||
export class CLOnChainComponent implements OnInit, OnDestroy {
|
||||
public selNode: SelNodeChild = {};
|
||||
public appConfig: RTLConfiguration;
|
||||
public addressTypes = [];
|
||||
public flgLoadingWallet: Boolean | 'error' = true;
|
||||
public selectedAddress: AddressTypeCL = {};
|
||||
public balance: BalanceCL = {};
|
||||
public information: GetInfoCL = {};
|
||||
public newAddress = '';
|
||||
public transaction: OnChainCL = {};
|
||||
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
|
||||
public selTransType = '1';
|
||||
public flgCustomAmount = '1';
|
||||
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private clEffects: CLEffects) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.store.select('root')
|
||||
.pipe(takeUntil(this.unsub[0]))
|
||||
.subscribe((rootStore) => {
|
||||
this.appConfig = rootStore.appConfig;
|
||||
this.logger.info(rootStore);
|
||||
});
|
||||
|
||||
this.store.select('cl')
|
||||
.pipe(takeUntil(this.unsub[0]))
|
||||
.subscribe((rtlStore) => {
|
||||
rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
if (effectsErr.action === 'FetchBalanceCL') {
|
||||
this.flgLoadingWallet = 'error';
|
||||
}
|
||||
});
|
||||
this.selNode = rtlStore.nodeSettings;
|
||||
this.information = rtlStore.information;
|
||||
this.addressTypes = rtlStore.addressTypes;
|
||||
|
||||
this.balance = rtlStore.balance;
|
||||
if (undefined === this.balance.totalBalance) {
|
||||
this.balance.totalBalance = '0';
|
||||
}
|
||||
if (undefined === this.balance.confBalance) {
|
||||
this.balance.confBalance = '0';
|
||||
}
|
||||
if (undefined === this.balance.unconfBalance) {
|
||||
this.balance.unconfBalance = '0';
|
||||
}
|
||||
if (this.flgLoadingWallet !== 'error') {
|
||||
this.flgLoadingWallet = false;
|
||||
}
|
||||
|
||||
this.logger.info(rtlStore);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onGenerateAddress() {
|
||||
this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...'));
|
||||
this.store.dispatch(new RTLActions.GetNewAddressCL(this.selectedAddress));
|
||||
this.clEffects.setNewAddressCL
|
||||
.pipe(takeUntil(this.unsub[1]))
|
||||
.subscribe(newAddress => {
|
||||
this.newAddress = newAddress;
|
||||
});
|
||||
}
|
||||
|
||||
onSendFunds() {
|
||||
// const confirmationMsg = {
|
||||
// 'BTC Address': this.transaction.address,
|
||||
// };
|
||||
// if (!+this.flgCustomAmount) {
|
||||
// confirmationMsg['Sweep All'] = 'True';
|
||||
// this.transaction.sendAll = true;
|
||||
// } else {
|
||||
// confirmationMsg['Amount (' + this.information.smaller_currency_unit + ')'] = this.transaction.amount;
|
||||
// this.transaction.sendAll = false;
|
||||
// }
|
||||
// if (this.selTransType === '1') {
|
||||
// delete this.transaction.fees;
|
||||
// confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
|
||||
// } else {
|
||||
// delete this.transaction.blocks;
|
||||
// confirmationMsg['Fee (' + this.information.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
|
||||
// }
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
|
||||
// {type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
|
||||
// }));
|
||||
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(takeUntil(this.unsub[2]))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// if (this.transaction.sendAll && !+this.appConfig.sso.rtlSSO) {
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
|
||||
// {type: 'CONFIRM', titleMessage: 'Enter Login Password', noBtnText: 'Cancel', yesBtnText: 'Authorize', flgShowInput: true, getInputs: [
|
||||
// {placeholder: 'Enter Login Password', inputType: 'password', inputValue: ''}
|
||||
// ]}
|
||||
// }));
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(takeUntil(this.unsub[3]))
|
||||
// .subscribe(pwdConfirmRes => {
|
||||
// if (pwdConfirmRes) {
|
||||
// const pwd = pwdConfirmRes[0].inputValue;
|
||||
// this.store.dispatch(new RTLActions.IsAuthorized(sha256(pwd)));
|
||||
// this.rtlEffects.isAuthorizedRes
|
||||
// .pipe(take(1))
|
||||
// .subscribe(authRes => {
|
||||
// if (authRes !== 'ERROR') {
|
||||
// this.dispatchToSendFunds();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// this.dispatchToSendFunds();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
dispatchToSendFunds() {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
|
||||
// this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
|
||||
// this.transaction = {address: '', amount: 0, blocks: 0, fees: 0};
|
||||
}
|
||||
|
||||
get invalidValues(): boolean {
|
||||
return (undefined === this.transaction.address || this.transaction.address === '')
|
||||
|| (+this.flgCustomAmount && (undefined === this.transaction.amount || this.transaction.amount <= 0))
|
||||
|| (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0))
|
||||
|| (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0));
|
||||
}
|
||||
|
||||
onCustomClicked() {
|
||||
this.flgCustomAmount = '1';
|
||||
}
|
||||
|
||||
onOptionChange(event) {
|
||||
if (!+this.flgCustomAmount) {
|
||||
delete this.transaction.amount;
|
||||
}
|
||||
}
|
||||
|
||||
resetData() {
|
||||
this.transaction.address = '';
|
||||
this.transaction.amount = 0;
|
||||
this.transaction.blocks = 0;
|
||||
this.transaction.fees = 0;
|
||||
}
|
||||
|
||||
resetReceiveData() {
|
||||
this.selectedAddress = {};
|
||||
this.newAddress = '';
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsub.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Query Routes</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap"
|
||||
(ngSubmit)="queryRoutesForm.form.valid && onQueryRoutes()" #queryRoutesForm="ngForm">
|
||||
<mat-form-field fxFlex="50" fxLayoutAlign="start end">
|
||||
<input matInput placeholder="Destination Pubkey" name="destinationPubkey" [(ngModel)]="destinationPubkey"
|
||||
tabindex="1" required #destPubkey="ngModel">
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="20" fxLayoutAlign="start end">
|
||||
<input matInput placeholder="Amount (Sats)" name="amount" [(ngModel)]="amount" tabindex="2" type="number"
|
||||
step="1000" min="0" required #destAmount="ngModel">
|
||||
</mat-form-field>
|
||||
<div fxFlex="15" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary"
|
||||
[disabled]="destPubkey.invalid || destAmount.invalid" type="submit" tabindex="3">
|
||||
<p *ngIf="(destPubkey.invalid && (destPubkey.dirty || destPubkey.touched) || (destAmount.invalid && (destAmount.dirty || destAmount.touched))); else queryText">Invalid Pubkey/Amount
|
||||
</p>
|
||||
<ng-template #queryText>
|
||||
<p>Query</p>
|
||||
</ng-template>
|
||||
</button>
|
||||
</div>
|
||||
<div fxFlex="15" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="4" type="reset"
|
||||
(click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content class="table-card-content">
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="qrHops" matSort
|
||||
[ngClass]="{'mat-elevation-z8 overflow-x-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-x-auto': true}">
|
||||
<ng-container matColumnDef="hop_sequence">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Hop </th>
|
||||
<td mat-cell *matCellDef="let hop"> {{hop?.hop_sequence}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="pubkey_alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Node </th>
|
||||
<td mat-cell *matCellDef="let hop"> {{hop?.pubkey_alias}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chan_id">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Channel </th>
|
||||
<td mat-cell *matCellDef="let hop"> {{hop?.chan_id}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chan_capacity">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Capacity (sats) </th>
|
||||
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.chan_capacity | number}}
|
||||
</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="amt_to_forward_msat">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount To Fwd (msats) </th>
|
||||
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.amt_to_forward_msat | number}}
|
||||
</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="fee_msat">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Fee (msat) </th>
|
||||
<td mat-cell *matCellDef="let hop"><span fxLayoutAlign="end center"> {{hop?.fee_msat | number}} </span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onHopClick(row, $event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>PAYMENTS QUERY ROUTES</h3>
|
@ -0,0 +1,3 @@
|
||||
table {
|
||||
width:100%;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLQueryRoutesComponent } from './query-routes.component';
|
||||
|
||||
describe('CLQueryRoutesComponent', () => {
|
||||
let component: CLQueryRoutesComponent;
|
||||
let fixture: ComponentFixture<CLQueryRoutesComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLQueryRoutesComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLQueryRoutesComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,98 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, take } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { HopCL } from '../../../shared/models/clModels';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
|
||||
import { CLEffects } from '../../store/cl.effects';
|
||||
import * as RTLActions from '../../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-query-routes',
|
||||
templateUrl: './query-routes.component.html',
|
||||
styleUrls: ['./query-routes.component.scss']
|
||||
})
|
||||
export class CLQueryRoutesComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
public destinationPubkey = '';
|
||||
public amount = null;
|
||||
public qrHops: any;
|
||||
public flgSticky = false;
|
||||
public displayedColumns = [];
|
||||
public flgLoading: Array<Boolean | 'error'> = [false]; // 0: peers
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
|
||||
ngOnInit() {}
|
||||
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private clEffects: CLEffects, private actions$: Actions) {
|
||||
// switch (true) {
|
||||
// case (window.innerWidth <= 415):
|
||||
// this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'fee_msat'];
|
||||
// break;
|
||||
// case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
// this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'chan_id', 'fee_msat'];
|
||||
// break;
|
||||
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
// this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'chan_id', 'chan_capacity', 'amt_to_forward_msat', 'fee_msat'];
|
||||
// break;
|
||||
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'chan_id', 'chan_capacity', 'amt_to_forward_msat', 'fee_msat'];
|
||||
// break;
|
||||
// default:
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'chan_id', 'chan_capacity', 'amt_to_forward_msat', 'fee_msat'];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ngOnInit() {
|
||||
// this.clEffects.setQueryRoutes
|
||||
// .pipe(takeUntil(this.unSubs[1]))
|
||||
// .subscribe(queryRoute => {
|
||||
// this.qrHops = new MatTableDataSource([]);
|
||||
// this.qrHops.data = [];
|
||||
// if (undefined !== queryRoute.routes && undefined !== queryRoute.routes[0].hops) {
|
||||
// this.flgLoading[0] = false;
|
||||
// this.qrHops = new MatTableDataSource<HopCL>([...queryRoute.routes[0].hops]);
|
||||
// this.qrHops.data = queryRoute.routes[0].hops;
|
||||
// } else {
|
||||
// this.flgLoading[0] = 'error';
|
||||
// }
|
||||
// this.qrHops.sort = this.sort;
|
||||
// });
|
||||
// }
|
||||
|
||||
// onQueryRoutes() {
|
||||
// this.flgLoading[0] = true;
|
||||
// this.store.dispatch(new RTLActions.GetQueryRoutes({destPubkey: this.destinationPubkey, amount: this.amount}));
|
||||
// }
|
||||
|
||||
// resetData() {
|
||||
// this.destinationPubkey = '';
|
||||
// this.amount = null;
|
||||
// this.flgLoading[0] = false;
|
||||
// }
|
||||
|
||||
// onHopClick(selRow: HopCL, event: any) {
|
||||
// const selHop = this.qrHops.data.filter(hop => {
|
||||
// return hop.hop_sequence === selRow.hop_sequence;
|
||||
// })[0];
|
||||
// const reorderedHop = JSON.parse(JSON.stringify(selHop, [
|
||||
// 'hop_sequence', 'pubkey_alias', 'pub_key', 'chan_id', 'chan_capacity', 'expiry', 'amt_to_forward', 'amt_to_forward_msat', 'fee_msat'
|
||||
// ] , 2));
|
||||
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: { type: 'INFO', message: JSON.stringify(reorderedHop)}}));
|
||||
// }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Verify and Send Payments</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap" #sendPaymentForm="ngForm">
|
||||
<div fxFlex="69" fxLayoutAlign="space-between stretch">
|
||||
<mat-form-field class="w-100">
|
||||
<input matInput placeholder="Payment Request" name="paymentRequest" [(ngModel)]="paymentRequest" tabindex="1" required #paymentReq="ngModel">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="30" fxLayoutAlign="space-between stretch">
|
||||
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="paymentReq.invalid" (click)="onSendPayment()" tabindex="2">
|
||||
<p *ngIf="paymentReq.invalid && (paymentReq.dirty || paymentReq.touched); else sendText">Invalid Req</p>
|
||||
<ng-template #sendText><p>Send Payment</p></ng-template>
|
||||
</button>
|
||||
<button fxFlex="48" mat-raised-button color="accent" type="reset" tabindex="3" type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content class="table-card-content">
|
||||
<div fxLayout="row" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="payments" matSort [ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
|
||||
<ng-container matColumnDef="creation_date">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Creation Date</th>
|
||||
<td mat-cell *matCellDef="let payment">{{payment?.creation_date_str}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="payment_hash">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Payment Hash</th>
|
||||
<td mat-cell *matCellDef="let payment">
|
||||
<div>{{payment?.payment_hash | slice:0:10}}...</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="fee">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Fee</th>
|
||||
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{payment?.fee | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Value</th>
|
||||
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{payment?.value | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="payment_preimage">
|
||||
<th mat-header-cell class="pl-4" *matHeaderCellDef mat-sort-header>Payment Pre Image</th>
|
||||
<td mat-cell class="pl-4" *matCellDef="let payment">
|
||||
<div>{{payment?.payment_preimage | slice:0:10}}...</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value_msat">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Value MSat</th>
|
||||
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{payment?.value_msat | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="value_sat">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Value Sat</th>
|
||||
<td mat-cell *matCellDef="let payment"><span fxLayoutAlign="end center">{{payment?.value_sat | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="path">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Path</th>
|
||||
<td mat-cell *matCellDef="let payment">{{payment?.path?.length || 0}} Hops</td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.payment_hash === newlyAddedPayment && flgAnimate) ? 'added' : 'notAdded'" (click)="onPaymentClick(row, $event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>PAYMENTS SEND RECEIVE</h3>
|
@ -0,0 +1,31 @@
|
||||
.mat-column-path {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mat-accordion .mat-expansion-panel {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.ml-minus-24px {
|
||||
margin-left: -24px;
|
||||
}
|
||||
|
||||
.info-column {
|
||||
flex: 1 1 34%;
|
||||
box-sizing: border-box;
|
||||
max-width: 34%;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1 1 64%;
|
||||
max-width: 64%;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLPaymentsComponent } from './payments.component';
|
||||
|
||||
describe('CLPaymentsComponent', () => {
|
||||
let component: CLPaymentsComponent;
|
||||
let fixture: ComponentFixture<CLPaymentsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLPaymentsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLPaymentsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,194 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, take } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { GetInfoCL, PaymentCL, PayRequestCL } from '../../../shared/models/clModels';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
|
||||
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
|
||||
import { CLEffects } from '../../store/cl.effects';
|
||||
import { RTLEffects } from '../../../store/rtl.effects';
|
||||
import * as RTLActions from '../../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-payments',
|
||||
templateUrl: './payments.component.html',
|
||||
styleUrls: ['./payments.component.scss'],
|
||||
animations: [newlyAddedRowAnimation]
|
||||
})
|
||||
export class CLPaymentsComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
@ViewChild('sendPaymentForm', { static: true }) form;
|
||||
public newlyAddedPayment = '';
|
||||
public flgAnimate = true;
|
||||
public flgLoading: Array<Boolean | 'error'> = [true];
|
||||
public information: GetInfoCL = {};
|
||||
public payments: any;
|
||||
public paymentJSONArr: PaymentCL[] = [];
|
||||
public displayedColumns = [];
|
||||
public paymentDecoded: PayRequestCL = {};
|
||||
public paymentRequest = '';
|
||||
public flgSticky = false;
|
||||
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
ngOnInit() {}
|
||||
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private clEffects: CLEffects) {
|
||||
// switch (true) {
|
||||
// case (window.innerWidth <= 415):
|
||||
// this.displayedColumns = ['creation_date', 'fee', 'value'];
|
||||
// break;
|
||||
// case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
// this.displayedColumns = ['creation_date', 'payment_hash', 'fee', 'value', 'payment_preimage'];
|
||||
// break;
|
||||
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
// this.displayedColumns = ['creation_date', 'payment_hash', 'fee', 'value', 'payment_preimage', 'path'];
|
||||
// break;
|
||||
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['creation_date', 'payment_hash', 'fee', 'value', 'payment_preimage', 'value_msat', 'value_sat', 'path'];
|
||||
// break;
|
||||
// default:
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['creation_date', 'payment_hash', 'fee', 'value', 'payment_preimage', 'value_msat', 'value_sat', 'path'];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ngOnInit() {
|
||||
// this.store.select('cl')
|
||||
// .pipe(takeUntil(this.unsub[0]))
|
||||
// .subscribe((rtlStore) => {
|
||||
// rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
// if (effectsErr.action === 'FetchPayments') {
|
||||
// this.flgLoading[0] = 'error';
|
||||
// }
|
||||
// });
|
||||
// this.information = rtlStore.information;
|
||||
// this.paymentJSONArr = (null !== rtlStore.payments && rtlStore.payments.length > 0) ? rtlStore.payments : [];
|
||||
// this.payments = (undefined === rtlStore.payments || null == rtlStore.payments) ? new MatTableDataSource([]) : new MatTableDataSource<Payment>([...this.paymentJSONArr]);
|
||||
// this.payments.data = this.paymentJSONArr;
|
||||
// this.payments.sort = this.sort;
|
||||
// this.payments.data.forEach(payment => {
|
||||
// payment.creation_date_str = (payment.creation_date_str === '') ? '' : formatDate(payment.creation_date_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// });
|
||||
// setTimeout(() => { this.flgAnimate = false; }, 3000);
|
||||
// if (this.flgLoading[0] !== 'error') {
|
||||
// this.flgLoading[0] = (undefined !== this.paymentJSONArr) ? false : true;
|
||||
// }
|
||||
// this.logger.info(rtlStore);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// onSendPayment() {
|
||||
// if (undefined !== this.paymentDecoded.timestamp_str) {
|
||||
// this.sendPayment();
|
||||
// } else {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...'));
|
||||
// this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest));
|
||||
// this.clEffects.setDecodedPayment
|
||||
// .pipe(take(1))
|
||||
// .subscribe(decodedPayment => {
|
||||
// this.paymentDecoded = decodedPayment;
|
||||
// if (undefined !== this.paymentDecoded.timestamp_str) {
|
||||
// this.paymentDecoded.timestamp_str = (this.paymentDecoded.timestamp_str === '') ? '' :
|
||||
// formatDate(this.paymentDecoded.timestamp_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// if (undefined === this.paymentDecoded.num_satoshis) {
|
||||
// this.paymentDecoded.num_satoshis = '0';
|
||||
// }
|
||||
// this.sendPayment();
|
||||
// } else {
|
||||
// this.resetData();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// sendPayment() {
|
||||
// this.flgAnimate = true;
|
||||
// this.newlyAddedPayment = this.paymentDecoded.payment_hash;
|
||||
// if (undefined === this.paymentDecoded.num_satoshis || this.paymentDecoded.num_satoshis === '' || this.paymentDecoded.num_satoshis === '0') {
|
||||
// const titleMsg = 'This is an empty invoice. Enter the amount (Sats) to pay.';
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data: {
|
||||
// type: 'CONFIRM', titleMessage: titleMsg, message: JSON.stringify(this.paymentDecoded), noBtnText: 'Cancel', yesBtnText: 'Send', flgShowInput: true, getInputs: [
|
||||
// {placeholder: 'Amount (Sats)', inputType: 'number', inputValue: ''}
|
||||
// ]
|
||||
// }}));
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(take(1))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// this.paymentDecoded.num_satoshis = confirmRes[0].inputValue;
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Sending Payment...'));
|
||||
// this.store.dispatch(new RTLActions.SendPayment([this.paymentRequest, this.paymentDecoded, true]));
|
||||
// this.resetData();
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data: {
|
||||
// type: 'CONFIRM', titleMessage: 'Send Payment', noBtnText: 'Cancel', yesBtnText: 'Send', message: JSON.stringify(this.paymentDecoded)
|
||||
// }}));
|
||||
// this.rtlEffects.closeConfirm
|
||||
// .pipe(take(1))
|
||||
// .subscribe(confirmRes => {
|
||||
// if (confirmRes) {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Sending Payment...'));
|
||||
// this.store.dispatch(new RTLActions.SendPayment([this.paymentRequest, this.paymentDecoded, false]));
|
||||
// this.resetData();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// onVerifyPayment() {
|
||||
// this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...'));
|
||||
// this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest));
|
||||
// this.clEffects.setDecodedPayment.subscribe(decodedPayment => {
|
||||
// this.paymentDecoded = decodedPayment;
|
||||
// if (undefined !== this.paymentDecoded.timestamp_str) {
|
||||
// this.paymentDecoded.timestamp_str = (this.paymentDecoded.timestamp_str === '') ? '' :
|
||||
// formatDate(this.paymentDecoded.timestamp_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// } else {
|
||||
// this.resetData();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// resetData() {
|
||||
// this.form.reset();
|
||||
// this.paymentDecoded = {};
|
||||
// }
|
||||
|
||||
// onPaymentClick(selRow: Payment, event: any) {
|
||||
// const flgExpansionClicked = event.target.className.includes('mat-expansion-panel-header') || event.target.className.includes('mat-expansion-indicator');
|
||||
// if (flgExpansionClicked) {
|
||||
// return;
|
||||
// }
|
||||
// const selPayment = this.payments.data.filter(payment => {
|
||||
// return payment.payment_hash === selRow.payment_hash;
|
||||
// })[0];
|
||||
// const reorderedPayment = JSON.parse(JSON.stringify(selPayment, [
|
||||
// 'creation_date_str', 'payment_hash', 'fee', 'value_msat', 'value_sat', 'value', 'payment_preimage', 'path'
|
||||
// ] , 2));
|
||||
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
|
||||
// type: 'INFO',
|
||||
// message: JSON.stringify(reorderedPayment)
|
||||
// }}));
|
||||
// }
|
||||
|
||||
// applyFilter(selFilter: string) {
|
||||
// this.payments.filter = selFilter;
|
||||
// }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unsub.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<div fxLayout="column">
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Connect Peer</h2>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayout.gt-sm="row wrap" (ngSubmit)="connectPeerForm.form.valid && onConnectPeer()" #connectPeerForm="ngForm">
|
||||
<mat-form-field fxFlex="70" fxLayoutAlign="start end">
|
||||
<input matInput placeholder="Lightning Address (pubkey OR pubkey@ip:port)" name="peerAddress" [(ngModel)]="peerAddress" tabindex="1" required #peerAdd="ngModel">
|
||||
</mat-form-field>
|
||||
<div fxFlex="15" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="peerAdd.invalid" type="submit" tabindex="2">
|
||||
<p *ngIf="peerAdd.invalid && (peerAdd.dirty || peerAdd.touched); else connectText">Invalid Address</p>
|
||||
<ng-template #connectText><p>Connect</p></ng-template>
|
||||
</button>
|
||||
</div>
|
||||
<div fxFlex="15" fxLayoutAlign="start start">
|
||||
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="2" type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content class="table-card-content">
|
||||
<div fxLayout="row" fxLayoutAlign="start start">
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="peers" matSort [ngClass]="{'mat-elevation-z8 overflow-x-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-x-auto': true}">
|
||||
<ng-container matColumnDef="detach">
|
||||
<th mat-header-cell *matHeaderCellDef>Detach</th>
|
||||
<td mat-cell *matCellDef="let peer"><mat-icon color="accent" (click)="onPeerDetach(peer)">link_off</mat-icon></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="open_channel">
|
||||
<th mat-header-cell *matHeaderCellDef>Open Channel</th>
|
||||
<td mat-cell *matCellDef="let peer"><mat-icon color="accent" (click)="onOpenChannel(peer)">playlist_add</mat-icon></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="id">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> ID </th>
|
||||
<td mat-cell *matCellDef="let peer">
|
||||
<div> {{peer?.id | slice:0:10}}... </div>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Alias </th>
|
||||
<td mat-cell *matCellDef="let peer"> {{peer?.alias}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="connected">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Connected </th>
|
||||
<td mat-cell *matCellDef="let peer"> {{peer?.connected}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="netaddr">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Network Address </th>
|
||||
<td mat-cell *matCellDef="let peer">
|
||||
<span *ngFor="let addr of peer?.netaddr; last as isLast">{{ addr}}<span *ngIf="!isLast">,<br></span></span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="globalfeatures">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Global Features </th>
|
||||
<td mat-cell *matCellDef="let peer"> {{peer?.globalfeatures}} </td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="localfeatures">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Local Features </th>
|
||||
<td mat-cell *matCellDef="let peer"> {{peer?.localfeatures}} </td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.id === newlyAddedPeer && flgAnimate) ? 'added' : 'notAdded'" (click)="onPeerClick(row, $event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,17 @@
|
||||
.mat-column-detach {
|
||||
flex: 0 0 5%;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.mat-column-alias, .mat-column-address {
|
||||
flex: 0 0 15%;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.mat-cell.mat-column-detach {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLPeersComponent } from './peers.component';
|
||||
|
||||
describe('CLPeersComponent', () => {
|
||||
let component: CLPeersComponent;
|
||||
let fixture: ComponentFixture<CLPeersComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLPeersComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLPeersComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,145 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, filter, take } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { PeerCL, GetInfoCL } from '../../shared/models/clModels';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
|
||||
import { newlyAddedRowAnimation } from '../../shared/animation/row-animation';
|
||||
import { CLEffects } from '../store/cl.effects';
|
||||
import { RTLEffects } from '../../store/rtl.effects';
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-peers',
|
||||
templateUrl: './peers.component.html',
|
||||
styleUrls: ['./peers.component.scss'],
|
||||
animations: [newlyAddedRowAnimation]
|
||||
})
|
||||
export class CLPeersComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
public newlyAddedPeer = '';
|
||||
public flgAnimate = true;
|
||||
public displayedColumns = [];
|
||||
public peerAddress = '';
|
||||
public peers: any;
|
||||
public information: GetInfoCL = {};
|
||||
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: peers
|
||||
public flgSticky = false;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private clEffects: CLEffects, private actions$: Actions, private router: Router) {
|
||||
switch (true) {
|
||||
case (window.innerWidth <= 415):
|
||||
this.displayedColumns = ['detach', 'id', 'alias', 'connected'];
|
||||
break;
|
||||
case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
this.displayedColumns = ['detach', 'id', 'alias', 'connected', 'netaddr'];
|
||||
break;
|
||||
case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
this.displayedColumns = ['detach', 'open_channel', 'id', 'alias', 'connected', 'netaddr', 'globalfeatures', 'localfeatures'];
|
||||
break;
|
||||
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
this.flgSticky = true;
|
||||
this.displayedColumns = ['detach', 'open_channel', 'id', 'alias', 'connected', 'netaddr', 'globalfeatures', 'localfeatures'];
|
||||
break;
|
||||
default:
|
||||
this.flgSticky = true;
|
||||
this.displayedColumns = ['detach', 'open_channel', 'id', 'alias', 'connected', 'netaddr', 'globalfeatures', 'localfeatures'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.store.dispatch(new RTLActions.FetchPeersCL());
|
||||
this.store.select('cl')
|
||||
.pipe(takeUntil(this.unSubs[0]))
|
||||
.subscribe((rtlStore) => {
|
||||
rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
if (effectsErr.action === 'FetchPeersCL') {
|
||||
this.flgLoading[0] = 'error';
|
||||
}
|
||||
});
|
||||
this.information = rtlStore.information;
|
||||
this.peers = new MatTableDataSource([]);
|
||||
this.peers.data = [];
|
||||
if (undefined !== rtlStore.peers) {
|
||||
this.peers = new MatTableDataSource<PeerCL>([...rtlStore.peers]);
|
||||
this.peers.data = rtlStore.peers;
|
||||
setTimeout(() => { this.flgAnimate = false; }, 3000);
|
||||
}
|
||||
this.peers.sort = this.sort;
|
||||
if (this.flgLoading[0] !== 'error') {
|
||||
this.flgLoading[0] = false;
|
||||
}
|
||||
this.logger.info(rtlStore);
|
||||
});
|
||||
this.actions$
|
||||
.pipe(
|
||||
takeUntil(this.unSubs[1]),
|
||||
filter((action) => action.type === RTLActions.SET_PEERS_CL)
|
||||
).subscribe((setPeers: RTLActions.SetPeersCL) => {
|
||||
this.peerAddress = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
onConnectPeer() {
|
||||
this.flgAnimate = true;
|
||||
this.newlyAddedPeer = this.peerAddress;
|
||||
this.store.dispatch(new RTLActions.OpenSpinner('Adding Peer...'));
|
||||
this.store.dispatch(new RTLActions.SaveNewPeerCL({id: this.peerAddress}));
|
||||
}
|
||||
|
||||
onPeerClick(selRow: PeerCL, event: any) {
|
||||
const flgCloseClicked = event.target.className.includes('mat-column-detach') || event.target.className.includes('mat-icon');
|
||||
if (flgCloseClicked) {
|
||||
return;
|
||||
}
|
||||
const selPeer = this.peers.data.filter(peer => {
|
||||
return peer.id === selRow.id;
|
||||
})[0];
|
||||
const reorderedPeer = JSON.parse(JSON.stringify(selPeer, [
|
||||
'id', 'alias', 'connected', 'netaddr', 'globalfeatures', 'localfeatures'
|
||||
] , 2));
|
||||
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: { type: 'INFO', message: JSON.stringify(reorderedPeer)}}));
|
||||
}
|
||||
|
||||
resetData() {
|
||||
this.peerAddress = '';
|
||||
}
|
||||
|
||||
onOpenChannel(peerToAddChannel: PeerCL) {
|
||||
this.router.navigate(['cl/chnlmanage'], { state: { peer: peerToAddChannel.id }});
|
||||
}
|
||||
|
||||
onPeerDetach(peerToDetach: PeerCL) {
|
||||
const msg = 'Detach peer: ' + peerToDetach.id;
|
||||
const msg_type = 'CONFIRM';
|
||||
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data: { type: msg_type, titleMessage: msg, noBtnText: 'Cancel', yesBtnText: 'Detach'}}));
|
||||
this.rtlEffects.closeConfirm
|
||||
.pipe(takeUntil(this.unSubs[3]))
|
||||
.subscribe(confirmRes => {
|
||||
if (confirmRes) {
|
||||
this.store.dispatch(new RTLActions.OpenSpinner('Detaching Peer...'));
|
||||
this.store.dispatch(new RTLActions.DetachPeerCL({id: peerToDetach.id, force: false}));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
applyFilter(selFilter: string) {
|
||||
this.peers.filter = selFilter;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
<!-- <div fxLayout="column">
|
||||
<div fxFlex="100" class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-subtitle>
|
||||
<h2>Forwarding History</h2>
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap"
|
||||
(ngSubmit)="fhForm.form.valid && onForwardingHistoryFetch()" #fhForm="ngForm" class="padding-gap">
|
||||
<div fxFlex="69" fxLayoutAlign="space-between stretch">
|
||||
<mat-form-field fxFlex="49" fxLayoutAlign="start">
|
||||
<input matInput [matDatepicker]="startDatepicker" placeholder="Start Date" [max]="yesterday"
|
||||
name="startDate" [(ngModel)]="startDate" tabindex="1" #strtDate="ngModel">
|
||||
<mat-datepicker-toggle matSuffix [for]="startDatepicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #startDatepicker [startAt]="startDate"></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex="49" fxLayoutAlign="start">
|
||||
<input matInput [matDatepicker]="endDatepicker" [max]="today" placeholder="End Date" name="endDate"
|
||||
[(ngModel)]="endDate" tabindex="2" #enDate="ngModel">
|
||||
<mat-datepicker-toggle matSuffix [for]="endDatepicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #endDatepicker [startAt]="endDate"></mat-datepicker>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div fxFlex="30" fxLayoutAlign="space-between stretch">
|
||||
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary"
|
||||
[disabled]="fhForm.invalid" type="submit" tabindex="3">Fetch</button>
|
||||
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="accent" class="ml-2" tabindex="4"
|
||||
type="reset" (click)="resetData()">Clear</button>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
<div class="padding-gap">
|
||||
<mat-card>
|
||||
<mat-card-content class="table-card-content">
|
||||
<div perfectScrollbar class="table-container mat-elevation-z8">
|
||||
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="forwardingHistoryEvents" matSort
|
||||
[ngClass]="{'mat-elevation-z8 overflow-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-auto': true}">
|
||||
<ng-container matColumnDef="timestamp">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Timestamp</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent.timestamp_str}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chan_id_in">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Chan Id In</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent.chan_id_in}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="alias_in">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Alias In</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent.alias_in}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="chan_id_out">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Chan Id Out</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent.chan_id_out}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="alias_out">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Alias Out</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent.alias_out}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="amt_out">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount
|
||||
Out (Sats)</th>
|
||||
<td mat-cell *matCellDef="let fhEvent"><span fxLayoutAlign="end center">{{fhEvent.amt_out | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="amt_in">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount
|
||||
In (Sats)</th>
|
||||
<td mat-cell *matCellDef="let fhEvent"><span fxLayoutAlign="end center">{{fhEvent.amt_in | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="fee">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Fee
|
||||
(Sats)</th>
|
||||
<td mat-cell *matCellDef="let fhEvent"><span fxLayoutAlign="end center">{{fhEvent.fee | number}}</span></td>
|
||||
</ng-container>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
|
||||
(click)="onForwardingEventClick(row, $event)"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div> -->
|
||||
<h3>FORWARDING HISTORY</h3>
|
@ -0,0 +1,9 @@
|
||||
.mat-column-amt_in {
|
||||
flex: 0 0 15%;
|
||||
min-width: 120px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
table {
|
||||
width:100%;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CLForwardingHistoryComponent } from './forwarding-history.component';
|
||||
|
||||
describe('CLForwardingHistoryComponent', () => {
|
||||
let component: CLForwardingHistoryComponent;
|
||||
let fixture: ComponentFixture<CLForwardingHistoryComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CLForwardingHistoryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLForwardingHistoryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,135 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { formatDate } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil, filter } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Actions } from '@ngrx/effects';
|
||||
|
||||
import { MatTableDataSource, MatSort } from '@angular/material';
|
||||
import { ForwardingEventCL } from '../../shared/models/clModels';
|
||||
import { LoggerService } from '../../shared/services/logger.service';
|
||||
|
||||
import * as RTLActions from '../../store/rtl.actions';
|
||||
import * as fromRTLReducer from '../../store/rtl.reducers';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-forwarding-history',
|
||||
templateUrl: './forwarding-history.component.html',
|
||||
styleUrls: ['./forwarding-history.component.scss']
|
||||
})
|
||||
export class CLForwardingHistoryComponent implements OnInit, OnDestroy {
|
||||
@ViewChild(MatSort, { static: true }) sort: MatSort;
|
||||
public displayedColumns = [];
|
||||
public forwardingHistoryEvents: any;
|
||||
public lastOffsetIndex = 0;
|
||||
public flgLoading: Array<Boolean | 'error'> = [true];
|
||||
public today = new Date(Date.now());
|
||||
public yesterday = new Date(this.today.getFullYear(), this.today.getMonth(), this.today.getDate() - 1, this.today.getHours(), this.today.getMinutes(), this.today.getSeconds());
|
||||
public endDate = this.today;
|
||||
public startDate = this.yesterday;
|
||||
public flgSticky = false;
|
||||
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
|
||||
ngOnInit() {}
|
||||
// constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
|
||||
// switch (true) {
|
||||
// case (window.innerWidth <= 415):
|
||||
// this.displayedColumns = ['timestamp', 'amt_out', 'amt_in'];
|
||||
// break;
|
||||
// case (window.innerWidth > 415 && window.innerWidth <= 730):
|
||||
// this.displayedColumns = ['timestamp', 'amt_out', 'amt_in', 'fee'];
|
||||
// break;
|
||||
// case (window.innerWidth > 730 && window.innerWidth <= 1024):
|
||||
// this.displayedColumns = ['timestamp', 'chan_id_in', 'chan_id_out', 'amt_out', 'amt_in', 'fee'];
|
||||
// break;
|
||||
// case (window.innerWidth > 1024 && window.innerWidth <= 1280):
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['timestamp', 'chan_id_in', 'chan_id_out', 'amt_out', 'amt_in', 'fee'];
|
||||
// break;
|
||||
// default:
|
||||
// this.flgSticky = true;
|
||||
// this.displayedColumns = ['timestamp', 'chan_id_in', 'chan_id_out', 'amt_out', 'amt_in', 'fee'];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ngOnInit() {
|
||||
// this.onForwardingHistoryFetch();
|
||||
// this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => {
|
||||
// this.onForwardingHistoryFetch();
|
||||
// });
|
||||
|
||||
// this.store.select('cl')
|
||||
// .pipe(takeUntil(this.unsub[0]))
|
||||
// .subscribe((rtlStore) => {
|
||||
// rtlStore.effectErrorsCl.forEach(effectsErr => {
|
||||
// if (effectsErr.action === 'GetForwardingHistory') {
|
||||
// this.flgLoading[0] = 'error';
|
||||
// }
|
||||
// });
|
||||
// if (undefined !== rtlStore.forwardingHistory && undefined !== rtlStore.forwardingHistory.forwarding_events) {
|
||||
// this.lastOffsetIndex = rtlStore.forwardingHistory.last_offset_index;
|
||||
// this.loadForwardingEventsTable(rtlStore.forwardingHistory.forwarding_events);
|
||||
// } else {
|
||||
// // To reset table after other Forwarding history calls
|
||||
// this.lastOffsetIndex = 0;
|
||||
// this.loadForwardingEventsTable([]);
|
||||
// }
|
||||
// if (this.flgLoading[0] !== 'error') {
|
||||
// this.flgLoading[0] = (undefined !== rtlStore.forwardingHistory) ? false : true;
|
||||
// }
|
||||
// this.logger.info(rtlStore);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// onForwardingEventClick(selRow: ForwardingEventCL, event: any) {
|
||||
// const selFEvent = this.forwardingHistoryEvents.data.filter(fhEvent => {
|
||||
// return (fhEvent.chan_id_in === selRow.chan_id_in && fhEvent.timestamp === selRow.timestamp);
|
||||
// })[0];
|
||||
// const reorderedFHEvent = JSON.parse(JSON.stringify(selFEvent, ['timestamp_str', 'chan_id_in', 'alias_in', 'chan_id_out', 'alias_out', 'amt_out', 'amt_in', 'fee'] , 2));
|
||||
// this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
|
||||
// type: 'INFO',
|
||||
// message: JSON.stringify(reorderedFHEvent)
|
||||
// }}));
|
||||
// }
|
||||
|
||||
// loadForwardingEventsTable(forwardingEvents: ForwardingEventCL[]) {
|
||||
// this.forwardingHistoryEvents = new MatTableDataSource<ForwardingEventCL>([...forwardingEvents]);
|
||||
// this.forwardingHistoryEvents.sort = this.sort;
|
||||
// this.forwardingHistoryEvents.data.forEach(event => {
|
||||
// event.timestamp_str = (event.timestamp_str === '') ? '' : formatDate(event.timestamp_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
|
||||
// });
|
||||
|
||||
// this.logger.info(this.forwardingHistoryEvents);
|
||||
// }
|
||||
|
||||
// onForwardingHistoryFetch() {
|
||||
// if (undefined === this.endDate || this.endDate == null) {
|
||||
// this.endDate = new Date();
|
||||
// }
|
||||
// if (undefined === this.startDate || this.startDate == null) {
|
||||
// this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 1);
|
||||
// }
|
||||
// this.store.dispatch(new RTLActions.GetForwardingHistory({
|
||||
// end_time: Math.round(this.endDate.getTime() / 1000).toString(),
|
||||
// start_time: Math.round(this.startDate.getTime() / 1000).toString()
|
||||
// }));
|
||||
// }
|
||||
|
||||
resetData() {
|
||||
this.endDate = new Date();
|
||||
this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 1);
|
||||
if (undefined !== this.forwardingHistoryEvents) {
|
||||
this.forwardingHistoryEvents.data = [];
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.resetData();
|
||||
this.unsub.forEach(completeSub => {
|
||||
completeSub.next();
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue