Channel restore

Channel restore
pull/209/head
Shahana Farooqui 5 years ago
parent 5c0c1fdc7e
commit aac9d42bb4

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -9,5 +9,5 @@
<link rel="stylesheet" href="styles.41a6644c686ce68dce93.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.66d0b5931cf64a2c9467.js"></script><script src="polyfills-es5.763f4f23e8aee5ec234d.js" nomodule></script><script src="polyfills.e59b6f9dc696bd89cf7f.js"></script><script src="main.271bb5b2dae0b00c178c.js"></script></body>
<script src="runtime.881b21e05dd0455c6919.js"></script><script src="polyfills-es5.763f4f23e8aee5ec234d.js" nomodule></script><script src="polyfills.e59b6f9dc696bd89cf7f.js"></script><script src="main.c17160159e9da3b43373.js"></script></body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

@ -107,7 +107,7 @@ exports.postRestore = (req, res, next) => {
let restore_backup = '';
if (req.params.channelPoint === 'ALL') {
message = 'All Channels Restore Successful!';
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'channel-all.bak';
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'restore' + common.path_separator + 'channel-all.bak';
let exists = fs.existsSync(channel_restore_file);
if (exists) {
restore_backup = fs.readFileSync(channel_restore_file, 'utf-8');
@ -124,7 +124,7 @@ exports.postRestore = (req, res, next) => {
}
} else {
message = 'Channel ' + req.params.channelPoint + ' Restore Successful!';
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'channel-' + req.params.channelPoint.replace(':', '-') + '.bak';
channel_restore_file = common.selectedNode.channel_backup_path + common.path_separator + 'restore' + common.path_separator + 'channel-' + req.params.channelPoint.replace(':', '-') + '.bak';
let exists = fs.existsSync(channel_restore_file);
if (exists) {
restore_backup = fs.readFileSync(channel_restore_file, 'utf-8');
@ -143,8 +143,30 @@ exports.postRestore = (req, res, next) => {
logger.error({fileName: 'Channels Backup Restore', lineNum: 143, msg: 'Channel Backup Restore: ' + JSON.stringify(err)});
return res.status(404).json({
message: 'Channel restore failed!',
error: err.error
error: err.error.error
});
});
}
};
exports.getRestoreList = (req, res, next) => {
let files_list = [];
let all_restore_exists = false;
fs.readdir(common.selectedNode.channel_backup_path + common.path_separator + 'restore', function (err, files) {
if (err) {
if (err.code === 'ENOENT' && err.errno === -4058) {
return res.status(200).json({all_restore_exists: false, files: []});
} else {
return res.status(500).json({ message: 'Channels Restore List Failed!', error: err });
}
}
files.forEach(file => {
if (file === 'channel-all.bak') {
all_restore_exists = true;
} else {
files_list.push({channel_point: file.substring(8, file.length - 4).replace('-', ':')});
}
});
return res.status(200).json({all_restore_exists: all_restore_exists, files: files_list});
});
};

@ -4,6 +4,7 @@ const router = express.Router();
const authCheck = require("../authCheck");
router.get("/:channelPoint", authCheck, ChannelsBackupController.getBackup);
router.get("/restore/list", authCheck, ChannelsBackupController.getRestoreList);
router.post("/verify/:channelPoint", authCheck, ChannelsBackupController.postBackupVerify);
router.post("/restore/:channelPoint", authCheck, ChannelsBackupController.postRestore);

@ -1,10 +1,9 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router, NavigationStart, ActivatedRoute } from '@angular/router';
import { ActivatedRoute } from '@angular/router';
import { Subject, Observable } from 'rxjs';
import { takeUntil, filter, map, subscribeOn } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { ChannelCL, PeerCL, GetInfoCL, ChannelEdgeCL } from '../../shared/models/clModels';

@ -3,15 +3,14 @@
<mat-card>
<mat-card-header>
<mat-card-subtitle>
<h2>All Channels Backup</h2>
<h2>Channels Backup</h2>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign="space-between start">
<h4 fxFlex="100">Backup folder location: {{selNode.channelBackupPath}}</h4>
<button fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="1" (click)="onBackupChannels({})">Backup</button>
<button fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2" (click)="onVerifyChannels({})">Verify Backup</button>
<button fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="accent" tabindex="3" (click)="onRestoreChannels({})">Restore</button>
<button fxFlex="49" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="1" (click)="onBackupChannels({})">All Channels Backup</button>
<button fxFlex="49" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2" (click)="onVerifyChannels({})">All Channels Verify Backup</button>
</div>
</mat-card-content>
</mat-card>
@ -27,9 +26,9 @@
<div perfectScrollbar class="table-container mat-elevation-z8">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="channels" matSort [ngClass]="{'mat-elevation-z8 overflow-x-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-x-auto': true}">
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Channel ID </th>
<td mat-cell *matCellDef="let channel">{{channel?.chan_id}}</td>
<ng-container matColumnDef="chan_point">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Channel Point </th>
<td mat-cell *matCellDef="let channel">{{channel?.channel_point}}</td>
</ng-container>
<ng-container matColumnDef="backup">
<th mat-header-cell *matHeaderCellDef>Backup</th>
@ -39,10 +38,6 @@
<th mat-header-cell *matHeaderCellDef>Verify</th>
<td mat-cell *matCellDef="let channel"><mat-icon color="primary" (click)="onVerifyChannels(channel)">verified_user</mat-icon></td>
</ng-container>
<ng-container matColumnDef="restore">
<th mat-header-cell *matHeaderCellDef>Restore</th>
<td mat-cell *matCellDef="let channel"><mat-icon color="accent" (click)="onRestoreChannels(channel)">restore</mat-icon></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="onChannelClick(row, $event)"></tr>
</table>

@ -1,6 +1,10 @@
.mat-column-chan_id {
flex: 0 0 25%;
.mat-column-chan_point {
flex: 1 1 25%;
min-width: 100px;
max-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
table {

@ -23,7 +23,7 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
export class ChannelBackupComponent implements OnInit, OnDestroy {
@ViewChild(MatSort, { static: true }) sort: MatSort;
public selNode: SelNodeChild = {};
public displayedColumns = ['chan_id', 'backup', 'verify', 'restore'];
public displayedColumns = ['chan_point', 'backup', 'verify'];
public selChannel: Channel;
public channels: any;
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: channels
@ -82,11 +82,6 @@ export class ChannelBackupComponent implements OnInit, OnDestroy {
this.store.dispatch(new RTLActions.VerifyChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL'}));
}
onRestoreChannels(selChannel: Channel) {
this.store.dispatch(new RTLActions.OpenSpinner('Restoring Channels...'));
this.store.dispatch(new RTLActions.RestoreChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL'}));
}
onChannelClick(selRow: Channel, event: any) {
const flgButtonsClicked = event.target.className.includes('mat-icon')
|| event.target.className.includes('mat-column-backup')

@ -0,0 +1,51 @@
<div fxLayout="column">
<div class="padding-gap" *ngIf="allRestoreExists">
<mat-card>
<mat-card-header>
<mat-card-subtitle>
<h2>Channels Restore</h2>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign="space-between start">
<h4 fxFlex="100">Restore folder location: {{selNode.channelBackupPath}}/restore</h4>
<button fxFlex="49" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="1" (click)="onRestoreChannels({})">All Channels Restore</button>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="padding-gap">
<mat-card>
<mat-card-header *ngIf="!allRestoreExists">
<mat-card-subtitle>
<h2>Channels Restore</h2>
<h4 fxLayout="row" fxLayoutAlign="start start" class="pt-2">Restore folder location: {{selNode.channelBackupPath}}/restore</h4>
</mat-card-subtitle>
</mat-card-header>
<mat-card-content class="table-card-content" *ngIf="!channels || channels.data.length<=0">Backup file/s not found!<br>To perform channel restoration, channel backup file/s must be placed at the above location.</mat-card-content>
<mat-card-content class="table-card-content" *ngIf="channels && channels.data.length>0">
<div fxLayout="row" fxLayoutAlign="start start">
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<div perfectScrollbar class="table-container mat-elevation-z8">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="channels" matSort [ngClass]="{'mat-elevation-z8 overflow-x-auto error-border': flgLoading[0]==='error','mat-elevation-z8 overflow-x-auto': true}">
<ng-container matColumnDef="chan_point">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Channel Point </th>
<td mat-cell *matCellDef="let channel">{{channel?.channel_point}}</td>
</ng-container>
<ng-container matColumnDef="restore">
<th mat-header-cell *matHeaderCellDef>Restore</th>
<td mat-cell *matCellDef="let channel"><mat-icon color="primary" (click)="onRestoreChannels(channel)">restore</mat-icon></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-card-content>
</mat-card>
</div>
</div>

@ -0,0 +1,12 @@
.mat-column-chan_point {
flex: 1 1 25%;
min-width: 100px;
max-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
table {
width:100%;
}

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

@ -0,0 +1,80 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { MatTableDataSource, MatSort } from '@angular/material';
import { SelNodeChild } from '../../../shared/models/RTLconfig';
import { Channel } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { LNDEffects } from '../../../lnd/store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-channel-restore',
templateUrl: './channel-restore.component.html',
styleUrls: ['./channel-restore.component.scss']
})
export class ChannelRestoreComponent implements OnInit {
@ViewChild(MatSort, { static: true }) sort: MatSort;
public selNode: SelNodeChild = {};
public displayedColumns = ['chan_point', 'restore'];
public selChannel: Channel;
public channels: any;
public allRestoreExists = false;
public flgLoading: Array<Boolean | 'error'> = [true]; // 0: channels
public flgSticky = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private lndEffects: LNDEffects, private actions$: Actions) {}
ngOnInit() {
this.store.dispatch(new RTLActions.RestoreChannelsList());
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => {
this.selNode = rtlStore.nodeSettings;
// rtlStore.effectErrorsLnd.forEach(effectsErr => {
// if (effectsErr.action === 'RestoreChannelsList') {
// this.flgLoading[0] = 'error';
// }
// });
this.logger.info(rtlStore);
});
this.lndEffects.setRestoreChannelList
.pipe(takeUntil(this.unSubs[0]))
.subscribe((resRCList) => {
this.allRestoreExists = resRCList.all_restore_exists;
this.channels = new MatTableDataSource([...resRCList.files]);
this.channels.data = resRCList.files;
this.channels.sort = this.sort;
if (this.flgLoading[0] !== 'error' || (resRCList && resRCList.files)) {
this.flgLoading[0] = false;
}
this.logger.info(resRCList);
});
}
onRestoreChannels(selChannel: Channel) {
this.store.dispatch(new RTLActions.OpenSpinner('Restoring Channels...'));
this.store.dispatch(new RTLActions.RestoreChannels({channelPoint: (selChannel.channel_point) ? selChannel.channel_point : 'ALL'}));
}
applyFilter(selFilter: string) {
this.channels.filter = selFilter;
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -21,6 +21,7 @@ import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelLookupComponent } from './lookups/channel-lookup/channel-lookup.component';
import { NodeLookupComponent } from './lookups/node-lookup/node-lookup.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component';
import { QueryRoutesComponent } from './payments/query-routes/query-routes.component';
import { CommonService } from '../shared/services/common.service';
@ -51,7 +52,8 @@ import { LNDUnlockedGuard } from '../shared/services/auth.guard';
ChannelLookupComponent,
NodeLookupComponent,
ChannelBackupComponent,
QueryRoutesComponent
QueryRoutesComponent,
ChannelRestoreComponent
],
providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService },

@ -17,6 +17,7 @@ import { LookupsComponent } from './lookups/lookups.component';
import { ForwardingHistoryComponent } from './switch/forwarding-history.component';
import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component';
import { LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
@ -31,6 +32,7 @@ export const LndRoutes: Routes = [
{ path: 'chnlmanage', component: ChannelManageComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlpending', component: ChannelPendingComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlbackup', component: ChannelBackupComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlrestore', component: ChannelRestoreComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'transsendreceive', component: SendReceiveTransComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'translist', component: ListTransactionsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'paymentsend', component: PaymentsComponent, canActivate: [LNDUnlockedGuard] },

@ -448,7 +448,7 @@ export class LNDEffects implements OnDestroy {
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Unable to Restore Channel. Try again later.',
message: JSON.stringify({ code: err.status, Message: err.error.message })
message: JSON.stringify({ code: err.status, Message: err.error.error })
}
}
}
@ -1166,6 +1166,51 @@ export class LNDEffects implements OnDestroy {
})
);
@Effect()
getRestoreChannelList = this.actions$.pipe(
ofType(RTLActions.RESTORE_CHANNELS_LIST),
mergeMap((action: RTLActions.RestoreChannelsList) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('RestoreChannelsList'));
return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_BACKUP_API + '/restore/list')
.pipe(
map((resRestoreList) => {
this.logger.info(resRestoreList);
this.store.dispatch(new RTLActions.CloseSpinner());
return {
type: RTLActions.SET_RESTORE_CHANNELS_LIST,
payload: (resRestoreList) ? resRestoreList : {all_restore_exists: false, files: []}
};
}),
catchError((err: any) => {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.EffectErrorLnd({ action: 'RestoreChannelsList', code: err.status, message: err.error.message }));
this.logger.error(err);
return of(
{
type: RTLActions.OPEN_ALERT,
payload: {
width: '70%', data: {
type: 'ERROR', titleMessage: 'Restore Channels List Failed',
message: JSON.stringify({ Code: err.status, Message: err.error, URL: this.CHILD_API_URL + environment.CHANNELS_BACKUP_API })
}
}
}
);
})
);
})
);
@Effect({ dispatch: false })
setRestoreChannelList = this.actions$.pipe(
ofType(RTLActions.SET_RESTORE_CHANNELS_LIST),
map((action: RTLActions.SetRestoreChannelsList) => {
this.logger.info(action.payload);
return action.payload;
})
);
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();

@ -24,8 +24,8 @@
</div>
</div>
</mat-tree-node>
<mat-nested-tree-node fxLayout="column" *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle routerLink="{{node.link}}">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" class="mat-nested-tree-node-parent" (click)="onParentNodeClicked()">
<mat-nested-tree-node fxLayout="column" *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" class="mat-nested-tree-node-parent">
<div fxFlex="89" fxLayoutAlign="start center">
<mat-icon class="mr-1" matTooltip="{{node.name}}" matTooltipPosition="right" [matTooltipDisabled]="settings.menuType !== 'Mini'">{{node.icon}}</mat-icon><span *ngIf="settings.menuType !== 'Mini'">{{node.name}}</span>
</div>
@ -46,12 +46,12 @@
</mat-tree>
<mat-tree [dataSource]="navMenus" [treeControl]="treeControlNested" class="example-tree" *ngIf="settings.menuType === 'Compact'">
<mat-tree-node fxLayout="column" fxLayoutAlign="center center" *matTreeNodeDef="let node" matTreeNodeToggle (click)="onChildNavClicked(node)" routerLinkActive="active-link" routerLink="{{node.link}}">
<mat-tree-node fxLayout="column" matTreeNodeToggle fxLayoutAlign="center center" *matTreeNodeDef="let node" (click)="onChildNavClicked(node)" 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>
<mat-nested-tree-node fxLayout="column" *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle routerLink="{{node.link}}">
<mat-nested-tree-node fxLayout="column" *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle>
<div class="ml-8" fxLayout="column" fxLayoutAlign="center center" class="mat-nested-tree-node-parent">
<mat-icon class="mat-icon-36">{{node.icon}}</mat-icon>
<span>{{node.name}}</span>

@ -113,18 +113,12 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
});
}
this.ChildNavClicked.emit(node);
this.treeControlNested.collapseAll();
}
onChildNavClicked(node) {
this.ChildNavClicked.emit(node);
this.treeControlNested.collapseAll();
}
onParentNodeClicked() {
this.treeControlNested.collapseAll();
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();

@ -10,7 +10,8 @@ export const MENU_DATA: MenuRootNode = {
{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: 44, parentId: 4, name: 'Backup', icon: 'cloud_circle', link: '/lnd/chnlbackup'},
{id: 45, parentId: 4, name: 'Restore', icon: 'restore', link: '/lnd/chnlrestore'}
]},
{id: 5, parentId: 0, name: 'Payments', icon: 'payment', link: '/lnd/paymentsend', children: [
{id: 51, parentId: 5, name: 'Send', icon: 'send', link: '/lnd/paymentsend'},

@ -60,6 +60,8 @@ export const BACKUP_CHANNELS = 'BACKUP_CHANNELS';
export const VERIFY_CHANNELS = 'VERIFY_CHANNELS';
export const BACKUP_CHANNELS_RES = 'BACKUP_CHANNELS_RES';
export const VERIFY_CHANNELS_RES = 'VERIFY_CHANNELS_RES';
export const RESTORE_CHANNELS_LIST = 'RESTORE_CHANNELS_LIST';
export const SET_RESTORE_CHANNELS_LIST = 'SET_RESTORE_CHANNELS_LIST';
export const RESTORE_CHANNELS = 'RESTORE_CHANNELS';
export const RESTORE_CHANNELS_RES = 'RESTORE_CHANNELS_RES';
export const FETCH_INVOICES = 'FETCH_INVOICES';
@ -394,6 +396,15 @@ export class VerifyChannelsRes implements Action {
constructor(public payload: string) {}
}
export class RestoreChannelsList implements Action {
readonly type = RESTORE_CHANNELS_LIST;
}
export class SetRestoreChannelsList implements Action {
readonly type = SET_RESTORE_CHANNELS_LIST;
constructor(public payload: {all_restore_exists: boolean, files: []}) {}
}
export class RestoreChannels implements Action {
readonly type = RESTORE_CHANNELS;
constructor(public payload: {channelPoint: string}) {}
@ -807,7 +818,8 @@ export type RTLActions =
FetchNetwork | SetNetwork |
FetchChannels | SetChannels | SetPendingChannels | SetClosedChannels | UpdateChannels |
SaveNewChannel | CloseChannel | RemoveChannel |
BackupChannels | VerifyChannels | BackupChannelsRes | VerifyChannelsRes | RestoreChannels | RestoreChannelsRes |
BackupChannels | VerifyChannels | BackupChannelsRes | VerifyChannelsRes |
RestoreChannels | RestoreChannelsRes | RestoreChannelsList | SetRestoreChannelsList |
FetchTransactions | SetTransactions |
FetchInvoices | SetInvoices | SetTotalInvoices |
FetchPayments | SetPayments | SendPayment |

@ -254,11 +254,11 @@ export class RTLEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
let selNode = { channelBackupPath: action.payload.lnNode.settings.channelBackupPath, satsToBTC: action.payload.lnNode.settings.satsToBTC };
this.store.dispatch(new RTLActions.ResetRootStore(action.payload.lnNode));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
if (sessionStorage.getItem('token')) {
let selNode = { channelBackupPath: action.payload.lnNode.settings.channelBackupPath, satsToBTC: action.payload.lnNode.settings.satsToBTC };
this.store.dispatch(new RTLActions.ResetRootStore(action.payload.lnNode));
this.store.dispatch(new RTLActions.ResetLNDStore(selNode));
this.store.dispatch(new RTLActions.ResetCLStore(selNode));
let newRoute = this.location.path();
if(action.payload.lnNode.lnImplementation.toUpperCase() === 'CLT') {
if(newRoute.includes('/lnd/')) {

Loading…
Cancel
Save