UX Updates

UX Updates
pull/260/head
Shahana Farooqui 4 years ago
parent 160c6645df
commit d256bf07a5

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

@ -9,8 +9,8 @@
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.bb61947bc04e5e880316.css"></head>
<link rel="stylesheet" href="styles.338691320cacab894cbc.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.27bfb56ae5ce2eeee2bd.js" defer></script><script src="polyfills-es5.b8e32dec482ae69710a2.js" nomodule defer></script><script src="polyfills.ebf9033c33aa4a5af12a.js" defer></script><script src="main.e03fbead8d2ea2dcc5eb.js" defer></script></body>
<script src="runtime.fd2304027495a03084f4.js" defer></script><script src="polyfills-es5.b8e32dec482ae69710a2.js" nomodule defer></script><script src="polyfills.ebf9033c33aa4a5af12a.js" defer></script><script src="main.3c7c21d18c4a53ccacf8.js" defer></script></body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +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++)a=i[p],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(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:"dbfa80f5eb3d9dedcde5",6:"9c41e3d9871cc0947fad",7:"6d45208b54eb5a5e833b"}[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,d=[];p<i.length;p++)a=i[p],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&d.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);d.length;)d.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:"dbfa80f5eb3d9dedcde5",6:"d53f7986e7638a0b1f30",7:"d63addcff4d7597f87ec"}[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()}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -226,7 +226,6 @@ exports.getCurrencyRates = (req, res, next) => {
options.url = 'https://blockchain.info/ticker';
console.log(options);
request(options).then((body) => {
logger.info({fileName: 'RTLConf', msg: 'Rates Received: ' + JSON.stringify(body)});
if(undefined === body || body.error) {
res.status(500).json({
message: "Fetching Rates Failed!",
@ -234,6 +233,8 @@ exports.getCurrencyRates = (req, res, next) => {
});
} else {
res.status(200).json(body);
body = JSON.parse(body);
logger.info({fileName: 'RTLConf', msg: 'Rates Received: ' + JSON.stringify(body)});
}
})
.catch(function (err) {

@ -1,9 +1,8 @@
import { Routes, RouterModule } from '@angular/router';
import { ModuleWithProviders } from '@angular/core';
import { AppSettingsComponent } from './shared/components/app-settings/app-settings.component';
import { SettingsComponent } from './shared/components/settings/settings.component';
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 { ErrorComponent } from './shared/components/error/error.component';
@ -12,8 +11,7 @@ import { AuthGuard } from './shared/services/auth.guard';
export const routes: Routes = [
{ 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: 'advanced', component: ServerConfigComponent, canActivate: [AuthGuard] },
{ path: 'settings', component: AppSettingsComponent, canActivate: [AuthGuard] },
{ path: 'settings', component: SettingsComponent, canActivate: [AuthGuard] },
{ path: 'help', component: HelpComponent },
{ path: 'login', component: SigninComponent },
{ path: 'error', component: ErrorComponent },

@ -45,10 +45,17 @@
</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 channel" fxLayoutAlign="end center" class="pl-3">
<th mat-header-cell *matHeaderCellDef fxLayoutAlign="end center" class="pl-1">
<div fxFlex="100" class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select placeholder="Table Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onChannelUpdate('all')">Update Fee Policy</mat-option>
</mat-select>
</div>
</th>
<td mat-cell *matCellDef="let channel" fxLayoutAlign="end center" class="pl-1">
<div fxFlex="100" class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="2" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option>
<mat-option (click)="onChannelUpdate(channel)">Update Fee Policy</mat-option>

@ -82,11 +82,11 @@ export class ChannelOpenTableComponent implements OnInit, OnDestroy {
onChannelUpdate(channelToUpdate: any) {
if (channelToUpdate === 'all') {
const titleMsg = 'Updated Values for ALL Channels';
const titleMsg = 'Updated fee policy for all the Channels';
const confirmationMsg = [];
this.store.dispatch(new RTLActions.OpenConfirmation({ data: {
type: AlertTypeEnum.CONFIRM,
alertTitle: 'Update Channel',
alertTitle: 'Update All Channels Fee Policy',
titleMessage: titleMsg,
noBtnText: 'Cancel',
yesBtnText: 'Update All Channels',

@ -1,18 +1,21 @@
<div fxLayout="column">
<mat-card fxLayout="column" fxLayoutAlign.gt-sm="space-between start" fxLayoutAlign.lt-md="space-between stretch" fxLayout.gt-sm="row wrap">
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="table-card-content">
<div perfectScrollbar class="table-container">
<div fxLayout="column" fxLayoutAlign="start stretch">
<div fxLayout="column" fxLayout.gt-md="row" fxFlex="100" fxLayoutAlign="space-between stretch" class="padding-gap-x page-sub-title-container">
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start start">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize === screenSizeEnum.XS, 'mt-1': screenSize === screenSizeEnum.SM}">
<div fxFlex="70">Incoming</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyIncomingFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<div perfectScrollbar fxLayout="row" fxLayoutAlign="start start" fxFlex="100" class="table-container w-100">
<table mat-table #tableIn [dataSource]="RoutingPeersIncoming" matSort fxFlex="100" class="overflow-auto incoming-table">
<ng-container matColumnDef="incoming">
<th mat-header-cell *matHeaderCellDef colspan="10">Incoming Traffic</th>
</ng-container>
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Channel ID</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.chan_id}}</td>
<td mat-cell *matCellDef="let rPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{rPeer.chan_id}}</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Peer Alias</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.alias}}</td>
<td mat-cell *matCellDef="let rPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{rPeer.alias}}</td>
</ng-container>
<ng-container matColumnDef="events">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Events</th>
@ -24,8 +27,8 @@
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.total_amount | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pl-4 pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let rPeer" class="pl-4">
<th mat-header-cell *matHeaderCellDef class="pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let rPeer" class="pl-2">
<button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onRoutingPeerClick(rPeer, $event, 'in')">View Info</button>
</td>
</ng-container>
@ -36,52 +39,52 @@
</ng-container>
<tr mat-footer-row *matFooterRowDef="['no_incoming_event']" [ngClass]="{'display-none': RoutingPeersIncoming.data && RoutingPeersIncoming.data.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-header-row *matHeaderRowDef="displayIncomingHeader"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<mat-card-content class="table-card-content" fxFlex="100">
<div perfectScrollbar class="table-container">
<table mat-table #tableOut [dataSource]="RoutingPeersOutgoing" class="overflow-auto outgoing-table">
<ng-container matColumnDef="outgoing">
<th mat-header-cell *matHeaderCellDef colspan="10">Outgoing Traffic</th>
</ng-container>
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Channel ID</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.chan_id}}</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Peer Alias</th>
<td mat-cell *matCellDef="let rPeer">{{rPeer.alias}}</td>
</ng-container>
<ng-container matColumnDef="events">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Events</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.events | number}}</span>
</td>
</ng-container>
<ng-container matColumnDef="total_amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Total Amount (Sats)</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.total_amount | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pl-4 pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let rPeer" class="pl-4">
<button mat-stroked-button color="primary" type="button" tabindex="5" (click)="onRoutingPeerClick(rPeer, $event, 'out')">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_outgoing_event">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="!RoutingPeersOutgoing.data || RoutingPeersOutgoing.data.length<1">No outgoing routing peer available.</p>
</td>
</ng-container>
<tr mat-footer-row *matFooterRowDef="['no_outgoing_event']" [ngClass]="{'display-none': RoutingPeersOutgoing.data && RoutingPeersOutgoing.data.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayOutgoingHeader"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</mat-card-content>
<div fxLayout="column" fxFlex="49" fxLayoutAlign="start start">
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="padding-gap-x page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize !== screenSizeEnum.LG}">
<div fxFlex="70">Outgoing</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyOutgoingFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<div perfectScrollbar fxLayout="row" fxLayoutAlign="start center" fxFlex="100" class="table-container w-100">
<table mat-table #tableOut [dataSource]="RoutingPeersOutgoing" matSort fxFlex="100" class="overflow-auto outgoing-table">
<ng-container matColumnDef="chan_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Channel ID</th>
<td mat-cell *matCellDef="let rPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{rPeer.chan_id}}</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Peer Alias</th>
<td mat-cell *matCellDef="let rPeer" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '28rem'}">{{rPeer.alias}}</td>
</ng-container>
<ng-container matColumnDef="events">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Events</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.events | number}}</span>
</td>
</ng-container>
<ng-container matColumnDef="total_amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Total Amount (Sats)</th>
<td mat-cell *matCellDef="let rPeer"><span fxLayoutAlign="end center">{{rPeer.total_amount | 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 rPeer" class="pl-2">
<button mat-stroked-button color="primary" type="button" tabindex="5" (click)="onRoutingPeerClick(rPeer, $event, 'out')">View Info</button>
</td>
</ng-container>
<ng-container matColumnDef="no_outgoing_event">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p *ngIf="!RoutingPeersOutgoing.data || RoutingPeersOutgoing.data.length<1">No outgoing routing peer available.</p>
</td>
</ng-container>
<tr mat-footer-row *matFooterRowDef="['no_outgoing_event']" [ngClass]="{'display-none': RoutingPeersOutgoing.data && RoutingPeersOutgoing.data.length>0}"></tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</mat-card>
</div>
</div>

@ -1,26 +1,6 @@
.mat-column-actions {
flex: 0 0 6%;
width: 6%;
}
.mat-column-chan_id, .mat-column-alias {
flex: 0 0 30%;
width: 30%;
}
.mat-column-events, .mat-column-total_amount {
flex: 0 0 17%;
width: 17%;
}
table.mat-table.incoming-table {
border-bottom: none !important;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
flex: 1 1 25%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
table.mat-table.outgoing-table {
border-top: none !important;
border-top-left-radius: 0 !important;
border-top-right-radius: 0 !important;
}

@ -21,26 +21,26 @@ export class RoutingPeersComponent implements OnInit, OnChanges {
@ViewChild(MatSort, { static: true }) sortOut: MatSort;
@Input() routingPeersData: any;
public displayedColumns = [];
public displayIncomingHeader = ['incoming'];
public displayOutgoingHeader = ['outgoing'];
public RoutingPeersIncoming: any;
public RoutingPeersOutgoing: any;
public flgSticky = false;
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {
let ss = this.commonService.getScreenSize();
if(ss === ScreenSizeEnum.XS) {
this.screenSize = this.commonService.getScreenSize();
if(this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['chan_id', 'events', 'actions'];
} else if(ss === ScreenSizeEnum.SM) {
} else if(this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['chan_id', 'events', 'total_amount', 'actions'];
} else if(ss === ScreenSizeEnum.MD) {
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
} else if(this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount', 'actions'];
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
} else {
this.flgSticky = true;
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount', 'actions'];
this.displayedColumns = ['chan_id', 'alias', 'events', 'total_amount'];
}
}
@ -115,4 +115,12 @@ export class RoutingPeersComponent implements OnInit, OnChanges {
return [this.commonService.sortDescByKey(incomingResults, 'total_amount'), this.commonService.sortDescByKey(outgoingResults, 'total_amount')];
}
applyIncomingFilter(selFilter: string) {
this.RoutingPeersIncoming.filter = selFilter;
}
applyOutgoingFilter(selFilter: string) {
this.RoutingPeersOutgoing.filter = selFilter;
}
}

@ -6,7 +6,7 @@
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start start" class="padding-gap-x">
<mat-card fxLayout="row" fxFlex="100" fxLayoutAlign="start start">
<mat-card-content fxLayout="column" fxFlex="100" fxLayoutAlign="start start" class="card-content-gap mt-1">
<form fxFlex="100" fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="w-100" (ngSubmit)="routingForm.form.valid && onEventsFetch()" #routingForm="ngForm">
<form fxFlex="100" fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="w-100 mb-1" (ngSubmit)="routingForm.form.valid && onEventsFetch()" #routingForm="ngForm">
<div fxFlex="100" fxLayoutAlign="space-between stretch">
<mat-form-field fxFlex="49" fxLayoutAlign="start">
<input matInput [matDatepicker]="startDatepicker" placeholder="Start Date" [max]="yesterday"

@ -7,7 +7,6 @@ import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { Location } from '@angular/common';
import { MatDialog } from '@angular/material';
import { MatSnackBar } from '@angular/material';
import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service';
@ -35,7 +34,6 @@ export class LNDEffects implements OnDestroy {
private logger: LoggerService,
private sessionService: SessionService,
public dialog: MatDialog,
private snackBar: MatSnackBar,
private router: Router,
private location: Location) { }
@ -170,11 +168,7 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ data: {
type: AlertTypeEnum.SUCCESS,
alertTitle: 'Peer Disconnected',
titleMessage: 'Peer Disconnected Successfully!'
}}));
this.store.dispatch(new RTLActions.OpenSnackBar('Peer Disconnected Successfully.'));
return {
type: RTLActions.REMOVE_PEER,
payload: { pubkey: action.payload.pubkey }
@ -261,7 +255,11 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ data: { type: AlertTypeEnum.SUCCESS, alertTitle: 'Channel Updated', titleMessage: 'Channel Updated Successfully!' }}));
if(action.payload.chanPoint === 'all') {
this.store.dispatch(new RTLActions.OpenSnackBar('All Channels Updated Successfully.'));
} else {
this.store.dispatch(new RTLActions.OpenSnackBar('Channel Updated Successfully!'));
}
return {
type: RTLActions.FETCH_ALL_CHANNELS
};
@ -315,7 +313,7 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.snackBar.open(action.payload.showMessage + ' ' + postRes.message);
this.store.dispatch(new RTLActions.OpenSnackBar(action.payload.showMessage + ' ' + postRes.message));
return {
type: RTLActions.BACKUP_CHANNELS_RES,
payload: postRes.message
@ -340,7 +338,7 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.snackBar.open(postRes.message);
this.store.dispatch(new RTLActions.OpenSnackBar(postRes.message));
return {
type: RTLActions.VERIFY_CHANNELS_RES,
payload: postRes.message
@ -365,7 +363,7 @@ export class LNDEffects implements OnDestroy {
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.snackBar.open(postRes.message);
this.store.dispatch(new RTLActions.OpenSnackBar(postRes.message));
this.store.dispatch(new RTLActions.SetRestoreChannelsList(postRes.list));
return {
type: RTLActions.RESTORE_CHANNELS_RES,
@ -752,8 +750,8 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
return {
type: RTLActions.OPEN_ALERT,
payload: { data: { type: AlertTypeEnum.SUCCESS, titleMessage: 'Fund Sent Successfully!' } }
type: RTLActions.OPEN_SNACK_BAR,
payload: 'Fund Sent Successfully!'
};
}),
catchError((err: any) => {

@ -1,57 +0,0 @@
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faTools" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Application Settings</span>
</div>
<div fxLayout="column" class="padding-gap-x settings-container">
<mat-card>
<mat-card-content fxLayout="column" class="card-content-gap mt-1">
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign="space-between stretch">
<mat-form-field fxFlex="32" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selNode.settings.userPersona" placeholder="User Persona" tabindex="1" required name="userPersona">
<mat-option *ngFor="let userPersona of userPersonas" [value]="userPersona">
{{userPersona | titlecase}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="32" fxLayoutAlign="start end" *ngIf="appConfig.nodes.length && appConfig.nodes.length > 1">
<mat-select [(ngModel)]="appConfig.defaultNodeIndex" placeholder="Default Node" tabindex="1" required name="defaultNode">
<mat-option *ngFor="let node of appConfig.nodes" [value]="node.index">
{{node.lnNode}} ({{node.lnImplementation}})
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="32" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selNode.settings.currencyUnit" placeholder="Currency Unit" (selectionChange)="onCurrencyChange($event)" tabindex="1" required name="currencyUnit">
<mat-option *ngFor="let currencyUnit of currencyUnits" [value]="currencyUnit.id">
{{currencyUnit.id}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign="start stretch" class="mt-1">
<div fxLayout="column" fxFlex="25" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="start space-between">
<h4>Mode</h4>
<mat-radio-group color="primary" [(ngModel)]="selectedThemeMode" (change)="chooseThemeMode()">
<mat-radio-button *ngFor="let themeMode of themeModes" [value]="themeMode" [ngClass]="{'mr-4': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">{{themeMode.name}}
</mat-radio-button>
</mat-radio-group>
</div>
<div fxLayout="column" fxFlex="9"></div>
<div fxLayout="column" fxFlex="40">
<h4>Skins</h4>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start">
<span *ngFor="let themeColor of themeColors">
<div [class]="themeColor" [ngClass]="{'skin': true, 'selected-color': selectedThemeColor === themeColor}" (click)="changeThemeColor(themeColor)"></div>
</span>
</div>
</div>
</div>
<div fxLayout="row" fxFlex="100" class="mt-4">
<div fxLayout="row" fxFlex="100" fxFlex.gt-sm="50" fxLayoutAlign="space-between stretch">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" (click)="onResetSettings()" tabindex="12">Reset</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onUpdateSettings()" tabindex="13">Update</button>
</div>
</div>
</mat-card-content>
</mat-card>
</div>

@ -1,5 +1,8 @@
<div fxLayout="row">
<div fxFlex="100" class="padding-gap-large">
<div perfectScrollbar fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign="space-between stretch">
<div fxFlex="30" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large" [ngClass]="{'display-none': showQRField === '' || screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">
<qrcode [qrdata]="showQRField" [size]="210" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>
</div>
<div [fxFlex]="showQRField === '' || screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM ? '100' : '70'" class="padding-gap-large pl-3">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">{{data.alertTitle || alertTypeEnum[data.type]}}</span>
@ -8,30 +11,37 @@
</mat-card-header>
<mat-card-content class="mt-5px mb-0">
<div fxLayout="column">
<p *ngIf="data.titleMessage" fxLayoutAlign="start center" class="pb-1">{{data.titleMessage}}</p>
<div *ngIf="messageObjs?.length>0">
<div *ngFor="let objs of messageObjs; index as i;">
<div fxLayout="row wrap" fxLayoutAlign="start center" fxLayoutAlign.gt-md="space-between start">
<div fxLayout="column" fxFlex="100" fxFlex.gt-md="{{obj.width}}" *ngFor="let obj of objs; index as j;">
<h4 fxLayoutAlign="start" class="font-bold-500">{{obj.title}}</h4>
<span *ngIf="obj && obj.value; else emptyField">
<span [ngSwitch]="obj.type" class="foreground-secondary-text">
<ng-container *ngSwitchCase="dataTypeEnum.ARRAY"><span *ngFor="let arrayObj of obj.value" class="display-block">{{arrayObj}}</span></ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.NUMBER">{{obj.value | number:'1.0-3'}}</ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.BOOLEAN">{{obj.value === true ? 'True' : 'False'}}</ng-container>
<ng-container *ngSwitchDefault>{{obj.value}}</ng-container>
<div fxFlex="50" fxLayoutAlign="center start" class="modal-qr-code-container padding-gap-large mb-1" [ngClass]="{'display-none': showQRField === '' || (screenSize !== screenSizeEnum.XS && screenSize !== screenSizeEnum.SM)}">
<qrcode [qrdata]="showQRField" [size]="210" [level]="'L'" [allowEmptyString]="true" class="qr-border"></qrcode>
</div>
<div fxLayout="row" fxFlex="100">
<p *ngIf="data.titleMessage" fxLayoutAlign="start center" class="pb-1">{{data.titleMessage}}</p>
<div *ngIf="messageObjs?.length>0" fxFlex="100">
<div *ngFor="let objs of messageObjs; index as i;">
<div fxLayout="row wrap" fxFlex="100" fxLayoutAlign="start center" fxLayoutAlign.gt-md="space-between start">
<div fxLayout="column" fxFlex="100" fxFlex.gt-md="{{obj.width}}" *ngFor="let obj of objs; index as j;">
<h4 fxLayoutAlign="start" class="font-bold-500">{{obj.title}}</h4>
<span *ngIf="obj && obj.value; else emptyField">
<span [ngSwitch]="obj.type" class="foreground-secondary-text">
<ng-container *ngSwitchCase="dataTypeEnum.ARRAY"><span *ngFor="let arrayObj of obj.value" class="display-block">{{arrayObj}}</span></ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.NUMBER">{{obj.value | number:'1.0-3'}}</ng-container>
<ng-container *ngSwitchCase="dataTypeEnum.BOOLEAN">{{obj.value === true ? 'True' : 'False'}}</ng-container>
<ng-container *ngSwitchDefault>{{obj.value}}</ng-container>
</span>
</span>
</span>
<ng-template #emptyField>
<span fxFlex="100" class="foreground-secondary-text">&nbsp;</span>
</ng-template>
<mat-divider class="w-100 my-1"></mat-divider>
</div>
<ng-template #emptyField>
<span fxFlex="100" class="foreground-secondary-text">&nbsp;</span>
</ng-template>
<mat-divider class="w-100 my-1"></mat-divider>
</div>
</div>
</div>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="end center">
<button fxLayoutAlign="center center" tabindex="1" autoFocus mat-raised-button color="primary" fxFlex="20" type="submit" [mat-dialog-close]="false" default>OK</button>
<button *ngIf="!showQRField || showQRField == ''" fxLayoutAlign="center center" tabindex="1" autoFocus mat-raised-button color="primary" fxFlex="20" type="submit" [mat-dialog-close]="false" default>OK</button>
<button *ngIf="showQRField !== ''" fxLayoutAlign="center center" tabindex="1" class="mr-2" mat-stroked-button color="primary" type="button" [mat-dialog-close]="false" default>OK</button>
<button *ngIf="showQRField !== ''" fxFlex="30" fxLayoutAlign="center center" autoFocus mat-raised-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="showQRField" (copied)="onCopyField($event)">Copy {{showQRName}}</button>
</div>
</div>
</mat-card-content>

@ -1,9 +1,10 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA, MatSnackBar } from '@angular/material';
import { CommonService } from '../../../services/common.service';
import { LoggerService } from '../../../services/logger.service';
import { AlertData, ErrorData } from '../../../models/alertData';
import { AlertTypeEnum, DataTypeEnum } from '../../../services/consts-enums-functions';
import { AlertData } from '../../../models/alertData';
import { AlertTypeEnum, DataTypeEnum, ScreenSizeEnum } from '../../../services/consts-enums-functions';
@Component({
selector: 'rtl-alert-message',
@ -11,15 +12,23 @@ import { AlertTypeEnum, DataTypeEnum } from '../../../services/consts-enums-func
styleUrls: ['./alert-message.component.scss']
})
export class AlertMessageComponent implements OnInit {
public showQRField = '';
public showQRName = '';
public errorMessage = '';
public messageObjs = [];
public alertTypeEnum = AlertTypeEnum;
public dataTypeEnum = DataTypeEnum;
constructor(public dialogRef: MatDialogRef<AlertMessageComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService, private snackBar: MatSnackBar) { }
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
constructor(public dialogRef: MatDialogRef<AlertMessageComponent>, @Inject(MAT_DIALOG_DATA) public data: AlertData, private logger: LoggerService, private snackBar: MatSnackBar, private commonService: CommonService) { }
ngOnInit() {
this.screenSize = this.commonService.getScreenSize();
this.messageObjs = this.data.message;
this.showQRField = this.data.showQRField ? this.data.showQRField : '';
this.showQRName = this.data.showQRName ? this.data.showQRName : '';
if (this.data.type === AlertTypeEnum.ERROR) {
if (undefined === this.data.message && undefined === this.data.titleMessage && this.messageObjs.length <= 0) {
this.data.titleMessage = 'Please Check Server Connection';
@ -28,6 +37,11 @@ export class AlertMessageComponent implements OnInit {
this.logger.info(this.messageObjs);
}
onCopyField(payload: string) {
this.snackBar.open(this.showQRName + ' copied');
this.logger.info('Copied Text: ' + payload);
}
onClose() {
this.dialogRef.close(false);
}

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between start">
<div perfectScrollbar fxLayout="column" fxFlex="100" fxLayoutAlign="space-between start">
<div fxLayout="column" fxFlex="90" fxLayoutAlign="start stretch" class="w-100">
<mat-select *ngIf="appConfig.nodes.length > 1" [value]="selNode" (selectionChange)="onNodeSelectionChange($event.value)" class="m-2 multi-node-select">
<mat-option *ngFor="let node of appConfig.nodes" [value]="node" tabindex="1">

@ -3,10 +3,6 @@
<fa-icon [icon]="faCodeBranch" class="fa-icon-small mr-1"></fa-icon>
<span>Version: {{version}}</span>
</p>
<a mat-menu-item routerLink="/advanced">
<fa-icon [icon]="faCog" class="fa-icon-small mr-1"></fa-icon>
<span routerLink="/advanced">Node Config</span>
</a>
<a mat-menu-item routerLink="/help">
<fa-icon [icon]="faLifeRing" class="fa-icon-small mr-1"></fa-icon>
<span routerLink="/help">Help</span>

@ -1,42 +0,0 @@
<div fxLayout="column" fxFlex="100">
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faCog" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Show Configurations</span>
</div>
<div fxLayout="row" class="padding-gap-x" fxLayoutAlign="start start">
<mat-card fxLayout="column" fxFlex="100" class="padding-gap-large">
<mat-card-content class="card-content-gap">
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-md="row wrap">
<mat-radio-group color="primary" fxFlex="100" fxLayoutAlign="start" (change)="onSelectionChange($event)" class="mt-1 mb-1">
<mat-radio-button tabindex="1" class="pr-5" value="rtl" [checked]="selectedNodeType=='rtl'">RTL</mat-radio-button>
<mat-radio-button tabindex="2" class="pr-5" value="ln" *ngIf="showLnConfig" [checked]="selectedNodeType=='ln'">{{lnImplementationStr}}</mat-radio-button>
<mat-radio-button tabindex="3" class="pr-5" value="bitcoind" *ngIf="showBitcoind" [checked]="selectedNodeType=='bitcoind'">BITCOIND</mat-radio-button>
</mat-radio-group>
<div fxLayout="row" fxFlex="100" fxFlex.gt-sm="50" fxLayoutAlign="space-between stretch">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="4" type="reset" (click)="resetData()">Clear</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onShowConfig()" tabindex="5">Show Config</button>
</div>
</form>
<mat-divider *ngIf="configData !== ''" class="my-1"></mat-divider>
<div *ngIf="configData !== '' && fileFormat === 'JSON'" class="mt-2 mb-6">
<pre class="pre-wrap">{{configData | json}}</pre>
<mat-divider *ngIf="configData !== ''" class="my-1"></mat-divider>
</div>
<div *ngIf="configData !== '' && fileFormat === 'INI'" class="mt-2">
<mat-list>
<mat-list-item *ngFor="let conf of configData; index as i;">
<mat-card-subtitle class="my-1">
<h2 *ngIf="conf.indexOf('[') >= 0">{{conf}}</h2>
</mat-card-subtitle>
<mat-card-subtitle class="m-0">
<h4 *ngIf="conf.indexOf('[') < 0" class="ml-4">{{conf}}</h4>
</mat-card-subtitle>
<mat-divider [inset]="true" *ngIf="conf.indexOf('[') < 0"></mat-divider>
</mat-list-item>
</mat-list>
</div>
</mat-card-content>
</mat-card>
</div>
</div>

@ -1,93 +0,0 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { LightningNode } from '../../models/RTLconfig';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
import { faCog } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'rtl-server-config',
templateUrl: './server-config.component.html',
styleUrls: ['./server-config.component.scss']
})
export class ServerConfigComponent implements OnInit, OnDestroy {
public selNode: LightningNode;
public selectedNodeType = 'rtl';
public showLnConfig = false;
public lnImplementationStr = '';
public showBitcoind = false;
public configData = '';
public fileFormat = 'INI';
public faCog = faCog;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects) {}
ngOnInit() {
this.store.select('root')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsRoot.forEach(effectsErr => {
if (effectsErr.action === 'fetchConfig') { this.resetData(); }
});
this.configData = '';
this.showLnConfig = false;
this.showBitcoind = false;
this.selNode = rtlStore.selNode;
this.lnImplementationStr = this.selNode.lnImplementation.toUpperCase() === 'CLT' ? 'CLT' : 'LND';
if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.configPath && this.selNode.authentication.configPath !== '') {
this.showLnConfig = true;
}
if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.bitcoindConfigPath && this.selNode.authentication.bitcoindConfigPath !== '') {
this.showBitcoind = true;
}
if (this.selectedNodeType === 'ln' && !this.showLnConfig) {
this.selectedNodeType = 'rtl';
}
if (this.selectedNodeType === 'bitcoind' && !this.showBitcoind) {
this.selectedNodeType = 'rtl';
}
});
}
onSelectionChange(event) {
this.selectedNodeType = event.value;
this.configData = '';
}
onShowConfig() {
this.store.dispatch(new RTLActions.OpenSpinner('Opening Config File...'));
this.store.dispatch(new RTLActions.FetchConfig(this.selectedNodeType));
this.rtlEffects.showLnConfig
.pipe(takeUntil(this.unSubs[1]))
.subscribe((config: any) => {
console.warn(config);
const configFile = config.data;
this.fileFormat = config.format;
if (configFile !== '' && undefined !== configFile && this.fileFormat === 'INI') {
this.configData = configFile.split('\n');
} else if (configFile !== '' && undefined !== configFile && this.fileFormat === 'JSON') {
this.configData = configFile;
} else {
this.configData = '';
}
});
}
resetData() {
this.configData = '';
this.selectedNodeType = 'rtl';
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -0,0 +1,51 @@
<div fxLayout="column" fxFlex="100" class="overflow-x-hidden">
<div fxLayout="column" class="settings-container mt-1">
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign="space-between stretch">
<mat-form-field fxFlex="32" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selNode.settings.userPersona" placeholder="User Persona" tabindex="1" required name="userPersona">
<mat-option *ngFor="let userPersona of userPersonas" [value]="userPersona">
{{userPersona | titlecase}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="32" fxLayoutAlign="start end" *ngIf="appConfig.nodes.length && appConfig.nodes.length > 1">
<mat-select [(ngModel)]="appConfig.defaultNodeIndex" placeholder="Default Node" tabindex="1" required name="defaultNode">
<mat-option *ngFor="let node of appConfig.nodes" [value]="node.index">
{{node.lnNode}} ({{node.lnImplementation}})
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex="32" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selNode.settings.currencyUnit" placeholder="Currency Unit" (selectionChange)="onCurrencyChange($event)" tabindex="1" required name="currencyUnit">
<mat-option *ngFor="let currencyUnit of currencyUnits" [value]="currencyUnit.id">
{{currencyUnit.id}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign="start stretch" class="mt-1">
<div fxLayout="column" fxFlex="25" fxLayoutAlign="start start" fxLayoutAlign.gt-sm="start space-between">
<h4>Mode</h4>
<mat-radio-group color="primary" [(ngModel)]="selectedThemeMode" (change)="chooseThemeMode()">
<mat-radio-button *ngFor="let themeMode of themeModes" [value]="themeMode" [ngClass]="{'mr-4': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM}">{{themeMode.name}}
</mat-radio-button>
</mat-radio-group>
</div>
<div fxLayout="column" fxFlex="9"></div>
<div fxLayout="column" fxFlex="40">
<h4>Skins</h4>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start">
<span *ngFor="let themeColor of themeColors">
<div [class]="themeColor" [ngClass]="{'skin': true, 'selected-color': selectedThemeColor === themeColor}" (click)="changeThemeColor(themeColor)"></div>
</span>
</div>
</div>
</div>
<div fxLayout="row" fxFlex="100" class="mt-4">
<div fxLayout="row" fxFlex="100" fxFlex.gt-sm="50" fxLayoutAlign="space-between stretch">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" (click)="onResetSettings()" tabindex="12">Reset</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onUpdateSettings()" tabindex="13">Update</button>
</div>
</div>
</div>
</div>

@ -3,15 +3,13 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { faTools } from '@fortawesome/free-solid-svg-icons';
import { CURRENCY_UNITS, UserPersonaEnum, ScreenSizeEnum, FIAT_CURRENCY_UNITS } from '../../../services/consts-enums-functions';
import { LightningNode, Settings, RTLConfiguration, GetInfoRoot } from '../../../models/RTLconfig';
import { LoggerService } from '../../../services/logger.service';
import { CommonService } from '../../../services/common.service';
import { CURRENCY_UNITS, AlertTypeEnum, UserPersonaEnum, ScreenSizeEnum } from '../../services/consts-enums-functions';
import { LightningNode, Settings, RTLConfiguration, GetInfoRoot } from '../../models/RTLconfig';
import { LoggerService } from '../../services/logger.service';
import { CommonService } from '../../services/common.service';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromRTLReducer from '../../../../store/rtl.reducers';
@Component({
selector: 'rtl-app-settings',
@ -19,11 +17,10 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
styleUrls: ['./app-settings.component.scss']
})
export class AppSettingsComponent implements OnInit, OnDestroy {
public faTools = faTools;
public selNode: LightningNode;
public information: GetInfoRoot = {};
public userPersonas = [UserPersonaEnum.OPERATOR, UserPersonaEnum.MERCHANT];
public currencyUnits = [{id: 'USD', name: 'United States Dollar'}, {id: 'GBP', name: 'Pound'}, {id: 'INR', name: 'Indian Rupee'}];
public currencyUnits = FIAT_CURRENCY_UNITS;
public menus = [{id: 'vertical', name: 'Vertical'}, {id: 'horizontal', name: 'Horizontal'}];
public selectedMenu = {id: 'vertical', name: 'Vertical'};
public menuTypes = [{id: 'regular', name: 'Regular'}, {id: 'compact', name: 'Compact'}, {id: 'mini', name: 'Mini'}];

@ -0,0 +1,22 @@
<div fxLayout="column" fxFlex="100">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start start">
<div *ngIf="configData !== '' && fileFormat === 'JSON'" fxFlex="100" class="mb-6">
<pre class="pre-wrap">{{configData | json}}</pre>
<mat-divider *ngIf="configData !== ''" class="my-1"></mat-divider>
</div>
<div *ngIf="configData !== '' && fileFormat === 'INI'" fxFlex="100">
<mat-list>
<mat-list-item *ngFor="let conf of configData; index as i;">
<mat-card-subtitle class="my-1">
<h2 *ngIf="conf.indexOf('[') >= 0">{{conf}}</h2>
</mat-card-subtitle>
<mat-card-subtitle class="m-0">
<h4 *ngIf="conf.indexOf('[') < 0" class="ml-4">{{conf}}</h4>
</mat-card-subtitle>
<mat-divider [inset]="true" *ngIf="conf.indexOf('[') < 0"></mat-divider>
</mat-list-item>
</mat-list>
</div>
</div>
</div>

@ -0,0 +1,43 @@
import { Component, OnInit, Input } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { RTLEffects } from '../../../../store/rtl.effects';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromRTLReducer from '../../../../store/rtl.reducers';
import { faCog } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'rtl-server-config',
templateUrl: './server-config.component.html',
styleUrls: ['./server-config.component.scss']
})
export class ServerConfigComponent implements OnInit {
@Input() selectedNodeType = '';
public configData = '';
public fileFormat = 'INI';
public faCog = faCog;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects) {}
ngOnInit() {
this.store.dispatch(new RTLActions.OpenSpinner('Opening Config File...'));
this.store.dispatch(new RTLActions.FetchConfig(this.selectedNodeType));
this.rtlEffects.showLnConfig
.pipe(takeUntil(this.unSubs[1]))
.subscribe((config: any) => {
const configFile = config.data;
this.fileFormat = config.format;
if (configFile !== '' && undefined !== configFile && this.fileFormat === 'INI') {
this.configData = configFile.split('\n');
} else if (configFile !== '' && undefined !== configFile && this.fileFormat === 'JSON') {
this.configData = configFile;
} else {
this.configData = '';
}
});
}
}

@ -0,0 +1,24 @@
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faTools" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Settings</span>
</div>
<div fxLayout="column" class="padding-gap-x">
<mat-card>
<mat-card-content fxLayout="column">
<mat-tab-group>
<mat-tab label="Settings"><rtl-app-settings></rtl-app-settings></mat-tab>
<mat-tab *ngIf="showLnConfig" [label]="lnImplementationStr">
<ng-template matTabContent>
<rtl-server-config [selectedNodeType]="'ln'"></rtl-server-config>
</ng-template>
</mat-tab>
<mat-tab *ngIf="showBitcoind" label="BitcoinD Config">
<ng-template matTabContent>
<rtl-server-config [selectedNodeType]="'bitcoind'"></rtl-server-config>
</ng-template>
</mat-tab>
</mat-tab-group>
</mat-card-content>
</mat-card>
</div>

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

@ -0,0 +1,49 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { faTools } from '@fortawesome/free-solid-svg-icons';
import { LightningNode } from '../../models/RTLconfig';
import { RTLEffects } from '../../../store/rtl.effects';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit, OnDestroy{
public faTools = faTools;
public showLnConfig = false;
public showBitcoind = false;
public selNode: LightningNode;
public lnImplementationStr = '';
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private store: Store<fromRTLReducer.RTLState>) {}
ngOnInit() {
this.store.select('root')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => {
this.showLnConfig = false;
this.showBitcoind = false;
this.selNode = rtlStore.selNode;
this.lnImplementationStr = this.selNode.lnImplementation.toUpperCase() === 'CLT' ? 'CLT Config' : 'LND Config';
if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.configPath && this.selNode.authentication.configPath !== '') {
this.showLnConfig = true;
}
if (undefined !== this.selNode.authentication && undefined !== this.selNode.authentication.bitcoindConfigPath && this.selNode.authentication.bitcoindConfigPath !== '') {
this.showBitcoind = true;
}
});
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

@ -12,7 +12,6 @@ export const MENU_DATA: MenuRootNode = {
{id: 35, parentId: 3, name: 'Graph Lookup', iconType: 'FA', icon: faSearch, link: '/lnd/lookups'},
{id: 36, parentId: 3, name: 'Network', iconType: 'FA', icon: faNetworkWired, link: '/lnd/network'}
]},
{id: 4, parentId: 0, name: 'Advanced', iconType: 'FA', icon: faCog, link: '/advanced'},
{id: 5, parentId: 0, name: 'Settings', iconType: 'FA', icon: faTools, link: '/settings'},
{id: 6, parentId: 0, name: 'Help', iconType: 'FA', icon: faQuestion, link: '/help'}
],

@ -8,6 +8,16 @@ export function getPaginatorLabel(field: string) {
export const CURRENCY_UNITS = [ 'Sats', 'BTC' ];
export const CURRENCY_UNIT_FORMATS = { Sats: '1.0-0', BTC: '1.6-6', OTHER: '1.2-2'};
export const FIAT_CURRENCY_UNITS = [
{id: 'USD', name: 'United States Dollar'},
{id: 'AUD', name: 'AUD'}, {id: 'BRL', name: 'BRL'}, {id: 'CAD', name: 'CAD'},
{id: 'CHF', name: 'CHF'}, {id: 'CLP', name: 'CLP'}, {id: 'CNY', name: 'CNY'},
{id: 'DKK', name: 'DKK'}, {id: 'EUR', name: 'EUR'}, {id: 'GBP', name: 'Pound'},
{id: 'HKD', name: 'HKD'}, {id: 'INR', name: 'Indian Rupee'}, {id: 'ISK', name: 'ISK'},
{id: 'JPY', name: 'JPY'}, {id: 'KRW', name: 'KRW'}, {id: 'NZD', name: 'NZD'},
{id: 'PLN', name: 'PLN'}, {id: 'RUB', name: 'RUB'}, {id: 'SEK', name: 'SEK'},
{id: 'SGD', name: 'SGD'}, {id: 'THB', name: 'THB'}, {id: 'TWD', name: 'TWD'}
];
export const TIME_UNITS = ['SECS', 'MINS', 'HOURS', 'DAYS'];

@ -26,7 +26,7 @@ const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
import { InvoiceInformationComponent } from './components/data-modal/invoice-information/invoice-information.component';
import { OnChainGeneratedAddressComponent } from './components/data-modal/on-chain-generated-address/on-chain-generated-address.component';
import { AppSettingsComponent } from './components/app-settings/app-settings.component';
import { AppSettingsComponent } from './components/settings/app-settings/app-settings.component';
import { AlertMessageComponent } from './components/data-modal/alert-message/alert-message.component';
import { ConfirmationMessageComponent } from './components/data-modal/confirmation-message/confirmation-message.component';
import { ErrorMessageComponent } from './components/data-modal/error-message/error-message.component';
@ -37,7 +37,8 @@ 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 { ServerConfigComponent } from './components/server-config/server-config.component';
import { SettingsComponent } from './components/settings/settings.component';
import { ServerConfigComponent } from './components/settings/server-config/server-config.component';
import { ErrorComponent } from './components/error/error.component';
import { CurrencyUnitConverterComponent } from './components/currency-unit-converter/currency-unit-converter.component';
import { ClipboardDirective } from './directive/clipboard.directive';
@ -126,6 +127,7 @@ import { SocketService } from './services/socket.service';
MatTabsModule,
MatSnackBarModule,
AppSettingsComponent,
SettingsComponent,
InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent,
@ -149,6 +151,7 @@ import { SocketService } from './services/socket.service';
],
declarations: [
AppSettingsComponent,
SettingsComponent,
InvoiceInformationComponent,
OnChainGeneratedAddressComponent,
AlertMessageComponent,

@ -88,6 +88,7 @@
padding-top: $regular-font-size;
}
.mat-tree .mat-tree-node, .mat-tree .mat-nested-tree-node-parent {
min-height: $tree-node-height;
height: $tree-node-height;
}
.mat-primary .mat-select-panel .mat-option.mat-selected:not(.mat-option-multiple),

@ -98,6 +98,9 @@
.mat-expansion-panel {
border: 1px solid $foreground-secondary-text;
}
.mat-tab-label, .mat-tab-link {
color: $foreground-secondary-text;
}
}
&.day {
@ -171,6 +174,13 @@
border-radius: 4px;
background: none;
}
.mat-tab-label, .mat-tab-link {
color: $foreground-secondary-text;
}
.mat-card, .mat-card:not([class*='mat-elevation-z']){
box-shadow: none;
border: 1px solid $foreground-divider;
}
}
.mat-progress-bar-buffer {
@ -181,6 +191,7 @@
color: $foreground-secondary-text !important;
white-space: pre-line;
overflow-wrap: break-word;
word-break: break-all;
}
.foreground.mat-progress-spinner circle, .foreground.mat-spinner circle {

@ -17,7 +17,7 @@ $settings-nav-width: 150px;
$gap: 8px;
$icon-size: 3.6rem;
$pubkey-info-height: 15px;
$tree-node-height:48px;
$tree-node-height:44px;
$fa-icon-small-size: 2rem;
$fa-icon-regular-size: 4rem;

@ -526,8 +526,16 @@ body {
overflow: auto;
}
.mat-footer-row, .mat-header-row, .mat-row {
border-bottom-width: 0;
.mat-footer-row {
& .mat-footer-cell {
border-bottom: none !important;
}
}
.mat-row:last-child {
& .mat-cell {
border-bottom: none !important;
}
}
.flex-ellipsis {
@ -737,6 +745,8 @@ a {
}
.mat-tree-node, .mat-nested-tree-node-parent {
min-height: 4rem;
height: 4rem;
padding: 0 1.2rem 0 1.2rem;
cursor: pointer;
}

@ -14,6 +14,7 @@ export const UPDATE_SELECTED_NODE_OPTIONS = 'UPDATE_SELECTED_NODE_OPTIONS';
export const RESET_ROOT_STORE = 'RESET_ROOT_STORE';
export const CLEAR_EFFECT_ERROR_ROOT = 'CLEAR_EFFECT_ERROR_ROOT';
export const EFFECT_ERROR_ROOT = 'EFFECT_ERROR_ROOT';
export const OPEN_SNACK_BAR = 'OPEN_SNACKBAR';
export const OPEN_SPINNER = 'OPEN_SPINNER';
export const CLOSE_SPINNER = 'CLOSE_SPINNER';
export const OPEN_ALERT = 'OPEN_ALERT';
@ -186,6 +187,11 @@ export class EffectErrorCl implements Action {
constructor(public payload: ErrorPayload) {}
}
export class OpenSnackBar implements Action {
readonly type = OPEN_SNACK_BAR;
constructor(public payload: string) {}
}
export class OpenSpinner implements Action {
readonly type = OPEN_SPINNER;
constructor(public payload: string) {} // payload = titleMessage
@ -824,7 +830,7 @@ export class SetChannelTransactionCL implements Action {
export type RTLActions =
ClearEffectErrorRoot | EffectErrorRoot | ClearEffectErrorLnd | EffectErrorLnd | ClearEffectErrorCl | EffectErrorCl |
VoidAction | OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings |
VoidAction | OpenSnackBar | OpenSpinner | CloseSpinner | FetchRTLConfig | SetRTLConfig | SaveSettings |
OpenAlert | CloseAlert | OpenConfirmation | CloseConfirmation | ShowPubkey |
UpdateSelectedNodeOptions | ResetRootStore | ResetLNDStore | ResetCLStore |
SetSelelectedNode | SetNodeData | SetNodePendingChannelsData | SetChildNodeSettings | FetchInfo | SetInfo |

@ -45,6 +45,14 @@ export class RTLEffects implements OnDestroy {
private snackBar: MatSnackBar,
private router: Router) {}
@Effect({ dispatch: false })
openSnackBar = this.actions$.pipe(
ofType(RTLActions.OPEN_SNACK_BAR),
map((action: RTLActions.OpenSnackBar) => {
this.snackBar.open(action.payload);
}
));
@Effect({ dispatch: false })
openSpinner = this.actions$.pipe(
ofType(RTLActions.OPEN_SPINNER),
@ -180,12 +188,8 @@ export class RTLEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.logger.info(updateStatus);
return {
type: RTLActions.OPEN_ALERT,
payload: { width: '55%', data: {
type: AlertTypeEnum.SUCCESS,
alertTitle: 'Settings updated',
titleMessage: (!updateStatus.length) ? updateStatus.message : updateStatus[0].message + '. ' + updateStatus[1].message
}}
type: RTLActions.OPEN_SNACK_BAR,
payload: (!updateStatus.length) ? updateStatus.message + '.' : updateStatus[0].message + '.'
};
},
catchError((err) => {

Loading…
Cancel
Save