Release 0.10.2 (#666)

High CPU usage by browser when session inactivity dialog is showing #624
Block Altcoins #627
Remove slide right animation on route change #642
Update the initiator field for Loop APIs #643
Filter Bug fix #623
Transaction id for pending waiting channel #603
Empty cookie security risk bug fix #610
Material container repositions on Mac Firefox #268 & #619 
Mask config file passwords #636
Downloaded all channels backup fails to restore #614
CLT Routing list disappears on navigation #652
Update Bump Fee modal #628
LND Paying zero amount invoice fails #657
Open channel fails after adding peer with uri #662
Update Fee Policy Bug Fix #659
Changed default password from `changeme` to `password` (#653) (Contributed By: Andrew Leschinsky <andrew@leschinsky.com>)
pull/671/head v0.10.2
ShahanaFarooqui 3 years ago committed by GitHub
parent de0e8294b1
commit e4d6256803
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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

@ -12,8 +12,8 @@
<link rel="mask-icon" href="assets/images/favicon-light/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="styles.b19cbfbd6204e537cd8b.css"></head>
<link rel="stylesheet" href="styles.34373e0f495fd5a53b6a.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.4a1371653e10aae2a656.js" defer></script><script src="polyfills.ea991b800cfaf577eb9d.js" defer></script><script src="main.bf1f3d303d9abc6dfc78.js" defer></script></body>
<script src="runtime.76e78b7c520ee74ce1af.js" defer></script><script src="polyfills.a290c5ced4c403cfee17.js" defer></script><script src="main.023be7f19d26fb1d812e.js" defer></script></body>
</html>

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,c=r[0],i=r[1],f=r[2],p=0,s=[];p<c.length;p++)a=c[p],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[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,c=1;c<t.length;c++)0!==o[t[c]]&&(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,c=document.createElement("script");c.charset="utf-8",c.timeout=120,a.nc&&c.setAttribute("nonce",a.nc),c.src=function(e){return a.p+""+({}[e]||e)+"."+{1:"731a8de203edc88f38d8",5:"3cc9f14aefc4012c6f28",6:"d59c34ac7722c1fea6aa",7:"3f5e1768ebd105934cfb"}[e]+".js"}(e);var i=new Error;u=function(r){c.onerror=c.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;i.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",i.name="ChunkLoadError",i.type=n,i.request=u,t[1](i)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:c})},12e4);c.onerror=c.onload=u,document.head.appendChild(c)}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 c=window.webpackJsonp=window.webpackJsonp||[],i=c.push.bind(c);c.push=r,c=c.slice();for(var f=0;f<c.length;f++)r(c[f]);var l=i;t()}([]);

@ -0,0 +1 @@
!function(e){function r(r){for(var n,a,i=r[0],c=r[1],l=r[2],p=0,s=[];p<i.length;p++)a=i[p],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);s.length;)s.shift()();return u.push.apply(u,l||[]),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)+"."+{1:"237c2154eb3e4109a251",5:"25446aaee9f74a416633",6:"eee0e0f329ec52d3bce7",7:"e4068d65b9329bce7749"}[e]+".js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(l);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 l=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 l=0;l<i.length;l++)r(i[l]);var f=c;t()}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -194,7 +194,7 @@ common.sortAscByKey = (array, key) => {
common.sortDescByKey = (array, key) => {
const temp = array.sort(function (a, b) {
var x = +a[key]; var y = +b[key];
var x = +a[key] ? +a[key] : 0; var y = +b[key] ? +b[key] : 0;
return (x > y) ? -1 : ((x < y) ? 1 : 0);
});
return temp;

@ -96,7 +96,7 @@ exports.connectPeer = (req, res, next) => {
peer.alias = foundPeer ? foundPeer.alias : peer.nodeId.substring(0, 20);
});
let peers = (body) ? common.sortDescByStrKey(body, 'alias') : [];
peers = common.newestOnTop(peers, 'nodeId', req.query.nodeId ? req.query.nodeId : '');
peers = common.newestOnTop(peers, 'nodeId', req.query.nodeId ? req.query.nodeId : req.query.uri ? req.query.uri.substring(0, req.query.uri.indexOf('@')) : '');
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);

@ -235,17 +235,9 @@ exports.postChannel = (req, res, next) => {
exports.postTransactions = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/v1/channels/transactions';
if(req.body.paymentReq) {
options.form = {
payment_request: req.body.paymentReq
};
} else if(req.body.paymentDecoded) {
options.form = {
payment_hash_string: req.body.paymentDecoded.payment_hash,
final_cltv_delta: parseInt(req.body.paymentDecoded.cltv_expiry),
amt: req.body.paymentDecoded.num_satoshis,
dest_string: req.body.paymentDecoded.destination
};
options.form = { payment_request: req.body.paymentReq };
if(req.body.paymentAmount) {
options.form.amt = req.body.paymentAmount;
}
if (req.body.feeLimit) { options.form.fee_limit = req.body.feeLimit; }
if (req.body.outgoingChannel) { options.form.outgoing_chan_id = req.body.outgoingChannel; }

@ -13,7 +13,7 @@ function getFilesList(callback) {
if( files && files.length > 0) {
files.forEach(file => {
if (!file.includes('.restored')) {
if (file === 'channel-all.bak') {
if (file.toLowerCase() === 'channel-all.bak' || file.toLowerCase() === 'backup-channel-all.bak') {
all_restore_exists = true;
} else {
files_list.push({channel_point: file.substring(8, file.length - 4).replace('-', ':')});
@ -159,10 +159,19 @@ exports.postRestore = (req, res, next) => {
let restore_backup = '';
if (req.params.channelPoint === 'ALL') {
message = 'All Channels Restore Successful.';
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'restore' + common.path_separator + 'channel-all.bak';
let exists = fs.existsSync(channel_restore_file);
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'restore' + common.path_separator;
let exists = fs.existsSync(channel_restore_file + 'channel-all.bak');
let downloaded_exists = fs.existsSync(channel_restore_file + 'backup-channel-all.bak');
if (exists) {
restore_backup = fs.readFileSync(channel_restore_file, 'utf-8');
restore_backup = fs.readFileSync(channel_restore_file + 'channel-all.bak', 'utf-8');
if (restore_backup !== '') {
restore_backup = JSON.parse(restore_backup);
options.form = JSON.stringify({multi_chan_backup: restore_backup.multi_chan_backup.multi_chan_backup});
} else {
res.status(404).json({ message: 'Channels backup to restore does not Exist!' });
}
} else if (downloaded_exists) {
restore_backup = fs.readFileSync(channel_restore_file + 'backup-channel-all.bak', 'utf-8');
if (restore_backup !== '') {
restore_backup = JSON.parse(restore_backup);
options.form = JSON.stringify({multi_chan_backup: restore_backup.multi_chan_backup.multi_chan_backup});

@ -165,7 +165,7 @@ exports.getConfig = (req, res, next) => {
logger.info({fileName: 'RTLConf', msg: 'Node Type: ' + req.params.nodeType + ', File Path: ' + confFile});
fs.readFile(confFile, 'utf8', function(err, data) {
if (err) {
logger.error({fileName: 'Conf', lineNum: 171, msg: 'Reading Conf Failed!'});
logger.error({fileName: 'Conf', lineNum: 168, msg: 'Reading Conf Failed!'});
res.status(500).json({
message: "Reading Config File Failed!",
error: err
@ -175,45 +175,14 @@ exports.getConfig = (req, res, next) => {
if (fileFormat === 'JSON') {
jsonConfig = JSON.parse(data);
} else {
fileFormat = 'INI';
jsonConfig = ini.parse(data);
switch (common.selectedNode.ln_implementation) {
case 'ECL':
if (jsonConfig['eclair.api.password']) {
if (jsonConfig['eclair.api.password']) {
jsonConfig['eclair.api.password'] = jsonConfig['eclair.api.password'].replace(/./g, '*');
}
if (jsonConfig['eclair.bitcoind.rpcpassword']) {
jsonConfig['eclair.bitcoind.rpcpassword'] = jsonConfig['eclair.bitcoind.rpcpassword'].replace(/./g, '*');
}
} else {
fileFormat = 'HOCON';
jsonConfig = parseHocon(data);
if (jsonConfig.eclair && jsonConfig.eclair.api && jsonConfig.eclair.api.password) {
jsonConfig.eclair.api.password = jsonConfig.eclair.api.password.replace(/./g, '*');
}
if (jsonConfig.eclair && jsonConfig.eclair.bitcoind && jsonConfig.eclair.bitcoind.rpcpassword) {
jsonConfig.eclair.bitcoind.rpcpassword = jsonConfig.eclair.bitcoind.rpcpassword.replace(/./g, '*');
}
}
break;
default:
fileFormat = 'INI';
break;
if (common.selectedNode.ln_implementation === 'ECL' && !jsonConfig['eclair.api.password']) {
fileFormat = 'HOCON';
jsonConfig = parseHocon(data);
}
}
if (jsonConfig.Bitcoind && jsonConfig.Bitcoind['bitcoind.rpcpass']) {
jsonConfig.Bitcoind['bitcoind.rpcpass'] = jsonConfig.Bitcoind['bitcoind.rpcpass'].replace(/./g, '*');
}
if (jsonConfig['bitcoind.rpcpass']) {
jsonConfig['bitcoind.rpcpass'] = jsonConfig['bitcoind.rpcpass'].replace(/./g, '*');
}
if (jsonConfig['rpcpassword']) {
jsonConfig['rpcpassword'] = jsonConfig['rpcpassword'].replace(/./g, '*');
}
if (jsonConfig.multiPass) {
jsonConfig.multiPass = jsonConfig.multiPass.replace(/./g, '*');
}
jsonConfig = maskPasswords(jsonConfig);
const responseJSON = (fileFormat === 'JSON') ? jsonConfig : ini.stringify(jsonConfig);
res.status(200).json({format: fileFormat, data: responseJSON});
}
@ -335,3 +304,22 @@ exports.updateServiceSettings = (req, res, next) => {
});
}
};
var maskPasswords = function(obj) {
var keys = Object.keys(obj);
var length = keys.length;
if (length !== 0) {
for (var i = 0; i < length; i++) {
if (typeof obj[keys[i]] === 'object') {
keys[keys[i]] = maskPasswords(obj[keys[i]]);
}
if (typeof keys[i] === 'string'
&& (keys[i].toLowerCase().includes('password') || keys[i].toLowerCase().includes('multipass')
|| keys[i].toLowerCase().includes('rpcpass') || keys[i].toLowerCase().includes('rpcpassword'))
) {
obj[keys[i]] = obj[keys[i]].replace(/./g, '*');
}
}
}
return obj;
};

@ -50,7 +50,7 @@ exports.authenticateUser = (req, res, next) => {
if(+common.rtl_sso) {
if(req.body.authenticateWith === 'JWT' && jwt.verify(req.body.authenticationValue, common.secret_key)) {
res.status(200).json({ token: token });
} else if (req.body.authenticateWith === 'PASSWORD' && crypto.createHash('sha256').update(common.cookie).digest('hex') === req.body.authenticationValue) {
} else if (req.body.authenticateWith === 'PASSWORD' && common.cookie.trim().length >= 32 && crypto.timingSafeEqual(Buffer.from(crypto.createHash('sha256').update(common.cookie).digest('hex'), 'utf-8'), Buffer.from(req.body.authenticationValue, 'utf-8'))) {
connect.refreshCookie(common.rtl_cookie_path);
const token = jwt.sign(
{ user: 'SSO_USER', configPath: common.nodes[0].config_path, macaroonPath: common.nodes[0].macaroon_path },
@ -58,10 +58,10 @@ exports.authenticateUser = (req, res, next) => {
);
res.status(200).json({ token: token });
} else {
logger.error({fileName: 'Authenticate', lineNum: 20, msg: 'SSO Authentication Failed!'});
logger.error({fileName: 'Authenticate', lineNum: 61, msg: 'SSO Authentication Failed! Access key too short or does not match.'});
res.status(406).json({
message: "Login Failure!",
error: "SSO Authentication Failed!"
message: "SSO Authentication Failed!",
error: "SSO failed. Access key too short or does not match."
});
}
} else {
@ -72,7 +72,7 @@ exports.authenticateUser = (req, res, next) => {
if (common.rtl_pass === password && failed.count < ALLOWED_LOGIN_ATTEMPTS) {
if (req.body.twoFAToken && req.body.twoFAToken !== '') {
if (!this.verifyToken(req.body.twoFAToken)) {
logger.error({fileName: 'Authenticate', lineNum: 61, msg: 'Invalid Token! Failed IP ' + reqIP});
logger.error({fileName: 'Authenticate', lineNum: 75, msg: 'Invalid Token! Failed IP ' + reqIP});
failed.count = failed.count + 1;
failed.lastTried = currentTime;
return res.status(401).json(handleError(failed, currentTime, 'Invalid 2FA Token!'));
@ -86,7 +86,7 @@ exports.authenticateUser = (req, res, next) => {
);
res.status(200).json({ token: token });
} else {
logger.error({fileName: 'Authenticate', lineNum: 85, msg: 'Invalid Password! Failed IP ' + reqIP});
logger.error({fileName: 'Authenticate', lineNum: 89, msg: 'Invalid Password! Failed IP ' + reqIP});
failed.count = common.rtl_pass !== password ? (failed.count + 1) : failed.count;
failed.lastTried = common.rtl_pass !== password ? currentTime : failed.lastTried;
return res.status(401).json(handleError(failed, currentTime, 'Invalid Password!'));
@ -96,7 +96,7 @@ exports.authenticateUser = (req, res, next) => {
exports.resetPassword = (req, res, next) => {
if(+common.rtl_sso) {
logger.error({fileName: 'Authenticate', lineNum: 47, msg: 'Password Reset Failed!'});
logger.error({fileName: 'Authenticate', lineNum: 99, msg: 'Password Reset Failed!'});
res.status(401).json({
message: "Password Reset Failed!",
error: "Password cannot be reset for SSO authentication!"
@ -112,7 +112,7 @@ exports.resetPassword = (req, res, next) => {
);
res.status(200).json({ token: token });
} else {
logger.error({fileName: 'Authenticate', lineNum: 63, msg: 'Password Reset Failed!'});
logger.error({fileName: 'Authenticate', lineNum: 115, msg: 'Password Reset Failed!'});
res.status(401).json({
message: "Password Reset Failed!",
error: "Old password is not correct!"

@ -16,7 +16,7 @@ exports.loopOut = (req, res, next) => {
max_prepay_amt: req.body.prepayAmt,
max_swap_fee: req.body.swapFee,
swap_publication_deadline: req.body.swapPublicationDeadline,
label: 'RTL'
initiator: 'RTL'
};
if (req.body.chanId !== '') { options.body['loop_out_channel'] = req.body.chanId; }
if (req.body.destAddress !== '') { options.body['dest'] = req.body.destAddress; }
@ -159,7 +159,7 @@ exports.loopIn = (req, res, next) => {
amt: req.body.amount,
max_swap_fee: req.body.swapFee,
max_miner_fee: req.body.minerFee,
label: 'RTL'
initiator: 'RTL'
};
logger.info({fileName: 'Loop', msg: 'Loop In Body: ' + JSON.stringify(options.body)});
request.post(options).then(function (body) {

@ -39,8 +39,8 @@ $ docker-compose logs bitcoind lnd rtl
Once the containers are running you can access the RTL UI at http://localhost:3000
- Default password is `changeme`.
- Default host, port and password can be changed in `.env`.
- Default password is `password`.
- Default host, port and password can be changed in `.env`.
When you are done you can destroy containers with:
```

1438
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "rtl",
"version": "0.10.1-beta",
"version": "0.10.2-beta",
"license": "MIT",
"scripts": {
"ng": "ng",
@ -58,7 +58,7 @@
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1100.4",
"@angular/cli": "~11.0.4",
"@angular/cli": "^11.2.9",
"@ngrx/store-devtools": "^10.1.0",
"@types/jasmine": "~3.6.0",
"@types/node": "^12.19.9",

@ -24,7 +24,7 @@
<rtl-side-navigation (ChildNavClicked)="onNavigationClicked($event)" fxFlex="100"></rtl-side-navigation>
</mat-sidenav>
<mat-sidenav-content [perfectScrollbar] #sideNavContent>
<div [@routeAnimation]="outlet && outlet.activatedRouteData" class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<router-outlet #outlet="outlet"></router-outlet>
</div>
</mat-sidenav-content>>

@ -51,7 +51,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
document.getElementsByTagName('mat-sidenav-content')[0].scrollTo(0, 0);
});
this.breakpointObserver.observe([Breakpoints.XSmall, Breakpoints.TabletPortrait, Breakpoints.Small, Breakpoints.Medium, Breakpoints.Large, Breakpoints.XLarge])
.pipe(takeUntil(this.unSubs[5]))
.pipe(takeUntil(this.unSubs[0]))
.subscribe((matches) => {
if(matches.breakpoints[Breakpoints.XSmall]) {
this.commonService.setScreenSize(ScreenSizeEnum.XS);
@ -73,7 +73,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.store.dispatch(new RTLActions.FetchRTLConfig());
this.accessKey = this.readAccessKey();
this.store.select('root')
.pipe(takeUntil(this.unSubs[0]))
.pipe(takeUntil(this.unSubs[1]))
.subscribe(rtlStore => {
this.selNode = rtlStore.selNode;
this.settings = this.selNode.settings;
@ -86,15 +86,20 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.flgLoading[0] = false;
} else {
this.flgLoggedIn = true;
this.userIdle.startWatching();
}
});
this.actions$.pipe(takeUntil(this.unSubs[1]),
this.actions$.pipe(takeUntil(this.unSubs[2]),
filter((action) => action.type === RTLActions.SET_RTL_CONFIG || action.type === RTLActions.LOGOUT))
.subscribe((action: (RTLActions.SetRTLConfig | RTLActions.Logout)) => {
if (action.type === RTLActions.SET_RTL_CONFIG) {
if (!this.sessionService.getItem('token')) {
if (+action.payload.sso.rtlSSO) {
this.store.dispatch(new RTLActions.Login({password: sha256(this.accessKey), defaultPassword: false}));
if(!this.accessKey || this.accessKey.trim().length < 32) {
this.router.navigate(['./error'], { state: {errorCode: '406', errorMessage: 'Access key too short. It should be at least 32 characters long.'} });
} else {
this.store.dispatch(new RTLActions.Login({password: sha256(this.accessKey), defaultPassword: false}));
}
} else {
this.router.navigate(['./login']);
}
@ -102,11 +107,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
}
if (action.type === RTLActions.LOGOUT) {
this.flgLoggedIn = false;
this.userIdle.stopWatching();
this.userIdle.stopTimer();
}
});
this.userIdle.startWatching();
this.userIdle.onTimerStart().pipe(takeUntil(this.unSubs[2])).subscribe(count => {});
this.userIdle.onTimeout().pipe(takeUntil(this.unSubs[3])).subscribe(() => {
this.userIdle.onTimerStart().pipe(takeUntil(this.unSubs[3])).subscribe(count => {this.logger.info('Counting Down: ' + (11 - count))});
this.userIdle.onTimeout().pipe(takeUntil(this.unSubs[4])).subscribe(() => {
this.logger.info('Time Out!');
if (this.sessionService.getItem('token')) {
this.flgLoggedIn = false;
this.logger.warn('Time limit exceeded for session inactivity.');
@ -117,14 +124,13 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
titleMessage: 'Time limit exceeded for session inactivity.'
}}));
this.store.dispatch(new RTLActions.Logout());
this.userIdle.resetTimer();
}
});
}
private readAccessKey() {
const url = window.location.href;
return url.includes('access-key=') ? url.substring(url.lastIndexOf('access-key=') + 11).trim() : '';
return url.includes('access-key=') ? url.substring(url.lastIndexOf('access-key=') + 11).trim() : null;
}
ngAfterViewInit() {

@ -36,7 +36,7 @@ import { LayoutModule } from '@angular/cdk/layout';
routing,
LayoutModule,
HammerModule,
UserIdleModule.forRoot({idle: 60 * 60, timeout: 1}),
UserIdleModule.forRoot({idle: 3590, timeout: 10, ping: 12000}), // One hour
StoreModule.forRoot(RTLReducer, {
runtimeChecks: {
strictStateImmutability: false,

@ -1,4 +1,4 @@
<div [@routeAnimation]="outlet && outlet.activatedRouteData" class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<router-outlet #outlet="outlet"></router-outlet>
</div>

@ -30,7 +30,7 @@
</div>
</div>
<ng-template #noChannelBlock>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1 w-100">
No channels available.
<button mat-stroked-button color="primary" (click)="goToChannels()" tabindex="1">Open Channel</button>
</div>

@ -1,4 +1,4 @@
<div fxLayout="column" class="padding-gap-x-large">
<div fxLayout="column" class="padding-gap-x">
<div fxLayout="row" fxLayoutAlign="space-between end" fxLayoutAlign.gt-sm="start end">
<mat-form-field fxFlex="48" fxFlex.gt-md="25" fxLayoutAlign="start end" class="mr-2">
<mat-select [(ngModel)]="selectedAddressType" placeholder="Address Type" name="address_type" tabindex="1">

@ -1,13 +1,13 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{sweepAll ? 'Sweep All Funds' : 'Send Funds'}}</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" *ngIf="!sweepAll; else sweepAllBlock;" class="padding-gap overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" *ngIf="!sweepAll; else sweepAllBlock;" class="overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-form-field fxFlex="55">
<input matInput autoFocus [(ngModel)]="transaction.address" placeholder="Bitcoin Address" tabindex="1" name="address" required #address="ngModel">
<mat-error *ngIf="!transaction.address">Bitcoin address is required.</mat-error>

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x">
<div fxLayout="row">
<button mat-flat-button color="primary" type="button" tabindex="1" (click)="openSendFundsModal()">{{sweepAll ? 'Sweep All' : 'Send Funds'}}</button>
</div>

@ -62,10 +62,9 @@
</ng-container>
<tr mat-footer-row *matFooterRowDef="['no_utxo']" [ngClass]="{'display-none': listUTXOs?.data && listUTXOs?.data?.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<!-- <tr mat-row *matRowDef="let row; columns: displayedColumns;" [ngClass]="{'alert alert-warn': !isDustUTXO && row.value < 10000}"></tr> -->
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>
</div>

@ -1,4 +1,4 @@
import { Component, ViewChild, Input, OnChanges } from '@angular/core';
import { Component, ViewChild, Input, OnChanges, AfterViewInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
@ -21,7 +21,7 @@ import * as fromRTLReducer from '../../../../store/rtl.reducers';
{ provide: MatPaginatorIntl, useValue: getPaginatorLabel('UTXOs') }
]
})
export class CLOnChainUtxosComponent implements OnChanges {
export class CLOnChainUtxosComponent implements OnChanges, AfterViewInit {
@ViewChild(MatSort, { static: false }) sort: MatSort|undefined;
@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator|undefined;
@Input() numDustUTXOs = 0;
@ -53,6 +53,12 @@ export class CLOnChainUtxosComponent implements OnChanges {
}
}
ngAfterViewInit() {
if (this.utxos && this.utxos.length > 0 && this.sort && this.paginator) {
this.loadUTXOsTable(this.utxos);
}
}
ngOnChanges() {
if (this.utxos && this.utxos.length > 0) {
this.loadUTXOsTable(this.utxos);
@ -81,8 +87,8 @@ export class CLOnChainUtxosComponent implements OnChanges {
loadUTXOsTable(utxos: any[]) {
this.listUTXOs = new MatTableDataSource<UTXO>([...utxos]);
this.listUTXOs.sort = this.sort;
this.listUTXOs.sortingDataAccessor = (data: any, sortHeaderId: string) => (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
this.listUTXOs.sort = this.sort;
this.listUTXOs.filterPredicate = (utxo: UTXO, fltr: string) => JSON.stringify(utxo).toLowerCase().includes(fltr);
this.listUTXOs.paginator = this.paginator;
this.logger.info(this.listUTXOs);

@ -1,13 +1,13 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="padding-gap-large pl-3">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-1">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Channel Information</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxLayout="row">
<div fxFlex="50">
@ -71,8 +71,8 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.private ? 'Yes' : 'No'}}</span>
</div>
</div>
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div *ngIf="showAdvanced">
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Funding Transaction Id</h4>

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -100,5 +100,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -157,9 +157,9 @@ export class CLChannelOpenTableComponent implements OnInit, AfterViewInit, OnDes
this.clEffects.setLookupCL
.pipe(take(1))
.subscribe((resLookup: ChannelEdge[]) => {
if (resLookup.length > 0 && resLookup[0].destination === this.information.id) {
if (resLookup.length > 0 && resLookup[0].source === this.information.id) {
this.myChanPolicy = {fee_base_msat: resLookup[0].base_fee_millisatoshi, fee_rate_milli_msat: resLookup[0].fee_per_millionth};
} else if (resLookup.length > 1 && resLookup[1].destination === this.information.id) {
} else if (resLookup.length > 1 && resLookup[1].source === this.information.id) {
this.myChanPolicy = {fee_base_msat: resLookup[1].base_fee_millisatoshi, fee_rate_milli_msat: resLookup[1].fee_per_millionth};
} else {
this.myChanPolicy = {fee_base_msat: 0, fee_rate_milli_msat: 0};
@ -232,10 +232,10 @@ export class CLChannelOpenTableComponent implements OnInit, AfterViewInit, OnDes
});
this.channels = new MatTableDataSource<Channel>([...mychannels]);
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id : '') +
(channel.short_channel_id ? channel.short_channel_id : '') + (channel.id ? channel.id : '') + (channel.alias ? channel.alias : '') +
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id.toLowerCase() : '') +
(channel.short_channel_id ? channel.short_channel_id.toLowerCase() : '') + (channel.id ? channel.id.toLowerCase() : '') + (channel.alias ? channel.alias.toLowerCase() : '') +
(channel.private ? 'private' : 'public') + (channel.state ? channel.state.toLowerCase() : '') +
(channel.funding_txid ? channel.funding_txid : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.funding_txid ? channel.funding_txid.toLowerCase() : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.msatoshi_total ? channel.msatoshi_total : '') + (channel.their_channel_reserve_satoshis ? channel.their_channel_reserve_satoshis : '') +
(channel.our_channel_reserve_satoshis ? channel.our_channel_reserve_satoshis : '') + (channel.spendable_msatoshi ? channel.spendable_msatoshi : '');
return newChannel.includes(fltr);

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -73,5 +73,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -79,7 +79,7 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
}
this.numPeers = (rtlStore.peers && rtlStore.peers.length) ? rtlStore.peers.length : 0;
this.totalBalance = rtlStore.balance.totalBalance;
this.channelsData = rtlStore.allChannels.filter(channel => !(channel.state === 'CHANNELD_NORMAL' && channel.connected));
this.channelsData = this.commonService.sortByKey(rtlStore.allChannels.filter(channel => !(channel.state === 'CHANNELD_NORMAL' && channel.connected)), 'state', 'string');
if (this.channelsData.length > 0) {
this.loadChannelsTable(this.channelsData);
}
@ -132,10 +132,10 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
});
this.channels = new MatTableDataSource<Channel>([...mychannels]);
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id : '') +
(channel.short_channel_id ? channel.short_channel_id : '') + (channel.id ? channel.id : '') + (channel.alias ? channel.alias : '') +
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id.toLowerCase() : '') +
(channel.short_channel_id ? channel.short_channel_id.toLowerCase() : '') + (channel.id ? channel.id.toLowerCase() : '') + (channel.alias ? channel.alias.toLowerCase() : '') +
(channel.private ? 'private' : 'public') + (channel.state ? channel.state.toLowerCase() : '') +
(channel.funding_txid ? channel.funding_txid : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.funding_txid ? channel.funding_txid.toLowerCase() : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.msatoshi_total ? channel.msatoshi_total : '') + (channel.their_channel_reserve_satoshis ? channel.their_channel_reserve_satoshis : '') +
(channel.our_channel_reserve_satoshis ? channel.our_channel_reserve_satoshis : '') + (channel.spendable_msatoshi ? channel.spendable_msatoshi : '');
return newChannel.includes(fltr);

@ -1,8 +1,8 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxLayout="row">
<button mat-flat-button color="primary" (click)="onOpenChannel()" type="submit" tabindex="1">Open Channel</button>
</div>
<div fxLayout="column" fxFlex="100" class="mt-2 bordered-box">
<div fxLayout="column" fxFlex="100" class="my-2 bordered-box">
<mat-tab-group [(selectedIndex)]="activeLink" (selectedTabChange)="onSelectedTabChange($event)">
<mat-tab>
<ng-template mat-tab-label>

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{alertTitle}}</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="column" (submit)="onOpenChannel()" (reset)="resetData()" #form="ngForm">
<div fxLayout="column">
<mat-form-field fxFlex="100" *ngIf="!peer && peers && peers.length > 0">

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Connect to a new peer</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<div fxLayout="column">
<mat-vertical-stepper [linear]="true" #stepper (selectionChange)="stepSelectionChanged($event)">
<mat-step [stepControl]="peerFormGroup" [editable]="flgEditable">

@ -1,9 +1,9 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #peersForm="ngForm">
<button mat-flat-button color="primary" type="submit" tabindex="1" (click)="onConnectPeer({})">Add Peer</button>
</form>
<div fxLayout="column">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70">
<fa-icon [icon]="faUsers" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Connected Peers</span>
@ -68,6 +68,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.pub_key === newlyAddedPeer && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -1,6 +1,6 @@
<div fxLayout="column" fxLayoutAlign="start stretch" [ngClass]="{'error-border': errorMessage !== '', 'padding-gap-x': true}">
<div class="p-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target)" placeholder="Filter">
@ -69,5 +69,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -101,7 +101,7 @@ export class CLFailedTransactionsComponent implements OnInit, AfterViewInit, OnD
this.forwardingHistoryEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
this.forwardingHistoryEvents.paginator = this.paginator;
this.forwardingHistoryEvents.filterPredicate = (event: ForwardingEvent, fltr: string) => {
const newEvent = event.status + event.received_time_str + event.resolved_time_str + event.in_channel + event.out_channel + (event.in_msatoshi/1000) + (event.out_msatoshi/1000) + event.fee;
const newEvent = (event.status ? event.status.toLowerCase() : '') + (event.received_time_str ? event.received_time_str.toLowerCase() : '') + (event.resolved_time_str ? event.resolved_time_str.toLowerCase() : '') + (event.in_channel ? event.in_channel.toLowerCase() : '') + (event.out_channel ? event.out_channel.toLowerCase() : '') + (event.in_msatoshi ? (event.in_msatoshi/1000) : '') + (event.out_msatoshi ? (event.out_msatoshi/1000) : '') + (event.fee ? event.fee : '');
return newEvent.includes(fltr);
};
this.logger.info(this.forwardingHistoryEvents);

@ -1,6 +1,6 @@
<div fxLayout="column" fxLayoutAlign="start stretch" [ngClass]="{'error-border': errorMessage !== '', 'padding-gap-x': true}">
<div class="p-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput [(ngModel)]="filterValue" (input)="applyFilter()" (keyup)="applyFilter()" name="filter" placeholder="Filter">
@ -69,5 +69,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -116,7 +116,7 @@ export class CLForwardingHistoryComponent implements OnInit, AfterViewInit, OnDe
this.forwardingHistoryEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
this.forwardingHistoryEvents.paginator = this.paginator;
this.forwardingHistoryEvents.filterPredicate = (event: ForwardingEvent, fltr: string) => {
const newEvent = event.received_time_str.toLowerCase() + event.resolved_time_str.toLowerCase() + event.in_channel + event.out_channel + (event.in_msatoshi/1000) + (event.out_msatoshi/1000) + event.fee;
const newEvent = (event.received_time_str ? event.received_time_str.toLowerCase() : '') + (event.resolved_time_str ? event.resolved_time_str.toLowerCase() : '') + (event.in_channel ? event.in_channel.toLowerCase() : '') + (event.out_channel ? event.out_channel.toLowerCase() : '') + (event.in_msatoshi ? (event.in_msatoshi/1000) : '') + (event.out_msatoshi ? (event.out_msatoshi/1000) : '') + (event.fee ? event.fee : '');
return newEvent.includes(fltr);
};
this.logger.info(this.forwardingHistoryEvents);

@ -5,10 +5,8 @@ import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { faMapSigns } from '@fortawesome/free-solid-svg-icons';
import * as CLActions from '../store/cl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
@Component({
selector: 'rtl-cl-routing',
templateUrl: './routing.component.html',
@ -33,7 +31,6 @@ export class CLRoutingComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.store.dispatch(new CLActions.SetForwardingHistory({}));
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();

@ -19,6 +19,7 @@ import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
import * as CLActions from './cl.actions';
import * as fromCLReducers from '../store/cl.reducers';
import { AlertTypeEnum, CurrencyUnitEnum } from '../../shared/services/consts-enums-functions';
@Injectable()
export class CLEffects implements OnDestroy {
@ -55,11 +56,25 @@ export class CLEffects implements OnDestroy {
takeUntil(this.actions$.pipe(ofType(RTLActions.SET_SELECTED_NODE))),
map((info) => {
this.logger.info(info);
this.initializeRemainingData(info, action.payload.loadPage);
return {
type: CLActions.SET_INFO_CL,
payload: info ? info : {}
};
if (info.chains && info.chains.length && info.chains[0]
&& (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain') && info.chains[0].chain.toLowerCase().indexOf('bitcoin') < 0)
) {
this.store.dispatch(new RTLActions.CloseAllDialogs());
this.store.dispatch(new RTLActions.OpenAlert({ data: {
type: AlertTypeEnum.ERROR,
alertTitle: 'Shitcoin Found',
titleMessage: 'Sorry Not Sorry, RTL is Bitcoin Only!'
}}));
return {
type: RTLActions.LOGOUT
};
} else {
this.initializeRemainingData(info, action.payload.loadPage);
return {
type: CLActions.SET_INFO_CL,
payload: info ? info : {}
};
}
}),
catchError((err) => {
const code = (err.error && err.error.error && err.error.error.message && err.error.error.message.code) ? err.error.error.message.code : (err.error && err.error.error && err.error.error.code) ? err.error.error.code : err.status ? err.status : '';
@ -310,9 +325,9 @@ export class CLEffects implements OnDestroy {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
if(action.payload.channelId === 'all') {
this.store.dispatch(new RTLActions.OpenSnackBar('All Channels Updated Successfully.'));
this.store.dispatch(new RTLActions.OpenSnackBar({message:'All Channels Updated Successfully. Fee policy updates may take some time to reflect on the channel.', duration: 5000}));
} else {
this.store.dispatch(new RTLActions.OpenSnackBar('Channel Updated Successfully!'));
this.store.dispatch(new RTLActions.OpenSnackBar({message:'Channel Updated Successfully. Fee policy updates may take some time to reflect on the channel.', duration: 5000}));
}
return {
type: CLActions.FETCH_CHANNELS_CL
@ -724,13 +739,13 @@ export class CLEffects implements OnDestroy {
const node_data = {
identity_pubkey: info.id,
alias: info.alias,
testnet: (info.network === 'testnet' || info.network === 'litecoin-testnet') ? true : false,
testnet: (info.network.toLowerCase() === 'testnet') ? true : false,
chains: info.chains,
uris: info.uris,
version: info.version,
api_version: info.api_version,
currency_unit: 'BTC',
smaller_currency_unit: 'Sats',
currency_unit: CurrencyUnitEnum.BTC,
smaller_currency_unit: CurrencyUnitEnum.SATS,
numberOfPendingChannels: info.num_pending_channels
};
this.store.dispatch(new RTLActions.OpenSpinner('Initializing Node Data...'));

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Create Invoice</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #addInvoiceForm="ngForm">
<mat-form-field fxFlex="100" fxLayoutAlign="start end">
<input matInput autoFocus [(ngModel)]="description" placeholder="Description" tabindex="2" name="description">
@ -34,7 +34,7 @@
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
<span *ngIf="invoiceError !== ''">{{invoiceError}}</span>
</div>
<div fxLayout="row" fxFlex="100" class="mt-2" fxLayoutAlign="end center">
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">
<button class="mr-1" mat-stroked-button color="primary" tabindex="7" type="reset" (click)="resetData()">Clear Field</button>
<button mat-flat-button color="primary" (click)="onAddInvoice(addInvoiceForm)" tabindex="8">Create Invoice</button>
</div>

@ -2,15 +2,15 @@
<div fxFlex="35" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.bolt11" [margin]="2" [width]="qrWidth" [errorCorrectionLevel]="'L'" [allowEmptyString]="true"></qrcode>
</div>
<div fxFlex="65" class="padding-gap-large">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-1">
<div fxFlex="65">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">{{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}}</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxFlex="30" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.bolt11" [margin]="2" [width]="qrWidth" [errorCorrectionLevel]="'L'" [allowEmptyString]="true"></qrcode>

@ -81,6 +81,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.label == newlyAddedInvoiceMemo && row.value == newlyAddedInvoiceValue && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -135,6 +135,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns; when: !is_group;" [@newlyAddedRowAnimation]="(row.payment_hash === newlyAddedPayment && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -17,7 +17,7 @@
<button mat-flat-button color="primary" type="submit" tabindex="4">Query Route</button>
</div>
</form>
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2 mb-1">
<div fxLayout="row" fxLayoutAlign="start center" class="page-sub-title-container mt-2 mb-1">
<div fxFlex="70">
<fa-icon [icon]="faRoute" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Transaction Route</span>

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Send Payment</span>
</div>
<button tabindex="12" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px" fxLayout="column" fxLayoutAlign="start stretch">
<mat-card-content class="padding-gap-x-large" fxLayout="column" fxLayoutAlign="start stretch">
<mat-radio-group *ngIf="isCompatibleVersion" class="my-1" color="primary" name="paymentType" [(ngModel)]="paymentType" (change)="onPaymentTypeChange()" fxFlex="100" fxLayoutAlign="start stretch">
<mat-radio-button fxFlex="25" tabindex="1" value="invoice" class="mr-2">Invoice Payment</mat-radio-button>
<mat-radio-button fxFlex="25" tabindex="2" value="keysend">Keysend Payment</mat-radio-button>

@ -1,4 +1,4 @@
<div [@routeAnimation]="outlet && outlet.activatedRouteData" class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<router-outlet #outlet="outlet"></router-outlet>
</div>

@ -30,7 +30,7 @@
</div>
</div>
<ng-template #noChannelBlock>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1 w-100">
No channels available.
<button mat-stroked-button color="primary" (click)="goToChannels()" tabindex="1">Open Channel</button>
</div>

@ -1,5 +1,5 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<div fxLayout="row" class="mt-1">
<button mat-flat-button color="primary" (click)="onGenerateAddress()" tabindex="1" class="top-minus-15px">Generate Address</button>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxLayout="row">
<button mat-flat-button color="primary" (click)="onGenerateAddress()" tabindex="1">Generate Address</button>
</div>
</div>

@ -1,13 +1,13 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Send Payment</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<form fxLayout="row wrap" fxFlex="100" fxLayoutAlign="space-between start" class="padding-gap overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxFlex="100" fxLayoutAlign="space-between start" class="overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-form-field fxFlex="55">
<input matInput autoFocus [(ngModel)]="transaction.address" placeholder="Bitcoin Address" tabindex="1" name="addr" required #addrs="ngModel">
<mat-error *ngIf="!transaction.address">Bitcoin address is required.</mat-error>

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x-large">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxLayout="row">
<button mat-flat-button color="primary" type="button" tabindex="1" (click)="openSendFundsModal()">{{sweepAll ? 'Sweep All' : 'Send Funds'}}</button>
</div>

@ -1,4 +1,4 @@
<div fxLayout="row wrap" fxLayoutAlign="start start" fxLayout.gt-sm="column" fxFlex="100" fxLayoutAlign.gt-sm="start stretch" class="padding-gap-x-large">
<div fxLayout="row wrap" fxLayoutAlign="start start" fxLayout.gt-sm="column" fxFlex="100" fxLayoutAlign.gt-sm="start stretch">
<div fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70">
<fa-icon [icon]="faHistory" class="page-title-img mr-1"></fa-icon>
@ -59,7 +59,7 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>
</div>

@ -1,13 +1,13 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="padding-gap-large pl-3">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-1">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Channel Information</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxLayout="row">
<div *ngIf="channelsType === 'open'" fxFlex="50">
@ -59,8 +59,8 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.isFunder ? 'Yes' : 'No'}}</span>
</div>
</div>
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div *ngIf="showAdvanced && channelsType === 'open'">
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Base Fee (mSats)</h4>

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -78,5 +78,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -78,5 +78,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -49,5 +49,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,8 +1,8 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxLayout="row">
<button mat-flat-button color="primary" (click)="onOpenChannel()" type="submit" tabindex="1">Open Channel</button>
</div>
<div fxLayout="column" fxFlex="100" class="mt-2 bordered-box">
<div fxLayout="column" fxFlex="100" class="my-2 bordered-box">
<mat-tab-group [(selectedIndex)]="activeLink" (selectedTabChange)="onSelectedTabChange($event)">
<mat-tab>
<ng-template mat-tab-label>

@ -47,6 +47,8 @@ export class ECLChannelsTablesComponent implements OnInit, OnDestroy {
this.information = rtlStore.information;
this.peers = rtlStore.peers;
this.totalBalance = rtlStore.onchainBalance.total;
console.warn(this.numOfPendingChannels);
console.warn(rtlStore.channelsStatus.pending);
this.logger.info(rtlStore);
});
}

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{alertTitle}}</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="column" (submit)="onOpenChannel()" (reset)="resetData()" #form="ngForm">
<div fxLayout="column">
<mat-form-field fxFlex="100" *ngIf="!peer && peers && peers.length > 0">

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Connect to a new peer</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<div fxLayout="column">
<mat-vertical-stepper [linear]="true" #stepper (selectionChange)="stepSelectionChanged($event)">
<mat-step [stepControl]="peerFormGroup" [editable]="flgEditable">

@ -1,9 +1,9 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #peersForm="ngForm">
<button mat-flat-button color="primary" type="submit" tabindex="1" (click)="onConnectPeer({})">Add Peer</button>
</form>
<div fxLayout="column">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70">
<fa-icon [icon]="faUsers" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Peers</span>
@ -74,6 +74,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.pub_key === newlyAddedPeer && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -1,6 +1,6 @@
<div fxLayout="column" fxLayoutAlign="start stretch" [ngClass]="{'error-border': errorMessage !== '', 'padding-gap-x': true}">
<div class="p-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput [(ngModel)]="filterValue" (input)="applyFilter()" (keyup)="applyFilter()" name="filter" placeholder="Filter">
@ -55,5 +55,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,8 +1,8 @@
<div fxLayout="column" fxLayoutAlign="start stretch" [ngClass]="{'error-border': errorMessage !== '', 'padding-gap': true}">
<div class="p-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-md="row" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x page-sub-title-container">
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-md="row" fxFlex="100" fxLayoutAlign="space-between stretch" class="page-sub-title-container">
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start end" class="mb-6">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize === screenSizeEnum.XS, 'mt-1': screenSize === screenSizeEnum.SM}">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize === screenSizeEnum.XS, 'mt-1': screenSize === screenSizeEnum.SM}">
<div fxFlex="70">Incoming</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyIncomingFilter($event.target)" placeholder="Filter">
@ -41,10 +41,10 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator #paginatorIn [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator #paginatorIn [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start start">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize !== screenSizeEnum.LG}">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize !== screenSizeEnum.LG}">
<div fxFlex="70">Outgoing</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyOutgoingFilter($event.target)" placeholder="Filter">
@ -82,7 +82,7 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #paginatorOut [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator #paginatorOut [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>
</div>

@ -125,7 +125,7 @@ export class ECLEffects implements OnDestroy {
this.store.dispatch(new ECLActions.SetPendingChannels((channelsRes && channelsRes.pendingChannels.length > 0) ? channelsRes.pendingChannels : []));
this.store.dispatch(new ECLActions.SetInactiveChannels((channelsRes && channelsRes.inactiveChannels.length > 0) ? channelsRes.inactiveChannels : []));
this.store.dispatch(new ECLActions.SetLightningBalance(channelsRes.lightningBalances));
if (action.payload.fetchPayments) {
if (action.payload && action.payload.fetchPayments) {
this.store.dispatch(new ECLActions.FetchPayments());
}
return {
@ -243,11 +243,12 @@ export class ECLEffects implements OnDestroy {
.pipe(
map((postRes: Peer[]) => {
this.logger.info(postRes);
postRes = (postRes && postRes.length) ? postRes : [];
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new ECLActions.SetPeers((postRes && postRes.length) ? postRes : []));
this.store.dispatch(new ECLActions.SetPeers(postRes));
return {
type: ECLActions.NEWLY_ADDED_PEER_ECL,
payload: { peer: postRes[0] }
payload: { peer: postRes.find(peer => peer.nodeId === (action.payload.id.includes('@') ? action.payload.id.substring(0, action.payload.id.indexOf('@')) : action.payload.id)) }
};
}),
catchError((err: any) => {
@ -298,7 +299,8 @@ export class ECLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenSnackBar('Channel Added Successfully!'));
return {
type: ECLActions.FETCH_CHANNELS_ECL
type: ECLActions.FETCH_CHANNELS_ECL,
payload: { fetchPayments: false }
};
}),
catchError((err: any) => {
@ -330,7 +332,8 @@ export class ECLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.OpenSnackBar('Channel Updated Successfully!'));
}
return {
type: ECLActions.FETCH_CHANNELS_ECL
type: ECLActions.FETCH_CHANNELS_ECL,
payload: { fetchPayments: false }
};
}),
catchError((err: any) => {

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Create Invoice</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #addInvoiceForm="ngForm">
<mat-form-field fxFlex="100" fxLayoutAlign="start end">
<input matInput autoFocus [(ngModel)]="description" placeholder="Description" tabindex="2" name="description" required>

@ -2,15 +2,15 @@
<div fxFlex="35" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.serialized" [margin]="2" [width]="qrWidth" [errorCorrectionLevel]="'L'" [allowEmptyString]="true"></qrcode>
</div>
<div fxFlex="65" class="padding-gap-large">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-1">
<div fxFlex="65">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">{{screenSize === screenSizeEnum.XS ? (newlyAdded ? 'Created' : 'Invoice') : (newlyAdded ? 'Invoice Created' : 'Invoice Information')}}</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxFlex="30" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap" [ngClass]="{'display-none': screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM}">
<qrcode [qrdata]="invoice.serialized" [margin]="2" [width]="qrWidth" [errorCorrectionLevel]="'L'" [allowEmptyString]="true"></qrcode>

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="padding-gap">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<form *ngIf="calledFrom === 'home'" fxLayout="row wrap" fxLayoutAlign="stretch start" fxFlex="100" #addInvoiceForm="ngForm">
<mat-form-field fxFlex="100" fxLayoutAlign="space-between stretch">
<input matInput [(ngModel)]="description" placeholder="Description" tabindex="2" name="description" required="true">
@ -86,6 +86,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.label == newlyAddedInvoiceMemo && row.value == newlyAddedInvoiceValue && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -1,12 +1,12 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="padding-gap-large pl-3">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Payment Information</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [perfectScrollbar] class="mt-5px mb-0 pr-2 h-40" #scrollContainer>
<mat-card-content [perfectScrollbar] class="h-40 padding-gap-x-large" #scrollContainer>
<div fxLayout="column">
<div fxLayout="row">
<div fxFlex="30">
@ -96,12 +96,12 @@
</div>
</div>
</mat-card-content>
<div fxLayout="row" fxLayoutAlign="start end" class="btn-sticky-container">
<div fxLayout="row" fxLayoutAlign="start end" class="btn-sticky-container padding-gap-x-large">
<button mat-mini-fab aria-label="Scroll Down" fxLayoutAlign="center center" (click)="onScrollDown()">
<mat-icon fxLayoutAlign="center center">arrow_downward</mat-icon>
</button>
</div>
<div fxLayout="row" fxLayoutAlign="end center" class="mt-1">
<div fxLayout="row" fxLayoutAlign="end center" class="padding-gap-x-large padding-gap-bottom-large">
<button class="mr-1" fxLayoutAlign="center center" tabindex="1" mat-stroked-button color="primary" type="button" [mat-dialog-close]="false" default>OK</button>
</div>
</div>

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<form *ngIf="calledFrom === 'home'" fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #sendPaymentForm="ngForm">
<mat-form-field fxFlex="100">
<textarea [perfectScrollbar] matInput placeholder="Payment Request" name="paymentRequest" tabindex="1" [ngModel]="paymentRequest" (ngModelChange)="onPaymentRequestEntry($event)" required (matTextareaAutosize)="true" #paymentReq="ngModel"></textarea>
@ -140,6 +140,6 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;" [@newlyAddedRowAnimation]="(row.payment_hash === newlyAddedPayment && flgAnimate) ? 'added' : 'notAdded'"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" class="padding-gap">
<div fxLayout="column" fxFlex="100">
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" (ngSubmit)="queryRoutesForm.form.valid && onQueryRoutes()" #queryRoutesForm="ngForm">
<div fxFlex="100" class="alert alert-warn">
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
@ -17,7 +17,7 @@
<button mat-flat-button color="primary" type="submit" tabindex="4">Query Route</button>
</div>
</form>
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2 mb-1">
<div fxLayout="row" fxLayoutAlign="start center" class="page-sub-title-container mt-2 mb-1">
<div fxFlex="70">
<fa-icon [icon]="faRoute" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Transaction Route</span>

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Send Payment</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayoutAlign="space-between stretch" fxLayout="column" #sendPaymentForm="ngForm">
<mat-form-field fxFlex="100">
<textarea autoFocus matInput placeholder="Payment Request" name="paymentRequest" tabindex="1" [ngModel]="paymentRequest" (ngModelChange)="onPaymentRequestEntry($event)" (matTextareaAutosize)="true" required #paymentReq="ngModel"></textarea>

@ -14,7 +14,7 @@
<button mat-flat-button color="primary" tabindex="3" (click)="onDownloadBackup({})">Download Backup</button>
</div>
</div>
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container mt-2">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-2">
<div fxFlex="70">
<fa-icon [icon]="faArchive" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Backups</span>
@ -54,5 +54,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -76,7 +76,7 @@ export class ChannelBackupTableComponent implements OnInit, AfterViewInit, OnDes
this.selectedChannel = undefined;
}
if(action.type === RTLActions.SHOW_FILE) {
this.commonService.downloadFile(action.payload, 'Backup-Channel-' + (this.selectedChannel.channel_point ? this.selectedChannel.channel_point : 'All'), '.bak', '.bak');
this.commonService.downloadFile(action.payload, 'channel-' + (this.selectedChannel.channel_point ? this.selectedChannel.channel_point : 'all'), '.bak', '.bak');
this.selectedChannel = undefined;
this.store.dispatch(new RTLActions.CloseSpinner());
}
@ -123,8 +123,8 @@ export class ChannelBackupTableComponent implements OnInit, AfterViewInit, OnDes
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
this.channels.paginator = this.paginator;
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
const newChannel = ((channel.active) ? 'active' : 'inactive') + (channel.channel_point ? channel.channel_point : '') + (channel.chan_id ? channel.chan_id : '') +
(channel.remote_pubkey ? channel.remote_pubkey : '') + (channel.remote_alias ? channel.remote_alias : '') +
const newChannel = ((channel.active) ? 'active' : 'inactive') + (channel.channel_point ? channel.channel_point.toLowerCase() : '') + (channel.chan_id ? channel.chan_id.toLowerCase() : '') +
(channel.remote_pubkey ? channel.remote_pubkey.toLowerCase() : '') + (channel.remote_alias ? channel.remote_alias.toLowerCase() : '') +
(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 : '') +

@ -12,7 +12,7 @@
<div fxLayout="column" fxLayoutAlign="space-between start" fxLayout.gt-md="row wrap" *ngIf="!allRestoreExists && channels && channels?.data?.length && channels?.data?.length>0">
<h4 fxFlex="100">Restore folder location: {{selNode.channelBackupPath}}/restore</h4>
</div>
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container mt-2">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container mt-2">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target)" placeholder="Filter">
@ -43,5 +43,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -30,7 +30,7 @@
</div>
</div>
<ng-template #noChannelBlock>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" class="mt-1 w-100">
No channels available.
<button mat-stroked-button color="primary" (click)="goToChannels()" tabindex="1">Open Channel</button>
</div>

@ -1,4 +1,4 @@
<div [@routeAnimation]="outlet && outlet.activatedRouteData" class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div class="inner-sidenav-content" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<router-outlet #outlet="outlet"></router-outlet>
</div>

@ -1,13 +1,13 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Label UTXO</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" class="padding-gap overflow-x-hidden" (submit)="onLabelUTXO()" (reset)="resetData()" #form="ngForm">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" class="overflow-x-hidden" (submit)="onLabelUTXO()" (reset)="resetData()" #form="ngForm">
<mat-form-field fxFlex.gt-sm="100">
<input autoFocus matInput [(ngModel)]="label" placeholder="UTXO Label" name="label" tabindex="1" required>
<mat-error *ngIf="!label">UTXO Label is required.</mat-error>

@ -1,13 +1,13 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{sweepAll ? 'Sweep All Funds' : 'Send Funds'}}</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" *ngIf="!sweepAll; else sweepAllBlock;" class="padding-gap overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" *ngIf="!sweepAll; else sweepAllBlock;" class="overflow-x-hidden" (submit)="onSendFunds()" (reset)="resetData()" #form="ngForm">
<mat-form-field fxFlex.gt-sm="55">
<input autoFocus matInput [(ngModel)]="transactionAddress" placeholder="Bitcoin Address" tabindex="1" name="address" required #address="ngModel">
<mat-error *ngIf="!transactionAddress">Bitcoin address is required.</mat-error>

@ -59,7 +59,7 @@
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>
</div>

@ -72,7 +72,7 @@
<!-- <tr mat-row *matRowDef="let row; columns: displayedColumns;" [ngClass]="{'alert alert-warn': !isDustUTXO && row.amount_sat < 1000}"></tr> -->
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>
</div>
</div>

@ -93,9 +93,9 @@ export class OnChainUTXOsComponent implements OnChanges, OnDestroy {
loadUTXOsTable(UTXOs: UTXO[]) {
this.listUTXOs = new MatTableDataSource<UTXO>([...UTXOs]);
this.listUTXOs.filterPredicate = (utxo: UTXO, fltr: string) => {
const newUTXO = ((utxo.label ? utxo.label : '') + (utxo.outpoint.txid_str ? utxo.outpoint.txid_str : '') + (utxo.outpoint.output_index ? utxo.outpoint.output_index : '')
+ (utxo.outpoint.txid_bytes ? utxo.outpoint.txid_bytes : '') + (utxo.address ? utxo.address : '') + (utxo.address_type ? utxo.address_type : '')
+ (utxo.amount_sat ? utxo.amount_sat : '') + (utxo.confirmations ? utxo.confirmations : '') + (utxo.pk_script ? utxo.pk_script : ''));
const newUTXO = ((utxo.label ? utxo.label.toLowerCase() : '') + (utxo.outpoint.txid_str ? utxo.outpoint.txid_str.toLowerCase() : '') + (utxo.outpoint.output_index ? utxo.outpoint.output_index : '')
+ (utxo.outpoint.txid_bytes ? utxo.outpoint.txid_bytes.toLowerCase() : '') + (utxo.address ? utxo.address.toLowerCase() : '') + (utxo.address_type ? utxo.address_type.toLowerCase() : '')
+ (utxo.amount_sat ? utxo.amount_sat : '') + (utxo.confirmations ? utxo.confirmations : '') + (utxo.pk_script ? utxo.pk_script.toLowerCase() : ''));
return newUTXO.includes(fltr);
};
this.listUTXOs.sortingDataAccessor = (data: any, sortHeaderId: string) => {

@ -1,15 +1,17 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Bump Fee</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<form fxLayout="column">
<div fxLayout="column" class="bordered-box my-2 p-2">
<p fxLayoutAlign="start center" class="pb-1 word-break">Bump fee for channel point: {{bumpFeeChannel?.channel?.channel_point}}</p>
<div fxLayout="column" class="bordered-box mb-1 p-2">
<p fxLayoutAlign="start center" class="pb-1 word-break">Bump fee for channel point: {{bumpFeeChannel?.channel?.channel_point}}
<fa-icon class="ml-1" [icon]="faCopy" matSuffix rtlClipboard [payload]="bumpFeeChannel?.channel?.txid_str" (copied)="onCopyID($event)" matTooltip="Copy transaction ID"></fa-icon>
</p>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info">
<fa-icon [icon]="faInfoCircle" class="mr-1 alert-icon"></fa-icon>

@ -1,10 +1,11 @@
import { Component, OnInit, OnDestroy, ViewChild, Inject } from '@angular/core';
import { NgModel } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { faCopy, faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { PendingOpenChannel } from '../../../../shared/models/lndModels';
import { PendingOpenChannelInformation } from '../../../../shared/models/alertData';
@ -23,16 +24,17 @@ export class BumpFeeComponent implements OnInit, OnDestroy {
@ViewChild('outputIdx') set payReq(outIdx: NgModel) {if(outIdx) { this.outputIdx = outIdx; }}
public bumpFeeChannel: PendingOpenChannel;
public transTypes = [...TRANS_TYPES];
public selTransType = '1';
public selTransType = '2';
public blocks = null;
public fees = null;
public outputIndex = null;
public faCopy = faCopy;
public faInfoCircle = faInfoCircle;
public faExclamationTriangle = faExclamationTriangle;
public bumpFeeError = '';
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(public dialogRef: MatDialogRef<BumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: PendingOpenChannelInformation, private store: Store<fromRTLReducer.RTLState>, private dataService: DataService) {}
constructor(public dialogRef: MatDialogRef<BumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: PendingOpenChannelInformation, private store: Store<fromRTLReducer.RTLState>, private dataService: DataService, private snackBar: MatSnackBar) {}
ngOnInit() {
this.transTypes = this.transTypes.splice(1);
@ -57,9 +59,13 @@ export class BumpFeeComponent implements OnInit, OnDestroy {
});
}
onCopyID(payload: string) {
this.snackBar.open('Transaction ID copied.');
}
resetData() {
this.bumpFeeError = '';
this.selTransType = '1';
this.selTransType = '2';
this.blocks = null;
this.fees = null;
this.outputIdx.control.setErrors(null);

@ -1,13 +1,13 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="padding-gap-large pl-3">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header mb-1">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Channel Information</span>
</div>
<button tabindex="3" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<mat-card-content class="padding-gap-x-large" [ngClass]="{'xs-scroll-y': screenSize === screenSizeEnum.XS}">
<div fxLayout="column">
<div fxLayout="row">
<div fxFlex="50">
@ -71,8 +71,8 @@
<span class="overflow-wrap foreground-secondary-text">{{channel.num_updates | number}}</span>
</div>
</div>
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div *ngIf="showAdvanced">
<mat-divider [inset]="true" class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Commit Fee</h4>
@ -131,7 +131,7 @@
</div>
<mat-divider [inset]="true" class="my-1"></mat-divider>
</div>
<div [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}" fxLayout="row" fxLayoutAlign="end center" fxFlex="100">
<div class="mt-1" fxLayout="row" fxLayoutAlign="end center" fxFlex="100">
<button mat-stroked-button color="primary" type="reset" (click)="onShowAdvanced()" tabindex="1" class="mr-1">
<p *ngIf="!showAdvanced; else hideAdvancedText">Show Advanced</p>
<ng-template #hideAdvancedText><p>Hide Advanced</p></ng-template>

@ -1,12 +1,12 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start" class="padding-gap-x-large"><span class="page-title">Channel Rebalance</span></div>
<div fxFlex="95" fxLayoutAlign="start start"><span class="page-title">Channel Rebalance</span></div>
<button tabindex="15" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="mt-5px">
<mat-card-content class="padding-gap-x-large">
<div fxLayout="column">
<div class="padding-gap-x-large" fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign="space-between stretch">
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info">
<fa-icon [icon]="faInfoCircle" class="mr-1 alert-icon"></fa-icon>
<span>Circular Rebalance is a payment you make to *yourselves* to affect a relative change in the balances of two channels.

@ -179,7 +179,7 @@ export class ChannelRebalanceComponent implements OnInit, OnDestroy {
sendPayment(payReq: string) {
this.flgInvoiceGenerated = true;
this.paymentRequest = payReq;
this.store.dispatch(new LNDActions.SendPayment({paymentReq: payReq, paymentDecoded: {}, zeroAmtInvoice: false, outgoingChannel: this.selChannel, feeLimitType: this.feeFormGroup.controls.selFeeLimitType.value, feeLimit: this.feeFormGroup.controls.feeLimit.value, allowSelfPayment: true, lastHopPubkey: this.inputFormGroup.controls.selRebalancePeer.value.remote_pubkey, fromDialog: true}));
this.store.dispatch(new LNDActions.SendPayment({paymentReq: payReq, outgoingChannel: this.selChannel, feeLimitType: this.feeFormGroup.controls.selFeeLimitType.value, feeLimit: this.feeFormGroup.controls.feeLimit.value, allowSelfPayment: true, lastHopPubkey: this.inputFormGroup.controls.selRebalancePeer.value.remote_pubkey, fromDialog: true}));
}
filterActiveChannels() {

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target)" placeholder="Filter">
@ -91,5 +91,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -131,7 +131,8 @@ export class ChannelActiveHTLCsTableComponent implements OnInit, AfterViewInit,
};
this.channels.paginator = this.paginator;
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
const newChannel = channel.remote_alias + channel.pending_htlcs.map(htlc => JSON.stringify(htlc) + (htlc.incoming ? 'yes' : 'no'));
const newChannel = (channel.remote_alias ? channel.remote_alias.toLowerCase() : '') +
channel.pending_htlcs.map(htlc => JSON.stringify(htlc) + (htlc.incoming ? 'yes' : 'no'));
return newChannel.includes(fltr);
};
}

@ -1,5 +1,5 @@
<div fxLayout="column">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target)" placeholder="Filter">
@ -56,5 +56,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -1,5 +1,5 @@
<div fxLayout="column" class="padding-gap">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" class="padding-gap-x">
<div fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
<div fxFlex="70"></div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" name="filter" placeholder="Filter">
@ -84,5 +84,5 @@
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-4"></mat-paginator>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

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

Loading…
Cancel
Save