Incomplete lazy load 4

Incomplete lazy load 4
pull/209/head
Shahana Farooqui 5 years ago
parent 0948ea139c
commit 75a50e83d5

1419
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "rtl",
"version": "0.4.7-beta",
"version": "0.4.8-beta",
"license": "MIT",
"scripts": {
"ng": "ng",
@ -40,10 +40,13 @@
"hammerjs": "^2.0.8",
"ini": "^1.3.5",
"jsonwebtoken": "^8.4.0",
"material-design-icons": "^3.0.1",
"ngx-perfect-scrollbar": "^6.3.1",
"node-sass": "^4.12.0",
"nodemon": "^1.19.1",
"optimist": "^0.6.1",
"request-promise": "^4.2.2",
"roboto-fontface": "^0.10.0",
"rxjs": "~6.5.2",
"rxjs-compat": "^6.5.2",
"sha256": "^0.2.0",
@ -67,7 +70,6 @@
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"nodemon": "1.19.1",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",

@ -31,7 +31,7 @@
</div>
</mat-toolbar>
<div [ngClass]="{'mt-minus-1': smallScreen, 'inner-sidenav-content': true}">
<rtl-super-user-dashboard></rtl-super-user-dashboard>
<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>

@ -11,8 +11,8 @@ import { LoggerService } from './shared/services/logger.service';
import { RTLConfiguration, Settings, Node } from './shared/models/RTLconfig';
import { GetInfo } from './shared/models/lndModels';
import * as RTLActions from './store/rtl.actions';
import * as fromApp from './store/rtl.reducers';
import * as RTLActions from './shared/store/rtl.actions';
import * as fromRTLReducer from './shared/store/rtl.reducers';
@Component({
selector: 'rtl-app',
@ -22,25 +22,30 @@ import * as fromApp from './store/rtl.reducers';
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild('sideNavigation', { static: false }) sideNavigation: any;
@ViewChild('settingSidenav', { static: true }) settingSidenav: any;
public selNode: Node;
public settings: Settings;
public information: GetInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true];
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(), new Subject()];
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions, private userIdle: UserIdleService, private router: Router, private activatedRoute: ActivatedRoute) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions,
private userIdle: UserIdleService, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchRTLConfig());
this.accessKey = this.readAccessKey();
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.pipe(takeUntil(this.unsubs[0]))
.subscribe(rtlStore => {
this.settings = rtlStore.selNode.settings;
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;
@ -50,27 +55,44 @@ 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.store.dispatch(new RTLActions.FetchInfo());
}
this.actions$
.pipe(
takeUntil(this.unSubs[3]),
filter(action => action.type === RTLActions.SET_RTL_CONFIG)
).subscribe((actionPayload: RTLActions.SetRTLConfig) => {
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], { relativeTo: this.activatedRoute });
this.router.navigate([this.appConfig.sso.logoutRedirectLink]);
}
}
if (
this.settings.menu === 'Horizontal' ||
this.settings.menuType === 'Compact' ||
this.settings.menuType === 'Mini') {
this.settingSidenav.toggle();
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 RTLActions.FetchInfo());
}
});
this.actions$
.pipe(
takeUntil(this.unsubs[1]),
filter((action) => action.type === RTLActions.SET_INFO)
).subscribe((infoData: RTLActions.SetInfo) => {
if (undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
});
this.userIdle.startWatching();
@ -93,6 +115,17 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
return url.substring(url.lastIndexOf('access-key=') + 11).trim();
}
initializeRemainingData() {
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchFees());
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
}
ngAfterViewInit() {
if (!this.settings.flgSidenavPinned) {
this.sideNavigation.close();
@ -130,7 +163,7 @@ export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
}
ngOnDestroy() {
this.unSubs.forEach(unsub => {
this.unsubs.forEach(unsub => {
unsub.next();
unsub.complete();
});

@ -1,14 +1,14 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { UserIdleModule } from 'angular-user-idle';
import { UserIdleModule } from 'angular-user-idle';
import { OverlayContainer } from '@angular/cdk/overlay';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar';
import { PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
@ -17,46 +17,40 @@ const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollX: false
};
import { environment } from '../environments/environment';
import { routing } from './app.routing';
import { SharedModule } from './shared/shared.module';
import { ThemeOverlay } from './shared/theme/overlay-container/theme-overlay';
import { AppComponent } from './app.component';
import { SuperUserDashboardComponent } from './super-user-dashboard/super-user-dashboard.component';
import { environment } from '../environments/environment';
import { RTLRootReducer } from './shared/store/rtl.reducers';
import { RTLEffects } from './shared/store/rtl.effects';
import { CommonService } from './shared/services/common.service';
import { LoggerService, ConsoleLoggerService } from './shared/services/logger.service';
import { AuthGuard, LNDUnlockedGuard } from './shared/services/auth.guard';
import { AuthGuard } from './shared/services/auth.guard';
import { AuthInterceptor } from './shared/services/auth.interceptor';
import * as fromApp from './store/rtl.reducers';
import { RTLEffects } from './store/rtl.effects';
import { LNDEffects } from './lnd/store/lnd.effects';
import { CLEffects } from './c-lightning/store/cl.effects';
@NgModule({
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
PerfectScrollbarModule,
SharedModule,
PerfectScrollbarModule,
routing,
UserIdleModule.forRoot({idle: 60 * 60, timeout: 1, ping: null}),
StoreModule.forRoot(fromApp.appReducer),
EffectsModule.forRoot([RTLEffects, LNDEffects, CLEffects]),
!environment.production ? StoreDevtoolsModule.instrument() : []
StoreModule.forRoot({rtlRoot: RTLRootReducer}),
EffectsModule.forRoot([RTLEffects]),
!environment.production ? StoreDevtoolsModule.instrument() : []
],
declarations: [
AppComponent,
SuperUserDashboardComponent
AppComponent
],
providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService },
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG },
{ provide: OverlayContainer, useClass: ThemeOverlay },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
AuthGuard, LNDUnlockedGuard, CommonService
{ provide: PERFECT_SCROLLBAR_CONFIG, useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
AuthGuard, CommonService
],
bootstrap: [AppComponent]
})

@ -1,20 +1,16 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
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 { SsoFailedComponent } from './shared/components/sso-failed/sso-failed.component';
import { NotFoundComponent } from './shared/components/not-found/not-found.component';
import { AuthGuard } from './shared/services/auth.guard';
import { SuperUserDashboardComponent } from './super-user-dashboard/super-user-dashboard.component';
export const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: SuperUserDashboardComponent },
{ path: 'lnd', loadChildren: () => import('./lnd/lnd.module').then(childModule => childModule.LndModule)},
{ path: 'cl', loadChildren: () => import('./c-lightning/cl.module').then(childModule => childModule.ClModule)},
{ path: 'lnd', loadChildren: () => import('./lnd/lnd.module').then(childModule => childModule.LNDModule), canActivate: [AuthGuard] },
{ path: 'cl', loadChildren: () => import('./clightning/cl.module').then(childModule => childModule.CLModule), canActivate: [AuthGuard] },
{ path: 'sconfig', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'login', component: SigninComponent },
{ path: 'help', component: HelpComponent },
@ -22,4 +18,4 @@ export const routes: Routes = [
{ path: '**', component: NotFoundComponent }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes, { enableTracing: true });
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

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

@ -1,67 +0,0 @@
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 fromApp 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<fromApp.AppState>, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
console.warn('CL ROOT');
// this.store.dispatch(new CLActions.FetchCLInfo());
this.router.navigate(['./home'], {relativeTo: this.activatedRoute});
// this.store.select('cl')
// .pipe(takeUntil(this.unsubs[0]))
// .subscribe(clStore => {
// console.warn(clStore);
// if (undefined !== clStore.information.identity_pubkey) {
// this.initializeRemainingData();
// }
// });
// this.actions$
// .pipe(
// takeUntil(this.unSubs[3]),
// filter(action => action.type === RTLActions.INIT_APP_DATA || action.type === LNDActions.SET_INFO || action.type === CLActions.SET_CL_INFO)
// ).subscribe((actionPayload: RTLActions.InitAppData | LNDActions.SetInfo | CLActions.SetCLInfo) => {
// // if (actionPayload.type === RTLActions.INIT_APP_DATA) {
// if(this.information.identity_pubkey) {
// this.initializeRemainingData();
// }
// });
}
initializeRemainingData() {
console.warn('SOMETHING IS WRONG HERE');
// this.store.dispatch(new CLActions.FetchCLFees());
// 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();
});
}
}

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

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

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

@ -1,56 +0,0 @@
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 fromApp from '../../store/rtl.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 store: Store<fromApp.AppState>) {}
ngOnInit() {
console.warn('CL HOME');
this.store.select('cl')
.pipe(takeUntil(this.unsubs[1]))
.subscribe(clStore => {
this.information = clStore.information;
if (undefined !== this.information.identity_pubkey) {
this.initializeRemainingData();
}
this.logger.info(clStore);
});
}
initializeRemainingData() {
console.warn('SOMETHING IS WRONG HERE');
// this.store.dispatch(new CLActions.FetchCLFees());
// 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(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -1,33 +0,0 @@
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 const FETCH_CL_FEES = 'FETCH_CL_FEES';
export const SET_CL_FEES = 'SET_CL_FEES';
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 class FetchCLFees implements Action {
readonly type = FETCH_CL_FEES;
}
export class SetCLFees implements Action {
readonly type = SET_CL_FEES;
constructor(public payload: {}) {}
}
export type CLActions =
ResetCLStore | FetchCLInfo | SetCLInfo | FetchCLFees | SetCLFees;

@ -1,102 +0,0 @@
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router, ActivatedRoute } 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 CLActions from './cl.actions';
import * as fromApp from '../../store/rtl.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<fromApp.AppState>,
private logger: LoggerService,
public dialog: MatDialog,
private router: Router,
private activatedRoute: ActivatedRoute) { }
@Effect()
infoFetch = this.actions$.pipe(
ofType(CLActions.FETCH_CL_INFO),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [CLActions.FetchCLInfo, fromApp.RootState]) => {
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) {
sessionStorage.removeItem('clUnlocked');
return {
type: CLActions.SET_CL_INFO,
payload: {}
};
} else {
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'], {relativeTo: this.activatedRoute});
} else {
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
this.router.navigate([store.appConfig.sso.logoutRedirectLink], {relativeTo: this.activatedRoute});
return of();
}
}
})
);
}
));
@Effect()
fetchFees = this.actions$.pipe(
ofType(CLActions.FETCH_CL_FEES),
mergeMap((action: CLActions.FetchCLFees) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchCLFees'));
return this.httpClient.get(environment.FEES_API);
}),
map((fees) => {
this.logger.info(fees);
return {
type: CLActions.SET_CL_FEES,
payload: (undefined !== fees) ? fees : {}
};
}),
catchError((err: any) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectError({ action: 'FetchCLFees', code: err.status, message: err.error.error }));
return of();
}
));
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -1,49 +0,0 @@
import * as CLActions from './cl.actions';
import { GetInfo, GetInfoChain } from '../../shared/models/clModels';
export interface CLState {
information: GetInfo;
fees: {};
}
export const CLInitialState: CLState = {
information: {},
fees: {}
};
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
};
case CLActions.SET_CL_FEES:
return {
...state,
fees: action.payload
};
default:
return state;
}
}

@ -0,0 +1,166 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'rtl-cl-root',
templateUrl: './cl-root.component.html',
styleUrls: ['./cl-root.component.scss']
})
export class CLRootComponent implements OnInit {
constructor(private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
console.warn('CL ROOT');
this.router.navigate(['./home'], {relativeTo: this.activatedRoute});
}
// @ViewChild('sideNavigation', { static: false }) 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()];
// 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.store.select('rtlRoot')
// .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 RTLActions.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 RTLActions.FetchInfo());
// }
// });
// this.actions$
// .pipe(
// takeUntil(this.unsubs[1]),
// filter((action) => action.type === RTLActions.SET_INFO)
// ).subscribe((infoData: RTLActions.SetInfo) => {
// if (undefined !== infoData.payload.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() {
// this.store.dispatch(new RTLActions.FetchPeers());
// this.store.dispatch(new RTLActions.FetchBalance('channels'));
// this.store.dispatch(new RTLActions.FetchFees());
// this.store.dispatch(new RTLActions.FetchNetwork());
// this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
// this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
// this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
// this.store.dispatch(new RTLActions.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();
// unsub.complete();
// });
// }
}

@ -0,0 +1,31 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CLRouting } from './cl.routing';
import { SharedModule } from '../shared/shared.module';
import { CLRootComponent } from './cl-root.component';
import { CLHomeComponent } from './home/home.component';
import { CommonService } from '../shared/services/common.service';
import { LoggerService, ConsoleLoggerService } from '../shared/services/logger.service';
import { CLUnlockedGuard } from '../shared/services/auth.guard';
@NgModule({
imports: [
CommonModule,
SharedModule,
CLRouting
],
declarations: [
CLRootComponent,
CLHomeComponent
],
providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService },
CLUnlockedGuard,
CommonService
],
bootstrap: [CLRootComponent]
})
export class CLModule {}

@ -0,0 +1,18 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { CLRootComponent } from './cl-root.component';
import { CLHomeComponent } from './home/home.component';
import { CLUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
export const ClRoutes: Routes = [
{ path: '', component: CLRootComponent,
children: [
{ path: 'home', component: CLHomeComponent, canActivate: [CLUnlockedGuard] },
{ path: '**', component: NotFoundComponent }
]}
];
export const CLRouting: ModuleWithProviders = RouterModule.forChild(ClRoutes);

@ -0,0 +1,237 @@
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="25" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[2]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center end">
<mat-card-title class="m-0 pt-2">
<h5>Wallet Balance</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">account_balance_wallet</mat-icon>
</mat-card-content>
<span *ngIf="information?.currency_unit; else withoutData">
<h3 *ngIf="selNode?.settings?.satsToBTC; else smallerUnit1">{{BTCtotalBalance | number}} {{information?.currency_unit}}</h3>
<ng-template #smallerUnit1><h3>{{totalBalance | number}} {{information?.smaller_currency_unit}}</h3></ng-template>
</span>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[2]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="25" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[0]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Peers</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">group</mat-icon>
</mat-card-content>
<h3 *ngIf="information.num_peers; else zeroPeers">{{totalPeers | number}}</h3>
<ng-template #zeroPeers>
<h3>0</h3>
</ng-template>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="25" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[3]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Channel Balance</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">linear_scale</mat-icon>
</mat-card-content>
<span *ngIf="information?.currency_unit; else withoutData">
<h3 *ngIf="selNode?.settings?.satsToBTC; else smallerUnit2">{{BTCchannelBalance | number}} {{information?.currency_unit}}</h3>
<ng-template #smallerUnit2><h3>{{channelBalance | number}} {{information?.smaller_currency_unit}}</h3></ng-template>
</span>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[3]===true || flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
<div fxFlex="25" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[0]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Chain Sync Status</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content fxLayout="column" fxLayoutAlign="center center">
<mat-card-content class="mt-1">
<mat-icon class="icon-large">sync</mat-icon>
</mat-card-content>
<mat-icon *ngIf="information?.synced_to_chain; else notSynced" class="size-30 green sync-to-chain">check_circle</mat-icon>
<ng-template #notSynced>
<mat-icon class="size-30 red">cancel</mat-icon>
</ng-template>
</mat-card-content>
<mat-progress-bar class="mt-minus-5" *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card>
</div>
</div>
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="25" class="padding-gap">
<div fxLayout="column">
<mat-card fxFlex="100" [ngClass]="{'custom-card error-border': flgLoading[1]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Fee Report</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" class="pl-4">
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Daily ({{information?.smaller_currency_unit}})</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{fees?.day_fee_sum}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Weekly ({{information?.smaller_currency_unit}})</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{fees?.week_fee_sum}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Monthly ({{information?.smaller_currency_unit}})</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{fees?.month_fee_sum}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
</div>
<mat-progress-bar *ngIf="flgLoading[1]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
<mat-card fxFlex="100" [ngClass]="{'mt-2 custom-card error-border': flgLoading[5]==='error','mt-2 custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Channel Status</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" class="pl-4">
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Active</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start"><p class="mat-button-text pt-2">{{activeChannels}}</p></mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Inactive</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start"><p class="mat-button-text pt-2">{{inactiveChannels}}</p></mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxFlex="100" fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Pending</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start"><p class="mat-button-text pt-2">{{pendingChannels}}</p></mat-list-item>
<mat-divider></mat-divider>
</mat-list>
</div>
<mat-progress-bar *ngIf="flgLoading[6]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
</div>
</div>
<div fxFlex="40" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[5]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Local-Remote Channel Capacity</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="row" class="card-chnl-balances">
<div fxFlex="100" fxLayoutAlign="center center" *ngIf="flgTotalCalculated">
<ngx-charts-bar-vertical
[view]="view"
[scheme]="colorScheme"
[results]="totalBalances"
[yAxisLabel]="yAxisLabel"
[yScaleMax]="maxBalanceValue"
xAxis="false"
yAxis="true"
showYAxis="true"
showDataLabel="true"
tooltipDisabled="true">
</ngx-charts-bar-vertical>
</div>
</div>
<mat-progress-bar *ngIf="flgLoading[5]===true" mode="indeterminate" class="mt-minus-5"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
</div>
<div fxFlex="35" class="padding-gap">
<mat-card [ngClass]="{'custom-card error-border': flgLoading[5]==='error','custom-card': true}">
<mat-card-header class="bg-primary" fxLayoutAlign="center center">
<mat-card-title class="m-0 pt-2">
<h5>Network Information</h5>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" class="pl-4 network-info-list">
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start" *ngIf="selNode?.settings?.satsToBTC; else smallerUnit6">Network Capacity ({{information?.currency_unit}})</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start" *ngIf="selNode?.settings?.satsToBTC; else smallerData6">{{networkInfo?.btc_total_network_capacity | number}}</mat-list-item>
<ng-template #smallerUnit6><mat-list-item fxFlex="65" fxLayoutAlign="start start">Network Capacity ({{information?.smaller_currency_unit}})</mat-list-item></ng-template>
<ng-template #smallerData6><mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.total_network_capacity | number}}</mat-list-item></ng-template>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Number of Nodes</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.num_nodes | number}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Number of Channels</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.num_channels | number}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Max Out Degree</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.max_out_degree | number}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start">Avg Out Degree</mat-list-item>
<mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.avg_out_degree | number:'1.0-2'}}</mat-list-item>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start" *ngIf="selNode?.settings?.satsToBTC; else smallerUnit7">Max Channel Size ({{information?.currency_unit}})</mat-list-item>
<ng-template #smallerUnit7><mat-list-item fxFlex="65" fxLayoutAlign="start start">Max Channel Size ({{information?.smaller_currency_unit}})</mat-list-item></ng-template>
<mat-list-item fxFlex="25" fxLayoutAlign="end start" *ngIf="selNode?.settings?.satsToBTC; else smallerData7">{{networkInfo?.btc_max_channel_size | number}}</mat-list-item>
<ng-template #smallerData7><mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.max_channel_size | number}}</mat-list-item></ng-template>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start" *ngIf="selNode?.settings?.satsToBTC; else smallerUnit8">Avg Channel Size ({{information?.currency_unit}})</mat-list-item>
<ng-template #smallerUnit8><mat-list-item fxFlex="65" fxLayoutAlign="start start">Avg Channel Size ({{information?.smaller_currency_unit}})</mat-list-item></ng-template>
<mat-list-item fxFlex="25" fxLayoutAlign="end start" *ngIf="selNode?.settings?.satsToBTC; else smallerData8">{{networkInfo?.btc_avg_channel_size | number}}</mat-list-item>
<ng-template #smallerData8><mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.avg_channel_size | number:'1.0-2'}}</mat-list-item></ng-template>
<mat-divider></mat-divider>
</mat-list>
<mat-list fxLayoutAlign="start start">
<mat-list-item fxFlex="65" fxLayoutAlign="start start" *ngIf="selNode?.settings?.satsToBTC; else smallerUnit9">Min Channel Size ({{information?.currency_unit}})</mat-list-item>
<ng-template #smallerUnit9><mat-list-item fxFlex="65" fxLayoutAlign="start start">Min Channel Size ({{information?.smaller_currency_unit}})</mat-list-item></ng-template>
<mat-list-item fxFlex="25" fxLayoutAlign="end start" *ngIf="selNode?.settings?.satsToBTC; else smallerData9">{{networkInfo?.btc_min_channel_size | number}}</mat-list-item>
<ng-template #smallerData9><mat-list-item fxFlex="25" fxLayoutAlign="end start">{{networkInfo?.min_channel_size | number}}</mat-list-item></ng-template>
<mat-divider></mat-divider>
</mat-list>
</div>
<mat-progress-bar *ngIf="flgLoading[4]===true" mode="indeterminate"></mat-progress-bar>
<mat-divider></mat-divider>
</mat-card-content>
</mat-card>
</div>
</div>
<ng-template #withoutData><h3>Sats</h3></ng-template>

@ -0,0 +1,12 @@
.network-info-list .mat-list-item {
height: 44px;
}
.mat-column-bytes_sent, .mat-column-bytes_recv, .mat-column-sat_sent, .mat-column-sat_recv, .mat-column-inbound, .mat-column-ping_time {
flex: 0 0 8%;
min-width: 80px;
}
.card-chnl-balances {
min-height: 354px;
}

@ -0,0 +1,148 @@
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, NetworkInfo, Fees, Peer } from '../../shared/models/lndModels';
import { Node } from '../../shared/models/RTLconfig';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-cl-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class CLHomeComponent implements OnInit, OnDestroy {
public selNode: Node;
public fees: Fees;
public information: GetInfo = {};
public remainder = 0;
public totalPeers = -1;
public totalBalance = '';
public channelBalance = '';
public BTCtotalBalance = '';
public BTCchannelBalance = '';
public networkInfo: NetworkInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
public channels: any;
public position = 'below';
public activeChannels = 0;
public inactiveChannels = 0;
public pendingChannels = 0;
public peers: Peer[] = [];
barPadding = 0;
maxBalanceValue = 0;
totalBalances = [...[{'name': 'Local Balance', 'value': 0}, {'name': 'Remote Balance', 'value': 0}]];
flgTotalCalculated = false;
view = [];
yAxisLabel = 'Balance';
colorScheme = {domain: ['#FFFFFF']};
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>) {
switch (true) {
case (window.innerWidth <= 730):
this.view = [250, 352];
break;
case (window.innerWidth > 415 && window.innerWidth <= 730):
this.view = [280, 352];
break;
case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.view = [300, 352];
break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.view = [350, 352];
break;
default:
this.view = [300, 352];
break;
}
Object.assign(this, this.totalBalances);
}
ngOnInit() {
this.flgTotalCalculated = false;
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchInfo') {
this.flgLoading[0] = 'error';
}
if (effectsErr.action === 'FetchFees') {
this.flgLoading[1] = 'error';
}
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoading[2] = 'error';
}
if (effectsErr.action === 'FetchBalance/channels') {
this.flgLoading[3] = 'error';
}
if (effectsErr.action === 'FetchNetwork') {
this.flgLoading[4] = 'error';
}
if (effectsErr.action === 'FetchChannels/all') {
this.flgLoading[5] = 'error';
this.flgLoading[6] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true;
}
this.fees = rtlStore.fees;
if (this.flgLoading[1] !== 'error') {
this.flgLoading[1] = (undefined !== this.fees.day_fee_sum) ? false : true;
}
this.totalBalance = rtlStore.blockchainBalance.total_balance;
this.BTCtotalBalance = rtlStore.blockchainBalance.btc_total_balance;
if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = ('' !== this.totalBalance) ? false : true;
}
this.channelBalance = rtlStore.channelBalance.balance;
this.BTCchannelBalance = rtlStore.channelBalance.btc_balance;
if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.channelBalance) ? false : true;
}
this.networkInfo = rtlStore.networkInfo;
if (this.flgLoading[4] !== 'error') {
this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true;
}
this.totalBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': +rtlStore.totalRemoteBalance}]];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) {
this.flgTotalCalculated = true;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
}
this.activeChannels = rtlStore.numberOfActiveChannels;
this.inactiveChannels = rtlStore.numberOfInactiveChannels;
this.pendingChannels = (undefined !== rtlStore.pendingChannels.pending_open_channels) ? rtlStore.pendingChannels.pending_open_channels.length : 0;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0 && this.flgLoading[6] !== 'error') {
this.flgLoading[6] = false;
}
this.totalPeers = (rtlStore.peers !== null) ? rtlStore.peers.length : 0;
this.logger.info(rtlStore);
});
}
ngOnDestroy() {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -1,4 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
@ -10,9 +11,9 @@ import { Node } from '../../../shared/models/RTLconfig';
import { Channel } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-channel-backup',
@ -25,21 +26,27 @@ export class ChannelBackupComponent implements OnInit, OnDestroy {
public displayedColumns = ['chan_id', 'backup', 'verify'];
public selChannel: Channel;
public channels: any;
public flgLoading: Array<Boolean | 'error'> = [true];
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: channels
public flgSticky = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions, private router: Router) {}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[4]))
.subscribe(lndStore => {
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
this.selNode = rtlStore.selNode;
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'Fetchchannels') {
this.flgLoading[0] = 'error';
}
});
this.channels = new MatTableDataSource([]);
this.channels.data = [];
if (undefined !== lndStore.allChannels) {
this.channels = new MatTableDataSource<Channel>([...lndStore.allChannels]);
this.channels.data = lndStore.allChannels;
if (undefined !== rtlStore.allChannels) {
this.channels = new MatTableDataSource<Channel>([...rtlStore.allChannels]);
this.channels.data = rtlStore.allChannels;
}
this.channels.sort = this.sort;
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
@ -54,36 +61,25 @@ export class ChannelBackupComponent implements OnInit, OnDestroy {
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = false;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
this.selNode = rtlStore.selNode;
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'Fetchchannels') {
this.flgLoading[0] = 'error';
}
});
this.logger.info(rtlStore);
});
this.actions$
.pipe(
takeUntil(this.unSubs[1]),
filter((action) => action.type === LNDActions.SET_CHANNELS)
).subscribe((setchannels: LNDActions.SetChannels) => {
filter((action) => action.type === RTLActions.SET_CHANNELS)
).subscribe((setchannels: RTLActions.SetChannels) => {
this.selChannel = undefined;
});
}
onBackupChannels(selChannel: Channel) {
this.store.dispatch(new RTLActions.OpenSpinner('Backup Channels...'));
this.store.dispatch(new LNDActions.BackupChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL', showMessage: ''}));
this.store.dispatch(new RTLActions.BackupChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL', showMessage: ''}));
}
onVerifyChannels(selChannel: Channel) {
this.store.dispatch(new RTLActions.OpenSpinner('Verify Channels...'));
this.store.dispatch(new LNDActions.VerifyChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL'}));
this.store.dispatch(new RTLActions.VerifyChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL'}));
}
onChannelClick(selRow: Channel, event: any) {

@ -8,9 +8,9 @@ import { MatTableDataSource, MatSort } from '@angular/material';
import { ClosedChannel } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-channel-closed',
@ -24,9 +24,9 @@ export class ChannelClosedComponent implements OnInit, OnDestroy {
public flgLoading: Array<Boolean | 'error'> = [true];
public selectedFilter = '';
public flgSticky = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['close_type', 'chan_id', 'settled_balance'];
@ -51,29 +51,24 @@ export class ChannelClosedComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'closed'}));
this.actions$.pipe(takeUntil(this.unsubs[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'closed'}));
});
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[3]))
.subscribe(lndStore => {
if (undefined !== lndStore.closedChannels) {
this.loadClosedChannelsTable(lndStore.closedChannels);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore.closedChannels) ? false : true;
}
this.logger.info(lndStore);
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'}));
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'}));
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchChannels/closed') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.closedChannels) {
this.loadClosedChannelsTable(rtlStore.closedChannels);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.closedChannels) ? false : true;
}
this.logger.info(rtlStore);
});
@ -107,7 +102,7 @@ export class ChannelClosedComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -1,19 +1,18 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Router, NavigationStart, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Subject, Observable } from 'rxjs';
import { takeUntil, filter, map, subscribeOn } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { Channel, Peer, GetInfo } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-channel-manage',
@ -41,10 +40,9 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
public moreOptions = false;
public flgSticky = false;
public redirectedWithPeer = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private rtlEffects: RTLEffects,
private lndEffects: LNDEffects, private activatedRoute: ActivatedRoute) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private activatedRoute: ActivatedRoute) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['close', 'update', 'active', 'chan_id', 'remote_alias'];
@ -69,35 +67,29 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[5]))
.subscribe(lndStore => {
this.information = lndStore.information;
this.peers = lndStore.peers;
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchChannels/all') {
this.flgLoading[0] = 'error';
}
});
this.information = rtlStore.information;
this.peers = rtlStore.peers;
this.peers.forEach(peer => {
if (undefined === peer.alias || peer.alias === '') {
peer.alias = peer.pub_key.substring(0, 15) + '...';
}
});
this.totalBalance = lndStore ? +lndStore.blockchainBalance.total_balance : -1;
if (undefined !== lndStore.allChannels) {
this.loadChannelsTable(lndStore.allChannels);
this.totalBalance = +rtlStore.blockchainBalance.total_balance;
if (undefined !== rtlStore.allChannels) {
this.loadChannelsTable(rtlStore.allChannels);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore.allChannels) ? false : true;
this.flgLoading[0] = (undefined !== rtlStore.allChannels) ? false : true;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchChannels/all') {
this.flgLoading[0] = 'error';
}
});
this.logger.info(rtlStore);
});
this.activatedRoute.paramMap.subscribe(() => {
@ -114,7 +106,7 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
} else if (this.selTransType === '2') {
transTypeValue = this.transTypeValue.fees;
}
this.store.dispatch(new LNDActions.SaveNewChannel({
this.store.dispatch(new RTLActions.SaveNewChannel({
selectedPeerPubkey: this.selectedPeer, fundingAmount: this.fundingAmount, private: this.isPrivate,
transType: this.selTransType, transTypeValue: transTypeValue, spendUnconfirmed: this.spendUnconfirmed
}));
@ -132,22 +124,22 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
]
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsubs[2]))
.pipe(takeUntil(this.unsub[2]))
.subscribe(confirmRes => {
if (confirmRes) {
const base_fee = confirmRes[0].inputValue;
const fee_rate = confirmRes[1].inputValue;
const time_lock_delta = confirmRes[2].inputValue;
this.store.dispatch(new RTLActions.OpenSpinner('Updating Channel Policy...'));
this.store.dispatch(new LNDActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: 'all'}));
this.store.dispatch(new RTLActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: 'all'}));
}
});
} else {
this.myChanPolicy = {fee_base_msat: 0, fee_rate_milli_msat: 0, time_lock_delta: 0};
this.store.dispatch(new RTLActions.OpenSpinner('Fetching Channel Policy...'));
this.store.dispatch(new LNDActions.ChannelLookup(channelToUpdate.chan_id.toString()));
this.lndEffects.setLookup
.pipe(takeUntil(this.unsubs[3]))
this.store.dispatch(new RTLActions.ChannelLookup(channelToUpdate.chan_id.toString()));
this.rtlEffects.setLookup
.pipe(takeUntil(this.unsub[3]))
.subscribe(resLookup => {
this.logger.info(resLookup);
if (resLookup.node1_pub === this.information.identity_pubkey) {
@ -170,14 +162,14 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
}}));
});
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsubs[4]))
.pipe(takeUntil(this.unsub[2]))
.subscribe(confirmRes => {
if (confirmRes) {
const base_fee = confirmRes[0].inputValue;
const fee_rate = confirmRes[1].inputValue;
const time_lock_delta = confirmRes[2].inputValue;
this.store.dispatch(new RTLActions.OpenSpinner('Updating Channel Policy...'));
this.store.dispatch(new LNDActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: channelToUpdate.channel_point}));
this.store.dispatch(new RTLActions.UpdateChannels({baseFeeMsat: base_fee, feeRate: fee_rate, timeLockDelta: time_lock_delta, chanPoint: channelToUpdate.channel_point}));
}
});
}
@ -189,11 +181,11 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Closing channel: ' + channelToClose.chan_id, noBtnText: 'Cancel', yesBtnText: 'Close Channel'
}}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsubs[1]))
.pipe(takeUntil(this.unsub[1]))
.subscribe(confirmRes => {
if (confirmRes) {
this.store.dispatch(new RTLActions.OpenSpinner('Closing Channel...'));
this.store.dispatch(new LNDActions.CloseChannel({channelPoint: channelToClose.channel_point, forcibly: !channelToClose.active}));
this.store.dispatch(new RTLActions.CloseChannel({channelPoint: channelToClose.channel_point, forcibly: !channelToClose.active}));
}
});
}
@ -263,7 +255,7 @@ export class ChannelManageComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -8,8 +8,9 @@ import { Channel, GetInfo, PendingChannels } from '../../../shared/models/lndMod
import { Node } from '../../../shared/models/RTLconfig';
import { LoggerService } from '../../../shared/services/logger.service';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-channel-pending',
@ -47,9 +48,9 @@ export class ChannelPendingComponent implements OnInit, OnDestroy {
public pendingWaitClosingChannelsLength = 0;
public pendingWaitClosingChannels: any;
public flgLoading: Array<Boolean | 'error'> = [true];
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedClosingColumns = ['remote_node_pub', 'local_balance', 'remote_balance'];
@ -95,11 +96,18 @@ export class ChannelPendingComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[2]))
.subscribe(lndStore => {
this.information = lndStore.information;
this.pendingChannels = lndStore.pendingChannels;
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchChannels/pending') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
this.pendingChannels = rtlStore.pendingChannels;
if (undefined !== this.pendingChannels.total_limbo_balance) {
this.flgLoading[1] = false;
if (undefined !== this.pendingChannels.pending_closing_channels) {
@ -118,19 +126,6 @@ export class ChannelPendingComponent implements OnInit, OnDestroy {
if (this.flgLoading[0] !== 'error') {
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: fromApp.RootState) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchChannels/pending') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.logger.info(rtlStore);
});
@ -237,7 +232,7 @@ export class ChannelPendingComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -7,7 +7,7 @@ import { LoggerService } from '../../shared/services/logger.service';
import { GetInfo, NetworkInfo, Fees, Peer } from '../../shared/models/lndModels';
import { Node } from '../../shared/models/RTLconfig';
import * as fromApp from '../../store/rtl.reducers';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-home',
@ -25,8 +25,8 @@ export class HomeComponent implements OnInit, OnDestroy {
public BTCtotalBalance = '';
public BTCchannelBalance = '';
public networkInfo: NetworkInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true];
private unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
public channels: any;
public position = 'below';
public activeChannels = 0;
@ -41,7 +41,7 @@ export class HomeComponent implements OnInit, OnDestroy {
yAxisLabel = 'Balance';
colorScheme = {domain: ['#FFFFFF']};
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>) {
switch (true) {
case (window.innerWidth <= 730):
this.view = [250, 352];
@ -64,51 +64,9 @@ export class HomeComponent implements OnInit, OnDestroy {
ngOnInit() {
this.flgTotalCalculated = false;
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[1]))
.subscribe(lndStore => {
this.information = lndStore.information;
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true;
}
this.fees = lndStore.fees;
if (this.flgLoading[1] !== 'error') {
this.flgLoading[1] = (undefined !== this.fees.day_fee_sum) ? false : true;
}
this.totalBalance = lndStore.blockchainBalance.total_balance;
this.BTCtotalBalance = lndStore.blockchainBalance.btc_total_balance;
if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = ('' !== this.totalBalance) ? false : true;
}
this.channelBalance = lndStore.channelBalance.balance;
this.BTCchannelBalance = lndStore.channelBalance.btc_balance;
if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.channelBalance) ? false : true;
}
this.networkInfo = lndStore.networkInfo;
if (this.flgLoading[4] !== 'error') {
this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true;
}
this.totalBalances = [...[{'name': 'Local Balance', 'value': +lndStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': +lndStore.totalRemoteBalance}]];
this.maxBalanceValue = (lndStore.totalLocalBalance > lndStore.totalRemoteBalance) ? lndStore.totalLocalBalance : lndStore.totalRemoteBalance;
if (lndStore.totalLocalBalance >= 0 && lndStore.totalRemoteBalance >= 0) {
this.flgTotalCalculated = true;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
}
this.activeChannels = lndStore.numberOfActiveChannels;
this.inactiveChannels = lndStore.numberOfInactiveChannels;
this.pendingChannels = (undefined !== lndStore.pendingChannels.pending_open_channels) ? lndStore.pendingChannels.pending_open_channels.length : 0;
if (lndStore.totalLocalBalance >= 0 && lndStore.totalRemoteBalance >= 0 && this.flgLoading[6] !== 'error') {
this.flgLoading[6] = false;
}
this.totalPeers = (lndStore.peers !== null) ? lndStore.peers.length : 0;
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchInfo') {
this.flgLoading[0] = 'error';
@ -131,12 +89,57 @@ export class HomeComponent implements OnInit, OnDestroy {
}
});
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== this.information.identity_pubkey) ? false : true;
}
this.fees = rtlStore.fees;
if (this.flgLoading[1] !== 'error') {
this.flgLoading[1] = (undefined !== this.fees.day_fee_sum) ? false : true;
}
this.totalBalance = rtlStore.blockchainBalance.total_balance;
this.BTCtotalBalance = rtlStore.blockchainBalance.btc_total_balance;
if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = ('' !== this.totalBalance) ? false : true;
}
this.channelBalance = rtlStore.channelBalance.balance;
this.BTCchannelBalance = rtlStore.channelBalance.btc_balance;
if (this.flgLoading[3] !== 'error') {
this.flgLoading[3] = ('' !== this.channelBalance) ? false : true;
}
this.networkInfo = rtlStore.networkInfo;
if (this.flgLoading[4] !== 'error') {
this.flgLoading[4] = (undefined !== this.networkInfo.num_nodes) ? false : true;
}
this.totalBalances = [...[{'name': 'Local Balance', 'value': +rtlStore.totalLocalBalance}, {'name': 'Remote Balance', 'value': +rtlStore.totalRemoteBalance}]];
this.maxBalanceValue = (rtlStore.totalLocalBalance > rtlStore.totalRemoteBalance) ? rtlStore.totalLocalBalance : rtlStore.totalRemoteBalance;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) {
this.flgTotalCalculated = true;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
}
this.activeChannels = rtlStore.numberOfActiveChannels;
this.inactiveChannels = rtlStore.numberOfInactiveChannels;
this.pendingChannels = (undefined !== rtlStore.pendingChannels.pending_open_channels) ? rtlStore.pendingChannels.pending_open_channels.length : 0;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0 && this.flgLoading[6] !== 'error') {
this.flgLoading[6] = false;
}
this.totalPeers = (rtlStore.peers !== null) ? rtlStore.peers.length : 0;
this.logger.info(rtlStore);
});
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -1,8 +1,9 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { formatDate } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { Node } from '../../shared/models/RTLconfig';
@ -10,10 +11,8 @@ import { GetInfo, Invoice } from '../../shared/models/lndModels';
import { LoggerService } from '../../shared/services/logger.service';
import { newlyAddedRowAnimation } from '../../shared/animation/row-animation';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-invoices',
@ -42,9 +41,9 @@ export class InvoicesComponent implements OnInit, OnDestroy {
public pageSizeOptions = [5, 10, 25, 100];
private firstOffset = -1;
private lastOffset = -1;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['settled', 'creation_date', 'memo', 'value'];
@ -67,29 +66,24 @@ export class InvoicesComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[5]))
.subscribe(lndStore => {
this.information = lndStore ? lndStore.information : {};
this.totalInvoices = lndStore ? lndStore.totalInvoices : -1;
this.firstOffset = lndStore ? +lndStore.invoices.first_index_offset : -1;
this.lastOffset = lndStore ? +lndStore.invoices.last_index_offset : -1;
this.loadInvoicesTable(lndStore.invoices.invoices);
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore && undefined !== lndStore.invoices) ? false : true;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchInvoices') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
this.totalInvoices = rtlStore.totalInvoices;
this.firstOffset = +rtlStore.invoices.first_index_offset;
this.lastOffset = +rtlStore.invoices.last_index_offset;
this.logger.info(rtlStore);
this.loadInvoicesTable(rtlStore.invoices.invoices);
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.invoices) ? false : true;
}
});
}
@ -99,7 +93,7 @@ export class InvoicesComponent implements OnInit, OnDestroy {
this.newlyAddedInvoiceMemo = this.memo;
this.newlyAddedInvoiceValue = this.invoiceValue;
this.store.dispatch(new RTLActions.OpenSpinner('Adding Invoice...'));
this.store.dispatch(new LNDActions.SaveNewInvoice({
this.store.dispatch(new RTLActions.SaveNewInvoice({
memo: this.memo, invoiceValue: this.invoiceValue, private: this.private, expiry: (this.expiry ? this.expiry : 3600), pageSize: this.pageSize
}));
this.resetData();
@ -157,7 +151,7 @@ export class InvoicesComponent implements OnInit, OnDestroy {
reversed = true;
index_offset = 0;
}
this.store.dispatch(new LNDActions.FetchInvoices({num_max_invoices: event.pageSize, index_offset: index_offset, reversed: reversed}));
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: event.pageSize, index_offset: index_offset, reversed: reversed}));
}
ngOnDestroy() {

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

@ -1,71 +1,166 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Component, OnInit } 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 LNDActions from './store/lnd.actions';
import * as fromApp from '../store/rtl.reducers';
@Component({
selector: 'rtl-lnd-root-app',
selector: 'rtl-lnd-root',
templateUrl: './lnd-root.component.html',
styleUrls: ['./lnd-root.component.scss']
})
export class LndRootComponent implements OnInit, OnDestroy {
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private store: Store<fromApp.AppState>, private router: Router, private activatedRoute: ActivatedRoute, private actions$: Actions) {}
export class LNDRootComponent implements OnInit {
constructor(private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
console.warn('LND ROOT');
// this.store.dispatch(new LNDActions.FetchInfo());
console.warn('LND ROOT')
this.router.navigate(['./home'], {relativeTo: this.activatedRoute});
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[0]))
.subscribe(lndStore => {
console.warn(lndStore);
if (undefined !== lndStore.information.identity_pubkey) {
this.initializeRemainingData();
}
});
this.actions$.pipe(takeUntil(this.unsubs[2]), filter((action) => action.type === LNDActions.SET_INFO))
.subscribe((infoData: LNDActions.SetInfo) => {
console.warn(infoData);
if (undefined !== infoData.payload.identity_pubkey) {
this.initializeRemainingData();
}
});
// this.actions$
// .pipe(
// takeUntil(this.unSubs[3]),
// filter(action => action.type === RTLActions.INIT_APP_DATA || action.type === LNDActions.SET_INFO || action.type === CLActions.SET_CL_INFO)
// ).subscribe((actionPayload: RTLActions.InitAppData | LNDActions.SetInfo | CLActions.SetCLInfo) => {
// // if (actionPayload.type === RTLActions.INIT_APP_DATA) {
// if(this.information.identity_pubkey) {
// this.initializeRemainingData();
// }
// });
}
initializeRemainingData() {
console.warn('SOMETHING IS WRONG HERE');
// this.store.dispatch(new LNDActions.FetchPeers());
// this.store.dispatch(new LNDActions.FetchBalance('channels'));
// this.store.dispatch(new LNDActions.FetchFees());
// this.store.dispatch(new LNDActions.FetchNetwork());
// this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'all'}));
// this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'pending'}));
// this.store.dispatch(new LNDActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
// this.store.dispatch(new LNDActions.FetchPayments());
}
// @ViewChild('sideNavigation', { static: false }) 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()];
ngOnDestroy() {
this.unsubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
// 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.store.select('rtlRoot')
// .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 RTLActions.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 RTLActions.FetchInfo());
// }
// });
// this.actions$
// .pipe(
// takeUntil(this.unsubs[1]),
// filter((action) => action.type === RTLActions.SET_INFO)
// ).subscribe((infoData: RTLActions.SetInfo) => {
// if (undefined !== infoData.payload.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() {
// this.store.dispatch(new RTLActions.FetchPeers());
// this.store.dispatch(new RTLActions.FetchBalance('channels'));
// this.store.dispatch(new RTLActions.FetchFees());
// this.store.dispatch(new RTLActions.FetchNetwork());
// this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
// this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
// this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 25, reversed: true}));
// this.store.dispatch(new RTLActions.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();
// unsub.complete();
// });
// }
}

@ -1,13 +1,10 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../../environments/environment';
import { LNDRouting } from './lnd.routing';
import { SharedModule } from '../shared/shared.module';
import { lndRouting } from './lnd.routing';
import { LndRootComponent } from './lnd-root.component';
import { LNDRootComponent } from './lnd-root.component';
import { HomeComponent } from './home/home.component';
import { PeersComponent } from './peers/peers.component';
import { SendReceiveTransComponent } from './transactions/send-receive/send-receive-trans.component';
@ -26,16 +23,18 @@ import { NodeLookupComponent } from './lookups/node-lookup/node-lookup.component
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { QueryRoutesComponent } from './payments/query-routes/query-routes.component';
import { CommonService } from '../shared/services/common.service';
import { LoggerService, ConsoleLoggerService } from '../shared/services/logger.service';
import { LNDUnlockedGuard } from '../shared/services/auth.guard';
@NgModule({
imports: [
CommonModule,
SharedModule,
lndRouting,
NgxChartsModule,
!environment.production ? StoreDevtoolsModule.instrument() : []
LNDRouting
],
declarations: [
LndRootComponent,
LNDRootComponent,
HomeComponent,
PeersComponent,
SendReceiveTransComponent,
@ -54,7 +53,11 @@ import { QueryRoutesComponent } from './payments/query-routes/query-routes.compo
ChannelBackupComponent,
QueryRoutesComponent
],
providers: [],
bootstrap: [LndRootComponent]
providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService },
LNDUnlockedGuard,
CommonService
],
bootstrap: [LNDRootComponent]
})
export class LndModule {}
export class LNDModule {}

@ -1,10 +1,7 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
import { LndRootComponent } from './lnd-root.component';
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';
@ -21,27 +18,29 @@ import { ForwardingHistoryComponent } from './switch/forwarding-history.componen
import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
export const lndRoutes: Routes = [
{ path: '', component: LndRootComponent,
import { LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
export const LndRoutes: Routes = [
{ path: '', component: LNDRootComponent,
children: [
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard, LNDUnlockedGuard] },
{ path: 'unlocklnd', component: UnlockLNDComponent, canActivate: [AuthGuard] },
{ 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: '**', component: NotFoundComponent }
]
}
{ path: 'unlocklnd', component: UnlockLNDComponent },
{ path: 'home', component: HomeComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'peers', component: PeersComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlclosed', component: ChannelClosedComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlmanage', component: ChannelManageComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlpending', component: ChannelPendingComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlbackup', component: ChannelBackupComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'transsendreceive', component: SendReceiveTransComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'translist', component: ListTransactionsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'paymentsend', component: PaymentsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'queryroutes', component: QueryRoutesComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'invoices', component: InvoicesComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'switch', component: ForwardingHistoryComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'routingpeers', component: RoutingPeersComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'lookups', component: LookupsComponent, canActivate: [LNDUnlockedGuard] },
{ path: '**', component: NotFoundComponent }
]}
];
export const lndRouting: ModuleWithProviders = RouterModule.forChild(lndRoutes);
export const LNDRouting: ModuleWithProviders = RouterModule.forChild(LndRoutes);

@ -1,47 +1,40 @@
import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { Component, OnInit, Input } from '@angular/core';
import { formatDate } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { ChannelEdge } from '../../../shared/models/lndModels';
import * as fromLNDReducer from '../../store/lnd.reducers';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-channel-lookup',
templateUrl: './channel-lookup.component.html',
styleUrls: ['./channel-lookup.component.css']
})
export class ChannelLookupComponent implements OnInit, OnDestroy {
export class ChannelLookupComponent implements OnInit {
@Input() lookupResult: ChannelEdge;
public node1_match = false;
public node2_match = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private lndStore: Store<fromLNDReducer.LNDState>) { }
constructor(private store: Store<fromRTLReducer.State>) { }
ngOnInit() {
if (undefined !== this.lookupResult && undefined !== this.lookupResult.last_update_str) {
this.lookupResult.last_update_str = (this.lookupResult.last_update_str === '') ?
'' : formatDate(this.lookupResult.last_update_str, 'MMM/dd/yy HH:mm:ss', 'en-US');
}
this.lndStore.select('lnd')
.pipe(takeUntil(this.unSubs[1]))
.subscribe(lndStore => {
if (this.lookupResult.node1_pub === lndStore.information.identity_pubkey) {
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
if (this.lookupResult.node1_pub === rtlStore.information.identity_pubkey) {
this.node1_match = true;
}
if (this.lookupResult.node2_pub === lndStore.information.identity_pubkey) {
if (this.lookupResult.node2_pub === rtlStore.information.identity_pubkey) {
this.node2_match = true;
}
});
}
ngOnDestroy() {
this.unSubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
}

@ -6,9 +6,8 @@ import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../shared/services/logger.service';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-lookups',
@ -29,14 +28,14 @@ export class LookupsComponent implements OnInit, OnDestroy {
public flgLoading: Array<Boolean | 'error'> = [true];
private unSubs: Array<Subject<void>> = [new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions) {}
ngOnInit() {
this.actions$
.pipe(
takeUntil(this.unSubs[0]),
filter((action) => (action.type === LNDActions.SET_LOOKUP || action.type === RTLActions.EFFECT_ERROR))
).subscribe((resLookup: LNDActions.SetLookup) => {
filter((action) => (action.type === RTLActions.SET_LOOKUP || action.type === RTLActions.EFFECT_ERROR))
).subscribe((resLookup: RTLActions.SetLookup) => {
if (resLookup.payload.action === 'Lookup') {
this.flgLoading[0] = 'error';
} else {
@ -54,10 +53,10 @@ export class LookupsComponent implements OnInit, OnDestroy {
this.store.dispatch(new RTLActions.OpenSpinner('Searching ' + this.selectedField.name + '...'));
switch (this.selectedField.id) {
case '0':
this.store.dispatch(new LNDActions.PeerLookup(this.lookupKey.trim()));
this.store.dispatch(new RTLActions.PeerLookup(this.lookupKey.trim()));
break;
case '1':
this.store.dispatch(new LNDActions.ChannelLookup(this.lookupKey.trim()));
this.store.dispatch(new RTLActions.ChannelLookup(this.lookupKey.trim()));
break;
default:
break;

@ -9,10 +9,9 @@ import { MatTableDataSource, MatSort } from '@angular/material';
import { Hop } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { LNDEffects } from '../../store/lnd.effects';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-query-routes',
@ -26,10 +25,10 @@ export class QueryRoutesComponent implements OnInit, OnDestroy {
public qrHops: any;
public flgSticky = false;
public displayedColumns = [];
public flgLoading: Array<Boolean | 'error'> = [false];
public flgLoading: Array<Boolean | 'error'> = [false]; // 0: peers
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private lndEffects: LNDEffects, private actions$: Actions) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['hop_sequence', 'pubkey_alias', 'fee_msat'];
@ -54,10 +53,10 @@ export class QueryRoutesComponent implements OnInit, OnDestroy {
ngOnInit() {
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
this.logger.info(rtlStore);
});
this.lndEffects.setQueryRoutes
this.rtlEffects.setQueryRoutes
.pipe(takeUntil(this.unSubs[1]))
.subscribe(queryRoute => {
this.qrHops = new MatTableDataSource([]);
@ -75,7 +74,7 @@ export class QueryRoutesComponent implements OnInit, OnDestroy {
onQueryRoutes() {
this.flgLoading[0] = true;
this.store.dispatch(new LNDActions.GetQueryRoutes({destPubkey: this.destinationPubkey, amount: this.amount}));
this.store.dispatch(new RTLActions.GetQueryRoutes({destPubkey: this.destinationPubkey, amount: this.amount}));
}
resetData() {

@ -10,12 +10,9 @@ import { GetInfo, Payment, PayRequest } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-payments',
@ -37,9 +34,9 @@ export class PaymentsComponent implements OnInit, OnDestroy {
public paymentDecoded: PayRequest = {};
public paymentRequest = '';
public flgSticky = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['creation_date', 'fee', 'value'];
@ -62,13 +59,18 @@ export class PaymentsComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[4]))
.subscribe(lndStore => {
this.information = lndStore.information;
this.paymentJSONArr = (null !== lndStore.payments && lndStore.payments.length > 0) ? lndStore.payments : [];
this.payments = (undefined === lndStore.payments || null == lndStore.payments) ?
new MatTableDataSource([]) : new MatTableDataSource<Payment>([...this.paymentJSONArr]);
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchPayments') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
this.paymentJSONArr = (null !== rtlStore.payments && rtlStore.payments.length > 0) ? rtlStore.payments : [];
this.payments = (undefined === rtlStore.payments || null == rtlStore.payments) ? new MatTableDataSource([]) : new MatTableDataSource<Payment>([...this.paymentJSONArr]);
this.payments.data = this.paymentJSONArr;
this.payments.sort = this.sort;
this.payments.data.forEach(payment => {
@ -78,18 +80,6 @@ export class PaymentsComponent implements OnInit, OnDestroy {
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== this.paymentJSONArr) ? false : true;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchPayments') {
this.flgLoading[0] = 'error';
}
});
this.selNode = rtlStore.selNode;
this.logger.info(rtlStore);
});
@ -100,8 +90,8 @@ export class PaymentsComponent implements OnInit, OnDestroy {
this.sendPayment();
} else {
this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...'));
this.store.dispatch(new LNDActions.DecodePayment(this.paymentRequest));
this.lndEffects.setDecodedPayment
this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest));
this.rtlEffects.setDecodedPayment
.pipe(take(1))
.subscribe(decodedPayment => {
this.paymentDecoded = decodedPayment;
@ -136,7 +126,7 @@ export class PaymentsComponent implements OnInit, OnDestroy {
if (confirmRes) {
this.paymentDecoded.num_satoshis = confirmRes[0].inputValue;
this.store.dispatch(new RTLActions.OpenSpinner('Sending Payment...'));
this.store.dispatch(new LNDActions.SendPayment([this.paymentRequest, this.paymentDecoded, true]));
this.store.dispatch(new RTLActions.SendPayment([this.paymentRequest, this.paymentDecoded, true]));
this.resetData();
}
});
@ -149,7 +139,7 @@ export class PaymentsComponent implements OnInit, OnDestroy {
.subscribe(confirmRes => {
if (confirmRes) {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Payment...'));
this.store.dispatch(new LNDActions.SendPayment([this.paymentRequest, this.paymentDecoded, false]));
this.store.dispatch(new RTLActions.SendPayment([this.paymentRequest, this.paymentDecoded, false]));
this.resetData();
}
});
@ -158,8 +148,8 @@ export class PaymentsComponent implements OnInit, OnDestroy {
onVerifyPayment() {
this.store.dispatch(new RTLActions.OpenSpinner('Decoding Payment...'));
this.store.dispatch(new LNDActions.DecodePayment(this.paymentRequest));
this.lndEffects.setDecodedPayment.subscribe(decodedPayment => {
this.store.dispatch(new RTLActions.DecodePayment(this.paymentRequest));
this.rtlEffects.setDecodedPayment.subscribe(decodedPayment => {
this.paymentDecoded = decodedPayment;
if (undefined !== this.paymentDecoded.timestamp_str) {
this.paymentDecoded.timestamp_str = (this.paymentDecoded.timestamp_str === '') ? '' :
@ -197,7 +187,7 @@ export class PaymentsComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter, take } from 'rxjs/operators';
@ -11,12 +11,9 @@ import { Peer, GetInfo } from '../../shared/models/lndModels';
import { LoggerService } from '../../shared/services/logger.service';
import { newlyAddedRowAnimation } from '../../shared/animation/row-animation';
import { LNDEffects } from '../store/lnd.effects';
import { RTLEffects } from '../../store/rtl.effects';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import { RTLEffects } from '../../shared/store/rtl.effects';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-peers',
@ -32,12 +29,11 @@ export class PeersComponent implements OnInit, OnDestroy {
public peerAddress = '';
public peers: any;
public information: GetInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true];
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: peers
public flgSticky = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private rtlEffects: RTLEffects,
private lndEffects: LNDEffects, private actions$: Actions, private router: Router, private activatedRoute: ActivatedRoute) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions, private router: Router) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['detach', 'pub_key', 'alias'];
@ -60,39 +56,33 @@ export class PeersComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[4]))
.subscribe(lndStore => {
this.information = lndStore.information;
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchPeers') {
this.flgLoading[0] = 'error';
}
});
this.information = rtlStore.information;
this.peers = new MatTableDataSource([]);
this.peers.data = [];
if (undefined !== lndStore.peers) {
this.peers = new MatTableDataSource<Peer>([...lndStore.peers]);
this.peers.data = lndStore.peers;
if (undefined !== rtlStore.peers) {
this.peers = new MatTableDataSource<Peer>([...rtlStore.peers]);
this.peers.data = rtlStore.peers;
setTimeout(() => { this.flgAnimate = false; }, 3000);
}
this.peers.sort = this.sort;
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = false;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchPeers') {
this.flgLoading[0] = 'error';
}
});
this.logger.info(rtlStore);
});
this.actions$
.pipe(
takeUntil(this.unSubs[1]),
filter((action) => action.type === LNDActions.SET_PEERS)
).subscribe((setPeers: LNDActions.SetPeers) => {
filter((action) => action.type === RTLActions.SET_PEERS)
).subscribe((setPeers: RTLActions.SetPeers) => {
this.peerAddress = undefined;
});
}
@ -111,8 +101,8 @@ export class PeersComponent implements OnInit, OnDestroy {
} else {
pubkey = (deviderIndex > -1) ? this.peerAddress.substring(0, deviderIndex) : this.peerAddress;
this.store.dispatch(new RTLActions.OpenSpinner('Getting Node Address...'));
this.store.dispatch(new LNDActions.FetchGraphNode(pubkey));
this.lndEffects.setGraphNode
this.store.dispatch(new RTLActions.FetchGraphNode(pubkey));
this.rtlEffects.setGraphNode
.pipe(take(1))
.subscribe(graphNode => {
host = (undefined === graphNode.node.addresses || undefined === graphNode.node.addresses[0].addr) ? '' : graphNode.node.addresses[0].addr;
@ -124,7 +114,7 @@ export class PeersComponent implements OnInit, OnDestroy {
connectPeerWithParams(pubkey: string, host: string) {
this.newlyAddedPeer = pubkey;
this.store.dispatch(new RTLActions.OpenSpinner('Adding Peer...'));
this.store.dispatch(new LNDActions.SaveNewPeer({pubkey: pubkey, host: host, perm: false}));
this.store.dispatch(new RTLActions.SaveNewPeer({pubkey: pubkey, host: host, perm: false}));
}
onPeerClick(selRow: Peer, event: any) {
@ -146,7 +136,7 @@ export class PeersComponent implements OnInit, OnDestroy {
}
onOpenChannel(peerToAddChannel: Peer) {
this.router.navigate(['chnlmanage'], { relativeTo: this.activatedRoute, state: { peer: peerToAddChannel.pub_key }});
this.router.navigate(['lnd/chnlmanage'], { state: { peer: peerToAddChannel.pub_key }});
}
onPeerDetach(peerToDetach: Peer) {
@ -158,7 +148,7 @@ export class PeersComponent implements OnInit, OnDestroy {
.subscribe(confirmRes => {
if (confirmRes) {
this.store.dispatch(new RTLActions.OpenSpinner('Detaching Peer...'));
this.store.dispatch(new LNDActions.DetachPeer({pubkey: peerToDetach.pub_key}));
this.store.dispatch(new RTLActions.DetachPeer({pubkey: peerToDetach.pub_key}));
}
});
}

@ -9,9 +9,8 @@ import { ForwardingEvent, RoutingPeers } from '../../shared/models/lndModels';
import { LoggerService } from '../../shared/services/logger.service';
import { CommonService } from '../../shared/services/common.service';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-routing-peers',
@ -34,9 +33,9 @@ export class RoutingPeersComponent implements OnInit, OnDestroy {
public endDate = this.today;
public startDate = this.lastMonthDay;
public flgSticky = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<fromApp.AppState>, private actions$: Actions) {
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<fromRTLReducer.State>, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['chan_id', 'events', 'total_amount'];
@ -60,30 +59,26 @@ export class RoutingPeersComponent implements OnInit, OnDestroy {
ngOnInit() {
this.onRoutingPeersFetch();
this.actions$.pipe(takeUntil(this.unsubs[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.onRoutingPeersFetch();
});
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[3]))
.subscribe(lndStore => {
if (undefined !== lndStore.forwardingHistory && undefined !== lndStore.forwardingHistory.forwarding_events) {
this.loadRoutingPeersTable(lndStore.forwardingHistory.forwarding_events);
} else {
this.loadRoutingPeersTable([]);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore.forwardingHistory) ? false : true;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'GetForwardingHistory') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.forwardingHistory && undefined !== rtlStore.forwardingHistory.forwarding_events) {
this.loadRoutingPeersTable(rtlStore.forwardingHistory.forwarding_events);
} else {
// To reset table after other Forwarding history calls
this.loadRoutingPeersTable([]);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.forwardingHistory) ? false : true;
}
this.logger.info(rtlStore);
});
@ -117,6 +112,7 @@ export class RoutingPeersComponent implements OnInit, OnDestroy {
this.RoutingPeersOutgoing.sort = this.sortOut;
this.logger.info(this.RoutingPeersOutgoing);
} else {
// To reset table after other Forwarding history calls
this.RoutingPeersIncoming = new MatTableDataSource<RoutingPeers>([]);
this.RoutingPeersOutgoing = new MatTableDataSource<RoutingPeers>([]);
}
@ -151,7 +147,7 @@ export class RoutingPeersComponent implements OnInit, OnDestroy {
if (undefined === this.startDate || this.startDate == null) {
this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 30);
}
this.store.dispatch(new LNDActions.GetForwardingHistory({
this.store.dispatch(new RTLActions.GetForwardingHistory({
end_time: Math.round(this.endDate.getTime() / 1000).toString(),
start_time: Math.round(this.startDate.getTime() / 1000).toString()
}));
@ -170,7 +166,7 @@ export class RoutingPeersComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.resetData();
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -9,9 +9,8 @@ import { MatTableDataSource, MatSort } from '@angular/material';
import { ForwardingEvent } from '../../shared/models/lndModels';
import { LoggerService } from '../../shared/services/logger.service';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-forwarding-history',
@ -29,9 +28,9 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy {
public endDate = this.today;
public startDate = this.yesterday;
public flgSticky = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['timestamp', 'amt_out', 'amt_in'];
@ -55,32 +54,29 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy {
ngOnInit() {
this.onForwardingHistoryFetch();
this.actions$.pipe(takeUntil(this.unsubs[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.onForwardingHistoryFetch();
});
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[3]))
.subscribe(lndStore => {
if (undefined !== lndStore.forwardingHistory && undefined !== lndStore.forwardingHistory.forwarding_events) {
this.lastOffsetIndex = lndStore.forwardingHistory.last_offset_index;
this.loadForwardingEventsTable(lndStore.forwardingHistory.forwarding_events);
} else {
this.lastOffsetIndex = 0;
this.loadForwardingEventsTable([]);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore.forwardingHistory) ? false : true;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'GetForwardingHistory') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.forwardingHistory && undefined !== rtlStore.forwardingHistory.forwarding_events) {
this.lastOffsetIndex = rtlStore.forwardingHistory.last_offset_index;
this.loadForwardingEventsTable(rtlStore.forwardingHistory.forwarding_events);
} else {
// To reset table after other Forwarding history calls
this.lastOffsetIndex = 0;
this.loadForwardingEventsTable([]);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.forwardingHistory) ? false : true;
}
this.logger.info(rtlStore);
});
@ -115,7 +111,7 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy {
if (undefined === this.startDate || this.startDate == null) {
this.startDate = new Date(this.endDate.getFullYear(), this.endDate.getMonth(), this.endDate.getDate() - 1);
}
this.store.dispatch(new LNDActions.GetForwardingHistory({
this.store.dispatch(new RTLActions.GetForwardingHistory({
end_time: Math.round(this.endDate.getTime() / 1000).toString(),
start_time: Math.round(this.startDate.getTime() / 1000).toString()
}));
@ -131,7 +127,7 @@ export class ForwardingHistoryComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.resetData();
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -9,9 +9,9 @@ import { MatTableDataSource, MatSort } from '@angular/material';
import { Transaction } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-list-transactions',
@ -24,9 +24,9 @@ export class ListTransactionsComponent implements OnInit, OnDestroy {
public listTransactions: any;
public flgLoading: Array<Boolean | 'error'> = [true];
public flgSticky = false;
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['dest_addresses', 'total_fees', 'amount'];
@ -49,29 +49,25 @@ export class ListTransactionsComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.dispatch(new LNDActions.FetchTransactions());
this.actions$.pipe(takeUntil(this.unsubs[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.store.dispatch(new LNDActions.FetchTransactions());
});
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[3]))
.subscribe(lndStore => {
if (undefined !== lndStore.transactions) {
this.loadTransactionsTable(lndStore.transactions);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== lndStore.transactions) ? false : true;
}
this.logger.info(lndStore);
this.store.dispatch(new RTLActions.FetchTransactions());
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_STORE)).subscribe((resetStore: RTLActions.ResetStore) => {
this.store.dispatch(new RTLActions.FetchTransactions());
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchTransactions') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.transactions) {
this.loadTransactionsTable(rtlStore.transactions);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.transactions) ? false : true;
}
this.logger.info(rtlStore);
});
@ -113,7 +109,7 @@ export class ListTransactionsComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -98,7 +98,7 @@
<button fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="3" (click)="resetReceiveData()" class="top-minus-15px">Clear</button>
</div>
</div>
<div fxFlex="42" fxLayoutAlign.lt-xl="start start" fxLayoutAlign.gt-md="start end">
<div fxFlex="42" fxLayoutAlign="start end">
<mat-form-field fxFlex="100">
<input matInput [value]="newAddress" placeholder="Generated Address" readonly>
</mat-form-field>

@ -9,11 +9,9 @@ import { RTLConfiguration } from '../../../shared/models/RTLconfig';
import { LoggerService } from '../../../shared/services/logger.service';
import * as sha256 from 'sha256';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as LNDActions from '../../store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import { RTLEffects } from '../../../shared/store/rtl.effects';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-send-receive-trans',
@ -33,18 +31,25 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1';
public flgCustomAmount = '1';
private unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects) {}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[5]))
.subscribe(lndStore => {
this.information = lndStore.information;
this.addressTypes = lndStore.addressTypes;
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoadingWallet = 'error';
}
});
this.selNode = rtlStore.selNode;
this.appConfig = rtlStore.appConfig;
this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = lndStore.blockchainBalance;
this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = '0';
}
@ -57,19 +62,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false;
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoadingWallet = 'error';
}
});
this.selNode = rtlStore.selNode;
this.appConfig = rtlStore.appConfig;
this.logger.info(rtlStore);
});
@ -77,9 +70,9 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
onGenerateAddress() {
this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...'));
this.store.dispatch(new LNDActions.GetNewAddress(this.selectedAddress));
this.lndEffects.setNewAddress
.pipe(takeUntil(this.unsubs[1]))
this.store.dispatch(new RTLActions.GetNewAddress(this.selectedAddress));
this.rtlEffects.setNewAddress
.pipe(takeUntil(this.unsub[1]))
.subscribe(newAddress => {
this.newAddress = newAddress;
});
@ -108,7 +101,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsubs[2]))
.pipe(takeUntil(this.unsub[2]))
.subscribe(confirmRes => {
if (confirmRes) {
if (this.transaction.sendAll && !+this.appConfig.sso.rtlSSO) {
@ -118,7 +111,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
]}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsubs[3]))
.pipe(takeUntil(this.unsub[3]))
.subscribe(pwdConfirmRes => {
if (pwdConfirmRes) {
const pwd = pwdConfirmRes[0].inputValue;
@ -141,7 +134,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
dispatchToSendFunds() {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
this.store.dispatch(new LNDActions.SetChannelTransaction(this.transaction));
this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
this.transaction = {address: '', amount: 0, blocks: 0, fees: 0};
}
@ -175,7 +168,7 @@ export class SendReceiveTransComponent implements OnInit, OnDestroy {
}
ngOnDestroy() {
this.unsubs.forEach(completeSub => {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});

@ -1,17 +1,15 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { takeUntil, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { FormBuilder, FormGroup, Validators, ValidatorFn, ValidationErrors } from '@angular/forms';
import { FormBuilder, FormGroup, Validators, ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
import { MatStepper } from '@angular/material';
import { LNDEffects } from '../store/lnd.effects';
import { RTLEffects } from '../../store/rtl.effects';
import * as LNDActions from '../store/lnd.actions';
import * as RTLActions from '../../store/rtl.actions';
import * as fromApp from '../../store/rtl.reducers';
import { RTLEffects } from '../../shared/store/rtl.effects';
import * as RTLActions from '../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../shared/store/rtl.reducers';
export const matchedPasswords: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const initWalletPassword = control.get('initWalletPassword');
@ -48,8 +46,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
warnRes = true;
private unsubs = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private store: Store<fromApp.AppState>, private formBuilder: FormBuilder, private rtlEffects: RTLEffects,
private lndEffects: LNDEffects, private router: Router, private activatedRoute: ActivatedRoute) {}
constructor(private store: Store<fromRTLReducer.State>, private formBuilder: FormBuilder, private rtlEffects: RTLEffects, private router: Router) {}
ngOnInit() {
this.walletPassword = '';
@ -88,13 +85,13 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
this.insecureLND = !window.location.protocol.includes('https://');
this.lndEffects.initWalletRes
this.rtlEffects.initWalletRes
.pipe(takeUntil(this.unsubs[2]))
.subscribe(initWalletResponse => {
this.initWalletResponse = initWalletResponse;
});
this.lndEffects.genSeedResponse
this.rtlEffects.genSeedResponse
.pipe(takeUntil(this.unsubs[3]))
.subscribe(genSeedRes => {
this.genSeedResponse = genSeedRes;
@ -105,7 +102,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
// passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value)
// }));
// } else {
this.store.dispatch(new LNDActions.InitWallet({
this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: this.genSeedResponse
}));
@ -116,7 +113,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
onOperateWallet() {
this.store.dispatch(new RTLActions.OpenSpinner('Unlocking...'));
this.store.dispatch(new LNDActions.UnlockWallet({pwd: window.btoa(this.walletPassword)}));
this.store.dispatch(new RTLActions.UnlockWallet({pwd: window.btoa(this.walletPassword)}));
}
onInitWallet() {
@ -124,22 +121,22 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
if (this.cipherFormGroup.controls.existingCipher.value) {
const cipherArr = this.cipherFormGroup.controls.cipherSeed.value.toString().trim().split(',');
if (this.passphraseFormGroup.controls.enterPassphrase.value) {
this.store.dispatch(new LNDActions.InitWallet({
this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: cipherArr,
passphrase: window.btoa(this.passphraseFormGroup.controls.passphrase.value)
}));
} else {
this.store.dispatch(new LNDActions.InitWallet({
this.store.dispatch(new RTLActions.InitWallet({
pwd: window.btoa(this.passwordFormGroup.controls.initWalletPassword.value),
cipher: cipherArr
}));
}
} else {
if (this.passphraseFormGroup.controls.enterPassphrase.value) {
this.store.dispatch(new LNDActions.GenSeed(window.btoa(this.passphraseFormGroup.controls.passphrase.value)));
this.store.dispatch(new RTLActions.GenSeed(window.btoa(this.passphraseFormGroup.controls.passphrase.value)));
} else {
this.store.dispatch(new LNDActions.GenSeed(''));
this.store.dispatch(new RTLActions.GenSeed(''));
}
}
}
@ -147,7 +144,7 @@ export class UnlockLNDComponent implements OnInit, OnDestroy {
onGoToHome() {
setTimeout(() => {
this.store.dispatch(new RTLActions.InitAppData());
this.router.navigate(['../'], { relativeTo: this.activatedRoute });
this.router.navigate(['/lnd/']);
}, 1000 * 1);
}

@ -5,8 +5,8 @@ import { Store } from '@ngrx/store';
import { LoggerService } from '../../../shared/services/logger.service';
import { AlertData, InputData } from '../../../shared/models/alertData';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import * as RTLActions from '../../../shared/store/rtl.actions';
import * as fromRTLReducer from '../../../shared/store/rtl.reducers';
@Component({
selector: 'rtl-confirmation-message',
@ -24,7 +24,7 @@ export class ConfirmationMessageComponent implements OnInit {
public getInputs: Array<InputData> = [{placeholder: '', inputType: 'text', inputValue: ''}];
constructor(public dialogRef: MatDialogRef<ConfirmationMessageComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService,
private store: Store<fromApp.AppState>) { }
private store: Store<fromRTLReducer.State>) { }
ngOnInit() {
this.flgShowInput = this.data.flgShowInput;

@ -21,6 +21,8 @@ export class HelpComponent implements OnInit {
constructor() {}
ngOnInit() {
// this.helpTopics.push(new HelpTopic('Set LND home directory?',
// 'Pass the directroy information while getting the server up with --lndir "local-lnd-path".<br>Example: node rtl --lndir C:\lnd\dir\path'));
this.helpTopics.push(new HelpTopic('Change theme?', 'Click on rotating setting icon on the right side of the screen and choose from the given options.'));
}

@ -1,6 +1,6 @@
<div fxLayout="row" fxLayoutAlign="start center">
<div *ngFor="let menuNode of menuNodes">
<button mat-button *ngIf="undefined === menuNode.children" class="horizontal-button" routerLinkActive="h-active-link" [routerLinkActiveOptions]="{exact: true}" [routerLink]="[{}, menuNode.link]" matTooltip="{{menuNode.name}}" matTooltipPosition="above" (click)="onClick(menuNode)">
<button mat-button *ngIf="undefined === menuNode.children" class="horizontal-button" routerLinkActive="h-active-link" [routerLinkActiveOptions]="{exact: true}" routerLink="{{menuNode.link}}" matTooltip="{{menuNode.name}}" matTooltipPosition="above" (click)="onClick(menuNode)">
<mat-icon class="mat-icon-36">{{menuNode.icon}}</mat-icon>
</button>
<div *ngIf="undefined !== menuNode.children" fxLayoutAlign="center center">
@ -9,7 +9,7 @@
</button>
<mat-menu #childMenu="matMenu" xPosition="after" overlapTrigger="false" class="child-menu">
<div *ngFor="let childNode of menuNode.children">
<button mat-button class="horizontal-button bg-primary p-0" fxFlex="100" [routerLinkActive]="'h-active-link'" [routerLink]="[{}, childNode.link]" [routerLinkActiveOptions]="{exact: true}">
<button mat-button class="horizontal-button bg-primary p-0" fxFlex="100" [routerLinkActive]="'h-active-link'" routerLink="{{childNode.link}}" [routerLinkActiveOptions]="{exact: true}">
<mat-icon matTooltip="{{childNode.name}}" matTooltipPosition="after" class="mat-icon-36">{{childNode.icon}}<span *ngIf="childNode.name === 'Pending'" [matBadgeHidden]="numPendingChannels<1" matBadge="{{numPendingChannels}}" matBadgeOverlap="false" matBadgeColor="accent"></span></mat-icon>
</button>
</div>

@ -7,9 +7,9 @@ import { Actions } from '@ngrx/effects';
import { LoggerService } from '../../../services/logger.service';
import { MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromApp from '../../../../store/rtl.reducers';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-horizontal-navigation',
@ -23,16 +23,19 @@ export class HorizontalNavigationComponent implements OnInit {
public numPendingChannels = 0;
private unSubs = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions, private rtlEffects: RTLEffects) {
this.menuNodes = MENU_DATA.children;
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions, private rtlEffects: RTLEffects) {
}
ngOnInit() {
this.store.select('lnd')
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe(lndStore => {
this.numPendingChannels = lndStore.numberOfPendingChannels;
this.logger.info(lndStore);
.subscribe((rtlStore: fromRTLReducer.State) => {
this.numPendingChannels = rtlStore.numberOfPendingChannels;
if(+rtlStore.selNode.index === 1) {
this.menuNodes = MENU_DATA.LNDChildren;
} else {
this.menuNodes = MENU_DATA.LNDChildren;
}
});
this.actions$
.pipe(
@ -41,14 +44,14 @@ export class HorizontalNavigationComponent implements OnInit {
).subscribe((action) => {
this.logger.warn(action);
if (action.type === RTLActions.SIGNIN) {
this.menuNodes.push({id: 100, parentId: 0, name: 'Logout', icon: 'eject'});
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'});
}
if (action.type === RTLActions.SIGNOUT) {
this.menuNodes.pop();
}
});
if (sessionStorage.getItem('token')) {
this.menuNodes.push({id: 100, parentId: 0, name: 'Logout', icon: 'eject'});
this.menuNodes.push({id: 200, parentId: 0, name: 'Logout', icon: 'eject'});
}
}

@ -1,6 +1,6 @@
<mat-toolbar color="primary" [fxLayoutAlign] = "settings.menuType === 'Mini' ? 'center center' : 'space-between center'">
<a *ngIf="settings.menuType === 'Mini'" routerLink="/home" class="logo padding-gap-x mat-elevation-z6">R</a>
<a *ngIf="settings.menuType !== 'Mini'" routerLink="/home" class="logo">RTL</a>
<a *ngIf="settings.menuType === 'Mini'" [routerLink]="[navMenus.data[0].link]" class="logo padding-gap-x mat-elevation-z6">R</a>
<a *ngIf="settings.menuType !== 'Mini'" [routerLink]="[navMenus.data[0].link]" class="logo">RTL</a>
<svg *ngIf="settings.menuType !== 'Mini' && !smallScreen" style="width:24px;height:24px;cursor:pointer;" viewBox="0 0 24 24"
(click)="settings.flgSidenavPinned = !settings.flgSidenavPinned">
<path fill="currentColor" *ngIf="!settings.flgSidenavPinned" d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" />
@ -16,7 +16,7 @@
</div>
<mat-tree [dataSource]="navMenus" [treeControl]="treeControl" *ngIf="settings.menuType !== 'Compact'">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle (click)="onChildNavClicked(node)" matTreeNodePadding [matTreeNodePaddingIndent]="settings.menuType === 'Mini' ? 28 : 40" routerLinkActive="active-link" [routerLink]="[{}, node.link]">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle (click)="onChildNavClicked(node)" matTreeNodePadding [matTreeNodePaddingIndent]="settings.menuType === 'Mini' ? 28 : 40" routerLinkActive="active-link" [routerLink]="[node.link]">
<mat-icon class="mr-1" matTooltip="{{node.name}}" matTooltipPosition="right" [matTooltipDisabled]="settings.menuType !== 'Mini'">{{node.icon}}<span *ngIf="node.name === 'Pending' && settings.menuType === 'Mini'" [matBadgeHidden]="numPendingChannels<1" matBadge="{{numPendingChannels}}" matBadgeOverlap="false" matBadgeColor="accent"></span></mat-icon>
<span *ngIf="settings.menuType !== 'Mini'">{{node.name}}<span *ngIf="node.name === 'Pending'" [matBadgeHidden]="numPendingChannels<1" matBadge="{{numPendingChannels}}" matBadgeOverlap="false" matBadgeColor="accent"></span></span>
</mat-tree-node>
@ -40,7 +40,7 @@
</mat-tree>
<mat-tree [dataSource]="navMenus" [treeControl]="treeControl" *ngIf="settings.menuType === 'Compact'">
<mat-tree-node fxLayout="column" fxLayoutAlign="center center" *matTreeNodeDef="let node" matTreeNodeToggle (click)="onChildNavClicked(node)" matTreeNodePadding matTreeNodePaddingIndent="60" routerLinkActive="active-link" [routerLink]="[{}, node.link]">
<mat-tree-node fxLayout="column" fxLayoutAlign="center center" *matTreeNodeDef="let node" matTreeNodeToggle (click)="onChildNavClicked(node)" matTreeNodePadding matTreeNodePaddingIndent="60" routerLinkActive="active-link" [routerLink]="[node.link]">
<mat-icon class="mat-icon-36">{{node.icon}}</mat-icon>
<span>{{node.name}}<span *ngIf="node.name === 'Pending'" [matBadgeHidden]="numPendingChannels<1" matBadge="{{numPendingChannels}}" matBadgeOverlap="false" matBadgeColor="accent"></span></span>
</mat-tree-node>

@ -9,14 +9,14 @@ import { environment } from '../../../../../environments/environment';
import { FlatTreeControl } from '@angular/cdk/tree';
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
import { GetInfo, GetInfoChain } from '../../../models/lndModels';
import { Node, Settings } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service';
import { MenuNode, FlatMenuNode, MENU_DATA } from '../../../models/navMenu';
import { GetInfo, GetInfoChain } from '../../../models/lndModels';
import { MenuChildNode, FlatMenuNode, MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromApp from '../../../../store/rtl.reducers';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-side-navigation',
@ -29,29 +29,30 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
public settings: Settings;
public version = '';
public information: GetInfo = {};
public informationChain: GetInfoChain = {};
public informationChain: GetInfoChain = {};
public flgLoading = true;
public logoutNode = [{id: 100, parentId: 0, name: 'Logout', icon: 'eject'}];
public logoutNode = [{id: 200, parentId: 0, name: 'Logout', icon: 'eject'}];
public showLogout = false;
public numPendingChannels = 0;
public smallScreen = false;
private unSubs = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
public childRootRoute = '';
private unSubs = [new Subject(), new Subject(), new Subject()];
treeControl: FlatTreeControl<FlatMenuNode>;
treeControlLogout: FlatTreeControl<FlatMenuNode>;
treeFlattener: MatTreeFlattener<MenuNode, FlatMenuNode>;
treeFlattenerLogout: MatTreeFlattener<MenuNode, FlatMenuNode>;
navMenus: MatTreeFlatDataSource<MenuNode, FlatMenuNode>;
navMenusLogout: MatTreeFlatDataSource<MenuNode, FlatMenuNode>;
treeFlattener: MatTreeFlattener<MenuChildNode, FlatMenuNode>;
treeFlattenerLogout: MatTreeFlattener<MenuChildNode, FlatMenuNode>;
navMenus: MatTreeFlatDataSource<MenuChildNode, FlatMenuNode>;
navMenusLogout: MatTreeFlatDataSource<MenuChildNode, FlatMenuNode>;
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
this.version = environment.VERSION;
if (MENU_DATA.children[MENU_DATA.children.length - 1].id === 100) {
MENU_DATA.children.pop();
if (MENU_DATA.LNDChildren[MENU_DATA.LNDChildren.length - 1].id === 200) {
MENU_DATA.LNDChildren.pop();
}
this.treeFlattener = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
this.treeControl = new FlatTreeControl<FlatMenuNode>(this.getLevel, this.isExpandable);
this.navMenus = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
this.navMenus.data = MENU_DATA.children;
this.navMenus.data = MENU_DATA.LNDChildren;
this.treeFlattenerLogout = new MatTreeFlattener(this.transformer, this.getLevel, this.isExpandable, this.getChildren);
this.treeControlLogout = new FlatTreeControl<FlatMenuNode>(this.getLevel, this.isExpandable);
@ -60,39 +61,41 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[3]))
.subscribe(lndStore => {
this.numPendingChannels = lndStore ? lndStore.numberOfPendingChannels : -1;
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
this.selNode = rtlStore.selNode;
this.settings = this.selNode.settings;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
if (this.selNode.lnImplementation.toLowerCase() === 'clightning') {
this.store.select('cl')
.pipe(takeUntil(this.unSubs[4]))
.subscribe((clStore) => {
this.information = clStore.information;
this.readInformation();
});
this.information = rtlStore.information;
this.numPendingChannels = rtlStore.numberOfPendingChannels;
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.store.select('lnd')
.pipe(takeUntil(this.unSubs[5]))
.subscribe((lndStore) => {
this.information = lndStore.information;
this.readInformation();
});
this.informationChain.chain = '';
this.informationChain.network = '';
}
this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;
}
if (window.innerWidth <= 414) {
this.smallScreen = true;
}
if(+this.selNode.index === 1) {
this.navMenus.data = MENU_DATA.LNDChildren;
} else {
this.navMenus.data = MENU_DATA.CLChildren;
}
this.logger.info(rtlStore);
});
this.actions$
@ -104,30 +107,13 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
});
}
private readInformation() {
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;
}
private transformer(node: MenuNode, level: number) { return new FlatMenuNode(!!node.children, level, node.id, node.parentId, node.name, node.icon, node.link); }
private transformer(node: MenuChildNode, level: number) { return new FlatMenuNode(!!node.children, level, node.id, node.parentId, node.name, node.icon, node.link); }
private getLevel(node: FlatMenuNode) { return node.level; }
private isExpandable(node: FlatMenuNode) { return node.expandable; }
private getChildren(node: MenuNode): Observable<MenuNode[]> { return of(node.children); }
private getChildren(node: MenuChildNode): Observable<MenuChildNode[]> { return of(node.children); }
hasChild(_: number, _nodeData: FlatMenuNode) { return _nodeData.expandable; }
@ -144,7 +130,7 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
}
}
onClick(node: MenuNode) {
onClick(node: MenuChildNode) {
if (node.name === 'Logout') {
this.store.dispatch(new RTLActions.OpenConfirmation({
width: '70%', data: { type: 'CONFIRM', titleMessage: 'Logout from this device?', noBtnText: 'Cancel', yesBtnText: 'Logout'

@ -9,9 +9,9 @@ import { LoggerService } from '../../../services/logger.service';
import { GetInfo, GetInfoChain } from '../../../models/lndModels';
import { environment } from '../../../../../environments/environment';
import { RTLEffects } from '../../../../store/rtl.effects';
import * as fromApp from '../../../../store/rtl.reducers';
import * as RTLActions from '../../../../store/rtl.actions';
import { RTLEffects } from '../../../store/rtl.effects';
import * as fromRTLReducer from '../../../store/rtl.reducers';
import * as RTLActions from '../../../store/rtl.actions';
@Component({
selector: 'rtl-top-menu',
@ -25,17 +25,19 @@ export class TopMenuComponent implements OnInit, OnDestroy {
public informationChain: GetInfoChain = {};
public flgLoading = true;
public showLogout = false;
private unSubs = [new Subject(), new Subject(), new Subject(), new Subject()];
private unSubs = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private rtlEffects: RTLEffects, private actions$: Actions) {
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects, private actions$: Actions) {
this.version = environment.VERSION;
}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[3]))
.subscribe(lndStore => {
this.information = lndStore ? lndStore.information : {};
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromRTLReducer.State) => {
this.selNode = rtlStore.selNode;
this.information = rtlStore.information;
this.flgLoading = (undefined !== this.information.identity_pubkey) ? false : true;
if (undefined !== this.information.identity_pubkey) {
@ -51,13 +53,8 @@ export class TopMenuComponent implements OnInit, OnDestroy {
this.informationChain.chain = '';
this.informationChain.network = '';
}
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
this.selNode = rtlStore.selNode;
this.showLogout = (sessionStorage.getItem('token')) ? true : false;
this.logger.info(rtlStore);
if (!sessionStorage.getItem('token')) {
this.flgLoading = false;

@ -9,6 +9,7 @@
<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)="goToHelp()">HELP</button>
</mat-card>
</mat-card-content>
</mat-card>

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

@ -4,11 +4,9 @@ import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Node } from '../../models/RTLconfig';
import { LNDEffects } from '../../../lnd/store/lnd.effects';
import * as LNDActions from '../../../lnd/store/lnd.actions';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
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',
@ -24,12 +22,12 @@ export class ServerConfigComponent implements OnInit, OnDestroy {
public fileFormat = 'INI';
private unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private store: Store<fromApp.AppState>, private lndEffects: LNDEffects) {}
constructor(private store: Store<fromRTLReducer.State>, private rtlEffects: RTLEffects) {}
ngOnInit() {
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
if (effectsErr.action === 'fetchConfig') {
this.resetData();
@ -61,8 +59,8 @@ export class ServerConfigComponent implements OnInit, OnDestroy {
onShowConfig() {
this.store.dispatch(new RTLActions.OpenSpinner('Opening Config File...'));
this.store.dispatch(new LNDActions.FetchConfig(this.selectedNodeType));
this.lndEffects.showLNDConfig
this.store.dispatch(new RTLActions.FetchConfig(this.selectedNodeType));
this.rtlEffects.showLNDConfig
.pipe(takeUntil(this.unsubs[1]))
.subscribe((config: any) => {
const configFile = config.data;

@ -7,8 +7,8 @@ import { Node, RTLConfiguration } from '../../models/RTLconfig';
import { GetInfo } from '../../models/lndModels';
import { LoggerService } from '../../services/logger.service';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromApp from '../../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
@Component({
selector: 'rtl-settings-nav',
@ -26,22 +26,15 @@ export class SettingsNavComponent implements OnInit, OnDestroy {
public showSettingOption = true;
public appConfig: RTLConfiguration;
unsubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@Output() done: EventEmitter<void> = new EventEmitter();
unsubs: Array<Subject<void>> = [new Subject(), new Subject()];
@Output('done') done: EventEmitter<void> = new EventEmitter();
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>) {}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unsubs[2]))
.subscribe(lndStore => {
this.information = lndStore ? lndStore.information : {};
this.currencyUnit = (undefined !== this.information && undefined !== this.information.currency_unit) ? this.information.currency_unit : 'BTC';
this.logger.info(lndStore);
});
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsubs[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
this.appConfig = rtlStore.appConfig;
this.selNode = rtlStore.selNode;
this.selectedMenu = this.selNode.settings.menu;
@ -52,6 +45,8 @@ export class SettingsNavComponent implements OnInit, OnDestroy {
this.selNode.settings.flgSidenavPinned = false;
this.showSettingOption = false;
}
this.information = rtlStore.information;
this.currencyUnit = (undefined !== this.information && undefined !== this.information.currency_unit) ? this.information.currency_unit : 'BTC';
this.logger.info(rtlStore);
});
}

@ -6,8 +6,8 @@ import { Store } from '@ngrx/store';
import { Node } from '../../models/RTLconfig';
import { LoggerService } from '../../services/logger.service';
import * as fromApp from '../../../store/rtl.reducers';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
@Component({
selector: 'rtl-signin',
@ -25,12 +25,12 @@ export class SigninComponent implements OnInit, OnDestroy {
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>) { }
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.State>) { }
ngOnInit() {
this.store.select('rtlRoot')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore: fromApp.RootState) => {
.subscribe((rtlStore: fromRTLReducer.State) => {
rtlStore.effectErrors.forEach(effectsErr => {
this.logger.error(effectsErr);
});
@ -40,7 +40,7 @@ export class SigninComponent implements OnInit, OnDestroy {
if (this.nodeAuthType.toUpperCase() === 'DEFAULT') {
this.hintStr = 'Enter RPC password';
} else {
this.hintStr = '';
this.hintStr = ''; // Do not remove, initial passowrd 'DEFAULT' is initilizing its value
}
});
}

@ -1,43 +0,0 @@
// 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;
}

@ -5,16 +5,16 @@ export interface AddressType {
}
export interface Balance {
btc_balance?: string;
balance?: string;
btc_pending_open_balance?: string;
pending_open_balance?: string;
btc_total_balance?: string;
total_balance?: string;
btc_confirmed_balance?: string;
confirmed_balance?: string;
btc_unconfirmed_balance?: string;
unconfirmed_balance?: string;
btc_balance?: string; // For Channels Balance
balance?: string; // For Channels Balance
btc_pending_open_balance?: string; // For Channels Balance
pending_open_balance?: string; // For Channels Balance
btc_total_balance?: string; // For Blockchain Balance
total_balance?: string; // For Blockchain Balance
btc_confirmed_balance?: string; // For Blockchain Balance
confirmed_balance?: string; // For Blockchain Balance
btc_unconfirmed_balance?: string; // For Blockchain Balance
unconfirmed_balance?: string; // For Blockchain Balance
}
export interface ChannelFeeReport {
@ -271,7 +271,7 @@ export interface PayRequest {
export interface Peer {
pub_key?: string;
alias?: string;
address?: string;
address?: string; // host
bytes_sent?: number;
bytes_recv?: number;
sat_sent?: string;

@ -1,42 +1,47 @@
export const MENU_DATA: MenuNode = {
id: 0,
parentId: 0,
name: 'root',
icon: 'root',
link: 'root',
children: [
{id: 1, parentId: 0, name: 'Home', icon: 'home', link: 'home'},
{id: 2, parentId: 0, name: 'LND Wallet', icon: 'account_balance_wallet', link: 'transsendreceive', children: [
{id: 21, parentId: 2, name: 'Send/Receive', icon: 'compare_arrows', link: 'transsendreceive'},
{id: 22, parentId: 2, name: 'List Transactions', icon: 'list_alt', link: 'translist'},
export const MENU_DATA: MenuRootNode = {
LNDChildren: [
{id: 1, parentId: 0, name: 'Home', icon: 'home', link: '/lnd/home'},
{id: 2, parentId: 0, name: 'LND Wallet', icon: 'account_balance_wallet', link: '/lnd/transsendreceive', children: [
{id: 21, parentId: 2, name: 'Send/Receive', icon: 'compare_arrows', link: '/lnd/transsendreceive'},
{id: 22, parentId: 2, name: 'List Transactions', icon: 'list_alt', link: '/lnd/translist'},
]},
{id: 3, parentId: 0, name: 'Peers', icon: 'group', link: 'peers'},
{id: 4, parentId: 0, name: 'Channels', icon: 'settings_ethernet', link: 'chnlmanage', children: [
{id: 41, parentId: 4, name: 'Management', icon: 'subtitles', link: 'chnlmanage'},
{id: 42, parentId: 4, name: 'Pending', icon: 'watch', link: 'chnlpending'},
{id: 43, parentId: 4, name: 'Closed', icon: 'watch_later', link: 'chnlclosed'},
{id: 44, parentId: 4, name: 'Backup', icon: 'cloud_circle', link: 'chnlbackup'}
{id: 3, parentId: 0, name: 'Peers', icon: 'group', link: '/lnd/peers'},
{id: 4, parentId: 0, name: 'Channels', icon: 'settings_ethernet', link: '/lnd/chnlmanage', children: [
{id: 41, parentId: 4, name: 'Management', icon: 'subtitles', link: '/lnd/chnlmanage'},
{id: 42, parentId: 4, name: 'Pending', icon: 'watch', link: '/lnd/chnlpending'},
{id: 43, parentId: 4, name: 'Closed', icon: 'watch_later', link: '/lnd/chnlclosed'},
{id: 44, parentId: 4, name: 'Backup', icon: 'cloud_circle', link: '/lnd/chnlbackup'}
]},
{id: 5, parentId: 0, name: 'Payments', icon: 'payment', link: 'paymentsend', children: [
{id: 51, parentId: 5, name: 'Send', icon: 'send', link: 'paymentsend'},
{id: 52, parentId: 5, name: 'Query Routes', icon: 'explore', link: 'queryroutes'}
{id: 5, parentId: 0, name: 'Payments', icon: 'payment', link: '/lnd/paymentsend', children: [
{id: 51, parentId: 5, name: 'Send', icon: 'send', link: '/lnd/paymentsend'},
{id: 52, parentId: 5, name: 'Query Routes', icon: 'explore', link: '/lnd/queryroutes'}
]},
{id: 6, parentId: 0, name: 'Invoices', icon: 'receipt', link: 'invoices'},
{id: 7, parentId: 0, name: 'Forwarding History', icon: 'timeline', link: 'switch'},
{id: 8, parentId: 0, name: 'Routing Peers', icon: 'group_work', link: 'routingpeers'},
{id: 9, parentId: 0, name: 'Lookups', icon: 'search', link: 'lookups'},
{id: 10, parentId: 0, name: 'Node Config', icon: 'perm_data_setting', link: 'sconfig'},
{id: 11, parentId: 0, name: 'Help', icon: 'help', link: 'help'}
{id: 6, parentId: 0, name: 'Invoices', icon: 'receipt', link: '/lnd/invoices'},
{id: 7, parentId: 0, name: 'Forwarding History', icon: 'timeline', link: '/lnd/switch'},
{id: 8, parentId: 0, name: 'Routing Peers', icon: 'group_work', link: '/lnd/routingpeers'},
{id: 9, parentId: 0, name: 'Lookups', icon: 'search', link: '/lnd/lookups'},
{id: 10, parentId: 0, name: 'Node Config', icon: 'perm_data_setting', link: '../sconfig'},
{id: 11, parentId: 0, name: 'Help', icon: 'help', link: '../help'}
],
CLChildren: [
{id: 1, parentId: 0, name: 'Home', icon: 'home', link: '/cl/home'},
{id: 10, parentId: 0, name: 'Node Config', icon: 'perm_data_setting', link: '../sconfig'},
{id: 11, parentId: 0, name: 'Help', icon: 'help', link: '../help'}
]
};
export class MenuNode {
export class MenuRootNode {
LNDChildren?: MenuChildNode[];
CLChildren?: MenuChildNode[];
}
export class MenuChildNode {
id: number;
parentId: number;
name?: string;
icon?: string;
link?: any;
children?: MenuNode[];
children?: MenuChildNode[];
}
export class FlatMenuNode {

@ -27,3 +27,17 @@ export class LNDUnlockedGuard implements CanActivate {
}
}
}
@Injectable()
export class CLUnlockedGuard implements CanActivate {
constructor() {}
canActivate(): boolean | Observable<boolean> | Promise<boolean> {
return true;
if (!sessionStorage.getItem('clUnlocked')) {
return false;
} else {
return true;
}
}
}

@ -1,7 +1,8 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatDialogModule, MatExpansionModule, MatGridListModule, MatDatepickerModule,
@ -9,21 +10,23 @@ import {
MatSelectModule, MatSidenavModule, MatSlideToggleModule, MatSortModule, MatTableModule, MatToolbarModule, MatTooltipModule, MAT_DIALOG_DEFAULT_OPTIONS, MatBadgeModule,
MatPaginatorModule, MatStepperModule
} from '@angular/material';
import { QRCodeModule } from 'angularx-qrcode';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { SideNavigationComponent } from './components/navigation/side-navigation/side-navigation.component';
import { TopMenuComponent } from './components/navigation/top-menu/top-menu.component';
import { HorizontalNavigationComponent } from './components/navigation/horizontal-navigation/horizontal-navigation.component';
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 { SigninComponent } from './components/signin/signin.component';
import { HelpComponent } from './components/help/help.component';
import { SideNavigationComponent } from './components/navigation/side-navigation/side-navigation.component';
import { TopMenuComponent } from './components/navigation/top-menu/top-menu.component';
import { HorizontalNavigationComponent } from './components/navigation/horizontal-navigation/horizontal-navigation.component';
import { SettingsNavComponent } from './components/settings-nav/settings-nav.component';
import { ClipboardDirective } from './directive/clipboard.directive';
import { ServerConfigComponent } from './components/server-config/server-config.component';
import { SsoFailedComponent } from './components/sso-failed/sso-failed.component';
import { ClipboardDirective } from './directive/clipboard.directive';
import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
@NgModule({
@ -31,7 +34,6 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
CommonModule,
FormsModule,
ReactiveFormsModule,
RouterModule,
FlexLayoutModule,
MatButtonModule,
MatButtonToggleModule,
@ -60,7 +62,11 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
MatBadgeModule,
MatPaginatorModule,
MatStepperModule,
QRCodeModule
QRCodeModule,
NgxChartsModule,
RouterModule,
HttpClientModule,
NgxChartsModule
],
exports: [
FormsModule,
@ -97,32 +103,33 @@ import { RemoveLeadingZerosPipe } from './pipes/remove-leading-zero.pipe';
ConfirmationMessageComponent,
SpinnerDialogComponent,
NotFoundComponent,
ServerConfigComponent,
HelpComponent,
SigninComponent,
SettingsNavComponent,
ClipboardDirective,
QRCodeModule,
RemoveLeadingZerosPipe,
SideNavigationComponent,
TopMenuComponent,
HorizontalNavigationComponent
HorizontalNavigationComponent,
SigninComponent,
HelpComponent,
ServerConfigComponent,
ClipboardDirective,
QRCodeModule,
NgxChartsModule,
RemoveLeadingZerosPipe
],
declarations: [
AlertMessageComponent,
ConfirmationMessageComponent,
SpinnerDialogComponent,
NotFoundComponent,
ServerConfigComponent,
HelpComponent,
SigninComponent,
SettingsNavComponent,
ClipboardDirective,
SsoFailedComponent,
RemoveLeadingZerosPipe,
SideNavigationComponent,
TopMenuComponent,
HorizontalNavigationComponent
HorizontalNavigationComponent,
SigninComponent,
HelpComponent,
ServerConfigComponent,
ClipboardDirective,
SsoFailedComponent,
RemoveLeadingZerosPipe
],
entryComponents: [
AlertMessageComponent,

@ -1,10 +1,27 @@
import { Action } from '@ngrx/store';
import { RTLConfiguration, Settings, Node } from '../models/RTLconfig';
import { ErrorPayload } from '../models/errorPayload';
import {
GetInfo, Peer, Balance, NetworkInfo, Fees, Channel, Invoice, ListInvoices, Payment, GraphNode, AddressType,
PayRequest, ChannelsTransaction, PendingChannels, ClosedChannel, Transaction, SwitchReq, SwitchRes, QueryRoutes
} from '../../shared/models/lndModels';
export const RESET_LND_STORE = 'RESET_LND_STORE';
} from '../models/lndModels';
import { MatDialogConfig } from '@angular/material';
export const RESET_STORE = 'RESET_STORE';
export const CLEAR_EFFECT_ERROR = 'CLEAR_EFFECT_ERROR';
export const EFFECT_ERROR = 'EFFECT_ERROR';
export const OPEN_SPINNER = 'OPEN_SPINNER';
export const CLOSE_SPINNER = 'CLOSE_SPINNER';
export const OPEN_ALERT = 'OPEN_ALERT';
export const CLOSE_ALERT = 'CLOSE_ALERT';
export const OPEN_CONFIRMATION = 'OPEN_CONFIRMATION';
export const CLOSE_CONFIRMATION = 'CLOSE_CONFIRMATION';
export const FETCH_STORE = 'FETCH_STORE';
export const SET_STORE = 'SET_STORE';
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 FETCH_INFO = 'FETCH_INFO';
export const SET_INFO = 'SET_INFO';
export const FETCH_PEERS = 'FETCH_PEERS';
@ -55,6 +72,11 @@ export const INIT_WALLET_RESPONSE = 'INIT_WALLET_RESPONSE';
export const UNLOCK_WALLET = 'UNLOCK_WALLET';
export const FETCH_CONFIG = 'FETCH_CONFIG';
export const SHOW_CONFIG = 'SHOW_CONFIG';
export const IS_AUTHORIZED = 'IS_AUTHORIZED';
export const IS_AUTHORIZED_RES = 'IS_AUTHORIZED_RES';
export const SIGNIN = 'SIGNIN';
export const SIGNOUT = 'SIGNOUT';
export const INIT_APP_DATA = 'INIT_APP_DATA';
export const PEER_LOOKUP = 'PEER_LOOKUP';
export const CHANNEL_LOOKUP = 'CHANNEL_LOOKUP';
export const INVOICE_LOOKUP = 'INVOICE_LOOKUP';
@ -64,8 +86,66 @@ 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 ClearEffectError implements Action {
readonly type = CLEAR_EFFECT_ERROR;
constructor(public payload: string) {} // payload = errorAction
}
export class EffectError implements Action {
readonly type = EFFECT_ERROR;
constructor(public payload: ErrorPayload) {}
}
export class OpenSpinner implements Action {
readonly type = OPEN_SPINNER;
constructor(public payload: string) {} // payload = titleMessage
}
export class CloseSpinner implements Action {
readonly type = CLOSE_SPINNER;
}
export class OpenAlert implements Action {
readonly type = OPEN_ALERT;
constructor(public payload: MatDialogConfig) {}
}
export class CloseAlert implements Action {
readonly type = CLOSE_ALERT;
}
export class OpenConfirmation implements Action {
readonly type = OPEN_CONFIRMATION;
constructor(public payload: MatDialogConfig) {}
}
export class CloseConfirmation implements Action {
readonly type = CLOSE_CONFIRMATION;
constructor(public payload: boolean) {}
}
export class ResetStore implements Action {
readonly type = RESET_STORE;
constructor(public payload: Node) {}
}
export class FetchRTLConfig implements Action {
readonly type = FETCH_RTL_CONFIG;
}
export class SetRTLConfig implements Action {
readonly type = SET_RTL_CONFIG;
constructor(public payload: RTLConfiguration) {}
}
export class SaveSettings implements Action {
readonly type = SAVE_SETTINGS;
constructor(public payload: Settings) {}
}
export class SetSelelectedNode implements Action {
readonly type = SET_SELECTED_NODE;
constructor(public payload: Node) {}
}
export class FetchInfo implements Action {
@ -352,11 +432,40 @@ export class SetQueryRoutes implements Action {
constructor(public payload: QueryRoutes) {}
}
export type LNDActions =
ResetLNDStore | FetchInfo | SetInfo | FetchPeers | SetPeers | AddPeer |
DetachPeer | SaveNewPeer | RemovePeer | AddInvoice | SaveNewInvoice |
GetForwardingHistory | SetForwardingHistory | FetchFees | SetFees |
FetchBalance | SetBalance | FetchNetwork | SetNetwork |
export class IsAuthorized implements Action {
readonly type = IS_AUTHORIZED;
constructor(public payload: string) {} // payload = password
}
export class IsAuthorizedRes implements Action {
readonly type = IS_AUTHORIZED_RES;
constructor(public payload: any) {} // payload = token/error
}
export class Signin implements Action {
readonly type = SIGNIN;
constructor(public payload: string) {} // payload = password
}
export class Signout implements Action {
readonly type = SIGNOUT;
constructor() {}
}
export class InitAppData implements Action {
readonly type = INIT_APP_DATA;
}
export type RTLActions =
ClearEffectError | EffectError | OpenSpinner | CloseSpinner |
FetchRTLConfig | SetRTLConfig | SaveSettings |
OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation |
ResetStore | SetSelelectedNode | FetchInfo | SetInfo |
FetchPeers | SetPeers | AddPeer | DetachPeer | SaveNewPeer | RemovePeer |
AddInvoice | SaveNewInvoice | GetForwardingHistory | SetForwardingHistory |
FetchFees | SetFees |
FetchBalance | SetBalance |
FetchNetwork | SetNetwork |
FetchChannels | SetChannels | SetPendingChannels | SetClosedChannels | UpdateChannels |
SaveNewChannel | CloseChannel | RemoveChannel |
BackupChannels | VerifyChannels | BackupChannelsRes | VerifyChannelsRes |
@ -367,4 +476,5 @@ export type LNDActions =
FetchGraphNode | SetGraphNode | GetQueryRoutes | SetQueryRoutes |
GetNewAddress | SetNewAddress | SetChannelTransaction |
GenSeed | GenSeedResponse | InitWallet | InitWalletResponse | UnlockWallet |
FetchConfig | ShowConfig | PeerLookup | ChannelLookup | InvoiceLookup | SetLookup;
FetchConfig | ShowConfig | PeerLookup | ChannelLookup | InvoiceLookup | SetLookup |
IsAuthorized | IsAuthorizedRes | Signin | Signout | InitAppData;

@ -1,41 +1,124 @@
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router, ActivatedRoute } from '@angular/router';
import { HttpClient, HttpParams, HttpHeaders } 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 { map, mergeMap, catchError, take, withLatestFrom } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { environment } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
import { GetInfo, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels';
import { LoggerService } from '../services/logger.service';
import { Settings } from '../models/RTLconfig';
import { GetInfo, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../models/lndModels';
import * as RTLActions from '../../store/rtl.actions';
import * as LNDActions from './lnd.actions';
import * as fromLNDReducer from './lnd.reducers';
import * as fromApp from '../../store/rtl.reducers';
import { SpinnerDialogComponent } from '../components/spinner-dialog/spinner-dialog.component';
import { AlertMessageComponent } from '../components/alert-message/alert-message.component';
import { ConfirmationMessageComponent } from '../components/confirmation-message/confirmation-message.component';
import * as RTLActions from './rtl.actions';
import * as fromRTLReducer from './rtl.reducers';
@Injectable()
export class LNDEffects implements OnDestroy {
export class RTLEffects implements OnDestroy {
dialogRef: any;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(
private actions$: Actions,
private httpClient: HttpClient,
private store: Store<fromApp.AppState>,
private store: Store<fromRTLReducer.State>,
private logger: LoggerService,
public dialog: MatDialog,
private router: Router,
private activatedRoute: ActivatedRoute) { }
private router: Router) { }
@Effect({ dispatch: false })
openSpinner = this.actions$.pipe(
ofType(RTLActions.OPEN_SPINNER),
map((action: RTLActions.OpenSpinner) => {
this.dialogRef = this.dialog.open(SpinnerDialogComponent, { data: { titleMessage: action.payload}});
}
));
@Effect({ dispatch: false })
closeSpinner = this.actions$.pipe(
ofType(RTLActions.CLOSE_SPINNER),
map((action: RTLActions.CloseSpinner) => {
if (this.dialogRef) { this.dialogRef.close(); }
}
));
@Effect({ dispatch: false })
openAlert = this.actions$.pipe(
ofType(RTLActions.OPEN_ALERT),
map((action: RTLActions.OpenAlert) => {
this.dialogRef = this.dialog.open(AlertMessageComponent, action.payload);
}
));
@Effect({ dispatch: false })
closeAlert = this.actions$.pipe(
ofType(RTLActions.CLOSE_ALERT),
map((action: RTLActions.CloseAlert) => {
if (this.dialogRef) { this.dialogRef.close(); }
}
));
@Effect({ dispatch: false })
openConfirm = this.actions$.pipe(
ofType(RTLActions.OPEN_CONFIRMATION),
map((action: RTLActions.OpenConfirmation) => {
this.dialogRef = this.dialog.open(ConfirmationMessageComponent, action.payload);
})
);
@Effect({ dispatch: false })
closeConfirm = this.actions$.pipe(
ofType(RTLActions.CLOSE_CONFIRMATION),
take(1),
map((action: RTLActions.CloseConfirmation) => {
this.dialogRef.close();
this.logger.info(action.payload);
return action.payload;
}
));
@Effect()
appConfigFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_RTL_CONFIG),
mergeMap((action: RTLActions.FetchRTLConfig) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchRTLConfig'));
return this.httpClient.get(environment.CONF_API + '/rtlconf');
}),
map((rtlConfig: any) => {
this.logger.info(rtlConfig);
if (+rtlConfig.sso.rtlSSO) { this.store.dispatch(new RTLActions.Signout()); }
return {
type: RTLActions.SET_RTL_CONFIG,
payload: rtlConfig
};
},
catchError((err) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectError({ action: 'FetchRTLConfig', code: err.status, message: err.error.error }));
return of();
})
));
@Effect({ dispatch: false })
settingSave = this.actions$.pipe(
ofType(RTLActions.SAVE_SETTINGS),
mergeMap((action: RTLActions.SaveSettings) => {
return this.httpClient.post<Settings>(environment.CONF_API, { updatedSettings: action.payload });
}
));
@Effect()
infoFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_INFO),
ofType(RTLActions.FETCH_INFO),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [LNDActions.FetchInfo, fromApp.RootState]) => {
mergeMap(([action, store]: [RTLActions.FetchInfo, fromRTLReducer.State]) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchInfo'));
return this.httpClient.get<GetInfo>(environment.GETINFO_API)
.pipe(
@ -44,15 +127,15 @@ export class LNDEffects implements OnDestroy {
if (undefined === info.identity_pubkey) {
sessionStorage.removeItem('lndUnlocked');
this.logger.info('Redirecting to Unlock');
this.router.navigate(['../unlocklnd'], { relativeTo: this.activatedRoute });
this.router.navigate(['/lnd/unlocklnd']);
return {
type: LNDActions.SET_INFO,
type: RTLActions.SET_INFO,
payload: {}
};
} else {
sessionStorage.setItem('lndUnlocked', 'true');
return {
type: LNDActions.SET_INFO,
type: RTLActions.SET_INFO,
payload: (undefined !== info) ? info : {}
};
}
@ -61,15 +144,15 @@ export class LNDEffects implements OnDestroy {
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'], { relativeTo: this.activatedRoute });
this.router.navigate(['/ssoerror']);
} else {
if (err.status === 401) {
this.logger.info('Redirecting to Signin');
this.router.navigate([store.appConfig.sso.logoutRedirectLink], { relativeTo: this.activatedRoute });
this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
return of();
} else {
this.logger.info('Redirecting to Unlock');
this.router.navigate(['../unlocklnd'], { relativeTo: this.activatedRoute });
this.router.navigate(['/lnd/unlocklnd']);
return of();
}
}
@ -80,15 +163,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
peersFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_PEERS),
mergeMap((action: LNDActions.FetchPeers) => {
ofType(RTLActions.FETCH_PEERS),
mergeMap((action: RTLActions.FetchPeers) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchPeers'));
return this.httpClient.get(environment.PEERS_API)
.pipe(
map((peers: any) => {
this.logger.info(peers);
return {
type: LNDActions.SET_PEERS,
type: RTLActions.SET_PEERS,
payload: (undefined !== peers) ? peers : []
};
}),
@ -103,8 +186,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
saveNewPeer = this.actions$.pipe(
ofType(LNDActions.SAVE_NEW_PEER),
mergeMap((action: LNDActions.SaveNewPeer) => {
ofType(RTLActions.SAVE_NEW_PEER),
mergeMap((action: RTLActions.SaveNewPeer) => {
return this.httpClient.post(environment.PEERS_API, {pubkey: action.payload.pubkey, host: action.payload.host, perm: action.payload.perm})
.pipe(
map((postRes: any) => {
@ -112,7 +195,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: { type: 'SUCCESS', titleMessage: 'Peer Added Successfully!'}}));
return {
type: LNDActions.SET_PEERS,
type: RTLActions.SET_PEERS,
payload: (undefined !== postRes && postRes.length > 0) ? postRes : []
};
}),
@ -134,8 +217,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
detachPeer = this.actions$.pipe(
ofType(LNDActions.DETACH_PEER),
mergeMap((action: LNDActions.DetachPeer) => {
ofType(RTLActions.DETACH_PEER),
mergeMap((action: RTLActions.DetachPeer) => {
return this.httpClient.delete(environment.PEERS_API + '/' + action.payload.pubkey)
.pipe(
map((postRes: any) => {
@ -143,7 +226,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: 'Peer Detached Successfully!'}}));
return {
type: LNDActions.REMOVE_PEER,
type: RTLActions.REMOVE_PEER,
payload: { pubkey: action.payload.pubkey }
};
}),
@ -165,8 +248,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
saveNewInvoice = this.actions$.pipe(
ofType(LNDActions.SAVE_NEW_INVOICE),
mergeMap((action: LNDActions.SaveNewInvoice) => {
ofType(RTLActions.SAVE_NEW_INVOICE),
mergeMap((action: RTLActions.SaveNewInvoice) => {
return this.httpClient.post(environment.INVOICES_API, {
memo: action.payload.memo, amount: action.payload.invoiceValue, private: action.payload.private, expiry: action.payload.expiry
})
@ -184,7 +267,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%',
data: { type: 'SUCCESS', titleMessage: 'Invoice Added Successfully!', message: JSON.stringify(msg) }}));
return {
type: LNDActions.FETCH_INVOICES,
type: RTLActions.FETCH_INVOICES,
payload: {num_max_invoices: action.payload.pageSize, reversed: true}
};
}),
@ -206,8 +289,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
openNewChannel = this.actions$.pipe(
ofType(LNDActions.SAVE_NEW_CHANNEL),
mergeMap((action: LNDActions.SaveNewChannel) => {
ofType(RTLActions.SAVE_NEW_CHANNEL),
mergeMap((action: RTLActions.SaveNewChannel) => {
return this.httpClient.post(environment.CHANNELS_API, {
node_pubkey: action.payload.selectedPeerPubkey, local_funding_amount: action.payload.fundingAmount, private: action.payload.private,
trans_type: action.payload.transType, trans_type_value: action.payload.transTypeValue, spend_unconfirmed: action.payload.spendUnconfirmed
@ -216,11 +299,11 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new LNDActions.FetchBalance('blockchain'));
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new LNDActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Added Successfully!'}));
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Added Successfully!'}));
return {
type: LNDActions.FETCH_CHANNELS,
type: RTLActions.FETCH_CHANNELS,
payload: {routeParam: 'pending', channelStatus: ''}
};
}),
@ -242,8 +325,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
updateChannel = this.actions$.pipe(
ofType(LNDActions.UPDATE_CHANNELS),
mergeMap((action: LNDActions.UpdateChannels) => {
ofType(RTLActions.UPDATE_CHANNELS),
mergeMap((action: RTLActions.UpdateChannels) => {
return this.httpClient.post(environment.CHANNELS_API + '/chanPolicy',
{ baseFeeMsat: action.payload.baseFeeMsat, feeRate: action.payload.feeRate, timeLockDelta: action.payload.timeLockDelta, chanPoint: action.payload.chanPoint })
.pipe(
@ -252,7 +335,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: 'Channel Updated Successfully!'}}));
return {
type: LNDActions.FETCH_CHANNELS,
type: RTLActions.FETCH_CHANNELS,
payload: {routeParam: 'all', channelStatus: ''}
};
}),
@ -274,24 +357,24 @@ export class LNDEffects implements OnDestroy {
@Effect()
closeChannel = this.actions$.pipe(
ofType(LNDActions.CLOSE_CHANNEL),
mergeMap((action: LNDActions.CloseChannel) => {
ofType(RTLActions.CLOSE_CHANNEL),
mergeMap((action: RTLActions.CloseChannel) => {
return this.httpClient.delete(environment.CHANNELS_API + '/' + action.payload.channelPoint + '?force=' + action.payload.forcibly)
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new LNDActions.FetchBalance('channels'));
this.store.dispatch(new LNDActions.FetchBalance('blockchain'));
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
if (action.payload.forcibly) {
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
} else {
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'closed'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'}));
}
this.store.dispatch(new LNDActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Closed Successfully!'}));
this.store.dispatch(new RTLActions.BackupChannels({channelPoint: 'ALL', showMessage: 'Channel Closed Successfully!'}));
return {
type: LNDActions.REMOVE_CHANNEL,
type: RTLActions.REMOVE_CHANNEL,
payload: { channelPoint: action.payload.channelPoint }
};
}),
@ -312,8 +395,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
backupChannels = this.actions$.pipe(
ofType(LNDActions.BACKUP_CHANNELS),
mergeMap((action: LNDActions.BackupChannels) => {
ofType(RTLActions.BACKUP_CHANNELS),
mergeMap((action: RTLActions.BackupChannels) => {
this.store.dispatch(new RTLActions.ClearEffectError('BackupChannels'));
return this.httpClient.get(environment.CHANNELS_BACKUP_API + '/' + action.payload.channelPoint)
.pipe(
@ -322,7 +405,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: action.payload.showMessage + ' ' + postRes.message}}));
return {
type: LNDActions.BACKUP_CHANNELS_RES,
type: RTLActions.BACKUP_CHANNELS_RES,
payload: postRes.message
};
}),
@ -344,8 +427,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
verifyChannels = this.actions$.pipe(
ofType(LNDActions.VERIFY_CHANNELS),
mergeMap((action: LNDActions.VerifyChannels) => {
ofType(RTLActions.VERIFY_CHANNELS),
mergeMap((action: RTLActions.VerifyChannels) => {
this.store.dispatch(new RTLActions.ClearEffectError('VerifyChannels'));
return this.httpClient.post(environment.CHANNELS_BACKUP_API + '/verify/' + action.payload.channelPoint, {})
.pipe(
@ -354,7 +437,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'SUCCESS', titleMessage: postRes.message}}));
return {
type: LNDActions.VERIFY_CHANNELS_RES,
type: RTLActions.VERIFY_CHANNELS_RES,
payload: postRes.message
};
}),
@ -376,15 +459,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
fetchFees = this.actions$.pipe(
ofType(LNDActions.FETCH_FEES),
mergeMap((action: LNDActions.FetchFees) => {
ofType(RTLActions.FETCH_FEES),
mergeMap((action: RTLActions.FetchFees) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchFees'));
return this.httpClient.get<Fees>(environment.FEES_API);
}),
map((fees) => {
this.logger.info(fees);
return {
type: LNDActions.SET_FEES,
type: RTLActions.SET_FEES,
payload: (undefined !== fees) ? fees : {}
};
}),
@ -397,19 +480,19 @@ export class LNDEffects implements OnDestroy {
@Effect()
balanceFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_BALANCE),
mergeMap((action: LNDActions.FetchBalance) => {
ofType(RTLActions.FETCH_BALANCE),
mergeMap((action: RTLActions.FetchBalance) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchBalance/' + action.payload));
return this.httpClient.get<Balance>(environment.BALANCE_API + '/' + action.payload)
.pipe(
map((res: any) => {
if (action.payload === 'channels') {
this.store.dispatch(new LNDActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
}
this.logger.info(res);
const emptyRes = (action.payload === 'channels') ? {balance: '', btc_balance: ''} : {total_balance: '', btc_total_balance: ''};
return {
type: LNDActions.SET_BALANCE,
type: RTLActions.SET_BALANCE,
payload: (undefined !== res) ? { target: action.payload, balance: res } : { target: action.payload, balance: emptyRes }
};
}),
@ -424,15 +507,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
networkInfoFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_NETWORK),
mergeMap((action: LNDActions.FetchNetwork) => {
ofType(RTLActions.FETCH_NETWORK),
mergeMap((action: RTLActions.FetchNetwork) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchNetwork'));
return this.httpClient.get<NetworkInfo>(environment.NETWORK_API + '/info');
}),
map((networkInfo) => {
this.logger.info(networkInfo);
return {
type: LNDActions.SET_NETWORK,
type: RTLActions.SET_NETWORK,
payload: (undefined !== networkInfo) ? networkInfo : {}
};
}),
@ -445,25 +528,25 @@ export class LNDEffects implements OnDestroy {
@Effect()
channelsFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_CHANNELS),
mergeMap((action: LNDActions.FetchChannels) => {
ofType(RTLActions.FETCH_CHANNELS),
mergeMap((action: RTLActions.FetchChannels) => {
return this.httpClient.get(environment.CHANNELS_API + '/' + action.payload.routeParam)
.pipe(
map((channels: any) => {
this.logger.info(channels);
if (action.payload.routeParam === 'pending') {
return {
type: LNDActions.SET_PENDING_CHANNELS,
type: RTLActions.SET_PENDING_CHANNELS,
payload: (undefined !== channels) ? channels : {}
};
} else if (action.payload.routeParam === 'closed') {
return {
type: LNDActions.SET_CLOSED_CHANNELS,
type: RTLActions.SET_CLOSED_CHANNELS,
payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : []
};
} else if (action.payload.routeParam === 'all') {
return {
type: LNDActions.SET_CHANNELS,
type: RTLActions.SET_CHANNELS,
payload: (undefined !== channels && undefined !== channels.channels && channels.channels.length > 0) ? channels.channels : []
};
}
@ -479,8 +562,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
invoicesFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_INVOICES),
mergeMap((action: LNDActions.FetchInvoices) => {
ofType(RTLActions.FETCH_INVOICES),
mergeMap((action: RTLActions.FetchInvoices) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchInvoices'));
const num_max_invoices = (action.payload.num_max_invoices) ? action.payload.num_max_invoices : 100;
const index_offset = (action.payload.index_offset) ? action.payload.index_offset : 0;
@ -489,10 +572,10 @@ export class LNDEffects implements OnDestroy {
.pipe(map((res: ListInvoices) => {
this.logger.info(res);
if (action.payload.reversed && !action.payload.index_offset) {
this.store.dispatch(new LNDActions.SetTotalInvoices(+res.last_index_offset));
this.store.dispatch(new RTLActions.SetTotalInvoices(+res.last_index_offset));
}
return {
type: LNDActions.SET_INVOICES,
type: RTLActions.SET_INVOICES,
payload: res
};
}),
@ -506,15 +589,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
transactionsFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_TRANSACTIONS),
mergeMap((action: LNDActions.FetchTransactions) => {
ofType(RTLActions.FETCH_TRANSACTIONS),
mergeMap((action: RTLActions.FetchTransactions) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchTransactions'));
return this.httpClient.get<Transaction[]>(environment.TRANSACTIONS_API);
}),
map((transactions) => {
this.logger.info(transactions);
return {
type: LNDActions.SET_TRANSACTIONS,
type: RTLActions.SET_TRANSACTIONS,
payload: (undefined !== transactions && transactions.length > 0) ? transactions : []
};
}),
@ -527,15 +610,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
paymentsFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_PAYMENTS),
mergeMap((action: LNDActions.FetchPayments) => {
ofType(RTLActions.FETCH_PAYMENTS),
mergeMap((action: RTLActions.FetchPayments) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchPayments'));
return this.httpClient.get<Payment[]>(environment.PAYMENTS_API);
}),
map((payments) => {
this.logger.info(payments);
return {
type: LNDActions.SET_PAYMENTS,
type: RTLActions.SET_PAYMENTS,
payload: (undefined !== payments && null != payments) ? payments : []
};
}),
@ -548,15 +631,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
decodePayment = this.actions$.pipe(
ofType(LNDActions.DECODE_PAYMENT),
mergeMap((action: LNDActions.DecodePayment) => {
ofType(RTLActions.DECODE_PAYMENT),
mergeMap((action: RTLActions.DecodePayment) => {
return this.httpClient.get(environment.PAYREQUEST_API + '/' + action.payload)
.pipe(
map((decodedPayment) => {
this.logger.info(decodedPayment);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_DECODED_PAYMENT,
type: RTLActions.SET_DECODED_PAYMENT,
payload: (undefined !== decodedPayment) ? decodedPayment : {}
};
}),
@ -577,8 +660,8 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
setDecodedPayment = this.actions$.pipe(
ofType(LNDActions.SET_DECODED_PAYMENT),
map((action: LNDActions.SetDecodedPayment) => {
ofType(RTLActions.SET_DECODED_PAYMENT),
map((action: RTLActions.SetDecodedPayment) => {
this.logger.info(action.payload);
return action.payload;
})
@ -586,9 +669,9 @@ export class LNDEffects implements OnDestroy {
@Effect()
sendPayment = this.actions$.pipe(
ofType(LNDActions.SEND_PAYMENT),
withLatestFrom(this.store.select('lnd')),
mergeMap(([action, store]: [LNDActions.SendPayment, fromLNDReducer.LNDState]) => {
ofType(RTLActions.SEND_PAYMENT),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.SendPayment, fromRTLReducer.State]) => {
let queryHeaders = {};
if (action.payload[2]) {
queryHeaders = {paymentDecoded: action.payload[1]};
@ -620,11 +703,11 @@ export class LNDEffects implements OnDestroy {
Object.assign(msg, confirmationMsg);
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%',
data: { type: 'SUCCESS', titleMessage: 'Payment Sent Successfully!', message: JSON.stringify(msg) }}));
this.store.dispatch(new LNDActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new LNDActions.FetchBalance('channels'));
this.store.dispatch(new LNDActions.FetchPayments());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchPayments());
return {
type: LNDActions.SET_DECODED_PAYMENT,
type: RTLActions.SET_DECODED_PAYMENT,
payload: {}
};
}
@ -646,14 +729,14 @@ export class LNDEffects implements OnDestroy {
@Effect()
graphNodeFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_GRAPH_NODE),
mergeMap((action: LNDActions.FetchGraphNode) => {
ofType(RTLActions.FETCH_GRAPH_NODE),
mergeMap((action: RTLActions.FetchGraphNode) => {
return this.httpClient.get<GraphNode>(environment.NETWORK_API + '/node/' + action.payload)
.pipe(map((graphNode: any) => {
this.logger.info(graphNode);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_GRAPH_NODE,
type: RTLActions.SET_GRAPH_NODE,
payload: (undefined !== graphNode) ? graphNode : {}
};
}),
@ -673,8 +756,8 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
setGraphNode = this.actions$.pipe(
ofType(LNDActions.SET_GRAPH_NODE),
map((action: LNDActions.SetGraphNode) => {
ofType(RTLActions.SET_GRAPH_NODE),
map((action: RTLActions.SetGraphNode) => {
this.logger.info(action.payload);
return action.payload;
})
@ -682,14 +765,14 @@ export class LNDEffects implements OnDestroy {
@Effect()
getNewAddress = this.actions$.pipe(
ofType(LNDActions.GET_NEW_ADDRESS),
mergeMap((action: LNDActions.GetNewAddress) => {
ofType(RTLActions.GET_NEW_ADDRESS),
mergeMap((action: RTLActions.GetNewAddress) => {
return this.httpClient.get(environment.NEW_ADDRESS_API + '?type=' + action.payload.addressId)
.pipe(map((newAddress: any) => {
this.logger.info(newAddress);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_NEW_ADDRESS,
type: RTLActions.SET_NEW_ADDRESS,
payload: (undefined !== newAddress && undefined !== newAddress.address) ? newAddress.address : {}
};
}),
@ -709,8 +792,8 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
setNewAddress = this.actions$.pipe(
ofType(LNDActions.SET_NEW_ADDRESS),
map((action: LNDActions.SetNewAddress) => {
ofType(RTLActions.SET_NEW_ADDRESS),
map((action: RTLActions.SetNewAddress) => {
this.logger.info(action.payload);
return action.payload;
})
@ -718,15 +801,15 @@ export class LNDEffects implements OnDestroy {
@Effect()
configFetch = this.actions$.pipe(
ofType(LNDActions.FETCH_CONFIG),
mergeMap((action: LNDActions.FetchConfig) => {
ofType(RTLActions.FETCH_CONFIG),
mergeMap((action: RTLActions.FetchConfig) => {
this.store.dispatch(new RTLActions.ClearEffectError('fetchConfig'));
return this.httpClient.get(environment.CONF_API + '/config/' + action.payload)
.pipe(
map((configFile: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SHOW_CONFIG,
type: RTLActions.SHOW_CONFIG,
payload: configFile
};
}),
@ -748,16 +831,16 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
showLNDConfig = this.actions$.pipe(
ofType(LNDActions.SHOW_CONFIG),
map((action: LNDActions.ShowConfig) => {
ofType(RTLActions.SHOW_CONFIG),
map((action: RTLActions.ShowConfig) => {
return action.payload;
})
);
@Effect()
SetChannelTransaction = this.actions$.pipe(
ofType(LNDActions.SET_CHANNEL_TRANSACTION),
mergeMap((action: LNDActions.SetChannelTransaction) => {
ofType(RTLActions.SET_CHANNEL_TRANSACTION),
mergeMap((action: RTLActions.SetChannelTransaction) => {
this.store.dispatch(new RTLActions.ClearEffectError('SetChannelTransaction'));
return this.httpClient.post(environment.TRANSACTIONS_API,
{ amount: action.payload.amount, address: action.payload.address, sendAll: action.payload.sendAll, fees: action.payload.fees, blocks: action.payload.blocks }
@ -766,7 +849,7 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new LNDActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
return {
type: RTLActions.OPEN_ALERT,
payload: { data: {type: 'SUCCESS', titleMessage: 'Fund Sent Successfully!'} }
@ -789,8 +872,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
fetchForwardingHistory = this.actions$.pipe(
ofType(LNDActions.GET_FORWARDING_HISTORY),
mergeMap((action: LNDActions.GetForwardingHistory) => {
ofType(RTLActions.GET_FORWARDING_HISTORY),
mergeMap((action: RTLActions.GetForwardingHistory) => {
this.store.dispatch(new RTLActions.ClearEffectError('GetForwardingHistory'));
const queryHeaders: SwitchReq = {
num_max_events: action.payload.num_max_events, index_offset: action.payload.index_offset, end_time: action.payload.end_time , start_time: action.payload.start_time
@ -800,7 +883,7 @@ export class LNDEffects implements OnDestroy {
map((fhRes: any) => {
this.logger.info(fhRes);
return {
type: LNDActions.SET_FORWARDING_HISTORY,
type: RTLActions.SET_FORWARDING_HISTORY,
payload: fhRes
};
}),
@ -821,19 +904,19 @@ export class LNDEffects implements OnDestroy {
@Effect()
queryRoutesFetch = this.actions$.pipe(
ofType(LNDActions.GET_QUERY_ROUTES),
mergeMap((action: LNDActions.GetQueryRoutes) => {
ofType(RTLActions.GET_QUERY_ROUTES),
mergeMap((action: RTLActions.GetQueryRoutes) => {
return this.httpClient.get(environment.NETWORK_API + '/routes/' + action.payload.destPubkey + '/' + action.payload.amount)
.pipe(
map((qrRes: any) => {
this.logger.info(qrRes);
return {
type: LNDActions.SET_QUERY_ROUTES,
type: RTLActions.SET_QUERY_ROUTES,
payload: qrRes
};
}),
catchError((err: any) => {
this.store.dispatch(new LNDActions.SetQueryRoutes({}));
this.store.dispatch(new RTLActions.SetQueryRoutes({}));
this.logger.error(err);
return of(
{
@ -849,16 +932,16 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
setQueryRoutes = this.actions$.pipe(
ofType(LNDActions.SET_QUERY_ROUTES),
map((action: LNDActions.SetQueryRoutes) => {
ofType(RTLActions.SET_QUERY_ROUTES),
map((action: RTLActions.SetQueryRoutes) => {
return action.payload;
})
);
@Effect()
genSeed = this.actions$.pipe(
ofType(LNDActions.GEN_SEED),
mergeMap((action: LNDActions.GenSeed) => {
ofType(RTLActions.GEN_SEED),
mergeMap((action: RTLActions.GenSeed) => {
return this.httpClient.get(environment.WALLET_API + '/genseed/' + action.payload)
.pipe(
map((postRes: any) => {
@ -866,7 +949,7 @@ export class LNDEffects implements OnDestroy {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.GEN_SEED_RESPONSE,
type: RTLActions.GEN_SEED_RESPONSE,
payload: postRes.cipher_seed_mnemonic
};
}),
@ -882,24 +965,24 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
genSeedResponse = this.actions$.pipe(
ofType(LNDActions.GEN_SEED_RESPONSE),
map((action: LNDActions.GenSeedResponse) => {
ofType(RTLActions.GEN_SEED_RESPONSE),
map((action: RTLActions.GenSeedResponse) => {
return action.payload;
})
);
@Effect({ dispatch: false })
initWalletRes = this.actions$.pipe(
ofType(LNDActions.INIT_WALLET_RESPONSE),
map((action: LNDActions.InitWalletResponse) => {
ofType(RTLActions.INIT_WALLET_RESPONSE),
map((action: RTLActions.InitWalletResponse) => {
return action.payload;
})
);
@Effect()
initWallet = this.actions$.pipe(
ofType(LNDActions.INIT_WALLET),
mergeMap((action: LNDActions.InitWallet) => {
ofType(RTLActions.INIT_WALLET),
mergeMap((action: RTLActions.InitWallet) => {
return this.httpClient.post(environment.WALLET_API + '/initwallet',
{ wallet_password: action.payload.pwd,
cipher_seed_mnemonic: action.payload.cipher ? action.payload.cipher : '',
@ -909,7 +992,7 @@ export class LNDEffects implements OnDestroy {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.INIT_WALLET_RESPONSE,
type: RTLActions.INIT_WALLET_RESPONSE,
payload: postRes
};
}),
@ -925,8 +1008,8 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch : false })
unlockWallet = this.actions$.pipe(
ofType(LNDActions.UNLOCK_WALLET),
mergeMap((action: LNDActions.UnlockWallet) => {
ofType(RTLActions.UNLOCK_WALLET),
mergeMap((action: RTLActions.UnlockWallet) => {
return this.httpClient.post(environment.WALLET_API + '/unlockwallet', { wallet_password: action.payload.pwd })
.pipe(
map((postRes) => {
@ -939,7 +1022,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.info('Successfully Initialized!');
this.store.dispatch(new RTLActions.InitAppData());
this.router.navigate(['/'], { relativeTo: this.activatedRoute });
this.router.navigate(['/lnd/']);
}, 1000 * 90);
return of({});
}),
@ -953,10 +1036,92 @@ export class LNDEffects implements OnDestroy {
}
));
@Effect()
isAuthorized = this.actions$.pipe(
ofType(RTLActions.IS_AUTHORIZED),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.IsAuthorized, fromRTLReducer.State]) => {
this.store.dispatch(new RTLActions.ClearEffectError('IsAuthorized'));
return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.logger.info('Successfully Authorized!');
return {
type: RTLActions.IS_AUTHORIZED_RES,
payload: postRes
};
}),
catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: 'Authorization Failed',
message: JSON.stringify({Code: err.status, Message: err.error.error})}}));
this.store.dispatch(new RTLActions.EffectError({ action: 'IsAuthorized', code: err.status, message: err.error.message }));
this.logger.error(err.error);
return of({
type: RTLActions.IS_AUTHORIZED_RES,
payload: 'ERROR'
});
})
);
}));
@Effect({ dispatch: false })
isAuthorizedRes = this.actions$.pipe(
ofType(RTLActions.IS_AUTHORIZED_RES),
map((action: RTLActions.IsAuthorizedRes) => {
return action.payload;
})
);
@Effect({ dispatch: false })
authSignin = this.actions$.pipe(
ofType(RTLActions.SIGNIN),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.Signin, fromRTLReducer.State]) => {
this.store.dispatch(new RTLActions.ClearEffectError('Signin'));
return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token);
this.router.navigate(['/lnd/']);
}),
catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}}));
this.store.dispatch(new RTLActions.EffectError({ action: 'Signin', code: err.status, message: err.error.message }));
this.logger.error(err.error);
this.logger.info('Redirecting to Signin Error Page');
if (+store.appConfig.sso.rtlSSO) {
this.router.navigate(['/ssoerror']);
} else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
}
return of();
})
);
}));
@Effect({ dispatch: false })
signOut = this.actions$.pipe(
ofType(RTLActions.SIGNOUT),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.Signout, fromRTLReducer.State]) => {
if (+store.appConfig.sso.rtlSSO) {
window.location.href = store.appConfig.sso.logoutRedirectLink;
} else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink]);
}
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
this.logger.warn('LOGGED OUT');
return of();
}));
@Effect()
peerLookup = this.actions$.pipe(
ofType(LNDActions.PEER_LOOKUP),
mergeMap((action: LNDActions.PeerLookup) => {
ofType(RTLActions.PEER_LOOKUP),
mergeMap((action: RTLActions.PeerLookup) => {
this.store.dispatch(new RTLActions.ClearEffectError('Lookup'));
return this.httpClient.get(environment.NETWORK_API + '/node/' + action.payload)
.pipe(
@ -964,7 +1129,7 @@ export class LNDEffects implements OnDestroy {
this.logger.info(resPeer);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_LOOKUP,
type: RTLActions.SET_LOOKUP,
payload: resPeer
};
}),
@ -986,8 +1151,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
channelLookup = this.actions$.pipe(
ofType(LNDActions.CHANNEL_LOOKUP),
mergeMap((action: LNDActions.ChannelLookup) => {
ofType(RTLActions.CHANNEL_LOOKUP),
mergeMap((action: RTLActions.ChannelLookup) => {
this.store.dispatch(new RTLActions.ClearEffectError('Lookup'));
return this.httpClient.get(environment.NETWORK_API + '/edge/' + action.payload)
.pipe(
@ -995,7 +1160,7 @@ export class LNDEffects implements OnDestroy {
this.logger.info(resChannel);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_LOOKUP,
type: RTLActions.SET_LOOKUP,
payload: resChannel
};
}),
@ -1017,8 +1182,8 @@ export class LNDEffects implements OnDestroy {
@Effect()
invoiceLookup = this.actions$.pipe(
ofType(LNDActions.INVOICE_LOOKUP),
mergeMap((action: LNDActions.InvoiceLookup) => {
ofType(RTLActions.INVOICE_LOOKUP),
mergeMap((action: RTLActions.InvoiceLookup) => {
this.store.dispatch(new RTLActions.ClearEffectError('Lookup'));
return this.httpClient.get(environment.INVOICES_API + '/' + action.payload)
.pipe(
@ -1026,7 +1191,7 @@ export class LNDEffects implements OnDestroy {
this.logger.info(resInvoice);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: LNDActions.SET_LOOKUP,
type: RTLActions.SET_LOOKUP,
payload: resInvoice
};
}),
@ -1048,13 +1213,66 @@ export class LNDEffects implements OnDestroy {
@Effect({ dispatch: false })
setLookup = this.actions$.pipe(
ofType(LNDActions.SET_LOOKUP),
map((action: LNDActions.SetLookup) => {
ofType(RTLActions.SET_LOOKUP),
map((action: RTLActions.SetLookup) => {
this.logger.info(action.payload);
return action.payload;
})
);
@Effect()
setSelectedNode = this.actions$.pipe(
ofType(RTLActions.SET_SELECTED_NODE),
mergeMap((action: RTLActions.SetSelelectedNode) => {
this.store.dispatch(new RTLActions.ClearEffectError('UpdateSelNode'));
return this.httpClient.post(environment.CONF_API + '/updateSelNode', { selNodeIndex: action.payload.index })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
if (sessionStorage.getItem('token')) {
if(+action.payload.index === 1) {
this.router.navigate(['/lnd/home']);
} else {
this.router.navigate(['/cl/home']);
}
this.store.dispatch(new RTLActions.ResetStore(action.payload));
return { type: RTLActions.FETCH_INFO };
} else {
return {
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'WARN', titleMessage: 'Authorization required to get the data from the node!' }}
};
}
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectError({ action: 'UpdateSelNode', code: err.status, message: err.error.message }));
this.logger.error(err);
return of(
{
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Update Selected Node Failed!',
message: JSON.stringify({code: err.status, Message: err.error.error})
}}
}
);
})
);
}
));
SetToken(token: string) {
if (token) {
sessionStorage.setItem('lndUnlocked', 'true');
sessionStorage.setItem('token', token);
this.store.dispatch(new RTLActions.InitAppData());
} else {
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
}
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();

@ -1,10 +1,15 @@
import * as LNDActions from './lnd.actions';
import * as RTLActions from './rtl.actions';
import { ErrorPayload } from '../models/errorPayload';
import { RTLConfiguration, Node } from '../models/RTLconfig';
import {
GetInfo, GetInfoChain, Peer, AddressType, Fees, NetworkInfo, Balance, Channel,
Payment, ListInvoices, PendingChannels, ClosedChannel, Transaction, SwitchRes, QueryRoutes
} from '../../shared/models/lndModels';
GetInfo, GetInfoChain, Peer, AddressType, Fees, NetworkInfo, Balance, Channel, Payment, ListInvoices, PendingChannels, ClosedChannel, Transaction, SwitchRes, QueryRoutes
} from '../models/lndModels';
export interface LNDState {
export interface State {
effectErrors: ErrorPayload[];
selNode: Node;
appConfig: RTLConfiguration;
information: GetInfo;
peers: Peer[];
fees: Fees;
@ -27,7 +32,17 @@ export interface LNDState {
addressTypes: AddressType[];
}
const LNDInitialState: LNDState = {
const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'Vertical', menuType: 'Regular', theme: 'dark-blue', satsToBTC: false };
const initNodeAuthentication = { nodeAuthType: 'CUSTOM', lndConfigPath: '', bitcoindConfigPath: '' };
const initialState: State = {
effectErrors: [],
selNode: {settings: initNodeSettings, authentication: initNodeAuthentication},
appConfig: {
selectedNodeIndex: -1,
sso: { rtlSSO: 0, logoutRedirectLink: '/login' },
nodes: [{ settings: initNodeSettings, authentication: initNodeAuthentication}]
},
information: {},
peers: [],
fees: {},
@ -53,13 +68,43 @@ const LNDInitialState: LNDState = {
]
};
export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDActions) {
export function RTLRootReducer(state = initialState, action: RTLActions.RTLActions) {
switch (action.type) {
case LNDActions.RESET_LND_STORE:
case RTLActions.CLEAR_EFFECT_ERROR:
const clearedEffectErrors = [...state.effectErrors];
const removeEffectIdx = state.effectErrors.findIndex(err => {
return err.action === action.payload;
});
if (removeEffectIdx > -1) {
clearedEffectErrors.splice(removeEffectIdx, 1);
}
return {
...state,
effectErrors: clearedEffectErrors
};
case RTLActions.EFFECT_ERROR:
return {
...state,
effectErrors: [...state.effectErrors, action.payload]
};
case RTLActions.RESET_STORE:
return {
...initialState,
appConfig: state.appConfig,
selNode: action.payload
};
case RTLActions.SET_SELECTED_NODE:
return {
...LNDInitialState
...state,
selNode: action.payload
};
case RTLActions.SET_RTL_CONFIG:
return {
...state,
selNode: action.payload.nodes.find(node => +node.index === action.payload.selectedNodeIndex),
appConfig: action.payload
};
case LNDActions.SET_INFO:
case RTLActions.SET_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';
@ -79,17 +124,17 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
...state,
information: action.payload
};
case LNDActions.SET_PEERS:
case RTLActions.SET_PEERS:
return {
...state,
peers: action.payload
};
case LNDActions.ADD_PEER:
case RTLActions.ADD_PEER:
return {
...state,
peers: [...state.peers, action.payload]
};
case LNDActions.REMOVE_PEER:
case RTLActions.REMOVE_PEER:
const modifiedPeers = [...state.peers];
const removePeerIdx = state.peers.findIndex(peer => {
return peer.pub_key === action.payload.pubkey;
@ -101,24 +146,24 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
...state,
peers: modifiedPeers
};
case LNDActions.ADD_INVOICE:
case RTLActions.ADD_INVOICE:
const newInvoices = state.invoices;
newInvoices.invoices.unshift(action.payload);
return {
...state,
invoices: newInvoices
};
case LNDActions.SET_FEES:
case RTLActions.SET_FEES:
return {
...state,
fees: action.payload
};
case LNDActions.SET_CLOSED_CHANNELS:
case RTLActions.SET_CLOSED_CHANNELS:
return {
...state,
closedChannels: action.payload,
};
case LNDActions.SET_PENDING_CHANNELS:
case RTLActions.SET_PENDING_CHANNELS:
let pendingChannels = -1;
if (action.payload) {
pendingChannels = 0;
@ -140,7 +185,7 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
pendingChannels: action.payload,
numberOfPendingChannels: pendingChannels,
};
case LNDActions.SET_CHANNELS:
case RTLActions.SET_CHANNELS:
let localBal = 0, remoteBal = 0, activeChannels = 0, inactiveChannels = 0;
if (action.payload) {
action.payload.filter(channel => {
@ -165,7 +210,7 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
totalLocalBalance: localBal,
totalRemoteBalance: remoteBal
};
case LNDActions.REMOVE_CHANNEL:
case RTLActions.REMOVE_CHANNEL:
const modifiedChannels = [...state.allChannels];
const removeChannelIdx = state.allChannels.findIndex(channel => {
return channel.channel_point === action.payload.channelPoint;
@ -177,7 +222,7 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
...state,
allChannels: modifiedChannels
};
case LNDActions.SET_BALANCE:
case RTLActions.SET_BALANCE:
if (action.payload.target === 'channels') {
return {
...state,
@ -189,32 +234,32 @@ export function LNDReducer(state = LNDInitialState, action: LNDActions.LNDAction
blockchainBalance: action.payload.balance
};
}
case LNDActions.SET_NETWORK:
case RTLActions.SET_NETWORK:
return {
...state,
networkInfo: action.payload
};
case LNDActions.SET_INVOICES:
case RTLActions.SET_INVOICES:
return {
...state,
invoices: action.payload
};
case LNDActions.SET_TOTAL_INVOICES:
case RTLActions.SET_TOTAL_INVOICES:
return {
...state,
totalInvoices: action.payload
};
case LNDActions.SET_TRANSACTIONS:
case RTLActions.SET_TRANSACTIONS:
return {
...state,
transactions: action.payload
};
case LNDActions.SET_PAYMENTS:
case RTLActions.SET_PAYMENTS:
return {
...state,
payments: action.payload
};
case LNDActions.SET_FORWARDING_HISTORY:
case RTLActions.SET_FORWARDING_HISTORY:
if (action.payload.forwarding_events) {
const storedChannels = [...state.allChannels];
action.payload.forwarding_events.forEach(event => {

@ -43,7 +43,7 @@
.active-link {
background: mat-color($primary);
color: white;
color: white; // mat-color($foreground, text); for dark theme but for light theme the foreground text color is black
}
.h-active-link {
@ -58,6 +58,10 @@
}
}
.mat-primary .mat-select, .mat-primary .mat-select-trigger, .mat-primary .mat-select-value, .mat-primary .mat-select-arrow {
// color: white !important;
}
.mat-primary .mat-select-panel .mat-option.mat-selected:not(.mat-option-multiple),
.mat-primary .mat-option.mat-selected:not(.mat-option-multiple):not(.mat-option-disabled) {
background: none;

@ -61,6 +61,24 @@ html, body {
overflow: hidden;
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}
.font-9px {
font-size: 9px !important;
}

@ -1,5 +1,5 @@
@import url('https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,500,500i,700,700i,900,900i');
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
@import '~material-design-icons/iconfont/material-icons.css';
@import '~roboto-fontface/css/roboto/roboto-fontface.css';
@import "/root";
@import "/perfect-scrollbar";

@ -1,118 +0,0 @@
import { Action } from '@ngrx/store';
import { RTLConfiguration, Settings, Node } from '../shared/models/RTLconfig';
import { ErrorPayload } from '../shared/models/errorPayload';
import { MatDialogConfig } from '@angular/material';
export const RESET_STORE = 'RESET_STORE';
export const CLEAR_EFFECT_ERROR = 'CLEAR_EFFECT_ERROR';
export const EFFECT_ERROR = 'EFFECT_ERROR';
export const OPEN_SPINNER = 'OPEN_SPINNER';
export const CLOSE_SPINNER = 'CLOSE_SPINNER';
export const OPEN_ALERT = 'OPEN_ALERT';
export const CLOSE_ALERT = 'CLOSE_ALERT';
export const OPEN_CONFIRMATION = 'OPEN_CONFIRMATION';
export const CLOSE_CONFIRMATION = 'CLOSE_CONFIRMATION';
export const FETCH_STORE = 'FETCH_STORE';
export const SET_STORE = 'SET_STORE';
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 IS_AUTHORIZED = 'IS_AUTHORIZED';
export const IS_AUTHORIZED_RES = 'IS_AUTHORIZED_RES';
export const SIGNIN = 'SIGNIN';
export const SIGNOUT = 'SIGNOUT';
export const INIT_APP_DATA = 'INIT_APP_DATA';
export class ClearEffectError implements Action {
readonly type = CLEAR_EFFECT_ERROR;
constructor(public payload: string) {} // payload = errorAction
}
export class EffectError implements Action {
readonly type = EFFECT_ERROR;
constructor(public payload: ErrorPayload) {}
}
export class OpenSpinner implements Action {
readonly type = OPEN_SPINNER;
constructor(public payload: string) {} // payload = titleMessage
}
export class CloseSpinner implements Action {
readonly type = CLOSE_SPINNER;
}
export class OpenAlert implements Action {
readonly type = OPEN_ALERT;
constructor(public payload: MatDialogConfig) {}
}
export class CloseAlert implements Action {
readonly type = CLOSE_ALERT;
}
export class OpenConfirmation implements Action {
readonly type = OPEN_CONFIRMATION;
constructor(public payload: MatDialogConfig) {}
}
export class CloseConfirmation implements Action {
readonly type = CLOSE_CONFIRMATION;
constructor(public payload: boolean) {}
}
export class ResetStore implements Action {
readonly type = RESET_STORE;
constructor(public payload: Node) {}
}
export class FetchRTLConfig implements Action {
readonly type = FETCH_RTL_CONFIG;
}
export class SetRTLConfig implements Action {
readonly type = SET_RTL_CONFIG;
constructor(public payload: RTLConfiguration) {}
}
export class SaveSettings implements Action {
readonly type = SAVE_SETTINGS;
constructor(public payload: Settings) {}
}
export class SetSelelectedNode implements Action {
readonly type = SET_SELECTED_NODE;
constructor(public payload: Node) {}
}
export class IsAuthorized implements Action {
readonly type = IS_AUTHORIZED;
constructor(public payload: string) {} // payload = password
}
export class IsAuthorizedRes implements Action {
readonly type = IS_AUTHORIZED_RES;
constructor(public payload: any) {} // payload = token/error
}
export class Signin implements Action {
readonly type = SIGNIN;
constructor(public payload: string) {} // payload = password
}
export class Signout implements Action {
readonly type = SIGNOUT;
constructor() {}
}
export class InitAppData implements Action {
readonly type = INIT_APP_DATA;
}
export type RTLActions =
ClearEffectError | EffectError | OpenSpinner | CloseSpinner |
FetchRTLConfig | SetRTLConfig | SaveSettings |
OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation |
ResetStore | SetSelelectedNode |
IsAuthorized | IsAuthorizedRes | Signin | Signout | InitAppData;

@ -1,261 +0,0 @@
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router, ActivatedRoute } from '@angular/router';
import { Store } from '@ngrx/store';
import { Actions, Effect, ofType } from '@ngrx/effects';
import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, take, withLatestFrom } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { environment } from '../../environments/environment';
import { LoggerService } from '../shared/services/logger.service';
import { Settings } from '../shared/models/RTLconfig';
import { SpinnerDialogComponent } from '../shared/components/spinner-dialog/spinner-dialog.component';
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 fromApp from './rtl.reducers';
@Injectable()
export class RTLEffects implements OnDestroy {
dialogRef: any;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(
private actions$: Actions,
private httpClient: HttpClient,
private store: Store<fromApp.AppState>,
private logger: LoggerService,
public dialog: MatDialog,
private router: Router,
private activatedRoute: ActivatedRoute) { }
@Effect({ dispatch: false })
openSpinner = this.actions$.pipe(
ofType(RTLActions.OPEN_SPINNER),
map((action: RTLActions.OpenSpinner) => {
this.dialogRef = this.dialog.open(SpinnerDialogComponent, { data: { titleMessage: action.payload}});
}
));
@Effect({ dispatch: false })
closeSpinner = this.actions$.pipe(
ofType(RTLActions.CLOSE_SPINNER),
map((action: RTLActions.CloseSpinner) => {
if (this.dialogRef) { this.dialogRef.close(); }
}
));
@Effect({ dispatch: false })
openAlert = this.actions$.pipe(
ofType(RTLActions.OPEN_ALERT),
map((action: RTLActions.OpenAlert) => {
this.dialogRef = this.dialog.open(AlertMessageComponent, action.payload);
}
));
@Effect({ dispatch: false })
closeAlert = this.actions$.pipe(
ofType(RTLActions.CLOSE_ALERT),
map((action: RTLActions.CloseAlert) => {
if (this.dialogRef) { this.dialogRef.close(); }
}
));
@Effect({ dispatch: false })
openConfirm = this.actions$.pipe(
ofType(RTLActions.OPEN_CONFIRMATION),
map((action: RTLActions.OpenConfirmation) => {
this.dialogRef = this.dialog.open(ConfirmationMessageComponent, action.payload);
})
);
@Effect({ dispatch: false })
closeConfirm = this.actions$.pipe(
ofType(RTLActions.CLOSE_CONFIRMATION),
take(1),
map((action: RTLActions.CloseConfirmation) => {
this.dialogRef.close();
this.logger.info(action.payload);
return action.payload;
}
));
@Effect()
appConfigFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_RTL_CONFIG),
mergeMap((action: RTLActions.FetchRTLConfig) => {
this.store.dispatch(new RTLActions.ClearEffectError('FetchRTLConfig'));
return this.httpClient.get(environment.CONF_API + '/rtlconf');
}),
map((rtlConfig: any) => {
this.logger.info(rtlConfig);
if (+rtlConfig.sso.rtlSSO) { this.store.dispatch(new RTLActions.Signout()); }
return {
type: RTLActions.SET_RTL_CONFIG,
payload: rtlConfig
};
},
catchError((err) => {
this.logger.error(err);
this.store.dispatch(new RTLActions.EffectError({ action: 'FetchRTLConfig', code: err.status, message: err.error.error }));
return of();
})
));
@Effect({ dispatch: false })
settingSave = this.actions$.pipe(
ofType(RTLActions.SAVE_SETTINGS),
mergeMap((action: RTLActions.SaveSettings) => {
return this.httpClient.post<Settings>(environment.CONF_API, { updatedSettings: action.payload });
}
));
@Effect()
isAuthorized = this.actions$.pipe(
ofType(RTLActions.IS_AUTHORIZED),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.IsAuthorized, fromApp.RootState]) => {
this.store.dispatch(new RTLActions.ClearEffectError('IsAuthorized'));
return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.logger.info('Successfully Authorized!');
return {
type: RTLActions.IS_AUTHORIZED_RES,
payload: postRes
};
}),
catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', titleMessage: 'Authorization Failed',
message: JSON.stringify({Code: err.status, Message: err.error.error})}}));
this.store.dispatch(new RTLActions.EffectError({ action: 'IsAuthorized', code: err.status, message: err.error.message }));
this.logger.error(err.error);
return of({
type: RTLActions.IS_AUTHORIZED_RES,
payload: 'ERROR'
});
})
);
}));
@Effect({ dispatch: false })
isAuthorizedRes = this.actions$.pipe(
ofType(RTLActions.IS_AUTHORIZED_RES),
map((action: RTLActions.IsAuthorizedRes) => {
return action.payload;
})
);
@Effect({ dispatch: false })
authSignin = this.actions$.pipe(
ofType(RTLActions.SIGNIN),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.Signin, fromApp.RootState]) => {
this.store.dispatch(new RTLActions.ClearEffectError('Signin'));
return this.httpClient.post(environment.AUTHENTICATE_API, { password: action.payload })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token);
this.router.navigate(['/'], { relativeTo: this.activatedRoute });
}),
catchError((err) => {
this.store.dispatch(new RTLActions.OpenAlert({ width: '70%', data: {type: 'ERROR', message: JSON.stringify(err.error)}}));
this.store.dispatch(new RTLActions.EffectError({ action: 'Signin', code: err.status, message: err.error.message }));
this.logger.error(err.error);
this.logger.info('Redirecting to Signin Error Page');
if (+store.appConfig.sso.rtlSSO) {
this.router.navigate(['/ssoerror'], { relativeTo: this.activatedRoute });
} else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink], { relativeTo: this.activatedRoute });
}
return of();
})
);
}));
@Effect({ dispatch: false })
signOut = this.actions$.pipe(
ofType(RTLActions.SIGNOUT),
withLatestFrom(this.store.select('rtlRoot')),
mergeMap(([action, store]: [RTLActions.Signout, fromApp.RootState]) => {
if (+store.appConfig.sso.rtlSSO) {
window.location.href = store.appConfig.sso.logoutRedirectLink;
} else {
this.router.navigate([store.appConfig.sso.logoutRedirectLink], { relativeTo: this.activatedRoute });
}
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
this.logger.warn('LOGGED OUT');
return of();
}));
@Effect()
setSelectedNode = this.actions$.pipe(
ofType(RTLActions.SET_SELECTED_NODE),
mergeMap((action: RTLActions.SetSelelectedNode) => {
this.store.dispatch(new RTLActions.ClearEffectError('UpdateSelNode'));
return this.httpClient.post(environment.CONF_API + '/updateSelNode', { selNodeIndex: action.payload.index })
.pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
if (sessionStorage.getItem('token')) {
this.store.dispatch(new RTLActions.ResetStore(action.payload));
if (action.payload.lnImplementation.toLowerCase() === 'clightning') {
this.router.navigate(['./cl'], { relativeTo: this.activatedRoute });
return { type: CLActions.FETCH_CL_INFO };
} else {
this.router.navigate(['./lnd'], { relativeTo: this.activatedRoute });
return { type: LNDActions.FETCH_INFO };
}
} else {
return {
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'WARN', titleMessage: 'Authorization required to get the data from the node!' }}
};
}
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectError({ action: 'UpdateSelNode', code: err.status, message: err.error.message }));
this.logger.error(err);
return of(
{
type: RTLActions.OPEN_ALERT,
payload: { width: '70%', data: {type: 'ERROR', titleMessage: 'Update Selected Node Failed!',
message: JSON.stringify({code: err.status, Message: err.error.error})
}}
}
);
})
);
}
));
SetToken(token: string) {
if (token) {
sessionStorage.setItem('lndUnlocked', 'true');
sessionStorage.setItem('token', token);
this.store.dispatch(new RTLActions.InitAppData());
} else {
sessionStorage.removeItem('lndUnlocked');
sessionStorage.removeItem('token');
}
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -1,82 +0,0 @@
import * as RTLActions from './rtl.actions';
import { ErrorPayload } from '../shared/models/errorPayload';
import { RTLConfiguration, Node } from '../shared/models/RTLconfig';
import { ActionReducerMap } from '@ngrx/store';
import * as fromLND from '../lnd/store/lnd.reducers';
import * as fromCL from '../c-lightning/store/cl.reducers';
export interface AppState {
rtlRoot: RootState;
lnd: fromLND.LNDState;
cl: fromCL.CLState;
}
export interface RootState {
effectErrors: ErrorPayload[];
selNode: Node;
appConfig: RTLConfiguration;
}
const initNodeSettings = { flgSidenavOpened: true, flgSidenavPinned: true, menu: 'Vertical', menuType: 'Regular', theme: 'dark-blue', satsToBTC: false };
const initNodeAuthentication = { nodeAuthType: 'CUSTOM', lndConfigPath: '', bitcoindConfigPath: '' };
const initialState: RootState = {
effectErrors: [],
selNode: {settings: initNodeSettings, authentication: initNodeAuthentication},
appConfig: {
selectedNodeIndex: -1,
sso: { rtlSSO: 0, logoutRedirectLink: '/login' },
nodes: [{ settings: initNodeSettings, authentication: initNodeAuthentication}]
}
};
export function RTLRootReducer(state = initialState, action: RTLActions.RTLActions) {
switch (action.type) {
case RTLActions.CLEAR_EFFECT_ERROR:
const clearedEffectErrors = [...state.effectErrors];
const removeEffectIdx = state.effectErrors.findIndex(err => {
return err.action === action.payload;
});
if (removeEffectIdx > -1) {
clearedEffectErrors.splice(removeEffectIdx, 1);
}
return {
...state,
effectErrors: clearedEffectErrors
};
case RTLActions.EFFECT_ERROR:
return {
...state,
effectErrors: [...state.effectErrors, action.payload]
};
case RTLActions.RESET_STORE:
return {
...initialState,
appConfig: state.appConfig,
selNode: action.payload
};
case RTLActions.SET_SELECTED_NODE:
return {
...state,
selNode: action.payload
};
case RTLActions.SET_RTL_CONFIG:
return {
...state,
selNode: action.payload.nodes.find(node => +node.index === action.payload.selectedNodeIndex),
appConfig: action.payload
};
default:
return state;
}
}
export const appReducer: ActionReducerMap<AppState> = {
rtlRoot: RTLRootReducer,
lnd: fromLND.LNDReducer,
cl: fromCL.CLReducer
};

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

@ -1,70 +0,0 @@
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 { LoggerService } from '../shared/services/logger.service';
import { RTLConfiguration, Settings, Node } from '../shared/models/RTLconfig';
import { GetInfo } from '../shared/models/lndModels';
import * as LNDActions from '../lnd/store/lnd.actions';
import * as CLActions from '../c-lightning/store/cl.actions';
import * as RTLActions from '../store/rtl.actions';
import * as fromApp from '../store/rtl.reducers';
@Component({
selector: 'rtl-super-user-dashboard',
templateUrl: './super-user-dashboard.component.html',
styleUrls: ['./super-user-dashboard.component.scss']
})
export class SuperUserDashboardComponent implements OnInit, OnDestroy {
public selNode: Node;
public settings: Settings;
public information: GetInfo = {};
public flgLoading: Array<Boolean | 'error'> = [true];
public flgCopied = false;
public appConfig: RTLConfiguration;
public accessKey = '';
public smallScreen = false;
unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromApp.AppState>, private actions$: Actions, private userIdle: UserIdleService, private router: Router, private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.actions$.pipe(takeUntil(this.unSubs[3]), filter(action => action.type === RTLActions.SET_RTL_CONFIG))
.subscribe((setConfigAction: RTLActions.SetRTLConfig) => {
console.warn(setConfigAction);
this.selNode = setConfigAction.payload.nodes.find(node => +node.index === setConfigAction.payload.selectedNodeIndex)
if (this.selNode.lnImplementation.toLowerCase() === 'clightning') {
this.store.dispatch(new CLActions.FetchCLInfo());
this.router.navigate(['../cl'], { relativeTo: this.activatedRoute });
} else {
this.store.dispatch(new LNDActions.FetchInfo());
this.router.navigate(['../lnd'], { relativeTo: this.activatedRoute });
}
});
// this.store.select('rtlRoot')
// .pipe(takeUntil(this.unSubs[0]))
// .subscribe(rtlStore => {
// this.selNode = rtlStore.selNode;
// if (this.selNode.lnImplementation.toLowerCase() === 'clightning') {
// this.store.dispatch(new CLActions.FetchCLInfo());
// this.router.navigate(['./cl'], { relativeTo: this.activatedRoute });
// } else {
// this.store.dispatch(new LNDActions.FetchInfo());
// this.router.navigate(['./lnd'], { relativeTo: this.activatedRoute });
// }
// });
}
ngOnDestroy() {
this.unSubs.forEach(unsub => {
unsub.next();
unsub.complete();
});
}
}

@ -1 +1 @@
export const VERSION = '0.4.7-beta';
export const VERSION = '0.4.8-beta';
Loading…
Cancel
Save