Release 0.12.2 (#964)
Release 0.12.2. Co-authored-by: saiy2k <saiy2k@gmail.com> Co-authored-by: bota87 <52842374+bota87@users.noreply.github.com> Co-authored-by: Bota <Bota@ASUS> Co-authored-by: Harshvardhan R <harshvardhanr.181it217@nitk.edu.in>pull/969/head
parent
9c59954205
commit
3910284d58
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var i=g[e];if(void 0!==i)return i.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(i,t,f,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,o]=e[n],s=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var d=f();void 0!==d&&(i=d)}}return i}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,f,o]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>e+"."+{632:"2ee91869a10494c2",637:"d1905636b60ffa80",859:"88e2ffd83f4b1f85",893:"bc205686870d1329"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="RTLApp:";r.l=(t,f,o,n)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==i+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+o),a.src=r.tu(t)),e[t]=[f];var c=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=f){var a=new Promise((l,c)=>n=e[f]=[l,c]);o.push(n[2]=a);var s=r.p+r.u(f),u=new Error;r.l(s,l=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",u.name="ChunkLoadError",u.type=c,u.request=p,n[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,o)=>{var u,d,[n,a,s]=o,l=0;if(n.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(s)var c=s(r)}for(f&&f(o);l<n.length;l++)r.o(e,d=n[l])&&e[d]&&e[d][0](),e[n[l]]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
@ -0,0 +1 @@
|
||||
(()=>{"use strict";var e,v={},g={};function r(e){var i=g[e];if(void 0!==i)return i.exports;var t=g[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(i,t,f,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,f,o]=e[n],c=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=f();void 0!==d&&(i=d)}}return i}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,f,o]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>e+"."+{37:"d8c372593cfce7d0",634:"eb0b1dccb37a5b7b",637:"ab593ccfc00736f3",893:"050b2235bfbe164a"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="RTLApp:";r.l=(t,f,o,n)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==i+o){a=l;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+o),a.src=r.tu(t)),e[t]=[f];var s=(m,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(_=>_(b)),m)return m(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(f,o)=>{var n=r.o(e,f)?e[f]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=f){var a=new Promise((l,s)=>n=e[f]=[l,s]);o.push(n[2]=a);var c=r.p+r.u(f),u=new Error;r.l(c,l=>{if(r.o(e,f)&&(0!==(n=e[f])&&(e[f]=void 0),n)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",u.name="ChunkLoadError",u.type=s,u.request=p,n[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var i=(f,o)=>{var u,d,[n,a,c]=o,l=0;if(n.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(c)var s=c(r)}for(f&&f(o);l<n.length;l++)r.o(e,d=n[l])&&e[d]&&e[d][0](),e[n[l]]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
@ -0,0 +1,54 @@
|
||||
<div fxLayout="column" fxLayoutAlign="start stretch" class="padding-gap-x">
|
||||
<div class="p-2 error-border my-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
|
||||
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
|
||||
<div fxFlex="70"></div>
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="errorMessage === ''" [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
|
||||
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="failedLocalForwardingEvents" fxFlex="100" matSort class="overflow-auto">
|
||||
<ng-container matColumnDef="received_time">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Received Time</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{(fhEvent?.received_time * 1000) | date:'dd/MMM/y HH:mm'}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="in_channel">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>In Channel</th>
|
||||
<td mat-cell *matCellDef="let fhEvent">{{fhEvent?.in_channel_alias}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="in_msatoshi">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount In (Sats)</th>
|
||||
<td mat-cell *matCellDef="let fhEvent"><span fxLayoutAlign="end center">{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="failreason">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header class="pl-3">Fail Reason</th>
|
||||
<td mat-cell *matCellDef="let fhEvent" class="pl-3">{{CLFailReason[fhEvent?.failreason]}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="px-3">
|
||||
<div class="bordered-box table-actions-select">
|
||||
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
|
||||
<mat-select-trigger></mat-select-trigger>
|
||||
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
|
||||
</mat-select>
|
||||
</div>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let fhEvent" class="px-3" fxLayoutAlign="end center">
|
||||
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onFailedLocalEventClick(fhEvent)">View Info</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="no_event">
|
||||
<td mat-footer-cell *matFooterCellDef colspan="4">
|
||||
<p *ngIf="(!failedLocalForwardingEvents?.data || failedLocalForwardingEvents?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.COMPLETED">No failed transaction available.</p>
|
||||
<p *ngIf="(!failedLocalForwardingEvents?.data || failedLocalForwardingEvents?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.INITIATED">Getting failed transactions...</p>
|
||||
<p *ngIf="(!failedLocalForwardingEvents?.data || failedLocalForwardingEvents?.data?.length<1) && apiCallStatus?.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-footer-row *matFooterRowDef="['no_event']" [ngClass]="{'display-none': failedLocalForwardingEvents?.data && failedLocalForwardingEvents?.data?.length>0}"></tr>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
<mat-paginator *ngIf="errorMessage === ''" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
|
||||
</div>
|
@ -0,0 +1,3 @@
|
||||
.mat-column-actions {
|
||||
min-height: 4.8rem;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
|
||||
import { RootReducer } from '../../../store/rtl.reducers';
|
||||
import { LNDReducer } from '../../../lnd/store/lnd.reducers';
|
||||
import { CLReducer } from '../../store/cl.reducers';
|
||||
import { ECLReducer } from '../../../eclair/store/ecl.reducers';
|
||||
import { CommonService } from '../../../shared/services/common.service';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
|
||||
import { CLLocalFailedTransactionsComponent } from './local-failed-transactions.component';
|
||||
import { mockDataService, mockLoggerService } from '../../../shared/test-helpers/mock-services';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { DataService } from '../../../shared/services/data.service';
|
||||
|
||||
describe('CLLocalFailedTransactionsComponent', () => {
|
||||
let component: CLLocalFailedTransactionsComponent;
|
||||
let fixture: ComponentFixture<CLLocalFailedTransactionsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CLLocalFailedTransactionsComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
RouterTestingModule,
|
||||
SharedModule,
|
||||
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cl: CLReducer, ecl: ECLReducer })
|
||||
],
|
||||
providers: [
|
||||
CommonService,
|
||||
{ provide: LoggerService, useClass: mockLoggerService },
|
||||
{ provide: DataService, useClass: mockDataService }
|
||||
]
|
||||
}).
|
||||
compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CLLocalFailedTransactionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
});
|
@ -0,0 +1,147 @@
|
||||
import { Component, OnInit, ViewChild, OnDestroy, AfterViewInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
|
||||
import { LocalFailedEvent } from '../../../shared/models/clModels';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, AlertTypeEnum, DataTypeEnum, ScreenSizeEnum, APICallStatusEnum, CLFailReason } from '../../../shared/services/consts-enums-functions';
|
||||
import { ApiCallStatusPayload } from '../../../shared/models/apiCallsPayload';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
import { CommonService } from '../../../shared/services/common.service';
|
||||
|
||||
import { RTLState } from '../../../store/rtl.state';
|
||||
import { openAlert } from '../../../store/rtl.actions';
|
||||
import { getLocalFailedForwardingHistory } from '../../store/cl.actions';
|
||||
import { localFailedForwardingHistory } from '../../store/cl.selector';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-cl-local-failed-history',
|
||||
templateUrl: './local-failed-transactions.component.html',
|
||||
styleUrls: ['./local-failed-transactions.component.scss'],
|
||||
providers: [
|
||||
{ provide: MatPaginatorIntl, useValue: getPaginatorLabel('Local Failed Events') }
|
||||
]
|
||||
})
|
||||
export class CLLocalFailedTransactionsComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
@ViewChild(MatSort, { static: false }) sort: MatSort | undefined;
|
||||
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator | undefined;
|
||||
public CLFailReason = CLFailReason;
|
||||
public failedLocalEvents: any;
|
||||
public errorMessage = '';
|
||||
public displayedColumns: any[] = [];
|
||||
public failedLocalForwardingEvents: any;
|
||||
public flgSticky = false;
|
||||
public selFilter = '';
|
||||
public pageSize = PAGE_SIZE;
|
||||
public pageSizeOptions = PAGE_SIZE_OPTIONS;
|
||||
public screenSize = '';
|
||||
public screenSizeEnum = ScreenSizeEnum;
|
||||
public apiCallStatus: ApiCallStatusPayload = null;
|
||||
public apiCallStatusEnum = APICallStatusEnum;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>, private datePipe: DatePipe, private router: Router) {
|
||||
this.screenSize = this.commonService.getScreenSize();
|
||||
if (this.screenSize === ScreenSizeEnum.XS) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['received_time', 'in_channel', 'in_msatoshi', 'actions'];
|
||||
} else if (this.screenSize === ScreenSizeEnum.SM || this.screenSize === ScreenSizeEnum.MD) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['received_time', 'in_channel', 'in_msatoshi', 'actions'];
|
||||
} else {
|
||||
this.flgSticky = true;
|
||||
this.displayedColumns = ['received_time', 'in_channel', 'in_msatoshi', 'failreason', 'actions'];
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||
this.router.onSameUrlNavigation = 'reload';
|
||||
this.store.dispatch(getLocalFailedForwardingHistory());
|
||||
this.store.select(localFailedForwardingHistory).pipe(takeUntil(this.unSubs[0])).
|
||||
subscribe((lffhSeletor: { localFailedForwardingHistory: LocalFailedEvent[], apiCallStatus: ApiCallStatusPayload }) => {
|
||||
this.errorMessage = '';
|
||||
this.apiCallStatus = lffhSeletor.apiCallStatus;
|
||||
if (this.apiCallStatus.status === APICallStatusEnum.ERROR) {
|
||||
this.errorMessage = (typeof (this.apiCallStatus.message) === 'object') ? JSON.stringify(this.apiCallStatus.message) : this.apiCallStatus.message;
|
||||
}
|
||||
this.failedLocalEvents = lffhSeletor.localFailedForwardingHistory || [];
|
||||
if (this.failedLocalEvents.length > 0 && this.sort && this.paginator) {
|
||||
this.loadLocalfailedLocalEventsTable(this.failedLocalEvents);
|
||||
}
|
||||
this.logger.info(lffhSeletor);
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
if (this.failedLocalEvents.length > 0) {
|
||||
this.loadLocalfailedLocalEventsTable(this.failedLocalEvents);
|
||||
}
|
||||
}
|
||||
|
||||
onFailedLocalEventClick(selFEvent: LocalFailedEvent) {
|
||||
const reorderedFHEvent = [
|
||||
[{ key: 'received_time', value: selFEvent.received_time, title: 'Received Time', width: 50, type: DataTypeEnum.DATE_TIME },
|
||||
{ key: 'in_channel_alias', value: selFEvent.in_channel_alias, title: 'Inbound Channel', width: 50, type: DataTypeEnum.STRING }],
|
||||
[{ key: 'in_msatoshi', value: selFEvent.in_msatoshi, title: 'Amount In (mSats)', width: 100, type: DataTypeEnum.NUMBER }],
|
||||
[{ key: 'failreason', value: this.CLFailReason[selFEvent.failreason], title: 'Reason for Failure', width: 100, type: DataTypeEnum.STRING }]
|
||||
];
|
||||
this.store.dispatch(openAlert({
|
||||
payload: {
|
||||
data: {
|
||||
type: AlertTypeEnum.INFORMATION,
|
||||
alertTitle: 'Local Failed Event Information',
|
||||
message: reorderedFHEvent
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
loadLocalfailedLocalEventsTable(forwardingEvents: LocalFailedEvent[]) {
|
||||
this.failedLocalForwardingEvents = new MatTableDataSource<LocalFailedEvent>([...forwardingEvents]);
|
||||
this.failedLocalForwardingEvents.filterPredicate = (event: LocalFailedEvent, fltr: string) => {
|
||||
const newEvent = ((event.received_time ? this.datePipe.transform(new Date(event.received_time * 1000), 'dd/MMM/YYYY HH:mm').toLowerCase() : '') +
|
||||
(event.in_channel_alias ? event.in_channel_alias.toLowerCase() : '') +
|
||||
((event.failreason && this.CLFailReason[event.failreason]) ? this.CLFailReason[event.failreason].toLowerCase() : '') +
|
||||
(event.in_msatoshi ? (event.in_msatoshi / 1000) : ''));
|
||||
return newEvent.includes(fltr);
|
||||
};
|
||||
this.failedLocalForwardingEvents.sort = this.sort;
|
||||
this.failedLocalForwardingEvents.sortingDataAccessor = (data: LocalFailedEvent, sortHeaderId: string) => {
|
||||
switch (sortHeaderId) {
|
||||
case 'failreason':
|
||||
return this.CLFailReason[data.failreason];
|
||||
|
||||
default:
|
||||
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
|
||||
}
|
||||
};
|
||||
this.failedLocalForwardingEvents.paginator = this.paginator;
|
||||
this.applyFilter();
|
||||
this.logger.info(this.failedLocalForwardingEvents);
|
||||
}
|
||||
|
||||
onDownloadCSV() {
|
||||
if (this.failedLocalForwardingEvents && this.failedLocalForwardingEvents.data && this.failedLocalForwardingEvents.data.length > 0) {
|
||||
this.commonService.downloadFile(this.failedLocalForwardingEvents.data, 'Local-failed-transactions');
|
||||
}
|
||||
}
|
||||
|
||||
applyFilter() {
|
||||
this.failedLocalForwardingEvents.filter = this.selFilter.trim().toLowerCase();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach((completeSub) => {
|
||||
completeSub.next(null);
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="padding-gap-x-large">
|
||||
<div class="p-2 error-border my-2" *ngIf="errorMessage !== ''">{{errorMessage}}</div>
|
||||
<div *ngIf="errorMessage === ''" fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
|
||||
<div *ngIf="errorMessage === ''" fxLayout="column" fxLayout.gt-xs="row" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch" class="page-sub-title-container">
|
||||
<div fxFlex="70">Non Routing Peers</div>
|
||||
<mat-form-field fxFlex="30">
|
||||
<input matInput (keyup)="applyFilter()" [(ngModel)]="filter" placeholder="Filter">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="errorMessage === ''" [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
|
||||
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
|
||||
<table mat-table #table [dataSource]="NonRoutingPeers" matSort class="overflow-auto">
|
||||
<ng-container matColumnDef="chan_id">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Channel ID</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{nonRPeer.chan_id}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="remote_alias">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Peer Alias</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{nonRPeer.remote_alias}}</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="total_satoshis_sent">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Sent</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer"><span fxLayoutAlign="end center">{{nonRPeer.total_satoshis_sent | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="total_satoshis_received">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Sats Received</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer"><span fxLayoutAlign="end center">{{nonRPeer.total_satoshis_received | number}}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="local_balance">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Local Balance (Sats)</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer"><span fxLayoutAlign="end center">{{nonRPeer.local_balance | number}}</span>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="remote_balance">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Remote Balance (Sats)</th>
|
||||
<td mat-cell *matCellDef="let nonRPeer"><span fxLayoutAlign="end center">{{nonRPeer.remote_balance | number}}</span></td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef class="pr-3"><span fxLayoutAlign="end center">Actions</span></th>
|
||||
<td mat-cell *matCellDef="let nonRPeer" class="pl-2" fxLayoutAlign="end center">
|
||||
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onManagePeer(nonRPeer)">Manage</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="no_non_routing_event">
|
||||
<td mat-footer-cell *matFooterCellDef colspan="4">
|
||||
<p *ngIf="(!NonRoutingPeers?.data || NonRoutingPeers?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.COMPLETED">All peers are routing.</p>
|
||||
<p *ngIf="(!NonRoutingPeers?.data || NonRoutingPeers?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.INITIATED">Getting non routing peers...</p>
|
||||
<p *ngIf="(!NonRoutingPeers?.data || NonRoutingPeers?.data?.length<1) && apiCallStatus.status === apiCallStatusEnum.ERROR">{{errorMessage}}</p>
|
||||
</td>
|
||||
</ng-container>
|
||||
<tr mat-footer-row *matFooterRowDef="['no_non_routing_event']" [ngClass]="{'display-none': NonRoutingPeers?.data?.length>0}"></tr>
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
<mat-paginator #paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" [showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,10 @@
|
||||
.mat-column-chan_id, .mat-column-alias {
|
||||
flex: 1 1 25%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mat-column-actions {
|
||||
min-height: 4.8rem;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { RootReducer } from '../../../store/rtl.reducers';
|
||||
import { LNDReducer } from '../../store/lnd.reducers';
|
||||
import { CLReducer } from '../../../clightning/store/cl.reducers';
|
||||
import { ECLReducer } from '../../../eclair/store/ecl.reducers';
|
||||
import { CommonService } from '../../../shared/services/common.service';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
|
||||
import { NonRoutingPeersComponent } from './non-routing-peers.component';
|
||||
import { mockDataService, mockLoggerService } from '../../../shared/test-helpers/mock-services';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { DataService } from '../../../shared/services/data.service';
|
||||
|
||||
describe('NonRoutingPeersComponent', () => {
|
||||
let component: NonRoutingPeersComponent;
|
||||
let fixture: ComponentFixture<NonRoutingPeersComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [NonRoutingPeersComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
SharedModule,
|
||||
RouterTestingModule,
|
||||
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cl: CLReducer, ecl: ECLReducer })
|
||||
],
|
||||
providers: [
|
||||
CommonService,
|
||||
{ provide: LoggerService, useClass: mockLoggerService },
|
||||
{ provide: DataService, useClass: mockDataService }
|
||||
]
|
||||
}).
|
||||
compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NonRoutingPeersComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
});
|
@ -0,0 +1,154 @@
|
||||
import { Component, OnInit, ViewChild, OnDestroy, AfterViewInit } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
|
||||
|
||||
import { ForwardingEvent, SwitchRes, Channel, ChannelsSummary, LightningBalance } from '../../../shared/models/lndModels';
|
||||
import { APICallStatusEnum, getPaginatorLabel, PAGE_SIZE, PAGE_SIZE_OPTIONS, ScreenSizeEnum } from '../../../shared/services/consts-enums-functions';
|
||||
import { ApiCallStatusPayload } from '../../../shared/models/apiCallsPayload';
|
||||
import { LoggerService } from '../../../shared/services/logger.service';
|
||||
import { CommonService } from '../../../shared/services/common.service';
|
||||
import { RTLState } from '../../../store/rtl.state';
|
||||
import { channels, forwardingHistory } from '../../store/lnd.selector';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'rtl-non-routing-peers',
|
||||
templateUrl: './non-routing-peers.component.html',
|
||||
styleUrls: ['./non-routing-peers.component.scss'],
|
||||
providers: [
|
||||
{ provide: MatPaginatorIntl, useValue: getPaginatorLabel('Non routing peers') }
|
||||
]
|
||||
})
|
||||
export class NonRoutingPeersComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
@ViewChild(MatSort, { static: false }) sort: MatSort | undefined;
|
||||
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator | undefined;
|
||||
public routingPeersData = [];
|
||||
public displayedColumns: any[] = [];
|
||||
public NonRoutingPeers = new MatTableDataSource<any>([]);
|
||||
public flgSticky = false;
|
||||
public pageSize = PAGE_SIZE;
|
||||
public pageSizeOptions = PAGE_SIZE_OPTIONS;
|
||||
public screenSize = '';
|
||||
public screenSizeEnum = ScreenSizeEnum;
|
||||
public errorMessage = '';
|
||||
public filter = '';
|
||||
public activeChannels: Channel[] = [];
|
||||
public apiCallStatus: ApiCallStatusPayload = null;
|
||||
public apiCallStatusEnum = APICallStatusEnum;
|
||||
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
|
||||
|
||||
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>, private router: Router, private activatedRoute: ActivatedRoute) {
|
||||
this.screenSize = this.commonService.getScreenSize();
|
||||
if (this.screenSize === ScreenSizeEnum.XS) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['remote_alias', 'local_balance', 'remote_balance', 'actions'];
|
||||
} else if (this.screenSize === ScreenSizeEnum.SM) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['remote_alias', 'local_balance', 'remote_balance', 'actions'];
|
||||
} else if (this.screenSize === ScreenSizeEnum.MD) {
|
||||
this.flgSticky = false;
|
||||
this.displayedColumns = ['chan_id', 'remote_alias', 'local_balance', 'remote_balance', 'actions'];
|
||||
} else {
|
||||
this.flgSticky = true;
|
||||
this.displayedColumns = ['chan_id', 'remote_alias', 'total_satoshis_received', 'total_satoshis_sent', 'local_balance', 'remote_balance', 'actions'];
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.store.select(forwardingHistory).pipe(takeUntil(this.unSubs[0])).
|
||||
subscribe((fhSelector: { forwardingHistory: SwitchRes, apiCallStatus: ApiCallStatusPayload }) => {
|
||||
this.errorMessage = '';
|
||||
this.apiCallStatus = fhSelector.apiCallStatus;
|
||||
if (fhSelector.apiCallStatus?.status === APICallStatusEnum.ERROR) {
|
||||
this.errorMessage = (typeof (this.apiCallStatus.message) === 'object') ? JSON.stringify(this.apiCallStatus.message) : this.apiCallStatus.message;
|
||||
}
|
||||
if (fhSelector.forwardingHistory.forwarding_events) {
|
||||
this.routingPeersData = fhSelector.forwardingHistory.forwarding_events;
|
||||
} else {
|
||||
this.routingPeersData = [];
|
||||
}
|
||||
if (this.routingPeersData.length > 0 && this.sort && this.paginator) {
|
||||
this.loadNonRoutingPeersTable(this.routingPeersData);
|
||||
}
|
||||
this.logger.info(fhSelector.apiCallStatus);
|
||||
this.logger.info(fhSelector.forwardingHistory);
|
||||
});
|
||||
this.store.select(channels).pipe(takeUntil(this.unSubs[1])).
|
||||
subscribe((channelsSelector: { channels: Channel[], channelsSummary: ChannelsSummary, lightningBalance: LightningBalance, apiCallStatus: ApiCallStatusPayload }) => {
|
||||
this.errorMessage = '';
|
||||
this.apiCallStatus = channelsSelector.apiCallStatus;
|
||||
if (this.apiCallStatus.status === APICallStatusEnum.ERROR) {
|
||||
this.errorMessage = (typeof (this.apiCallStatus.message) === 'object') ? JSON.stringify(this.apiCallStatus.message) : this.apiCallStatus.message;
|
||||
}
|
||||
this.activeChannels = channelsSelector.channels;
|
||||
this.logger.info(channelsSelector);
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
if (this.routingPeersData.length > 0) {
|
||||
this.loadNonRoutingPeersTable(this.routingPeersData);
|
||||
}
|
||||
}
|
||||
|
||||
onManagePeer(selNonRoutingChannel: Channel) {
|
||||
this.router.navigate(['../../', 'connections', 'channels', 'open'], { relativeTo: this.activatedRoute, state: { filter: selNonRoutingChannel.chan_id } });
|
||||
}
|
||||
|
||||
// groupRoutingPeers(forwardingEvents: ForwardingEvent[]) {
|
||||
// const results: any[] = [];
|
||||
// forwardingEvents.forEach((event: ForwardingEvent) => {
|
||||
// const foundEntryInIdx = results.findIndex((result) => result.chan_id === event.chan_id_in);
|
||||
// const foundEntryOutIdx = results.findIndex((result) => result.chan_id === event.chan_id_out);
|
||||
// if (foundEntryInIdx < 0 && foundEntryOutIdx < 0) {
|
||||
// results.push({ chan_id: event.chan_id_in, alias: event.alias_in, amt_in_msat: +event.amt_in_msat, amt_out_msat: 0 });
|
||||
// results.push({ chan_id: event.chan_id_out, alias: event.alias_out, amt_out_msat: +event.amt_out_msat, amt_in_msat: 0 });
|
||||
// }
|
||||
// if (foundEntryInIdx < 0 && foundEntryOutIdx > -1) {
|
||||
// results.push({ chan_id: event.chan_id_in, alias: event.alias_in, amt_in_msat: +event.amt_in_msat, amt_out_msat: 0 });
|
||||
// results[foundEntryOutIdx].amt_out_msat = results[foundEntryOutIdx].amt_out_msat + +event.amt_out_msat;
|
||||
// }
|
||||
// if (foundEntryInIdx > -1 && foundEntryOutIdx < 0) {
|
||||
// results.push({ chan_id: event.chan_id_out, alias: event.alias_out, amt_out_msat: +event.amt_out_msat, amt_in_msat: 0 });
|
||||
// results[foundEntryInIdx].amt_in_msat = results[foundEntryInIdx].amt_in_msat + +event.amt_in_msat;
|
||||
// }
|
||||
// if (foundEntryInIdx > -1 && foundEntryOutIdx > -1) {
|
||||
// results[foundEntryInIdx].amt_in_msat = results[foundEntryInIdx].amt_in_msat + +event.amt_in_msat;
|
||||
// results[foundEntryOutIdx].amt_out_msat = results[foundEntryOutIdx].amt_out_msat + +event.amt_out_msat;
|
||||
// }
|
||||
// });
|
||||
// return this.commonService.sortDescByKey(results, 'alias');
|
||||
// }
|
||||
|
||||
loadNonRoutingPeersTable(forwardingEvents: ForwardingEvent[]) {
|
||||
if (forwardingEvents.length > 0) {
|
||||
// const grpdRoutingPeers = this.groupRoutingPeers(forwardingEvents);
|
||||
const filteredNonRoutingChannels = this.activeChannels.filter((actvChnl) => forwardingEvents.findIndex((evnt) => (evnt.chan_id_in === actvChnl.chan_id || evnt.chan_id_out === actvChnl.chan_id)) < 0);
|
||||
this.NonRoutingPeers = new MatTableDataSource<Channel>(filteredNonRoutingChannels);
|
||||
this.NonRoutingPeers.sort = this.sort;
|
||||
this.NonRoutingPeers.filterPredicate = (nrchnl: Channel, fltr: string) => JSON.stringify(nrchnl).toLowerCase().includes(fltr);
|
||||
this.NonRoutingPeers.paginator = this.paginator;
|
||||
this.logger.info(this.NonRoutingPeers);
|
||||
} else {
|
||||
this.NonRoutingPeers = new MatTableDataSource<Channel>([]);
|
||||
}
|
||||
this.applyFilter();
|
||||
}
|
||||
|
||||
applyFilter() {
|
||||
this.NonRoutingPeers.filter = this.filter.toLowerCase();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.unSubs.forEach((completeSub) => {
|
||||
completeSub.next(null);
|
||||
completeSub.complete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue