Incomplete lazy load

Incomplete lazy load
pull/209/head
Shahana Farooqui 5 years ago
parent e93231c590
commit d318ad7c82

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -3,10 +3,11 @@
<head>
<meta charset="utf-8">
<title>RTL</title>
<base href="/rtl/"> <meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/rtl/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="assets/images/favicon.ico">
<link rel="stylesheet" href="styles.95c3afc83be2d91ee834.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime-es2015.daac63f861585ab7a235.js" type="module"></script><script src="polyfills-es2015.2a0da12c7706d5c3e2aa.js" type="module"></script><script src="runtime-es5.5a48a1a46f5d6db38cc2.js" nomodule></script><script src="polyfills-es5.84431ea76d33490d0941.js" nomodule></script><script src="main-es2015.31d82cbabd2de8337eaa.js" type="module"></script><script src="main-es5.2e2e9dbae4980e7e928a.js" nomodule></script></body>
<script src="runtime-es2015.6c92075aefa095411d25.js" type="module"></script><script src="polyfills-es2015.af35579f5b57e97fcdea.js" type="module"></script><script src="runtime-es5.18bd9dad956fbe3e232b.js" nomodule></script><script src="polyfills-es5.64372fcf007b6e0e7247.js" nomodule></script><script src="main-es2015.803decf729a522acb617.js" type="module"></script><script src="main-es5.69224cfebb64abd32219.js" nomodule></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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
!function(e){function r(r){for(var n,a,i=r[0],c=r[1],f=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,i=1;i<t.length;i++)0!==o[t[i]]&&(n=!1);n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={0:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,i=document.createElement("script");i.charset="utf-8",i.timeout=120,a.nc&&i.setAttribute("nonce",a.nc),i.src=function(e){return a.p+""+({}[e]||e)+"-es2015."+{1:"6aacfc3b356893189a11",5:"728790da8d674f1a9a03",6:"12f89c6eac1f84929add"}[e]+".js"}(e);var c=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:i})},12e4);i.onerror=i.onload=u,document.head.appendChild(i)}return Promise.all(r)},a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,(function(r){return e[r]}).bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="",a.oe=function(e){throw console.error(e),e};var i=window.webpackJsonp=window.webpackJsonp||[],c=i.push.bind(i);i.push=r,i=i.slice();for(var f=0;f<i.length;f++)r(i[f]);var l=c;t()}([]);

@ -1 +0,0 @@
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],p=0,s=[];p<a.length;p++)o[i=a[p]]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(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,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es2015."+{4:"d4064c76d94d78581525"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.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:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([]);

@ -0,0 +1 @@
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)o[i=a[p]]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es5."+{1:"988ddf44a4866c3ff558",4:"2ce4f749146b640b4203",5:"dc29e5cf514a69f8162d"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);

@ -1 +0,0 @@
!function(e){function r(r){for(var n,i,a=r[0],c=r[1],f=r[2],p=0,s=[];p<a.length;p++)o[i=a[p]]&&s.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++)0!==o[t[a]]&&(n=!1);n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={0:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise(function(r,n){t=o[e]=[r,n]});r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+""+({}[e]||e)+"-es5."+{3:"be011c3d61feb311e96f"}[e]+".js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(f);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var f=setTimeout(function(){u({type:"timeout",target:a})},12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,(function(r){return e[r]}).bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="",i.oe=function(e){throw console.error(e),e};var a=window.webpackJsonp=window.webpackJsonp||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var f=0;f<a.length;f++)r(a[f]);var l=c;t()}([]);

@ -27,27 +27,29 @@ common.setOptions = () => {
if(undefined !== common.nodes[0].options && undefined !== common.nodes[0].options.headers) { return; }
try {
common.nodes.forEach(node => {
console.log(node);
node.options = {
url: '',
rejectUnauthorized: false,
json: true,
headers: {
'Grpc-Metadata-macaroon': fs.readFileSync(node.macaroon_path + '/admin.macaroon').toString('hex'),
},
form: ''
};
};
if(node.ln_implementation !== 'CLightning') {
node.options.headers = {'Grpc-Metadata-macaroon': fs.readFileSync(node.macaroon_path + '/admin.macaroon').toString('hex')};
}
});
// Options cannot be set before selected node initializes. Updating selected node's options separatly
common.selectedNode.options = {
url: '',
rejectUnauthorized: false,
json: true,
headers: {
'Grpc-Metadata-macaroon': fs.readFileSync(common.selectedNode.macaroon_path + '/admin.macaroon').toString('hex'),
},
form: ''
};
};
if(common.selectedNode.ln_implementation !== 'CLightning') {
common.selectedNode.options.headers = {'Grpc-Metadata-macaroon': fs.readFileSync(common.selectedNode.macaroon_path + '/admin.macaroon').toString('hex')};
}
} catch(err) {
console.error('Common Set Options Error:' + JSON.stringify(err));
common.nodes.forEach(node => {
node.options = {
url: '',

@ -262,12 +262,16 @@ connect.validateMultiNodeConfig = (config) => {
config.nodes.forEach((node, idx) => {
common.nodes[idx] = {};
if(node.Authentication.macaroonPath === '' || undefined === node.Authentication.macaroonPath) {
errMsg = 'Please set macaroon path for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
if(node.lnImplementation === 'CLightning') {
common.nodes[idx].macaroon_path = '';
} else {
common.nodes[idx].macaroon_path = node.Authentication.macaroonPath;
if(node.Authentication.macaroonPath === '' || undefined === node.Authentication.macaroonPath) {
errMsg = 'Please set macaroon path for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else {
common.nodes[idx].macaroon_path = node.Authentication.macaroonPath;
}
}
if((node.Settings.lndServerUrl === '' || undefined === node.Settings.lndServerUrl)) {
errMsg = errMsg + '\nPlease set LND server URL for node index ' + node.index + ' in RTL-Multi-Node-Conf.json!';
} else {
@ -277,7 +281,7 @@ connect.validateMultiNodeConfig = (config) => {
common.nodes[idx].index = node.index;
common.nodes[idx].ln_node = node.lnNode;
common.nodes[idx].ln_implementation = node.lnImplementation;
common.nodes[idx].lnd_config_path = (undefined !== node.Authentication.lndConfigPath) ? node.Authentication.lndConfigPath : '';
common.nodes[idx].lnd_config_path = (undefined !== node.Authentication && undefined !== node.Authentication.lndConfigPath) ? node.Authentication.lndConfigPath : '';
common.nodes[idx].bitcoind_config_path = (undefined !== node.Settings.bitcoindConfigPath) ? node.Settings.bitcoindConfigPath : '';
common.nodes[idx].enable_logging = (undefined !== node.Settings.enableLogging) ? node.Settings.enableLogging : false;
common.nodes[idx].channel_backup_path = (undefined !== node.Settings.channelBackupPath) ? node.Settings.channelBackupPath : common.rtl_conf_file_path + common.path_separator + 'backup' + common.path_separator + 'node-' + node.index;

@ -60,7 +60,7 @@ exports.getRTLConfig = (req, res, next) => {
multiNodeConfig.nodes.forEach((node, i) => {
const authentication = {};
authentication.nodeAuthType = 'CUSTOM';
if(node.Authentication.lndConfigPath) {
if(node.Authentication && node.Authentication.lndConfigPath) {
authentication.lndConfigPath = node.Authentication.lndConfigPath;
}
if(node.Settings.bitcoindConfigPath) {

@ -5,9 +5,10 @@
"scripts": {
"ng": "ng",
"start": "ng serve --base-href /rtl/ --open --aot",
"prebuild": "node ./prebuild",
"build": "ng analytics off && ng build --prod --base-href /rtl/ --aot",
"serve": "ng serve",
"prebuild": "node ./prebuild",
"server": "nodemon ./rtl.js",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"

@ -18,10 +18,10 @@
<rtl-top-menu></rtl-top-menu>
</div>
</mat-toolbar>
<div fxLayout="row" fxLayoutAlign="center center" class="bg-primary flex-wrap pubkey-info-top" rtlClipboard [payload]="information?.identity_pubkey" (copied)="copiedText($event)">
<div fxLayout="row" fxLayoutAlign="center center" class="bg-primary flex-wrap pubkey-info-top" rtlClipboard [payload]="selNodeInfo?.identity_pubkey" (copied)="copiedText($event)">
<mat-icon [ngClass]="{'icon-smaller': smallScreen}">vpn_key</mat-icon>
<div [ngClass]="{'word-break font-9px': smallScreen, 'word-break': !smallScreen}">&nbsp;{{information?.identity_pubkey}}
<mat-spinner [diameter]="20" *ngIf="flgLoading[0]" class="inline-spinner foreground"></mat-spinner>
<div [ngClass]="{'word-break font-9px': smallScreen, 'word-break': !smallScreen}">&nbsp;{{selNodeInfo?.identity_pubkey}}
<mat-spinner [diameter]="20" *ngIf="!selNodeInfo?.identity_pubkey" class="inline-spinner foreground"></mat-spinner>
<mat-icon [ngClass]="{'icon-smaller cursor-pointer copy-icon-smaller': smallScreen, 'icon-small cursor-pointer copy-icon': !smallScreen}">file_copy</mat-icon><span [hidden]="!flgCopied">Copied</span>
</div>
</div>

@ -8,11 +8,8 @@ import { UserIdleService } from 'angular-user-idle';
import * as sha256 from 'sha256';
import { LoggerService } from './shared/services/logger.service';
import { RTLConfiguration, Settings, Node } from './shared/models/RTLconfig';
import { GetInfo } from './shared/models/lndModels';
import { RTLConfiguration, Settings, Node, SelNodeInfo } from './shared/models/RTLconfig';
import * as LNDActions from './lnd/store/lnd.actions';
import * as fromLNDReducer from './lnd/store/lnd.reducers';
import * as RTLActions from './store/rtl.actions';
import * as fromRTLReducer from './store/rtl.reducers';
@ -26,7 +23,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('settingSidenav', { static: true }) settingSidenav: any;
public selNode: Node;
public settings: Settings;
public information: GetInfo = {};
public selNodeInfo: SelNodeInfo;
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: Info
public flgCopied = false;
public appConfig: RTLConfiguration;
@ -34,22 +31,15 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
public smallScreen = false;
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private lndStore: Store<fromLNDReducer.LNDState>, private actions$: Actions,
private userIdle: UserIdleService, private router: Router) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions, private userIdle: UserIdleService, private router: Router) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchRTLConfig());
this.accessKey = this.readAccessKey();
this.lndStore.select('lnd')
.pipe(takeUntil(this.unsubs[3]))
.subscribe(lndStore => {
this.information = lndStore ? lndStore.information : {};
this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true;
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe(rtlStore => {
this.selNodeInfo = rtlStore.selNodeInfo;
this.selNode = rtlStore.selNode;
this.settings = this.selNode.settings;
this.appConfig = rtlStore.appConfig;
@ -62,18 +52,12 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.smallScreen = true;
}
this.logger.info(this.settings);
if (!sessionStorage.getItem('token')) {
this.flgLoading[0] = false;
}
});
if (sessionStorage.getItem('token')) {
this.lndStore.dispatch(new LNDActions.FetchInfo());
}
this.actions$
.pipe(
takeUntil(this.unsubs[1]),
filter((action) => action.type === RTLActions.INIT_APP_DATA || action.type === RTLActions.SET_RTL_CONFIG)
).subscribe((actionPayload: (RTLActions.InitAppData | RTLActions.SetRTLConfig)) => {
filter(action => action.type === RTLActions.SET_RTL_CONFIG)
).subscribe((actionPayload: RTLActions.SetRTLConfig) => {
if (actionPayload.type === RTLActions.SET_RTL_CONFIG) {
if (!sessionStorage.getItem('token')) {
if (+actionPayload.payload.sso.rtlSSO) {
@ -89,17 +73,6 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
this.settingSidenav.toggle(); // To dynamically update the width to 100% after side nav is closed
setTimeout(() => { this.settingSidenav.toggle(); }, 100);
}
} else if (actionPayload.type === RTLActions.INIT_APP_DATA) {
this.lndStore.dispatch(new LNDActions.FetchInfo());
}
});
this.actions$
.pipe(
takeUntil(this.unsubs[1]),
filter((action) => action.type === LNDActions.SET_INFO)
).subscribe((infoData: LNDActions.SetInfo) => {
if (undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
});
this.userIdle.startWatching();
@ -122,17 +95,6 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
return url.substring(url.lastIndexOf('access-key=') + 11).trim();
}
initializeRemainingData() {
this.lndStore.dispatch(new LNDActions.FetchPeers());
this.lndStore.dispatch(new LNDActions.FetchBalance('channels'));
this.lndStore.dispatch(new LNDActions.FetchFees());
this.lndStore.dispatch(new LNDActions.FetchNetwork());
this.lndStore.dispatch(new LNDActions.FetchChannels({routeParam: 'all'}));
this.lndStore.dispatch(new LNDActions.FetchChannels({routeParam: 'pending'}));
this.lndStore.dispatch(new LNDActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.lndStore.dispatch(new LNDActions.FetchPayments());
}
ngAfterViewInit() {
if (!this.settings.flgSidenavPinned) {
this.sideNavigation.close();

@ -1,8 +1,22 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { ServerConfigComponent } from './shared/components/server-config/server-config.component';
import { HelpComponent } from './shared/components/help/help.component';
import { SigninComponent } from './shared/components/signin/signin.component';
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
import { SsoFailedComponent } from './shared/components/sso-failed/sso-failed.component';
import { AuthGuard } from './shared/services/auth.guard';
export const routes: Routes = [
{ path: '', loadChildren: () => import('./lnd/lnd.module').then(childModule => childModule.LndModule)},
{ path: '', redirectTo: '/lnd', pathMatch: 'full' },
{ path: 'lnd', loadChildren: () => import('./lnd/lnd.module').then(childModule => childModule.LndModule)},
{ path: 'cl', loadChildren: () => import('./c-lightning/cl.module').then(childModule => childModule.ClModule)},
{ path: 'sconfig', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'login', component: SigninComponent },
{ path: 'help', component: HelpComponent },
{ path: 'ssoerror', component: SsoFailedComponent },
{ path: '**', component: NotFoundComponent }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

@ -0,0 +1 @@
<router-outlet></router-outlet>

@ -0,0 +1,4 @@
.inline-spinner {
display: inline-flex !important;
top: 0px !important;
}

@ -0,0 +1,54 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import * as CLActions from './store/cl.actions';
import * as RTLActions from '../store/rtl.actions';
import * as fromRTLReducer from '../store/rtl.reducers';
@Component({
selector: 'rtl-cl-root-app',
templateUrl: './cl-root.component.html',
styleUrls: ['./cl-root.component.scss']
})
export class ClRootComponent implements OnInit, OnDestroy {
unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private store: Store<fromRTLReducer.State>, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
console.warn('CL ROOT');
this.router.navigate(['./home'], {relativeTo: this.activatedRoute});
this.actions$.pipe(takeUntil(this.unsubs[0]), filter((action) => action.type === RTLActions.INIT_APP_DATA))
.subscribe((actionPayload: RTLActions.InitAppData) => {
this.store.dispatch(new CLActions.FetchCLInfo());
});
this.actions$.pipe(takeUntil(this.unsubs[1]), filter((action) => action.type === CLActions.SET_CL_INFO))
.subscribe((infoData: CLActions.SetCLInfo) => {
if (undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
});
}
initializeRemainingData() {
// this.store.dispatch(new CLActions.FetchPeers());
// this.store.dispatch(new CLActions.FetchBalance('channels'));
// this.store.dispatch(new CLActions.FetchFees());
// this.store.dispatch(new CLActions.FetchNetwork());
// this.store.dispatch(new CLActions.FetchChannels({routeParam: 'all'}));
// this.store.dispatch(new CLActions.FetchChannels({routeParam: 'pending'}));
// this.store.dispatch(new CLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
// this.store.dispatch(new CLActions.FetchPayments());
}
ngOnDestroy() {
this.unsubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
}

@ -0,0 +1,34 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { EffectsModule } from '@ngrx/effects';
import { environment } from '../../environments/environment';
import { SharedModule } from '../shared/shared.module';
import { CLReducer } from './store/cl.reducers';
import { CLEffects } from './store/cl.effects';
import { clRouting } from './cl.routing';
import { ClRootComponent } from './cl-root.component';
import { HomeComponent } from './home/home.component';
@NgModule({
imports: [
CommonModule,
SharedModule,
clRouting,
NgxChartsModule,
EffectsModule.forFeature([CLEffects]),
StoreModule.forFeature('cl', CLReducer),
!environment.production ? StoreDevtoolsModule.instrument() : []
],
declarations: [
ClRootComponent,
HomeComponent
],
providers: [],
bootstrap: [ClRootComponent]
})
export class ClModule {}

@ -0,0 +1,15 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { AuthGuard } from '../shared/services/auth.guard';
import { ClRootComponent } from './cl-root.component';
import { HomeComponent } from './home/home.component';
export const clRoutes: Routes = [
{ path: '', redirectTo: '.', pathMatch: 'full', canActivate: [AuthGuard]},
{ path: '.', component: ClRootComponent, canActivate: [AuthGuard] },
{ path: './home', component: HomeComponent, canActivate: [AuthGuard] }
];
export const clRouting: ModuleWithProviders = RouterModule.forChild(clRoutes);

@ -0,0 +1,2 @@
<h4>CL Home</h4>
<p>{{information | json}}</p>

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeComponent } from './home.component';
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HomeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,39 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { LoggerService } from '../../shared/services/logger.service';
import { GetInfo } from '../../shared/models/clModels';
import * as fromCLReducer from '../store/cl.reducers';
@Component({
selector: 'rtl-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit, OnDestroy {
public information: GetInfo = {};
private unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private logger: LoggerService, private clStore: Store<fromCLReducer.CLState>) {}
ngOnInit() {
console.warn('CL HOME');
this.clStore.select('cl')
.pipe(takeUntil(this.unsubs[1]))
.subscribe(clStore => {
this.information = clStore.information;
this.logger.info(clStore);
});
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -0,0 +1,22 @@
import { Action } from '@ngrx/store';
import { GetInfo } from '../../shared/models/clModels';
export const RESET_CL_STORE = 'RESET_CL_STORE';
export const FETCH_CL_INFO = 'FETCH_CL_INFO';
export const SET_CL_INFO = 'SET_CL_INFO';
export class ResetCLStore implements Action {
readonly type = RESET_CL_STORE;
}
export class FetchCLInfo implements Action {
readonly type = FETCH_CL_INFO;
}
export class SetCLInfo implements Action {
readonly type = SET_CL_INFO;
constructor(public payload: GetInfo) {}
}
export type CLActions =
ResetCLStore | FetchCLInfo | SetCLInfo;

@ -0,0 +1,83 @@
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { environment } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { GetInfo } from '../../shared/models/clModels';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as CLActions from './cl.actions';
import * as fromCLReducer from './cl.reducers';
@Injectable()
export class CLEffects implements OnDestroy {
dialogRef: any;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(
private actions$: Actions,
private httpClient: HttpClient,
private store: Store<fromCLReducer.CLState>,
private logger: LoggerService,
public dialog: MatDialog,
private router: Router) { }
@Effect()
infoFetch = this.actions$.pipe(
ofType(CLActions.FETCH_CL_INFO),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [CLActions.FetchCLInfo, fromRTLReducer.State]) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchInfo'));
return this.httpClient.get<GetInfo>(environment.GETINFO_API)
.pipe(
map((info) => {
this.logger.info(info);
if (undefined === info.identity_pubkey) {
this.store.dispatch(new RTLActions.SetSelNodeInfo({}));
sessionStorage.removeItem('clUnlocked');
return {
type: CLActions.SET_CL_INFO,
payload: {}
};
} else {
this.store.dispatch(new RTLActions.SetSelNodeInfo(info));
sessionStorage.setItem('clUnlocked', 'true');
return {
type: CLActions.SET_CL_INFO,
payload: (undefined !== info) ? info : {}
};
}
}),
catchError((err) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectError({ action: 'FetchInfo', code: err.status, message: err.error.error }));
if (+store.appConfig.sso.rtlSSO) {
this.router.navigate(['/ssoerror']);
} else {
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
return of();
}
}
})
);
}
));
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -0,0 +1,47 @@
import * as CLActions from './cl.actions';
import { GetInfo, GetInfoChain } from '../../shared/models/clModels';
import * as fromApp from '../../store/rtl.reducers';
export interface FeatureState extends fromApp.State {
cl: CLState;
}
export interface CLState {
information: GetInfo;
}
export const CLInitialState: CLState = {
information: {}
};
export function CLReducer(state = CLInitialState, action: CLActions.CLActions) {
switch (action.type) {
case CLActions.RESET_CL_STORE:
return {
...CLInitialState
};
case CLActions.SET_CL_INFO:
if (undefined !== action.payload.chains) {
if (typeof action.payload.chains[0] === 'string') {
action.payload.smaller_currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
action.payload.currency_unit = (action.payload.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
} else if (typeof action.payload.chains[0] === 'object' && action.payload.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>action.payload.chains[0];
action.payload.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats';
action.payload.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC';
}
action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0];
} else {
action.payload.smaller_currency_unit = 'Sats';
action.payload.currency_unit = 'BTC';
action.payload.version = (undefined === action.payload.version) ? '' : action.payload.version.split(' ')[0];
}
return {
...state,
information: action.payload
};
default:
return state;
}
}

@ -1,48 +1 @@
<div fxLayout="column" id="rtl-container" class="rtl-container" [ngClass]="settings.theme" [class.horizontal]="settings.menu === 'Horizontal'" [class.compact]="settings.menuType === 'Compact'" [class.mini]="settings.menuType === 'Mini'">
<mat-sidenav-container>
<mat-sidenav perfectScrollbar *ngIf="settings.menu === 'Vertical'" [opened]="settings.flgSidenavOpened" [mode]="(settings.flgSidenavPinned) ? 'side' : 'over'"
#sideNavigation class="sidenav mat-elevation-z6 overflow-auto">
<rtl-side-navigation (ChildNavClicked)="onNavigationClicked($event)"></rtl-side-navigation>
</mat-sidenav>
<mat-sidenav-content perfectScrollbar class="overflow-auto">
<mat-toolbar fxLayout="row" fxLayoutAlign="space-between center" color="primary" class="padding-gap-x">
<div fxLayoutAlign="center center">
<button *ngIf="settings.menu === 'Vertical'" mat-icon-button (click)="sideNavToggle()">
<mat-icon>menu</mat-icon>
</button>
</div>
<div>
<h2>Ride The Lightning <span class="font-60-percent">(Beta)</span></h2>
</div>
<div fxLayoutAlign="space-between center">
<rtl-top-menu></rtl-top-menu>
</div>
</mat-toolbar>
<div fxLayout="row" fxLayoutAlign="center center" class="bg-primary flex-wrap pubkey-info-top" rtlClipboard [payload]="information?.identity_pubkey" (copied)="copiedText($event)">
<mat-icon [ngClass]="{'icon-smaller': smallScreen}">vpn_key</mat-icon>
<div [ngClass]="{'word-break font-9px': smallScreen, 'word-break': !smallScreen}">&nbsp;{{information?.identity_pubkey}}
<mat-spinner [diameter]="20" *ngIf="flgLoading[0]" class="inline-spinner foreground"></mat-spinner>
<mat-icon [ngClass]="{'icon-smaller cursor-pointer copy-icon-smaller': smallScreen, 'icon-small cursor-pointer copy-icon': !smallScreen}">file_copy</mat-icon><span [hidden]="!flgCopied">Copied</span>
</div>
</div>
<mat-toolbar color="primary" *ngIf="settings.menu === 'Horizontal'" class="padding-gap-x horizontal-nav">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="center center" class="h-100">
<rtl-horizontal-navigation></rtl-horizontal-navigation>
</div>
</mat-toolbar>
<div [ngClass]="{'mt-minus-1': smallScreen, 'inner-sidenav-content': true}">
<router-outlet></router-outlet>
</div>
<div fxLayout="row" fxLayoutAlign="center center" class="bg-primary settings-icon" (click)="settingSidenav.toggle()">
<mat-icon class="animate-settings">settings</mat-icon>
</div>
</mat-sidenav-content>
<mat-sidenav #settingSidenav position="end" class="settings mat-elevation-z6" mode="side">
<rtl-settings-nav (done)="settingSidenav.toggle()"></rtl-settings-nav>
</mat-sidenav>
</mat-sidenav-container>
<div class="rtl-spinner" *ngIf="undefined === settings.theme">
<mat-spinner color="accent"></mat-spinner>
<h4>Loading RTL...</h4>
</div>
</div>
<router-outlet></router-outlet>

@ -1,18 +1,11 @@
import { Component, OnInit, AfterViewInit, OnDestroy, ViewChild, HostListener } from '@angular/core';
import { Router } from '@angular/router';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { UserIdleService } from 'angular-user-idle';
import * as sha256 from 'sha256';
import { LoggerService } from '../shared/services/logger.service';
import { RTLConfiguration, Settings, Node } from '../shared/models/RTLconfig';
import { GetInfo } from '../shared/models/lndModels';
import * as fromLNDReducer from './store/lnd.reducers';
import * as LNDActions from './store/lnd.actions';
import * as RTLActions from '../store/rtl.actions';
import * as fromRTLReducer from '../store/rtl.reducers';
@Component({
@ -20,100 +13,22 @@ import * as fromRTLReducer from '../store/rtl.reducers';
templateUrl: './lnd-root.component.html',
styleUrls: ['./lnd-root.component.scss']
})
export class LndRootComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('sideNavigation', { static: true }) sideNavigation: any;
@ViewChild('settingSidenav', { static: true }) settingSidenav: any;
public selNode: Node;
public settings: Settings;
public information: GetInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: Info
public flgCopied = false;
public appConfig: RTLConfiguration;
public accessKey = '';
public smallScreen = false;
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
export class LndRootComponent implements OnInit, OnDestroy {
unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions,
private userIdle: UserIdleService, private router: Router) {}
constructor(private store: Store<fromRTLReducer.State>, private lndStore: Store<fromLNDReducer.LNDState>, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchRTLConfig());
this.accessKey = this.readAccessKey();
this.store.select('rtlRoot')
console.warn('LND ROOT');
this.store.dispatch(new LNDActions.FetchInfo());
this.router.navigate(['./home'], {relativeTo: this.activatedRoute});
this.lndStore.select('lnd')
.pipe(takeUntil(this.unsubs[0]))
.subscribe(rtlStore => {
this.selNode = rtlStore.selNode;
this.settings = this.selNode.settings;
this.appConfig = rtlStore.appConfig;
this.information = rtlStore.information;
this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true;
if (window.innerWidth <= 768) {
this.settings.menu = 'Vertical';
this.settings.flgSidenavOpened = false;
this.settings.flgSidenavPinned = false;
}
if (window.innerWidth <= 414) {
this.smallScreen = true;
}
this.logger.info(this.settings);
if (!sessionStorage.getItem('token')) {
this.flgLoading[0] = false;
}
});
if (sessionStorage.getItem('token')) {
this.store.dispatch(new LNDActions.FetchInfo());
}
this.actions$
.pipe(
takeUntil(this.unsubs[1]),
filter((action) => action.type === RTLActions.INIT_APP_DATA || action.type === RTLActions.SET_RTL_CONFIG)
).subscribe((actionPayload: (RTLActions.InitAppData | RTLActions.SetRTLConfig)) => {
if (actionPayload.type === RTLActions.SET_RTL_CONFIG) {
if (!sessionStorage.getItem('token')) {
if (+actionPayload.payload.sso.rtlSSO) {
this.store.dispatch(new RTLActions.Signin(sha256(this.accessKey)));
} else {
this.router.navigate([this.appConfig.sso.logoutRedirectLink]);
}
}
if (
this.settings.menu === 'Horizontal' ||
this.settings.menuType === 'Compact' ||
this.settings.menuType === 'Mini') {
this.settingSidenav.toggle(); // To dynamically update the width to 100% after side nav is closed
setTimeout(() => { this.settingSidenav.toggle(); }, 100);
}
} else if (actionPayload.type === RTLActions.INIT_APP_DATA) {
this.store.dispatch(new LNDActions.FetchInfo());
}
});
this.actions$
.pipe(
takeUntil(this.unsubs[1]),
filter((action) => action.type === LNDActions.SET_INFO)
).subscribe((infoData: LNDActions.SetInfo) => {
if (undefined !== infoData.payload.identity_pubkey) {
.subscribe(lndStore => {
if (undefined !== lndStore.information.identity_pubkey) {
this.initializeRemainingData();
}
});
this.userIdle.startWatching();
this.userIdle.onTimerStart().subscribe(count => {});
this.userIdle.onTimeout().subscribe(() => {
if (sessionStorage.getItem('token')) {
this.logger.warn('Time limit exceeded for session inactivity! Logging out!');
this.store.dispatch(new RTLActions.OpenAlert({ width: '75%', data: {
type: 'WARN',
titleMessage: 'Time limit exceeded for session inactivity! Logging out!'
}}));
this.store.dispatch(new RTLActions.Signout());
this.userIdle.resetTimer();
}
});
}
private readAccessKey() {
const url = window.location.href;
return url.substring(url.lastIndexOf('access-key=') + 11).trim();
});
}
initializeRemainingData() {
@ -127,42 +42,6 @@ export class LndRootComponent implements OnInit, AfterViewInit, OnDestroy {
this.store.dispatch(new LNDActions.FetchPayments());
}
ngAfterViewInit() {
if (!this.settings.flgSidenavPinned) {
this.sideNavigation.close();
this.settingSidenav.toggle();
}
if (window.innerWidth <= 768) {
this.sideNavigation.close();
this.settingSidenav.toggle();
}
}
@HostListener('window:resize')
public onWindowResize(): void {
if (window.innerWidth <= 768) {
this.settings.menu = 'Vertical';
this.settings.flgSidenavOpened = false;
this.settings.flgSidenavPinned = false;
}
}
sideNavToggle() {
this.sideNavigation.toggle();
}
onNavigationClicked(event: any) {
if (window.innerWidth <= 414) {
this.sideNavigation.close();
}
}
copiedText(payload) {
this.flgCopied = true;
setTimeout(() => {this.flgCopied = false; }, 5000);
this.logger.info('Copied Text: ' + payload);
}
ngOnDestroy() {
this.unsubs.forEach(unsub => {
unsub.next();

@ -16,13 +16,10 @@ import { HomeComponent } from './home/home.component';
import { PeersComponent } from './peers/peers.component';
import { SendReceiveTransComponent } from './transactions/send-receive/send-receive-trans.component';
import { InvoicesComponent } from './invoices/invoices.component';
import { ServerConfigComponent } from './server-config/server-config.component';
import { HelpComponent } from './help/help.component';
import { UnlockLNDComponent } from './unlock-lnd/unlock-lnd.component';
import { PaymentsComponent } from './payments/send-receive/payments.component';
import { ChannelManageComponent } from './channels/channel-manage/channel-manage.component';
import { ChannelPendingComponent } from './channels/channel-pending/channel-pending.component';
import { SigninComponent } from './signin/signin.component';
import { ChannelClosedComponent } from './channels/channel-closed/channel-closed.component';
import { ListTransactionsComponent } from './transactions/list-transactions/list-transactions.component';
import { LookupsComponent } from './lookups/lookups.component';
@ -49,13 +46,10 @@ import { QueryRoutesComponent } from './payments/query-routes/query-routes.compo
PeersComponent,
SendReceiveTransComponent,
InvoicesComponent,
ServerConfigComponent,
HelpComponent,
UnlockLNDComponent,
PaymentsComponent,
ChannelManageComponent,
ChannelPendingComponent,
SigninComponent,
ChannelClosedComponent,
ListTransactionsComponent,
LookupsComponent,

@ -1,10 +1,9 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
import { SsoFailedComponent } from '../shared/components/sso-failed/sso-failed.component';
import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard';
import { LndRootComponent } from './lnd-root.component';
import { HomeComponent } from './home/home.component';
import { UnlockLNDComponent } from './unlock-lnd/unlock-lnd.component';
import { ChannelClosedComponent } from './channels/channel-closed/channel-closed.component';
@ -15,37 +14,30 @@ import { SendReceiveTransComponent } from './transactions/send-receive/send-rece
import { ListTransactionsComponent } from './transactions/list-transactions/list-transactions.component';
import { PaymentsComponent } from './payments/send-receive/payments.component';
import { QueryRoutesComponent } from './payments/query-routes/query-routes.component';
import { ServerConfigComponent } from './server-config/server-config.component';
import { HelpComponent } from './help/help.component';
import { InvoicesComponent } from './invoices/invoices.component';
import { LookupsComponent } from './lookups/lookups.component';
import { SigninComponent } from './signin/signin.component';
import { ForwardingHistoryComponent } from './switch/forwarding-history.component';
import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
export const lndRoutes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full', canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'unlocklnd', component: UnlockLNDComponent, canActivate: [AuthGuard] },
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'peers', component: PeersComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'chnlclosed', component: ChannelClosedComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'chnlmanage', component: ChannelManageComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'chnlpending', component: ChannelPendingComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'chnlbackup', component: ChannelBackupComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'transsendreceive', component: SendReceiveTransComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'translist', component: ListTransactionsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'paymentsend', component: PaymentsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'queryroutes', component: QueryRoutesComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'invoices', component: InvoicesComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'switch', component: ForwardingHistoryComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'routingpeers', component: RoutingPeersComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'lookups', component: LookupsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'sconfig', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'login', component: SigninComponent },
{ path: 'help', component: HelpComponent },
{ path: 'ssoerror', component: SsoFailedComponent },
{ path: '**', component: NotFoundComponent }
{ path: '', redirectTo: '.', pathMatch: 'full', canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: '.', component: LndRootComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './unlocklnd', component: UnlockLNDComponent, canActivate: [AuthGuard] },
{ path: './home', component: HomeComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './peers', component: PeersComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './chnlclosed', component: ChannelClosedComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './chnlmanage', component: ChannelManageComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './chnlpending', component: ChannelPendingComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './chnlbackup', component: ChannelBackupComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './transsendreceive', component: SendReceiveTransComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './translist', component: ListTransactionsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './paymentsend', component: PaymentsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './queryroutes', component: QueryRoutesComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './invoices', component: InvoicesComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './switch', component: ForwardingHistoryComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './routingpeers', component: RoutingPeersComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: './lookups', component: LookupsComponent, canActivate: [AuthGuard, LNDUnlockedGuard] }
];
export const lndRouting: ModuleWithProviders = RouterModule.forChild(lndRoutes);

@ -4,6 +4,7 @@ import {
PayRequest, ChannelsTransaction, PendingChannels, ClosedChannel, Transaction, SwitchReq, SwitchRes, QueryRoutes
} from '../../shared/models/lndModels';
export const RESET_LND_STORE = 'RESET_LND_STORE';
export const FETCH_INFO = 'FETCH_INFO';
export const SET_INFO = 'SET_INFO';
export const FETCH_PEERS = 'FETCH_PEERS';
@ -63,6 +64,10 @@ export const SET_FORWARDING_HISTORY = 'SET_FORWARDING_HISTORY';
export const GET_QUERY_ROUTES = 'GET_QUERY_ROUTES';
export const SET_QUERY_ROUTES = 'SET_QUERY_ROUTES';
export class ResetLNDStore implements Action {
readonly type = RESET_LND_STORE;
}
export class FetchInfo implements Action {
readonly type = FETCH_INFO;
}
@ -348,7 +353,7 @@ export class SetQueryRoutes implements Action {
}
export type LNDActions =
FetchInfo | SetInfo | FetchPeers | SetPeers | AddPeer |
ResetLNDStore | FetchInfo | SetInfo | FetchPeers | SetPeers | AddPeer |
DetachPeer | SaveNewPeer | RemovePeer | AddInvoice | SaveNewInvoice |
GetForwardingHistory | SetForwardingHistory | FetchFees | SetFees |
FetchBalance | SetBalance | FetchNetwork | SetNetwork |

@ -43,12 +43,14 @@ export class LNDEffects implements OnDestroy {
if (undefined === info.identity_pubkey) {
sessionStorage.removeItem('lndUnlocked');
this.logger.info('Redirecting to Unlock');
this.store.dispatch(new RTLActions.SetSelNodeInfo({}));
this.router.navigate(['/unlocklnd']);
return {
type: LNDActions.SET_INFO,
payload: {}
};
} else {
this.store.dispatch(new RTLActions.SetSelNodeInfo(info));
sessionStorage.setItem('lndUnlocked', 'true');
return {
type: LNDActions.SET_INFO,

@ -60,6 +60,10 @@ export const LNDInitialState: LNDState = {
export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDActions) {
switch (action.type) {
case LNDActions.RESET_LND_STORE:
return {
...LNDInitialState
};
case LNDActions.SET_INFO:
if (undefined !== action.payload.chains) {
if (typeof action.payload.chains[0] === 'string') {

@ -9,9 +9,9 @@
</mat-toolbar>
<div fxLayout="row" fxLayoutAlign="start center" class="lnd-info pl-2" *ngIf="settings.menuType !== 'Mini'">
<div fxLayout="column">
<p class="name">Alias: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{information?.alias}}</p>
<p>Chain: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{informationChain.chain | titlecase}}<span> [{{informationChain.network | titlecase}}]</span></p>
<p class="name">LND Version: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{information?.version}}</p>
<p class="name">Alias: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{selNodeInfo?.alias}}</p>
<p>Chain: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{selNodeInfoChain.chain | titlecase}}<span> [{{selNodeInfoChain.network | titlecase}}]</span></p>
<p class="name">LND Version: <mat-spinner [diameter]="20" *ngIf="flgLoading" class="inline-spinner"></mat-spinner>{{selNodeInfo?.version}}</p>
</div>
</div>

@ -9,9 +9,8 @@ import { environment } from '../../../../../environments/environment';
import { FlatTreeControl } from '@angular/cdk/tree';
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
import { Node, Settings } from '../../../models/RTLconfig';
import { Node, Settings, SelNodeInfo, SelNodeInfoChain } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service';
import { GetInfo, GetInfoChain } from '../../../models/lndModels';
import { MenuNode, FlatMenuNode, MENU_DATA } from '../../../models/navMenu';
import * as fromLNDReducer from '../../../../lnd/store/lnd.reducers';
@ -29,8 +28,8 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
public selNode: Node;
public settings: Settings;
public version = '';
public information: GetInfo = {};
public informationChain: GetInfoChain = {};
public selNodeInfo: SelNodeInfo = {};
public selNodeInfoChain: SelNodeInfoChain = {};
public flgLoading = true;
public logoutNode = [{id: 100, parentId: 0, name: 'Logout', icon: 'eject'}];
public showLogout = false;
@ -65,32 +64,32 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
this.lndStore.select('lnd')
.pipe(takeUntil(this.unSubs[3]))
.subscribe(lndStore => {
this.information = lndStore ? lndStore.information : {};
this.numPendingChannels = lndStore ? lndStore.numberOfPendingChannels : -1;
if (undefined !== this.information.identity_pubkey) {
if (undefined !== this.information.chains && typeof this.information.chains[0] === 'string') {
this.informationChain.chain = this.information.chains[0].toString();
this.informationChain.network = (this.information.testnet) ? 'Testnet' : 'Mainnet';
} else if (typeof this.information.chains[0] === 'object' && this.information.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>this.information.chains[0];
this.informationChain.chain = getInfoChain.chain;
this.informationChain.network = getInfoChain.network;
}
} else {
this.informationChain.chain = '';
this.informationChain.network = '';
}
this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true;
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
this.selNodeInfo = rtlStore.selNodeInfo;
this.selNode = rtlStore.selNode;
this.settings = this.selNode.settings;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
if (undefined !== this.selNodeInfo.identity_pubkey) {
if (undefined !== this.selNodeInfo.chains && typeof this.selNodeInfo.chains[0] === 'string') {
this.selNodeInfoChain.chain = this.selNodeInfo.chains[0].toString();
this.selNodeInfoChain.network = (this.selNodeInfo.testnet) ? 'Testnet' : 'Mainnet';
} else if (typeof this.selNodeInfo.chains[0] === 'object' && this.selNodeInfo.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <SelNodeInfoChain>this.selNodeInfo.chains[0];
this.selNodeInfoChain.chain = getInfoChain.chain;
this.selNodeInfoChain.network = getInfoChain.network;
}
} else {
this.selNodeInfoChain.chain = '';
this.selNodeInfoChain.network = '';
}
this.flgLoading = (undefined !== this.selNodeInfo.identity_pubkey) ? false : true;
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;
}

@ -9,7 +9,6 @@
<mat-card-content fxLayout="row" fxLayoutAlign="center center">
<mat-card fxLayout="column" fxLayoutAlign="center center" class="mat-elevation-z12 w-100">
<div class="box-text">This page does not exist!</div>
<button mat-raised-button color="primary" class="mat-elevation-z12 padding-gap-x" type="button" (click)="goHome()">HOME</button>
</mat-card>
</mat-card-content>
</mat-card>

@ -1,16 +1,7 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'rtl-not-found',
templateUrl: './not-found.component.html'
})
export class NotFoundComponent {
constructor(public router: Router) {}
goHome(): void {
this.router.navigate(['/']);
}
}
export class NotFoundComponent {}

@ -3,13 +3,13 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Node } from '../../shared/models/RTLconfig';
import { Node } from '../../models/RTLconfig';
import { LNDEffects } from '../store/lnd.effects';
import * as LNDActions from '../store/lnd.actions';
import { RTLEffects } from '../../store/rtl.effects';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
import { LNDEffects } from '../../../lnd/store/lnd.effects';
import * as LNDActions from '../../../lnd/store/lnd.actions';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-server-config',

@ -4,10 +4,10 @@ import { takeUntil } from 'rxjs/operators';
import * as sha256 from 'sha256';
import { Store } from '@ngrx/store';
import { Node } from '../../shared/models/RTLconfig';
import { LoggerService } from '../../shared/services/logger.service';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
import { Node } from '../../models/RTLconfig';
import { LoggerService } from '../../services/logger.service';
import * as fromRTLReducer from '../../../store/rtl.reducers';
import * as RTLActions from '../../../store/rtl.actions';
@Component({
selector: 'rtl-signin',

@ -45,3 +45,16 @@ export class RTLConfiguration {
public nodes: Node[]
) { }
}
export interface SelNodeInfo {
identity_pubkey?: string;
alias?: string;
testnet?: boolean;
chains?: SelNodeInfoChain[] | string[];
version?: string;
}
export interface SelNodeInfoChain {
chain?: string;
network?: string;
}

@ -0,0 +1,43 @@
// export interface GetInfoAddress {
// type?: string;
// address?: string;
// port?: number;
// }
// export interface GetInfo {
// id?: string;
// alias?: string;
// color?: string;
// num_peers?: number;
// num_pending_channels?: number;
// num_active_channels?: number;
// num_inactive_channels?: number;
// address?: GetInfoAddress[];
// binding?: GetInfoAddress[];
// version?: string;
// blockheight?: number;
// network?: string;
// msatoshi_fees_collected?: number;
// fees_collected_msat?: string;
// }
export interface GetInfoChain {
chain?: string;
network?: string;
}
export interface GetInfo {
identity_pubkey?: string;
alias?: string;
num_pending_channels?: number;
num_active_channels?: number;
num_inactive_channels?: number;
num_peers?: number;
block_height?: number;
synced_to_chain?: boolean;
testnet?: boolean;
chains?: GetInfoChain[];
version?: string;
currency_unit?: string;
smaller_currency_unit?: string;
}

@ -17,6 +17,9 @@ import { HorizontalNavigationComponent } from './components/navigation/horizonta
import { AlertMessageComponent } from './components/alert-message/alert-message.component';
import { ConfirmationMessageComponent } from './components/confirmation-message/confirmation-message.component';
import { SpinnerDialogComponent } from './components/spinner-dialog/spinner-dialog.component';
import { ServerConfigComponent } from './components/server-config/server-config.component';
import { HelpComponent } from './components/help/help.component';
import { SigninComponent } from './components/signin/signin.component';
import { NotFoundComponent } from './components/not-found/not-found.component';
import { SettingsNavComponent } from './components/settings-nav/settings-nav.component';
import { ClipboardDirective } from './directive/clipboard.directive';
@ -94,6 +97,9 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
ConfirmationMessageComponent,
SpinnerDialogComponent,
NotFoundComponent,
ServerConfigComponent,
HelpComponent,
SigninComponent,
SettingsNavComponent,
ClipboardDirective,
QRCodeModule,
@ -107,6 +113,9 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
ConfirmationMessageComponent,
SpinnerDialogComponent,
NotFoundComponent,
ServerConfigComponent,
HelpComponent,
SigninComponent,
SettingsNavComponent,
ClipboardDirective,
SsoFailedComponent,

@ -1,5 +1,5 @@
import { Action } from '@ngrx/store';
import { RTLConfiguration, Settings, Node } from '../shared/models/RTLconfig';
import { RTLConfiguration, Settings, Node, SelNodeInfo } from '../shared/models/RTLconfig';
import { ErrorPayload } from '../shared/models/errorPayload';
import { MatDialogConfig } from '@angular/material';
@ -18,6 +18,7 @@ export const FETCH_RTL_CONFIG = 'FETCH_RTL_CONFIG';
export const SET_RTL_CONFIG = 'SET_RTL_CONFIG';
export const SAVE_SETTINGS = 'SAVE_SETTINGS';
export const SET_SELECTED_NODE = 'SET_SELECTED_NODE';
export const SET_SELECTED_NODE_INFO = 'SET_SELECTED_NODE_INFO';
export const IS_AUTHORIZED = 'IS_AUTHORIZED';
export const IS_AUTHORIZED_RES = 'IS_AUTHORIZED_RES';
export const SIGNIN = 'SIGNIN';
@ -86,6 +87,11 @@ export class SetSelelectedNode implements Action {
constructor(public payload: Node) {}
}
export class SetSelNodeInfo implements Action {
readonly type = SET_SELECTED_NODE_INFO;
constructor(public payload: SelNodeInfo) {}
}
export class IsAuthorized implements Action {
readonly type = IS_AUTHORIZED;
constructor(public payload: string) {} // payload = password
@ -114,5 +120,5 @@ export type RTLActions =
ClearEffectError | EffectError | OpenSpinner | CloseSpinner |
FetchRTLConfig | SetRTLConfig | SaveSettings |
OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation |
ResetStore | SetSelelectedNode |
ResetStore | SetSelelectedNode | SetSelNodeInfo |
IsAuthorized | IsAuthorizedRes | Signin | Signout | InitAppData;

@ -15,6 +15,7 @@ import { SpinnerDialogComponent } from '../shared/components/spinner-dialog/spin
import { AlertMessageComponent } from '../shared/components/alert-message/alert-message.component';
import { ConfirmationMessageComponent } from '../shared/components/confirmation-message/confirmation-message.component';
import * as CLActions from '../c-lightning/store/cl.actions';
import * as LNDActions from '../lnd/store/lnd.actions';
import * as RTLActions from './rtl.actions';
import * as fromRTLReducer from './rtl.reducers';
@ -207,7 +208,17 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
if (sessionStorage.getItem('token')) {
this.store.dispatch(new RTLActions.ResetStore(action.payload));
return { type: LNDActions.FETCH_INFO };
if (action.payload.lnImplementation === 'CLightning') {
this.router.navigate(['./cl']);
this.store.dispatch(new CLActions.ResetCLStore());
this.store.dispatch(new LNDActions.ResetLNDStore());
return { type: CLActions.FETCH_CL_INFO };
} else {
this.router.navigate(['./lnd']);
this.store.dispatch(new CLActions.ResetCLStore());
this.store.dispatch(new LNDActions.ResetLNDStore());
return { type: LNDActions.FETCH_INFO };
}
} else {
return {
type: RTLActions.OPEN_ALERT,

@ -1,16 +1,12 @@
import * as RTLActions from './rtl.actions';
import { ErrorPayload } from '../shared/models/errorPayload';
import { RTLConfiguration, Node } from '../shared/models/RTLconfig';
import { LNDReducer, LNDState, LNDInitialState } from '../lnd/store/lnd.reducers';
import { ActionReducerMap } from '@ngrx/store';
import * as fromLNDReducer from '../lnd/store/lnd.reducers';
import { RTLConfiguration, Node, SelNodeInfo } from '../shared/models/RTLconfig';
export interface State {
effectErrors: ErrorPayload[];
selNode: Node;
appConfig: RTLConfiguration;
lnd: fromLNDReducer.LNDState;
selNodeInfo: SelNodeInfo;
}
const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'Vertical', menuType: 'Regular', theme: 'dark-blue', satsToBTC: false };
@ -24,7 +20,7 @@ const initialState: State = {
sso: { rtlSSO: 0, logoutRedirectLink: '/login' },
nodes: [{ settings: initNodeSettings, authentication: initNodeAuthentication}]
},
lnd: fromLNDReducer.LNDInitialState
selNodeInfo: {}
};
export function RTLRootReducer(state = initialState, action: RTLActions.RTLActions) {
@ -63,6 +59,11 @@ export function RTLRootReducer(state = initialState, action: RTLActions.RTLActio
selNode: action.payload.nodes.find(node => +node.index === action.payload.selectedNodeIndex),
appConfig: action.payload
};
case RTLActions.SET_SELECTED_NODE_INFO:
return {
...state,
selNodeInfo: action.payload
};
default:
return state;
}

Loading…
Cancel
Save