Code cleanup for currency convertor

Code cleanup for currency convertor
This commit is contained in:
Shahana Farooqui 2019-11-19 18:49:58 -05:00
parent 5421631d12
commit 125099fe08
74 changed files with 1241 additions and 268 deletions

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

View file

@ -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="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="icon" type="image/png" sizes="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest"> <link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.36940ff719dbed85b186.css"></head> <link rel="stylesheet" href="styles.6429b7a9527a146e7054.css"></head>
<body> <body>
<rtl-app></rtl-app> <rtl-app></rtl-app>
<script src="runtime.cf15072f755a92e0766f.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.17677b43ba5c7b8274d4.js"></script></body> <script src="runtime.85f0111a60b784d662a7.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.136ca1019950c55334b6.js"></script></body>
</html> </html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
!function(e){function r(r){for(var n,a,i=r[0],f=r[1],c=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,c||[]),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:"180f16dffe826f0afab2",6:"ed6f619a753cd468a3f1",7:"3b3d365a0c96df4907d8"}[e]+".js"}(e);var f=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(c);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;f.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",f.name="ChunkLoadError",f.type=n,f.request=u,t[1](f)}o[e]=void 0}};var c=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||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var c=0;c<i.length;c++)r(i[c]);var l=f;t()}([]); !function(e){function r(r){for(var n,a,i=r[0],f=r[1],c=r[2],p=0,s=[];p<i.length;p++)o[a=i[p]]&&s.push(o[a][0]),o[a]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(l&&l(r);s.length;)s.shift()();return u.push.apply(u,c||[]),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:"180f16dffe826f0afab2",6:"6461d7eefa28dc4efa39",7:"84ad670c3bfef8117d18"}[e]+".js"}(e);var f=new Error;u=function(r){i.onerror=i.onload=null,clearTimeout(c);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;f.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",f.name="ChunkLoadError",f.type=n,f.request=u,t[1](f)}o[e]=void 0}};var c=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||[],f=i.push.bind(i);i.push=r,i=i.slice();for(var c=0;c<i.length;c++)r(i[c]);var l=f;t()}([]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -57,7 +57,7 @@
</button> </button>
</div> </div>
<div fxFlex="10" fxLayoutAlign="end start"> <div fxFlex="10" fxLayoutAlign="end start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="9" type="reset" <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="9" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -1 +1,2 @@
<router-outlet></router-outlet> <mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<router-outlet *ngIf="!loading"></router-outlet>

View file

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
@Component({ @Component({
selector: 'rtl-cl-root', selector: 'rtl-cl-root',
@ -6,5 +7,25 @@ import { Component } from '@angular/core';
styleUrls: ['./cl-root.component.scss'] styleUrls: ['./cl-root.component.scss']
}) })
export class CLRootComponent { export class CLRootComponent {
constructor() {} loading = false;
constructor(private router: Router) {
this.router.events.subscribe((event: Event) => {
switch (true) {
case event instanceof NavigationStart: {
this.loading = true;
break;
}
case event instanceof NavigationEnd:
case event instanceof NavigationCancel:
case event instanceof NavigationError: {
this.loading = false;
break;
}
default: {
break;
}
}
});
}
} }

View file

@ -27,7 +27,7 @@
<div fxFlex="30" fxLayoutAlign="space-between stretch"> <div fxFlex="30" fxLayoutAlign="space-between stretch">
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary" <button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="fhForm.invalid" type="submit" tabindex="3">Fetch</button> [disabled]="fhForm.invalid" type="submit" tabindex="3">Fetch</button>
<button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="accent" class="ml-2" tabindex="4" <button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="primary" class="ml-2" tabindex="4"
type="reset" (click)="resetData()">Clear</button> type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -29,7 +29,7 @@
</div> </div>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit" <button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" type="submit"
tabindex="5" [disabled]="!addInvoiceForm.valid">Add</button> tabindex="5" [disabled]="!addInvoiceForm.valid">Add</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="6" type="reset" <button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="6" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="warn" tabindex="7" type="button" <button fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="warn" tabindex="7" type="button"
(click)="onDeleteExpiredInvoices()">Delete Expired</button> (click)="onDeleteExpiredInvoices()">Delete Expired</button>

View file

@ -22,7 +22,7 @@
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="3" type="submit" (click)="onLookup()" [disabled]="!form.valid">Lookup</button> <button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="3" type="submit" (click)="onLookup()" [disabled]="!form.valid">Lookup</button>
</div> </div>
<div fxFlex="12" fxLayoutAlign="start start"> <div fxFlex="12" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="4" type="reset" (click)="resetData()">Clear</button> <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="4" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -109,7 +109,7 @@
class="top-minus-15px">Generate Address</button> class="top-minus-15px">Generate Address</button>
</div> </div>
<div fxFlex.gt-md="30" fxFlex.lt-lg="49" fxLayoutAlign="start end"> <div fxFlex.gt-md="30" fxFlex.lt-lg="49" fxLayoutAlign="start end">
<button fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="3" <button fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="3"
(click)="resetReceiveData()" class="top-minus-15px">Clear</button> (click)="resetReceiveData()" class="top-minus-15px">Clear</button>
</div> </div>
</div> </div>
@ -167,7 +167,7 @@
</button> </button>
</div> </div>
<div fxFlex="10" fxLayoutAlign="end start"> <div fxFlex="10" fxLayoutAlign="end start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="9" type="reset" <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="9" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -30,7 +30,7 @@
</button> </button>
</div> </div>
<div fxFlex="15" fxLayoutAlign="start start"> <div fxFlex="15" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="4" type="reset" <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="4" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -23,7 +23,7 @@
<p>Send Payment</p> <p>Send Payment</p>
</ng-template> </ng-template>
</button> </button>
<button fxFlex="48" mat-stroked-button color="accent" type="reset" tabindex="3" type="reset" <button fxFlex="48" mat-stroked-button color="primary" type="reset" tabindex="3" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -18,7 +18,7 @@
</button> </button>
</div> </div>
<div fxFlex="15" fxLayoutAlign="start start"> <div fxFlex="15" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="2" type="reset" (click)="resetData()">Clear</button> <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="2" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -49,7 +49,7 @@
</button> </button>
</div> </div>
<div fxFlex="10" fxLayoutAlign="end start"> <div fxFlex="10" fxLayoutAlign="end start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="9" type="reset" (click)="resetData()">Clear</button> <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="9" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -1 +1,2 @@
<router-outlet></router-outlet> <mat-progress-bar *ngIf="loading" color="primary" mode="indeterminate"></mat-progress-bar>
<router-outlet *ngIf="!loading"></router-outlet>

View file

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
@Component({ @Component({
selector: 'rtl-lnd-root', selector: 'rtl-lnd-root',
@ -6,5 +7,25 @@ import { Component } from '@angular/core';
styleUrls: ['./lnd-root.component.scss'] styleUrls: ['./lnd-root.component.scss']
}) })
export class LNDRootComponent { export class LNDRootComponent {
constructor() {} loading = false;
constructor(private router: Router) {
this.router.events.subscribe((event: Event) => {
switch (true) {
case event instanceof NavigationStart: {
this.loading = true;
break;
}
case event instanceof NavigationEnd:
case event instanceof NavigationCancel:
case event instanceof NavigationError: {
this.loading = false;
break;
}
default: {
break;
}
}
});
}
} }

View file

@ -9,6 +9,9 @@ import { HomeComponent } from './home/home.component';
import { PeersComponent } from './peers/peers.component'; import { PeersComponent } from './peers/peers.component';
import { SendReceiveTransComponent } from './old-transactions/send-receive/send-receive-trans.component'; import { SendReceiveTransComponent } from './old-transactions/send-receive/send-receive-trans.component';
import { LightningInvoicesComponent } from './transactions/invoices/lightning-invoices.component'; import { LightningInvoicesComponent } from './transactions/invoices/lightning-invoices.component';
import { OnChainSendComponent } from './on-chain/on-chain-send/on-chain-send.component';
import { OnChainReceiveComponent } from './on-chain/on-chain-receive/on-chain-receive.component';
import { OnChainComponent } from './on-chain/on-chain.component';
import { UnlockLNDComponent } from './unlock-lnd/unlock-lnd.component'; import { UnlockLNDComponent } from './unlock-lnd/unlock-lnd.component';
import { LightningPaymentsComponent } from './transactions/payments/lightning-payments.component'; import { LightningPaymentsComponent } from './transactions/payments/lightning-payments.component';
import { ChannelManageComponent } from './channels/channel-manage/channel-manage.component'; import { ChannelManageComponent } from './channels/channel-manage/channel-manage.component';
@ -27,6 +30,7 @@ import { QueryRoutesComponent } from './payments/query-routes/query-routes.compo
import { LoggerService, ConsoleLoggerService } from '../shared/services/logger.service'; import { LoggerService, ConsoleLoggerService } from '../shared/services/logger.service';
import { LNDUnlockedGuard } from '../shared/services/auth.guard'; import { LNDUnlockedGuard } from '../shared/services/auth.guard';
import { OnChainTransactionHistoryComponent } from './on-chain/on-chain-transaction-history/on-chain-transaction-history.component';
@NgModule({ @NgModule({
imports: [ imports: [
@ -54,7 +58,11 @@ import { LNDUnlockedGuard } from '../shared/services/auth.guard';
NodeLookupComponent, NodeLookupComponent,
ChannelBackupComponent, ChannelBackupComponent,
QueryRoutesComponent, QueryRoutesComponent,
ChannelRestoreComponent ChannelRestoreComponent,
OnChainSendComponent,
OnChainReceiveComponent,
OnChainComponent,
OnChainTransactionHistoryComponent
], ],
providers: [ providers: [
{ provide: LoggerService, useClass: ConsoleLoggerService }, { provide: LoggerService, useClass: ConsoleLoggerService },

View file

@ -17,6 +17,7 @@ import { ForwardingHistoryComponent } from './switch/forwarding-history.componen
import { RoutingPeersComponent } from './routing-peers/routing-peers.component'; import { RoutingPeersComponent } from './routing-peers/routing-peers.component';
import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component'; import { ChannelBackupComponent } from './channels/channel-backup/channel-backup.component';
import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component'; import { ChannelRestoreComponent } from './channels/channel-restore/channel-restore.component';
import { OnChainComponent } from './on-chain/on-chain.component';
import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard'; import { AuthGuard, LNDUnlockedGuard } from '../shared/services/auth.guard';
import { NotFoundComponent } from '../shared/components/not-found/not-found.component'; import { NotFoundComponent } from '../shared/components/not-found/not-found.component';
@ -33,13 +34,12 @@ export const LndRoutes: Routes = [
{ path: 'chnlbackup', component: ChannelBackupComponent, canActivate: [LNDUnlockedGuard] }, { path: 'chnlbackup', component: ChannelBackupComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'chnlrestore', component: ChannelRestoreComponent, canActivate: [LNDUnlockedGuard] }, { path: 'chnlrestore', component: ChannelRestoreComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'transactions', component: TransactionsComponent, canActivate: [LNDUnlockedGuard] }, { path: 'transactions', component: TransactionsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'transsendreceive', component: SendReceiveTransComponent, canActivate: [LNDUnlockedGuard] }, { path: 'onchain', component: OnChainComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'translist', component: ListTransactionsComponent, canActivate: [LNDUnlockedGuard] }, { path: 'translist', component: ListTransactionsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'queryroutes', component: QueryRoutesComponent, canActivate: [LNDUnlockedGuard] }, { path: 'queryroutes', component: QueryRoutesComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'switch', component: ForwardingHistoryComponent, canActivate: [LNDUnlockedGuard] }, { path: 'switch', component: ForwardingHistoryComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'routingpeers', component: RoutingPeersComponent, canActivate: [LNDUnlockedGuard] }, { path: 'routingpeers', component: RoutingPeersComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'lookups', component: LookupsComponent, canActivate: [LNDUnlockedGuard] }, { path: 'lookups', component: LookupsComponent, canActivate: [LNDUnlockedGuard] },
{ path: 'onchain', redirectTo: 'transsendreceive' },
{ path: 'forwardinghistory', redirectTo: 'switch' }, { path: 'forwardinghistory', redirectTo: 'switch' },
{ path: '**', component: NotFoundComponent } { path: '**', component: NotFoundComponent }
]} ]}

View file

@ -22,7 +22,7 @@
<button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="3" type="submit" (click)="onLookup()" [disabled]="!form.valid">Lookup</button> <button fxFlex="90" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="3" type="submit" (click)="onLookup()" [disabled]="!form.valid">Lookup</button>
</div> </div>
<div fxFlex="12" fxLayoutAlign="start start"> <div fxFlex="12" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="4" type="reset" (click)="resetData()">Clear</button> <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="4" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -95,7 +95,7 @@
<button fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="undefined === selectedAddress.addressId" (click)="onGenerateAddress()" tabindex="2" class="top-minus-15px">Generate Address</button> <button fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="undefined === selectedAddress.addressId" (click)="onGenerateAddress()" tabindex="2" class="top-minus-15px">Generate Address</button>
</div> </div>
<div fxFlex.gt-md="30" fxFlex.lt-lg="49" fxLayoutAlign="start end"> <div fxFlex.gt-md="30" fxFlex.lt-lg="49" fxLayoutAlign="start end">
<button fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="3" (click)="resetReceiveData()" class="top-minus-15px">Clear</button> <button fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="3" (click)="resetReceiveData()" class="top-minus-15px">Clear</button>
</div> </div>
</div> </div>
<div fxFlex="42" fxLayoutAlign="start end"> <div fxFlex="42" fxLayoutAlign="start end">
@ -157,7 +157,7 @@
<p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">Invalid Values</p> <p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">Invalid Values</p>
<ng-template #sendText><p>Send</p></ng-template> <ng-template #sendText><p>Send</p></ng-template>
</button> </button>
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="9" type="reset" (click)="resetData()">Clear</button> <button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="9" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</div> </div>
</mat-card-content> </mat-card-content>

View file

@ -0,0 +1,15 @@
<div fxLayout="column">
<div fxLayout="row" fxLayoutAlign="space-between end" fxLayoutAlign.gt-sm="start end">
<mat-form-field fxFlex="48" fxFlex.gt-sm="25" fxLayoutAlign="start end">
<mat-select [(ngModel)]="selectedAddress" placeholder="Address Type" name="address_type" tabindex="1">
<mat-option *ngFor="let addressType of addressTypes" [value]="addressType">
{{addressType.addressTp}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="mt-2" fxFlex="48" fxFlex.gt-sm="25">
<button fxFlex="100" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onGenerateAddress()" [disabled]="undefined === selectedAddress.addressId" tabindex="2" class="top-minus-15px">Generate Address</button>
</div>
</div>
<rtl-on-chain-transaction-history fxLayout="row" fxFlex="100"></rtl-on-chain-transaction-history>
</div>

View file

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

View file

@ -0,0 +1,184 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { SelNodeChild } from '../../../shared/models/RTLconfig';
import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels';
import { RTLConfiguration } from '../../../shared/models/RTLconfig';
import { LoggerService } from '../../../shared/services/logger.service';
import * as sha256 from 'sha256';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-on-chain-receive',
templateUrl: './on-chain-receive.component.html',
styleUrls: ['./on-chain-receive.component.scss']
})
export class OnChainReceiveComponent implements OnInit, OnDestroy {
public selNode: SelNodeChild = {};
public appConfig: RTLConfiguration;
public addressTypes = [];
public flgLoadingWallet: Boolean | 'error' = true;
public selectedAddress: AddressType = {};
public blockchainBalance: Balance = {};
public information: GetInfo = {};
public newAddress = '';
public transaction: ChannelsTransaction = {};
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1';
public flgCustomAmount = '1';
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private lndEffects: LNDEffects) {}
ngOnInit() {
this.store.select('root')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rootStore) => {
this.appConfig = rootStore.appConfig;
this.logger.info(rootStore);
});
this.store.select('lnd')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsLnd.forEach(effectsErr => {
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoadingWallet = 'error';
}
});
this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = 0;
}
if (undefined === this.blockchainBalance.confirmed_balance) {
this.blockchainBalance.confirmed_balance = 0;
}
if (undefined === this.blockchainBalance.unconfirmed_balance) {
this.blockchainBalance.unconfirmed_balance = 0;
}
if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false;
}
this.logger.info(rtlStore);
});
}
onGenerateAddress() {
this.store.dispatch(new RTLActions.OpenSpinner('Getting New Address...'));
this.store.dispatch(new RTLActions.GetNewAddress(this.selectedAddress));
this.lndEffects.setNewAddress
.pipe(takeUntil(this.unsub[1]))
.subscribe(newAddress => {
this.newAddress = newAddress;
});
}
onSendFunds() {
const confirmationMsg = {
'BTC Address': this.transaction.address,
};
if (!+this.flgCustomAmount) {
confirmationMsg['Sweep All'] = 'True';
this.transaction.sendAll = true;
} else {
confirmationMsg['Amount (' + this.information.smaller_currency_unit + ')'] = this.transaction.amount;
this.transaction.sendAll = false;
}
if (this.selTransType === '1') {
delete this.transaction.fees;
confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
} else {
delete this.transaction.blocks;
confirmationMsg['Fee (' + this.information.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
}
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsub[2]))
.subscribe(confirmRes => {
if (confirmRes) {
if (this.transaction.sendAll && !+this.appConfig.sso.rtlSSO) {
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', titleMessage: 'Enter Login Password', noBtnText: 'Cancel', yesBtnText: 'Authorize', flgShowInput: true, getInputs: [
{placeholder: 'Enter Login Password', inputType: 'password', inputValue: ''}
]}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unsub[3]))
.subscribe(pwdConfirmRes => {
if (pwdConfirmRes) {
const pwd = pwdConfirmRes[0].inputValue;
this.store.dispatch(new RTLActions.IsAuthorized(sha256(pwd)));
this.rtlEffects.isAuthorizedRes
.pipe(take(1))
.subscribe(authRes => {
if (authRes !== 'ERROR') {
this.dispatchToSendFunds();
}
});
}
});
} else {
this.dispatchToSendFunds();
}
}
});
}
dispatchToSendFunds() {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
this.transaction = {address: '', amount: 0, blocks: 0, fees: 0};
}
get invalidValues(): boolean {
return (undefined === this.transaction.address || this.transaction.address === '')
|| (+this.flgCustomAmount && (undefined === this.transaction.amount || this.transaction.amount <= 0))
|| (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0))
|| (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0));
}
onCustomClicked() {
this.flgCustomAmount = '1';
}
onOptionChange(event) {
if (!+this.flgCustomAmount) {
delete this.transaction.amount;
}
}
resetData() {
this.transaction.address = '';
this.transaction.amount = 0;
this.transaction.blocks = 0;
this.transaction.fees = 0;
}
resetReceiveData() {
this.selectedAddress = {};
this.newAddress = '';
}
ngOnDestroy() {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

View file

@ -0,0 +1,68 @@
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="100" class="padding-gap">
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="58" fxLayoutAlign="start end">
<mat-form-field fxFlex="99">
<input matInput [(ngModel)]="transaction.address" placeholder="Bitcoin Address"
tabindex="1" name="address" #address="ngModel">
</mat-form-field>
</div>
<!-- <div fxFlex="38" fxLayoutAlign="start end">
<mat-radio-group fxFlex="100" fxLayoutAlign="space-between center" (change)="onOptionChange($event)" [(ngModel)]="flgCustomAmount">
<mat-radio-button fxFlex="35" value="0">Sweep All</mat-radio-button>
<mat-radio-button fxFlex="60" value="1">
<mat-form-field fxFlex="70"><input matInput [(ngModel)]="transaction.amount" (click)="onCustomClicked()" placeholder="Amount ({{information?.smaller_currency_unit}})" name="amount" type="number" step="100" min="0" tabindex="5" #amount="ngModel"></mat-form-field>
</mat-radio-button>
</mat-radio-group>
</div> -->
<div fxFlex="30" fxLayoutAlign="start end">
<mat-form-field fxFlex="70">
<input matInput [(ngModel)]="transaction.amount" placeholder="Amount" name="amount" type="number" step="100" min="0" tabindex="2" #amount="ngModel">
<span matSuffix> {{selAmountUnit}} </span>
</mat-form-field>
</div>
<mat-form-field fxFlex="10" fxLayoutAlign="start end">
<mat-select [value]="selAmountUnit" tabindex="3" required name="amountUnit" (selectionChange)="onAmountUnitChange($event)">
<mat-option *ngFor="let amountUnit of amountUnits" [value]="amountUnit">{{amountUnit}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="30" fxLayoutAlign="start start">
<mat-form-field fxFlex="99">
<mat-select [(value)]="selTransType" tabindex="4">
<mat-option *ngFor="let transType of transTypes" [value]="transType.id">
{{transType.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div fxFlex="30" fxLayoutAlign="start start">
<mat-form-field fxFlex="99" *ngIf="selTransType=='1'">
<input matInput [(ngModel)]="transaction.blocks" placeholder="Target Confirmation Blocks" type="number"
name="blocks" step="1" min="0" required tabindex="5" #blocks="ngModel">
</mat-form-field>
<mat-form-field fxFlex="99" *ngIf="selTransType=='2'">
<input matInput [(ngModel)]="transaction.fees"
placeholder="Fee ({{information?.smaller_currency_unit}}/Byte)" type="number" name="fees" step="1"
min="0" required tabindex="6" #fees="ngModel">
</mat-form-field>
</div>
<div fxFlex="40" fxLayoutAlign="space-between start">
<button fxFlex="48" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="7"
type="reset" (click)="resetData()">Clear Fields</button>
<button fxFlex="48" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="invalidValues" type="submit" tabindex="8" (click)="onSendFunds()">
<p *ngIf="invalidValues && (address.touched || address.dirty) && (amount.touched || amount.dirty); else sendText">
Invalid Values</p>
<ng-template #sendText>
<p>Send Funds</p>
</ng-template>
</button>
</div>
</div>
</div>
</div>
<ng-template #withoutData>
<h3>Sats</h3>
</ng-template>

View file

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

View file

@ -0,0 +1,196 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { SelNodeChild } from '../../../shared/models/RTLconfig';
import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../../shared/models/lndModels';
import { CURRENCY_UNITS } from '../../../shared/models/enums';
import { RTLConfiguration } from '../../../shared/models/RTLconfig';
import { LoggerService } from '../../../shared/services/logger.service';
import * as sha256 from 'sha256';
import { LNDEffects } from '../../store/lnd.effects';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-on-chain-send',
templateUrl: './on-chain-send.component.html',
styleUrls: ['./on-chain-send.component.scss']
})
export class OnChainSendComponent implements OnInit, OnDestroy {
public selNode: SelNodeChild = {};
public appConfig: RTLConfiguration;
public addressTypes = [];
public flgLoadingWallet: Boolean | 'error' = true;
public selectedAddress: AddressType = {};
public blockchainBalance: Balance = {};
public information: GetInfo = {};
public newAddress = '';
public transaction: ChannelsTransaction = {};
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1';
public flgCustomAmount = '1';
public amountUnits = CURRENCY_UNITS;
public selAmountUnit = CURRENCY_UNITS[0];
public currConvertorRate = {};
public unitConversionValue = 0;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private httpClient: HttpClient) {}
ngOnInit() {
this.store.select('root')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((rootStore) => {
this.appConfig = rootStore.appConfig;
this.logger.info(rootStore);
});
}
onSendFunds() {
const confirmationMsg = {
'BTC Address': this.transaction.address,
};
if (!+this.flgCustomAmount) {
confirmationMsg['Sweep All'] = 'True';
this.transaction.sendAll = true;
} else {
confirmationMsg['Amount (' + this.information.smaller_currency_unit + ')'] = this.transaction.amount;
this.transaction.sendAll = false;
}
if (this.selTransType === '1') {
delete this.transaction.fees;
confirmationMsg['Target Confirmation Blocks'] = this.transaction.blocks;
} else {
delete this.transaction.blocks;
confirmationMsg['Fee (' + this.information.smaller_currency_unit + '/Byte)'] = this.transaction.fees;
}
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', message: JSON.stringify(confirmationMsg), noBtnText: 'Cancel', yesBtnText: 'Send'}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[2]))
.subscribe(confirmRes => {
if (confirmRes) {
if (this.transaction.sendAll && !+this.appConfig.sso.rtlSSO) {
this.store.dispatch(new RTLActions.OpenConfirmation({ width: '70%', data:
{type: 'CONFIRM', titleMessage: 'Enter Login Password', noBtnText: 'Cancel', yesBtnText: 'Authorize', flgShowInput: true, getInputs: [
{placeholder: 'Enter Login Password', inputType: 'password', inputValue: ''}
]}
}));
this.rtlEffects.closeConfirm
.pipe(takeUntil(this.unSubs[3]))
.subscribe(pwdConfirmRes => {
if (pwdConfirmRes) {
const pwd = pwdConfirmRes[0].inputValue;
this.store.dispatch(new RTLActions.IsAuthorized(sha256(pwd)));
this.rtlEffects.isAuthorizedRes
.pipe(take(1))
.subscribe(authRes => {
if (authRes !== 'ERROR') {
this.dispatchToSendFunds();
}
});
}
});
} else {
this.dispatchToSendFunds();
}
}
});
}
dispatchToSendFunds() {
this.store.dispatch(new RTLActions.OpenSpinner('Sending Funds...'));
this.store.dispatch(new RTLActions.SetChannelTransaction(this.transaction));
this.transaction = {address: '', amount: 0, blocks: 0, fees: 0};
}
get invalidValues(): boolean {
return (undefined === this.transaction.address || this.transaction.address === '')
|| (+this.flgCustomAmount && (undefined === this.transaction.amount || this.transaction.amount <= 0))
|| (this.selTransType === '1' && (undefined === this.transaction.blocks || this.transaction.blocks <= 0))
|| (this.selTransType === '2' && (undefined === this.transaction.fees || this.transaction.fees <= 0));
}
onCustomClicked() {
this.flgCustomAmount = '1';
}
onOptionChange(event) {
if (!+this.flgCustomAmount) {
delete this.transaction.amount;
}
}
resetData() {
this.transaction.address = '';
this.transaction.amount = 0;
this.transaction.blocks = 0;
this.transaction.fees = 0;
}
resetReceiveData() {
this.selectedAddress = {};
this.newAddress = '';
}
onAmountUnitChange(event: any) {
if(this.transaction.amount && this.selAmountUnit !== event.value) {
switch (this.selAmountUnit) {
case this.amountUnits[0]:
switch (event.value) {
case this.amountUnits[1]:
this.transaction.amount = this.transaction.amount * 0.00000001;
break;
case this.amountUnits[2]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last * 0.00000001);
break;
default:
break;
}
break;
case this.amountUnits[1]:
switch (event.value) {
case this.amountUnits[0]:
this.transaction.amount = this.transaction.amount * 100000000;
break;
case this.amountUnits[2]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last);
break;
default:
break;
}
break;
case this.amountUnits[2]:
switch (event.value) {
case this.amountUnits[0]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last) * 10000000;
break;
case this.amountUnits[1]:
// this.transaction.amount = +this.currencyConvert.transform(this.transaction.amount.toString(), this.currConvertorRate[this.amountUnits[2]].last);
break;
default:
break;
}
break;
default:
break;
}
}
this.selAmountUnit = event.value;
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

View file

@ -0,0 +1,42 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start start">
<div fxLayout="row" fxFlex="100" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2 w-100">
<div fxFlex="70">
<fa-icon [icon]="faHistory" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Transaction History</span>
</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutAlign="start center" class="w-100">
<div perfectScrollbar class="table-container" fxFlex="100">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="listTransactions" matSort
[ngClass]="{'overflow-auto error-border': flgLoading[0]==='error','overflow-auto': true}">
<ng-container matColumnDef="time_stamp_str">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date/Time </th>
<td mat-cell *matCellDef="let transaction">{{transaction.time_stamp_str}}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Amount (Sats) </th>
<td mat-cell *matCellDef="let transaction"><span fxLayoutAlign="end center">{{transaction.amount | number}}</span></td>
</ng-container>
<ng-container matColumnDef="num_confirmations">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Confirmations </th>
<td mat-cell *matCellDef="let transaction"><span fxLayoutAlign="end center">
{{transaction?.num_confirmations | number}} </span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pl-3 pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let transaction" class="pl-3">
<button mat-stroked-button color="primary" type="button" tabindex="4"
(click)="onTransactionClick(transaction, $event)">View Info</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions" showFirstLastButtons class="mb-4"></mat-paginator>
</div>
</div>
</div>

View file

@ -0,0 +1,4 @@
.mat-column-actions {
flex: 0 0 5%;
width: 5%;
}

View file

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

View file

@ -0,0 +1,115 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faHistory } from '@fortawesome/free-solid-svg-icons';
import { MatTableDataSource, MatSort, MatPaginator, MatPaginatorIntl } from '@angular/material';
import { Transaction } from '../../../shared/models/lndModels';
import { LoggerService } from '../../../shared/services/logger.service';
import { RTLEffects } from '../../../store/rtl.effects';
import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({
selector: 'rtl-on-chain-transaction-history',
templateUrl: './on-chain-transaction-history.component.html',
styleUrls: ['./on-chain-transaction-history.component.scss']
})
export class OnChainTransactionHistoryComponent implements OnInit, OnDestroy {
@ViewChild(MatSort, { static: true }) sort: MatSort;
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
faHistory = faHistory;
public displayedColumns = [];
public listTransactions: any;
public flgLoading: Array<Boolean | 'error'> = [true];
public flgSticky = false;
public pageSize = 10;
public pageSizeOptions = [5, 10, 25, 100];
private unsub: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private rtlEffects: RTLEffects, private actions$: Actions) {
switch (true) {
case (window.innerWidth <= 415):
this.displayedColumns = ['time_stamp_str', 'amount', 'actions'];
break;
case (window.innerWidth > 415 && window.innerWidth <= 730):
this.displayedColumns = ['time_stamp_str', 'amount', 'num_confirmations', 'actions'];
break;
case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.displayedColumns = ['time_stamp_str', 'amount', 'num_confirmations', 'actions'];
break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.flgSticky = true;
this.displayedColumns = ['time_stamp_str', 'amount', 'num_confirmations', 'actions'];
break;
default:
this.flgSticky = true;
this.displayedColumns = ['time_stamp_str', 'amount', 'num_confirmations', 'actions'];
break;
}
}
ngOnInit() {
this.store.dispatch(new RTLActions.FetchTransactions());
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => {
this.store.dispatch(new RTLActions.FetchTransactions());
});
this.store.select('lnd')
.pipe(takeUntil(this.unsub[0]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsLnd.forEach(effectsErr => {
if (effectsErr.action === 'FetchTransactions') {
this.flgLoading[0] = 'error';
}
});
if (undefined !== rtlStore.transactions) {
this.loadTransactionsTable(rtlStore.transactions);
}
if (this.flgLoading[0] !== 'error') {
this.flgLoading[0] = (undefined !== rtlStore.transactions) ? false : true;
}
this.logger.info(rtlStore);
});
}
applyFilter(selFilter: string) {
this.listTransactions.filter = selFilter;
}
onTransactionClick(selRow: Transaction, event: any) {
const flgExpansionClicked = event.target.className.includes('mat-expansion-panel-header') || event.target.className.includes('mat-expansion-indicator');
if (flgExpansionClicked) {
return;
}
const selTransaction = this.listTransactions.data.filter(transaction => {
return transaction.tx_hash === selRow.tx_hash;
})[0];
const reorderedTransactions = JSON.parse(JSON.stringify(selTransaction, [
'dest_addresses', 'time_stamp_str', 'num_confirmations', 'total_fees', 'block_hash', 'block_height', 'tx_hash', 'amount'
] , 2));
this.store.dispatch(new RTLActions.OpenAlert({ config: { width: '75%', data: {
type: 'INFO',
message: JSON.stringify(reorderedTransactions)
}}}));
}
loadTransactionsTable(transactions) {
this.listTransactions = new MatTableDataSource<Transaction>([...transactions]);
this.listTransactions.sort = this.sort;
this.listTransactions.paginator = this.paginator;
this.logger.info(this.listTransactions);
}
ngOnDestroy() {
this.unsub.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

View file

@ -0,0 +1,32 @@
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faChartPie" class="page-title-img mr-1"></fa-icon>
<span class="page-title">On-chain Balance</span>
</div>
<div fxLayout="column" class="padding-gap-x mb-4">
<mat-card>
<mat-card-content fxLayout="column">
<rtl-currency-unit-converter [values]="balances" [currencyUnits]="selNode.currencyUnits"></rtl-currency-unit-converter>
</mat-card-content>
</mat-card>
</div>
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faExchangeAlt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">On-chain Transactions</span>
</div>
<div fxLayout="column" class="padding-gap-x">
<mat-card>
<mat-card-content fxLayout="column">
<mat-tab-group>
<mat-tab label="Send">
<rtl-on-chain-send></rtl-on-chain-send>
</mat-tab>
<mat-tab label="Receive">
<rtl-on-chain-receive></rtl-on-chain-receive>
</mat-tab>
<mat-tab label="Sweep All">
<rtl-on-chain-send></rtl-on-chain-send>
</mat-tab>
</mat-tab-group>
</mat-card-content>
</mat-card>
</div>

View file

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

View file

@ -0,0 +1,75 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faExchangeAlt, faChartPie } from '@fortawesome/free-solid-svg-icons';
import { SelNodeChild } from '../../shared/models/RTLconfig';
import { GetInfo, Balance, ChannelsTransaction, AddressType } from '../../shared/models/lndModels';
import { RTLConfiguration } from '../../shared/models/RTLconfig';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
@Component({
selector: 'rtl-on-chain',
templateUrl: './on-chain.component.html',
styleUrls: ['./on-chain.component.scss']
})
export class OnChainComponent implements OnInit, OnDestroy {
public selNode: SelNodeChild = {};
public appConfig: RTLConfiguration;
public addressTypes = [];
public flgLoadingWallet: Boolean | 'error' = true;
public selectedAddress: AddressType = {};
public blockchainBalance: Balance = {};
public information: GetInfo = {};
public newAddress = '';
public transaction: ChannelsTransaction = {};
public transTypes = [{id: '1', name: 'Target Confirmation Blocks'}, {id: '2', name: 'Fee'}];
public selTransType = '1';
public flgCustomAmount = '1';
faExchangeAlt = faExchangeAlt;
faChartPie = faChartPie;
balances = [{title: 'Total Balance', dataValue: 0}, {title: 'Confirmed', dataValue: 0}, {title: 'Unconfirmed', dataValue: 0}];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private store: Store<fromRTLReducer.RTLState>, private actions$: Actions) {}
ngOnInit() {
this.store.select('lnd')
.pipe(takeUntil(this.unSubs[1]))
.subscribe((rtlStore) => {
rtlStore.effectErrorsLnd.forEach(effectsErr => {
if (effectsErr.action === 'FetchBalance/blockchain') {
this.flgLoadingWallet = 'error';
}
});
this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information;
this.addressTypes = rtlStore.addressTypes;
this.blockchainBalance = rtlStore.blockchainBalance;
if (undefined === this.blockchainBalance.total_balance) {
this.blockchainBalance.total_balance = 0;
}
if (undefined === this.blockchainBalance.confirmed_balance) {
this.blockchainBalance.confirmed_balance = 0;
}
if (undefined === this.blockchainBalance.unconfirmed_balance) {
this.blockchainBalance.unconfirmed_balance = 0;
}
this.balances = [{title: 'Total Balance', dataValue: this.blockchainBalance.total_balance}, {title: 'Confirmed', dataValue: this.blockchainBalance.confirmed_balance}, {title: 'Unconfirmed', dataValue: this.blockchainBalance.unconfirmed_balance}];
if (this.flgLoadingWallet !== 'error') {
this.flgLoadingWallet = false;
}
});
}
ngOnDestroy() {
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
}
}

View file

@ -28,7 +28,7 @@
</button> </button>
</div> </div>
<div fxFlex="15" fxLayoutAlign="start start"> <div fxFlex="15" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="4" type="reset" <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="4" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -18,7 +18,7 @@
</button> </button>
</div> </div>
<div fxFlex="15" fxLayoutAlign="start start"> <div fxFlex="15" fxLayoutAlign="start start">
<button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="2" type="reset" (click)="resetData()">Clear</button> <button fxFlex="90" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="2" type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -27,7 +27,7 @@
<div fxFlex="30" fxLayoutAlign="space-between stretch"> <div fxFlex="30" fxLayoutAlign="space-between stretch">
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary" <button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="rpForm.invalid" type="submit" tabindex="3">Fetch</button> [disabled]="rpForm.invalid" type="submit" tabindex="3">Fetch</button>
<button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="accent" class="ml-2" tabindex="4" <button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="primary" class="ml-2" tabindex="4"
type="reset" (click)="resetData()">Clear</button> type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -6,14 +6,14 @@ import { Actions, Effect, ofType } from '@ngrx/effects';
import { of, Subject } from 'rxjs'; import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators'; import { map, mergeMap, catchError, withLatestFrom } from 'rxjs/operators';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { MatDialog } from '@angular/material'; import { MatDialog } from '@angular/material';
import { environment, API_URL } from '../../../environments/environment'; import { environment, API_URL } from '../../../environments/environment';
import { InvoiceInformationComponent } from '../../shared/components/invoice-information/invoice-information.component';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
import { SessionService } from '../../shared/services/session.service'; import { SessionService } from '../../shared/services/session.service';
import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels'; import { GetInfo, GetInfoChain, Fees, Balance, NetworkInfo, Payment, GraphNode, Transaction, SwitchReq, ListInvoices } from '../../shared/models/lndModels';
import { CurrencyUnitEnum } from '../../shared/models/enums';
import { InvoiceInformationComponent } from '../../shared/components/invoice-information/invoice-information.component';
import * as RTLActions from '../../store/rtl.actions'; import * as RTLActions from '../../store/rtl.actions';
import * as fromRTLReducer from '../../store/rtl.reducers'; import * as fromRTLReducer from '../../store/rtl.reducers';
@ -599,9 +599,9 @@ export class LNDEffects implements OnDestroy {
} else { } else {
const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry }; const confirmationMsg = { 'Destination': action.payload[1].destination, 'Timestamp': action.payload[1].timestamp_str, 'Expiry': action.payload[1].expiry };
confirmationMsg['Amount (' + ((undefined === store.nodeData.smaller_currency_unit) ? confirmationMsg['Amount (' + ((undefined === store.nodeData.smaller_currency_unit) ?
'Sats' : store.nodeData.smaller_currency_unit) + ')'] = action.payload[1].num_satoshis; CurrencyUnitEnum.SATS : store.nodeData.smaller_currency_unit) + ')'] = action.payload[1].num_satoshis;
const msg = {}; const msg = {};
msg['Total Fee (' + ((undefined === store.nodeData.smaller_currency_unit) ? 'Sats' : store.nodeData.smaller_currency_unit) + ')'] = msg['Total Fee (' + ((undefined === store.nodeData.smaller_currency_unit) ? CurrencyUnitEnum.SATS : store.nodeData.smaller_currency_unit) + ')'] =
(sendRes.payment_route.total_fees_msat / 1000); (sendRes.payment_route.total_fees_msat / 1000);
Object.assign(msg, confirmationMsg); Object.assign(msg, confirmationMsg);
this.store.dispatch(new RTLActions.OpenAlert({ config: { this.store.dispatch(new RTLActions.OpenAlert({ config: {
@ -999,17 +999,17 @@ export class LNDEffects implements OnDestroy {
this.sessionService.setItem('lndUnlocked', 'true'); this.sessionService.setItem('lndUnlocked', 'true');
if (undefined !== info.chains) { if (undefined !== info.chains) {
if (typeof info.chains[0] === 'string') { if (typeof info.chains[0] === 'string') {
info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; info.smaller_currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? CurrencyUnitEnum.LITOSHIS : CurrencyUnitEnum.SATS;
info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; info.currency_unit = (info.chains[0].toString().toLowerCase().indexOf('bitcoin') < 0) ? CurrencyUnitEnum.LTC : CurrencyUnitEnum.BTC;
} else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) { } else if (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain')) {
const getInfoChain = <GetInfoChain>info.chains[0]; const getInfoChain = <GetInfoChain>info.chains[0];
info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'Litoshis' : 'Sats'; info.smaller_currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? CurrencyUnitEnum.LITOSHIS : CurrencyUnitEnum.SATS;
info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? 'LTC' : 'BTC'; info.currency_unit = (getInfoChain.chain.toLowerCase().indexOf('bitcoin') < 0) ? CurrencyUnitEnum.LTC : CurrencyUnitEnum.BTC;
} }
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0]; info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} else { } else {
info.smaller_currency_unit = 'Sats'; info.smaller_currency_unit = CurrencyUnitEnum.SATS;
info.currency_unit = 'BTC'; info.currency_unit = CurrencyUnitEnum.BTC;
info.version = (undefined === info.version) ? '' : info.version.split(' ')[0]; info.version = (undefined === info.version) ? '' : info.version.split(' ')[0];
} }
const node_data = { const node_data = {

View file

@ -27,7 +27,7 @@
<div fxFlex="30" fxLayoutAlign="space-between stretch"> <div fxFlex="30" fxLayoutAlign="space-between stretch">
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary" <button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary"
[disabled]="fhForm.invalid" type="submit" tabindex="3">Fetch</button> [disabled]="fhForm.invalid" type="submit" tabindex="3">Fetch</button>
<button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="accent" class="ml-2" tabindex="4" <button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="primary" class="ml-2" tabindex="4"
type="reset" (click)="resetData()">Clear</button> type="reset" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>

View file

@ -4,33 +4,33 @@
<mat-form-field fxFlex="100" fxLayoutAlign="start end"> <mat-form-field fxFlex="100" fxLayoutAlign="start end">
<input matInput [(ngModel)]="memo" placeholder="Memo" tabindex="1" name="memo"> <input matInput [(ngModel)]="memo" placeholder="Memo" tabindex="1" name="memo">
</mat-form-field> </mat-form-field>
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="60" fxLayoutAlign.gt-sm="space-between center"> <div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="70" fxLayoutAlign.gt-sm="space-between center">
<mat-form-field fxFlex="50" fxLayoutAlign="start end"> <mat-form-field fxFlex="40" fxLayoutAlign="start end">
<input matInput [(ngModel)]="invoiceValue" (keyup)="onInvoiceValueChange()" placeholder="Amount" type="number" step="100" min="1" tabindex="2" name="invoiceValue"> <input matInput [(ngModel)]="invoiceValue" (keyup)="onInvoiceValueChange()" placeholder="Amount" type="number" step="100" min="1" tabindex="2" name="invoiceValue">
<span matSuffix> {{information?.smaller_currency_unit}} </span> <span matSuffix> {{information?.smaller_currency_unit | titlecase}} </span>
<mat-hint>{{invoiceValueHint}}</mat-hint> <mat-hint>{{invoiceValueHint}}</mat-hint>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="15" fxLayoutAlign="start end"> <mat-form-field fxFlex="15" fxLayoutAlign="start end">
<input matInput [(ngModel)]="expiry" placeholder="Expiry" type="number" step="{{selTimeUnit === 'Secs' ? 300 : selTimeUnit === 'Mins' ? 10 : selTimeUnit === 'Hours' ? 2 : 1}}" min="1" tabindex="3" name="expiry"> <input matInput [(ngModel)]="expiry" placeholder="Expiry" type="number" step="{{selTimeUnit === timeUnitEnum.SECS ? 300 : selTimeUnit === timeUnitEnum.MINS ? 10 : selTimeUnit === timeUnitEnum.HOURS ? 2 : 1}}" min="1" tabindex="3" name="expiry">
<span matSuffix> {{selTimeUnit}} </span> <span matSuffix> {{selTimeUnit | titlecase}} </span>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="15" fxLayoutAlign="start end"> <mat-form-field fxFlex="15" fxLayoutAlign="start end">
<mat-select [value]="selTimeUnit" tabindex="4" required name="timeUnit" (selectionChange)="onTimeUnitChange($event)"> <mat-select [value]="selTimeUnit" tabindex="4" required name="timeUnit" (selectionChange)="onTimeUnitChange($event)">
<mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">{{timeUnit}}</mat-option> <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">{{timeUnit | titlecase}}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div fxFlex="15" tabindex="4" fxLayoutAlign="start center"> <div fxFlex="25" tabindex="4" fxLayoutAlign="start center">
<mat-slide-toggle color="primary" [(ngModel)]="private" matTooltip="Include routing hints for private channels" [matTooltipPosition]="'above'" name="private">Private</mat-slide-toggle> <mat-slide-toggle color="primary" [(ngModel)]="private" matTooltip="Include routing hints for private channels" [matTooltipPosition]="'above'" name="private">Private Routing Hints</mat-slide-toggle>
</div> </div>
</div> </div>
</div> </div>
<div class="mt-2"> <div class="mt-2">
<button fxFlex="48" fxFlex.gt-md="10" fxLayoutAlign="center center" class="mr-2" mat-raised-button color="primary" [disabled]="addInvoiceForm.form.invalid" (click)="onAddInvoice(addInvoiceForm)" tabindex="5" class="mr-2"> <button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="primary" class="mr-2" tabindex="5" type="reset" (click)="resetData()">Clear Field</button>
<p *ngIf="addInvoiceForm.form.invalid; else createText">Invalid values</p> <button fxFlex="48" fxFlex.gt-md="10" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="addInvoiceForm.form.invalid" (click)="onAddInvoice(addInvoiceForm)" tabindex="6">
<ng-template #createText><p>Create Invoice</p></ng-template> <p *ngIf="addInvoiceForm.form.invalid; else createText">Invalid values</p>
</button> <ng-template #createText><p>Create Invoice</p></ng-template>
<button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="6" type="reset" (click)="resetData()">Clear Field</button> </button>
</div> </div>
</form> </form>
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2"> <div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2">
<div fxFlex="70"> <div fxFlex="70">
@ -44,16 +44,12 @@
<div perfectScrollbar class="table-container"> <div perfectScrollbar class="table-container">
<mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar> <mat-progress-bar *ngIf="flgLoading[0]===true" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="invoices" matSort [ngClass]="{'overflow-auto error-border': flgLoading[0]==='error','overflow-auto': true}"> <table mat-table #table [dataSource]="invoices" matSort [ngClass]="{'overflow-auto error-border': flgLoading[0]==='error','overflow-auto': true}">
<ng-container matColumnDef="settled">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Settled </th>
<td mat-cell *matCellDef="let invoice">
<span *ngIf="invoice.settled"><i class="material-icons primary">done_all</i></span>
<span *ngIf="!invoice.settled"><i class="material-icons primary">done</i></span>
</td>
</ng-container>
<ng-container matColumnDef="creation_date"> <ng-container matColumnDef="creation_date">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Date Created </th> <th mat-header-cell *matHeaderCellDef mat-sort-header> Date Created </th>
<td mat-cell *matCellDef="let invoice">{{invoice.creation_date_str}}</td> <td mat-cell *matCellDef="let invoice">
<span *ngIf="invoice.settled" class="green-dot"></span>
<span *ngIf="!invoice.settled" class="yellow-dot"></span>
{{invoice.creation_date_str}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="memo"> <ng-container matColumnDef="memo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Memo </th> <th mat-header-cell *matHeaderCellDef mat-sort-header> Memo </th>
@ -70,7 +66,7 @@
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pr-3"><span fxLayoutAlign="end center">Actions</span></th> <th mat-header-cell *matHeaderCellDef class="pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let invoice"> <td mat-cell *matCellDef="let invoice">
<button mat-stroked-button color="accent" type="button" tabindex="4" (click)="onInvoiceClick(invoice, $event)">View Info</button> <button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onInvoiceClick(invoice, $event)">View Info</button>
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>

View file

@ -1,19 +1,19 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { DecimalPipe } from '@angular/common'; import { DecimalPipe } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { faHistory } from '@fortawesome/free-solid-svg-icons'; import { faHistory } from '@fortawesome/free-solid-svg-icons';
import { getInvoicesPaginator } from '../../../shared/services/paginator.service';
import { MatTableDataSource, MatSort, MatPaginatorIntl } from '@angular/material'; import { MatTableDataSource, MatSort, MatPaginatorIntl } from '@angular/material';
import { getInvoicesPaginator } from '../../../shared/services/paginator.service';
import { TimeUnitEnum, CurrencyUnitEnum, TIME_UNITS } from '../../../shared/models/enums';
import { SelNodeChild } from '../../../shared/models/RTLconfig'; import { SelNodeChild } from '../../../shared/models/RTLconfig';
import { GetInfo, Invoice } from '../../../shared/models/lndModels'; import { GetInfo, Invoice } from '../../../shared/models/lndModels';
import { CurrencyUnitConvertPipe } from '../../../shared/pipes/app.pipe';
import { LoggerService } from '../../../shared/services/logger.service'; import { LoggerService } from '../../../shared/services/logger.service';
import { InvoiceInformationComponent } from '../../../shared/components/invoice-information/invoice-information.component'; import { CommonService } from '../../../shared/services/common.service';
import { InvoiceInformationComponent } from '../../../shared/components/invoice-information/invoice-information.component';
import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation'; import { newlyAddedRowAnimation } from '../../../shared/animation/row-animation';
import * as RTLActions from '../../../store/rtl.actions'; import * as RTLActions from '../../../store/rtl.actions';
import * as fromRTLReducer from '../../../store/rtl.reducers'; import * as fromRTLReducer from '../../../store/rtl.reducers';
@ -30,8 +30,6 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
export class LightningInvoicesComponent implements OnInit, OnDestroy { export class LightningInvoicesComponent implements OnInit, OnDestroy {
@ViewChild(MatSort, { static: true }) sort: MatSort; @ViewChild(MatSort, { static: true }) sort: MatSort;
faHistory = faHistory; faHistory = faHistory;
public currencyUnits = [];
public currConvertorRate = null;
public selNode: SelNodeChild = {}; public selNode: SelNodeChild = {};
public newlyAddedInvoiceMemo = ''; public newlyAddedInvoiceMemo = '';
public newlyAddedInvoiceValue = 0; public newlyAddedInvoiceValue = 0;
@ -47,34 +45,35 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
public flgLoading: Array<Boolean | 'error'> = [true]; public flgLoading: Array<Boolean | 'error'> = [true];
public flgSticky = false; public flgSticky = false;
public private = false; public private = false;
public timeUnits = ['Secs', 'Mins', 'Hours', 'Days'];
public selTimeUnit = 'Secs';
public expiryStep = 100; public expiryStep = 100;
public totalInvoices = 100; public totalInvoices = 100;
public pageSize = 10; public pageSize = 10;
public pageSizeOptions = [5, 10, 25, 100]; public pageSizeOptions = [5, 10, 25, 100];
public timeUnitEnum = TimeUnitEnum;
public timeUnits = TIME_UNITS;
public selTimeUnit = TimeUnitEnum.SECS;
private firstOffset = -1; private firstOffset = -1;
private lastOffset = -1; private lastOffset = -1;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private httpClient: HttpClient, private currencyConvert: CurrencyUnitConvertPipe, private decimalPipe: DecimalPipe) { constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private decimalPipe: DecimalPipe, private commonService: CommonService) {
switch (true) { switch (true) {
case (window.innerWidth <= 415): case (window.innerWidth <= 415):
this.displayedColumns = ['settled', 'creation_date', 'value', 'actions']; this.displayedColumns = ['creation_date', 'value', 'actions'];
break; break;
case (window.innerWidth > 415 && window.innerWidth <= 730): case (window.innerWidth > 415 && window.innerWidth <= 730):
this.displayedColumns = ['settled', 'creation_date', 'value', 'settle_date', 'actions']; this.displayedColumns = ['creation_date', 'value', 'settle_date', 'actions'];
break; break;
case (window.innerWidth > 730 && window.innerWidth <= 1024): case (window.innerWidth > 730 && window.innerWidth <= 1024):
this.displayedColumns = ['settled', 'creation_date', 'memo', 'value', 'settle_date', 'actions']; this.displayedColumns = ['creation_date', 'memo', 'value', 'settle_date', 'actions'];
break; break;
case (window.innerWidth > 1024 && window.innerWidth <= 1280): case (window.innerWidth > 1024 && window.innerWidth <= 1280):
this.flgSticky = true; this.flgSticky = true;
this.displayedColumns = ['settled', 'creation_date', 'memo', 'value', 'settle_date', 'actions']; this.displayedColumns = ['creation_date', 'memo', 'value', 'settle_date', 'actions'];
break; break;
default: default:
this.flgSticky = true; this.flgSticky = true;
this.displayedColumns = ['settled', 'creation_date', 'memo', 'value', 'settle_date', 'actions']; this.displayedColumns = ['creation_date', 'memo', 'value', 'settle_date', 'actions'];
break; break;
} }
} }
@ -88,7 +87,6 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
this.flgLoading[0] = 'error'; this.flgLoading[0] = 'error';
} }
}); });
this.currencyUnits = rtlStore.nodeSettings.currencyUnits;
this.selNode = rtlStore.nodeSettings; this.selNode = rtlStore.nodeSettings;
this.information = rtlStore.information; this.information = rtlStore.information;
this.totalInvoices = rtlStore.totalInvoices; this.totalInvoices = rtlStore.totalInvoices;
@ -105,21 +103,8 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
onAddInvoice(form: any) { onAddInvoice(form: any) {
let expiryInSecs = (this.expiry ? this.expiry : 3600); let expiryInSecs = (this.expiry ? this.expiry : 3600);
if (this.selTimeUnit !== this.timeUnits[0]) { if (this.selTimeUnit !== TimeUnitEnum.SECS) {
switch (this.selTimeUnit) { expiryInSecs = this.commonService.convertTime(this.expiry, this.selTimeUnit, TimeUnitEnum.SECS);
case this.timeUnits[1]:
expiryInSecs = this.expiry * 60;
break;
case this.timeUnits[2]:
expiryInSecs = this.expiry * 3600;
break;
case this.timeUnits[3]:
expiryInSecs = this.expiry * 3600 * 24;
break;
default:
expiryInSecs = this.expiry;
break;
}
} }
this.flgAnimate = true; this.flgAnimate = true;
this.newlyAddedInvoiceMemo = this.memo; this.newlyAddedInvoiceMemo = this.memo;
@ -159,7 +144,7 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
this.private = false; this.private = false;
this.expiry = undefined; this.expiry = undefined;
this.invoiceValueHint = ''; this.invoiceValueHint = '';
this.selTimeUnit = this.timeUnits[0]; this.selTimeUnit = TimeUnitEnum.SECS;
} }
applyFilter(selFilter: string) { applyFilter(selFilter: string) {
@ -181,89 +166,19 @@ export class LightningInvoicesComponent implements OnInit, OnDestroy {
} }
onInvoiceValueChange() { onInvoiceValueChange() {
let self = this; if(this.invoiceValue > 99) {
if(this.currencyUnits[2] && this.invoiceValue && this.invoiceValue.toString().length > 2) {
if(!this.currConvertorRate) {
this.httpClient.get('https://blockchain.info/ticker')
.pipe(takeUntil(this.unSubs[0]))
.subscribe((currConvertorData: any) => {
self.currConvertorRate = currConvertorData;
self.invoiceValueHint = '= ' + currConvertorData[self.currencyUnits[2]].symbol + self.decimalPipe.transform(self.currencyConvert.transform(self.invoiceValue.toString(), currConvertorData[self.currencyUnits[2]].last * 0.00000001), '1.2-2') + ' ' + self.currencyUnits[2];
});
} else {
self.invoiceValueHint = '= ' + this.currConvertorRate[self.currencyUnits[2]].symbol + self.decimalPipe.transform(self.currencyConvert.transform(self.invoiceValue.toString(), this.currConvertorRate[self.currencyUnits[2]].last * 0.00000001), '1.2-2') + ' ' + self.currencyUnits[2];
}
} else {
this.invoiceValueHint = ''; this.invoiceValueHint = '';
this.commonService.convertCurrency(this.invoiceValue, CurrencyUnitEnum.SATS, this.selNode.currencyUnits[2])
.pipe(takeUntil(this.unSubs[1]))
.subscribe(data => {
this.invoiceValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, '1.2-2') + ' ' + data.unit;
});
} }
} }
onTimeUnitChange(event: any) { onTimeUnitChange(event: any) {
if(this.expiry && this.selTimeUnit !== event.value) { if(this.expiry && this.selTimeUnit !== event.value) {
switch (this.selTimeUnit) { this.expiry = this.commonService.convertTime(this.expiry, this.selTimeUnit, event.value);
case this.timeUnits[0]:
switch (event.value) {
case this.timeUnits[1]:
this.expiry = this.expiry / 60;
break;
case this.timeUnits[2]:
this.expiry = this.expiry / 3600;
break;
case this.timeUnits[3]:
this.expiry = this.expiry / (3600 * 24);
break;
default:
break;
}
break;
case this.timeUnits[1]:
switch (event.value) {
case this.timeUnits[0]:
this.expiry = this.expiry * 60;
break;
case this.timeUnits[2]:
this.expiry = this.expiry / 60;
break;
case this.timeUnits[3]:
this.expiry = this.expiry / (60 * 24);
break;
default:
break;
}
break;
case this.timeUnits[2]:
switch (event.value) {
case this.timeUnits[0]:
this.expiry = this.expiry * 3600;
break;
case this.timeUnits[1]:
this.expiry = this.expiry * 60;
break;
case this.timeUnits[3]:
this.expiry = this.expiry / 24;
break;
default:
break;
}
break;
case this.timeUnits[3]:
switch (event.value) {
case this.timeUnits[0]:
this.expiry = this.expiry * 3600 * 24;
break;
case this.timeUnits[1]:
this.expiry = this.expiry * 60 * 24;
break;
case this.timeUnits[2]:
this.expiry = this.expiry * 24;
break;
default:
break;
}
break;
default:
break;
}
} }
this.selTimeUnit = event.value; this.selTimeUnit = event.value;
} }

View file

@ -4,12 +4,12 @@
<input matInput placeholder="Payment Request" name="paymentRequest" [(ngModel)]="paymentRequest" tabindex="1" required #paymentReq="ngModel"> <input matInput placeholder="Payment Request" name="paymentRequest" [(ngModel)]="paymentRequest" tabindex="1" required #paymentReq="ngModel">
</mat-form-field> </mat-form-field>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" fxLayoutAlign.gt-md="start start"> <div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start" fxLayoutAlign.gt-md="start start">
<button fxFlex="48" fxFlex.gt-md="10" fxLayoutAlign="center center" class="mr-2" mat-raised-button color="primary" [disabled]="paymentReq.invalid" (click)="onSendPayment();" tabindex="2"> <button fxFlex="48" fxFlex.gt-md="10" mat-stroked-button color="primary" class="mr-2" tabindex="2" type="reset" (click)="resetData()">Clear Field</button>
<p *ngIf="paymentReq.invalid && (paymentReq.dirty || paymentReq.touched); else sendText">Invalid Req</p> <button fxFlex="48" fxFlex.gt-md="10" fxLayoutAlign="center center" mat-raised-button color="primary" [disabled]="paymentReq.invalid" (click)="onSendPayment();" tabindex="3">
<ng-template #sendText><p>Send Payment</p></ng-template> <p *ngIf="paymentReq.invalid && (paymentReq.dirty || paymentReq.touched); else sendText">Invalid Req</p>
</button> <ng-template #sendText><p>Send Payment</p></ng-template>
<button fxFlex="48" fxFlex.gt-md="10" mat-stroked-button color="accent" type="reset" tabindex="3" type="reset" (click)="resetData()">Clear Field</button> </button>
</div> </div>
</form> </form>
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2"> <div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-sub-title-container mt-2">
<div fxFlex="70"> <div fxFlex="70">
@ -46,7 +46,7 @@
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="pl-4 pr-3"><span fxLayoutAlign="end center">Actions</span></th> <th mat-header-cell *matHeaderCellDef class="pl-4 pr-3"><span fxLayoutAlign="end center">Actions</span></th>
<td mat-cell *matCellDef="let payment" class="pl-4"> <td mat-cell *matCellDef="let payment" class="pl-4">
<button mat-stroked-button color="accent" type="button" tabindex="4" (click)="onPaymentClick(payment,$event)">View Info</button> <button mat-stroked-button color="primary" type="button" tabindex="4" (click)="onPaymentClick(payment,$event)">View Info</button>
</td> </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>

View file

@ -1,11 +1,11 @@
<div fxLayout="row" fxLayoutAlign="start center" class="padding-gap-x page-title-container"> <div fxLayout="row wrap" fxLayoutAlign="start center" class="padding-gap-x page-title-container">
<fa-icon [icon]="faChartPie" class="page-title-img mr-1"></fa-icon> <fa-icon [icon]="faChartPie" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Lightning Balance</span> <span class="page-title">Lightning Balance</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x mb-4"> <div fxLayout="column" class="padding-gap-x mb-4">
<mat-card> <mat-card>
<mat-card-content fxLayout="column"> <mat-card-content fxLayout="column">
<rtl-currency-unit-converter [values]="balances"></rtl-currency-unit-converter> <rtl-currency-unit-converter [values]="balances" [currencyUnits]="currencyUnits"></rtl-currency-unit-converter>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>

View file

@ -1,14 +0,0 @@
.tree-invisible {
display: none;
}
.lookup-tree ul,
.lookup-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
.pl-3 {
padding-left: 3rem;
}

View file

@ -16,6 +16,7 @@ import * as fromRTLReducer from '../../store/rtl.reducers';
export class TransactionsComponent implements OnInit, OnDestroy { export class TransactionsComponent implements OnInit, OnDestroy {
faExchangeAlt = faExchangeAlt; faExchangeAlt = faExchangeAlt;
faChartPie = faChartPie; faChartPie = faChartPie;
currencyUnits = [];
balances = [{title: 'Local Capacity', dataValue: 0, tooltip: 'Amount you can send'}, {title: 'Remote Capacity', dataValue: 0, tooltip: 'Amount you can receive'}]; balances = [{title: 'Local Capacity', dataValue: 0, tooltip: 'Amount you can send'}, {title: 'Remote Capacity', dataValue: 0, tooltip: 'Amount you can receive'}];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
@ -25,6 +26,7 @@ export class TransactionsComponent implements OnInit, OnDestroy {
this.store.select('lnd') this.store.select('lnd')
.pipe(takeUntil(this.unSubs[0])) .pipe(takeUntil(this.unSubs[0]))
.subscribe((rtlStore) => { .subscribe((rtlStore) => {
this.currencyUnits = rtlStore.nodeSettings.currencyUnits;
this.balances = [{title: 'Local Capacity', dataValue: rtlStore.totalLocalBalance, tooltip: 'Amount you can send'}, {title: 'Remote Capacity', dataValue: rtlStore.totalRemoteBalance, tooltip: 'Amount you can receive'}]; this.balances = [{title: 'Local Capacity', dataValue: rtlStore.totalLocalBalance, tooltip: 'Amount you can send'}, {title: 'Remote Capacity', dataValue: rtlStore.totalRemoteBalance, tooltip: 'Amount you can receive'}];
this.logger.info(rtlStore); this.logger.info(rtlStore);
}); });

View file

@ -21,7 +21,7 @@
<mat-hint>Enter Wallet Password</mat-hint> <mat-hint>Enter Wallet Password</mat-hint>
</mat-form-field> </mat-form-field>
<button mat-raised-button fxFlex="15" color="primary" [disabled]="walletPassword == ''" (click)="onOperateWallet()" tabindex="4">Unlock Wallet</button> <button mat-raised-button fxFlex="15" color="primary" [disabled]="walletPassword == ''" (click)="onOperateWallet()" tabindex="4">Unlock Wallet</button>
<button fxFlex="15" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="5" type="reset" (click)="resetData()">Clear</button> <button fxFlex="15" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="5" type="reset" (click)="resetData()">Clear</button>
</form> </form>
</div> </div>
<ng-template #initBlock> <ng-template #initBlock>
@ -29,7 +29,7 @@
<form fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign="start" fxLayoutAlign.gt-sm="space-between" class="mt-2"> <form fxLayout="column" fxLayout.gt-sm="row wrap" fxLayoutAlign="start" fxLayoutAlign.gt-sm="space-between" class="mt-2">
<div fxFlex="65" fxLayoutAlign="start" class="insecure-message">Warning: Your connection is unsecure, it's not safe to generate private keys over this connection.Are you sure you want to proceed?</div> <div fxFlex="65" fxLayoutAlign="start" class="insecure-message">Warning: Your connection is unsecure, it's not safe to generate private keys over this connection.Are you sure you want to proceed?</div>
<button mat-raised-button fxFlex="15" color="primary" type="submit" (click)="proceed=true;warnRes=true" tabindex="4">Proceed</button> <button mat-raised-button fxFlex="15" color="primary" type="submit" (click)="proceed=true;warnRes=true" tabindex="4">Proceed</button>
<button fxFlex="15" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="5" type="reset" (click)="proceed=false;warnRes=true">Cancel</button> <button fxFlex="15" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="5" type="reset" (click)="proceed=false;warnRes=true">Cancel</button>
</form> </form>
</div> </div>
<div *ngIf="warnRes && !proceed" fxFlex="100" fxLayoutAlign="start" class="insecure-message mt-2">Please reconfig & restart RTL after securing your LND connction. You can close this window now.</div> <div *ngIf="warnRes && !proceed" fxFlex="100" fxLayoutAlign="start" class="insecure-message mt-2">Please reconfig & restart RTL after securing your LND connction. You can close this window now.</div>
@ -61,7 +61,7 @@
<mat-hint>Cipher Seed</mat-hint> <mat-hint>Cipher Seed</mat-hint>
</mat-form-field> </mat-form-field>
<button mat-raised-button color="primary" fxFlex="10" [disabled]="!cipherFormGroup.valid" type="submit" matStepperNext>Next</button> <button mat-raised-button color="primary" fxFlex="10" [disabled]="!cipherFormGroup.valid" type="submit" matStepperNext>Next</button>
<button mat-stroked-button color="accent" fxFlex="10" type="reset" matStepperPrevious>Back</button> <button mat-stroked-button color="primary" fxFlex="10" type="reset" matStepperPrevious>Back</button>
<div *ngIf="cipherFormGroup.errors?.invalidCipher && cipherFormGroup.controls.existingCipher.value && (cipherFormGroup.controls.cipherSeed.touched || cipherFormGroup.controls.cipherSeed.dirty)" class="validation-error-message"> <div *ngIf="cipherFormGroup.errors?.invalidCipher && cipherFormGroup.controls.existingCipher.value && (cipherFormGroup.controls.cipherSeed.touched || cipherFormGroup.controls.cipherSeed.dirty)" class="validation-error-message">
<mat-icon class="validation-error-icon red">cancel</mat-icon>Invalid Cipher. Enter comma separated 24 words cipher seed. <mat-icon class="validation-error-icon red">cancel</mat-icon>Invalid Cipher. Enter comma separated 24 words cipher seed.
</div> </div>

View file

@ -27,8 +27,8 @@ export class AlertMessageComponent implements OnInit {
setStyleOnAlertType() { setStyleOnAlertType() {
// INFO/WARN/ERROR/SUCCESS/CONFIRM // INFO/WARN/ERROR/SUCCESS/CONFIRM
if (this.data.type === 'WARN') { if (this.data.type === 'WARN') {
this.msgTypeBackground = 'bg-accent p-1'; this.msgTypeBackground = 'primary p-1';
this.msgTypeForeground = 'accent'; this.msgTypeForeground = 'primary';
} }
if (this.data.type === 'ERROR') { if (this.data.type === 'ERROR') {
this.msgTypeBackground = 'bg-warn p-1'; this.msgTypeBackground = 'bg-warn p-1';

View file

@ -122,7 +122,7 @@
<div class="mt-2"> <div class="mt-2">
<button class="mr-2" fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary" <button class="mr-2" fxFlex="10" fxLayoutAlign="center center" mat-raised-button color="primary"
(click)="onUpdateSettings()" tabindex="12">Update</button> (click)="onUpdateSettings()" tabindex="12">Update</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="accent" (click)="onResetSettings()" <button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="primary" (click)="onResetSettings()"
tabindex="13">Reset</button> tabindex="13">Reset</button>
</div> </div>
</div> </div>

View file

@ -31,7 +31,7 @@
</div> </div>
<mat-divider class="pb-1"></mat-divider> <mat-divider class="pb-1"></mat-divider>
<div fxLayoutAlign="center"> <div fxLayoutAlign="center">
<button mat-stroked-button color="accent" fxFlex="20" type="button" fxLayoutAlign="center center" class="mr-2" (click)="onClose(false)" default>{{noBtnText}}</button> <button mat-stroked-button color="primary" fxFlex="20" type="button" fxLayoutAlign="center center" class="mr-2" (click)="onClose(false)" default>{{noBtnText}}</button>
<button *ngIf="flgShowInput" mat-raised-button [color]="msgTypeForeground" fxLayoutAlign="center center" fxFlex="20" type="button" (click)="onClose(getInputs)" [disabled]="!getInputs[0].inputValue">{{yesBtnText}}</button> <button *ngIf="flgShowInput" mat-raised-button [color]="msgTypeForeground" fxLayoutAlign="center center" fxFlex="20" type="button" (click)="onClose(getInputs)" [disabled]="!getInputs[0].inputValue">{{yesBtnText}}</button>
<button *ngIf="!flgShowInput" mat-raised-button [color]="msgTypeForeground" fxLayoutAlign="center center" fxFlex="20" type="button" (click)="onClose(true)">{{yesBtnText}}</button> <button *ngIf="!flgShowInput" mat-raised-button [color]="msgTypeForeground" fxLayoutAlign="center center" fxFlex="20" type="button" (click)="onClose(true)">{{yesBtnText}}</button>
</div> </div>

View file

@ -1,11 +1,11 @@
<mat-tab-group> <mat-tab-group>
<mat-tab *ngFor="let currencyUnit of currencyUnits" [label]="currencyUnit"> <mat-tab *ngFor="let currencyUnit of currencyUnits" label="{{ currencyUnit }}">
<div fxLayout="row" fxFlex="100"> <div fxLayout="row" fxFlex="100">
<div fxLayout="column" *ngFor="let value of values" [matTooltip]="value.tooltip" [matTooltipPosition]="'below'" class="cc-data-block"> <div fxLayout="column" *ngFor="let value of values" [matTooltip]="value.tooltip" [matTooltipPosition]="'below'" class="cc-data-block">
<div class="cc-data-title">{{value.title}}</div> <div class="cc-data-title">{{value.title}}</div>
<span class="cc-data-value" *ngIf="currencyUnit === CurrencyUnitEnum.SATS">{{value.dataValue | number}}</span> <span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.SATS">{{value.dataValue | number}}</span>
<span class="cc-data-value" *ngIf="currencyUnit === CurrencyUnitEnum.BTC">{{value.dataValue | unitconvert:0.00000001 | number:'1.6-6'}}</span> <span class="cc-data-value" *ngIf="currencyUnit === currencyUnitEnum.BTC">{{value.dataValueBTC | number:'1.6-6'}}</span>
<span class="cc-data-value" *ngIf="currencyUnit !== CurrencyUnitEnum.SATS && currencyUnit !== CurrencyUnitEnum.BTC">{{value.dataValue | unitconvert:(unitConversionValue * 0.00000001) | number:'1.2-2'}}</span> <span class="cc-data-value" *ngIf="currencyUnit !== currencyUnitEnum.SATS && currencyUnit !== currencyUnitEnum.BTC">{{value.dataValueOTHER | number:'1.2-2'}}</span>
</div> </div>
</div> </div>
</mat-tab> </mat-tab>

View file

@ -1,13 +1,9 @@
import { Component, OnInit, OnDestroy, Input } from '@angular/core'; import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil, take } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { LoggerService } from '../../services/logger.service'; import { CurrencyUnitEnum } from '../../models/enums';
import { CurrencyUnit } from '../../models/enums'; import { CommonService } from '../../services/common.service';
import * as fromRTLReducer from '../../../store/rtl.reducers';
@Component({ @Component({
selector: 'rtl-currency-unit-converter', selector: 'rtl-currency-unit-converter',
@ -15,26 +11,41 @@ import * as fromRTLReducer from '../../../store/rtl.reducers';
styleUrls: ['./currency-unit-converter.component.scss'] styleUrls: ['./currency-unit-converter.component.scss']
}) })
export class CurrencyUnitConverterComponent implements OnInit, OnDestroy { export class CurrencyUnitConverterComponent implements OnInit, OnDestroy {
@Input() values = []; public currencyUnitEnum = CurrencyUnitEnum;
currencyUnits = []; private _values: Array<any>;
CurrencyUnitEnum = CurrencyUnit; private _currencyUnits = [];
unitConversionValue = 0; private unSubs = [new Subject()];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()]; get values(): Array<any> { return this._values; }
get currencyUnits(): Array<any> { return this._currencyUnits; }
@Input() set values(data: Array<any>) {
this._values = data;
if(this._currencyUnits.length > 2 && this._values[0].dataValue >= 0) {
this.getCurrencyValues(this._values);
}
}
@Input() set currencyUnits(data: Array<any>) {
this._currencyUnits = data;
if(this._currencyUnits.length > 2 && this._values[0].dataValue >= 0) {
this.getCurrencyValues(this._values);
}
}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private httpClient: HttpClient) {} constructor(public commonService: CommonService) {}
ngOnInit() { ngOnInit() {}
this.store.select('lnd')
.pipe(take(2)) getCurrencyValues(values) {
.subscribe((rtlStore) => { values.forEach(value => {
this.currencyUnits = rtlStore.nodeSettings.currencyUnits; if(value.dataValue > 0) {
this.logger.info(rtlStore); this.commonService.convertCurrency(value.dataValue, CurrencyUnitEnum.SATS, this.currencyUnits[2])
if(this.currencyUnits[2]) {
this.httpClient.get('https://blockchain.info/ticker')
.pipe(takeUntil(this.unSubs[0])) .pipe(takeUntil(this.unSubs[0]))
.subscribe((data: any) => { .subscribe(data => {
this.unitConversionValue = data[this.currencyUnits[2]].last; value.dataValueBTC = data.BTC;
value.dataValueOTHER = data.OTHER;
}); });
} else {
value.dataValueBTC = value.dataValue;
value.dataValueOTHER = value.dataValue;
} }
}); });
} }
@ -45,5 +56,4 @@ export class CurrencyUnitConverterComponent implements OnInit, OnDestroy {
completeSub.complete(); completeSub.complete();
}); });
} }
} }

View file

@ -8,7 +8,7 @@
<fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon> <fa-icon [icon]="faReceipt" class="page-title-img mr-1"></fa-icon>
<span class="page-title">Invoice Information</span> <span class="page-title">Invoice Information</span>
</div> </div>
<mat-icon fxFlex="5" type="button" (click)="onClose()" class="cursor-pointer icon-medium">close</mat-icon> <mat-icon tabindex="3" fxFlex="5" type="button" fxLayoutAlign="center center" (click)="onClose()" class="cursor-pointer icon-medium">close</mat-icon>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<div fxLayout="column"> <div fxLayout="column">
@ -69,11 +69,11 @@
<mat-divider class="w-100 my-1"></mat-divider> <mat-divider class="w-100 my-1"></mat-divider>
</div> </div>
<div [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}" fxLayout="row" fxLayoutAlign="end center"> <div [ngClass]="{'mt-2': !showAdvanced, 'mt-1': showAdvanced}" fxLayout="row" fxLayoutAlign="end center">
<button fxFlex="33" fxLayoutAlign="center center" class="mr-2" mat-raised-button color="primary" tabindex="2" type="submit" rtlClipboard [payload]="invoice.payment_request" (copied)="onCopyPayment($event)">Copy Payment Request</button> <button fxFlex="25" fxLayoutAlign="center center" mat-stroked-button color="primary" type="reset" (click)="onShowAdvanced()" tabindex="2" class="mr-2">
<button fxFlex="25" fxLayoutAlign="center center" mat-stroked-button color="accent" type="reset" (click)="onShowAdvanced()" tabindex="1">
<p *ngIf="!showAdvanced; else hideAdvancedText">Show Advanced</p> <p *ngIf="!showAdvanced; else hideAdvancedText">Show Advanced</p>
<ng-template #hideAdvancedText><p>Hide Advanced</p></ng-template> <ng-template #hideAdvancedText><p>Hide Advanced</p></ng-template>
</button> </button>
<button autoFocus fxFlex="33" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="1" type="submit" rtlClipboard [payload]="invoice.payment_request" (copied)="onCopyPayment($event)">Copy Payment Request</button>
</div> </div>
</div> </div>
</mat-card-content> </mat-card-content>

View file

@ -15,7 +15,7 @@
</mat-radio-group> </mat-radio-group>
<div fxFlex="30" fxLayoutAlign="space-between stretch"> <div fxFlex="30" fxLayoutAlign="space-between stretch">
<button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onShowConfig()" tabindex="2">Show Config</button> <button fxFlex="50" fxLayoutAlign="center center" mat-raised-button color="primary" (click)="onShowConfig()" tabindex="2">Show Config</button>
<button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="3" type="reset" class="ml-2" (click)="resetData()">Clear</button> <button fxFlex="50" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="3" type="reset" class="ml-2" (click)="resetData()">Clear</button>
</div> </div>
</form> </form>
<div *ngIf="configData !== '' && fileFormat === 'JSON'"> <div *ngIf="configData !== '' && fileFormat === 'JSON'">

View file

@ -14,7 +14,7 @@
</mat-form-field> </mat-form-field>
<button fxFlex="10" class="mr-2" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2" <button fxFlex="10" class="mr-2" fxLayoutAlign="center center" mat-raised-button color="primary" tabindex="2"
type="submit" [disabled]="!password">Login</button> type="submit" [disabled]="!password">Login</button>
<button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="accent" tabindex="3" type="reset" <button fxFlex="10" fxLayoutAlign="center center" mat-stroked-button color="primary" tabindex="3" type="reset"
(click)="resetData()">Clear</button> (click)="resetData()">Clear</button>
</form> </form>
</mat-card-content> </mat-card-content>

View file

@ -0,0 +1,17 @@
import { AfterContentInit, Directive, ElementRef, Input } from '@angular/core';
@Directive({
selector: '[autoFocus]'
})
export class AutoFocusDirective implements AfterContentInit {
@Input() public appAutoFocus: boolean;
public constructor(private el: ElementRef) {}
public ngAfterContentInit() {
setTimeout(() => {
this.el.nativeElement.focus();
}, 500);
}
}

View file

@ -1,11 +1,23 @@
export const CURRENCY_UNITS = [ 'SATS', 'BTC' ]; export const CURRENCY_UNITS = [ 'SATS', 'BTC' ];
export const TIME_UNITS = ['SECS', 'MINS', 'HOURS', 'DAYS'];
export enum AuthenticateWith { export enum AuthenticateWith {
TOKEN = 'TOKEN', TOKEN = 'TOKEN',
PASSWORD = 'PASSWORD' PASSWORD = 'PASSWORD'
} }
export enum CurrencyUnit { export enum TimeUnitEnum {
SATS = 'SATS', SECS = 'SECS',
BTC = 'BTC' MINS = 'MINS',
HOURS = 'HOURS',
DAYS = 'DAYS'
}
export enum CurrencyUnitEnum {
SATS = 'SATS',
BTC = 'BTC',
LITOSHIS = 'LITOSHIS',
LTC = 'LTC',
OTHER = 'OTHER'
} }

View file

@ -3,7 +3,7 @@ import { faTachometerAlt, faLink, faBolt, faExchangeAlt, faUsers, faProjectDiagr
export const MENU_DATA: MenuRootNode = { export const MENU_DATA: MenuRootNode = {
LNDChildren: [ LNDChildren: [
{id: 1, parentId: 0, name: 'Dashboard', iconType: 'FA', icon: faTachometerAlt, link: '/lnd/home'}, {id: 1, parentId: 0, name: 'Dashboard', iconType: 'FA', icon: faTachometerAlt, link: '/lnd/home'},
{id: 2, parentId: 0, name: 'On-chain', iconType: 'FA', icon: faLink, link: '/lnd/transsendreceive'}, {id: 2, parentId: 0, name: 'On-chain', iconType: 'FA', icon: faLink, link: '/lnd/onchain'},
{id: 3, parentId: 0, name: 'Lightning', iconType: 'FA', icon: faBolt, link: '/lnd/chnlmanage', children: [ {id: 3, parentId: 0, name: 'Lightning', iconType: 'FA', icon: faBolt, link: '/lnd/chnlmanage', children: [
{id: 31, parentId: 3, name: 'Peers/Channels', iconType: 'FA', icon: faUsers, link: '/lnd/chnlpending'}, {id: 31, parentId: 3, name: 'Peers/Channels', iconType: 'FA', icon: faUsers, link: '/lnd/chnlpending'},
{id: 32, parentId: 3, name: 'Transactions', iconType: 'FA', icon: faExchangeAlt, link: '/lnd/transactions'}, {id: 32, parentId: 3, name: 'Transactions', iconType: 'FA', icon: faExchangeAlt, link: '/lnd/transactions'},

View file

@ -10,12 +10,3 @@ export class RemoveLeadingZerosPipe implements PipeTransform {
} }
} }
@Pipe({ name: 'unitconvert' })
export class CurrencyUnitConvertPipe implements PipeTransform {
transform(value: string, multiplier?: number): string {
return (+value * multiplier).toString();
}
}

View file

@ -1,9 +1,23 @@
import { Injectable, OnDestroy } from '@angular/core'; import { Injectable, OnDestroy, OnInit } from '@angular/core';
import { Subject } from 'rxjs'; import { HttpClient } from '@angular/common/http';
import { Subject, of, Observable } from 'rxjs';
import { take, map } from 'rxjs/operators';
import { CurrencyUnitEnum, TimeUnitEnum } from '../models/enums';
@Injectable() @Injectable()
export class CommonService implements OnDestroy { export class CommonService implements OnInit, OnDestroy {
currencyUnits = [];
CurrencyUnitEnum = CurrencyUnitEnum;
unitConversionValue = 0;
containerWidthChanged = new Subject<string>(); containerWidthChanged = new Subject<string>();
conversionData = { data: null, last_fetched: null };
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private httpClient: HttpClient) {}
ngOnInit() {}
sortDescByKey(array, key) { sortDescByKey(array, key) {
return array.sort(function (a, b) { return array.sort(function (a, b) {
@ -23,8 +37,120 @@ export class CommonService implements OnDestroy {
this.containerWidthChanged.next(fieldType); this.containerWidthChanged.next(fieldType);
} }
convertCurrency(value: number, from: string, otherCurrencyUnit: string): Observable<any> {
let latest_date = new Date().valueOf();
if(this.conversionData.data && this.conversionData.last_fetched && (latest_date < (this.conversionData.last_fetched.valueOf() + 600000))) {
return of(this.convert(value, from, otherCurrencyUnit));
} else {
return this.httpClient.get('https://blockchain.info/ticker')
.pipe(take(1),
map(data => {
this.conversionData.data = data;
this.conversionData.last_fetched = latest_date;
this.unitConversionValue = this.conversionData.data[otherCurrencyUnit].last;
return this.convert(value, from, otherCurrencyUnit);
}));
}
}
convert(value: number, from: string, otherCurrencyUnit: string) {
let returnValue = {unit: otherCurrencyUnit, symbol: this.conversionData.data[otherCurrencyUnit].symbol, SATS: 0, BTC: 0, OTHER: 0};
switch (from) {
case CurrencyUnitEnum.SATS:
returnValue.SATS = value;
returnValue.BTC = value * 0.00000001;
returnValue.OTHER = value * 0.00000001 * this.unitConversionValue;
break;
case CurrencyUnitEnum.BTC:
returnValue.SATS = value * 100000000;
returnValue.BTC = value;
returnValue.OTHER = value * this.unitConversionValue;
break;
case CurrencyUnitEnum.OTHER:
returnValue.SATS = value / this.unitConversionValue * 100000000;
returnValue.BTC = value / this.unitConversionValue;
returnValue.OTHER = value;
break;
default:
break;
}
return returnValue;
}
convertTime(value: number, from: string, to: string) {
switch (from) {
case TimeUnitEnum.SECS:
switch (to) {
case TimeUnitEnum.MINS:
value = value / 60;
break;
case TimeUnitEnum.HOURS:
value = value / 3600;
break;
case TimeUnitEnum.DAYS:
value = value / (3600 * 24);
break;
default:
break;
}
break;
case TimeUnitEnum.MINS:
switch (to) {
case TimeUnitEnum.SECS:
value = value * 60;
break;
case TimeUnitEnum.HOURS:
value = value / 60;
break;
case TimeUnitEnum.DAYS:
value = value / (60 * 24);
break;
default:
break;
}
break;
case TimeUnitEnum.HOURS:
switch (to) {
case TimeUnitEnum.SECS:
value = value * 3600;
break;
case TimeUnitEnum.MINS:
value = value * 60;
break;
case TimeUnitEnum.DAYS:
value = value / 24;
break;
default:
break;
}
break;
case TimeUnitEnum.DAYS:
switch (to) {
case TimeUnitEnum.SECS:
value = value * 3600 * 24;
break;
case TimeUnitEnum.MINS:
value = value * 60 * 24;
break;
case TimeUnitEnum.HOURS:
value = value * 24;
break;
default:
break;
}
break;
default:
break;
}
return value;
}
ngOnDestroy() { ngOnDestroy() {
this.containerWidthChanged.next(); this.containerWidthChanged.next();
this.containerWidthChanged.complete(); this.containerWidthChanged.complete();
this.unSubs.forEach(completeSub => {
completeSub.next();
completeSub.complete();
});
} }
} }

View file

@ -31,7 +31,8 @@ import { ServerConfigComponent } from './components/server-config/server-config.
import { ErrorComponent } from './components/error/error.component'; import { ErrorComponent } from './components/error/error.component';
import { CurrencyUnitConverterComponent } from './components/currency-unit-converter/currency-unit-converter.component'; import { CurrencyUnitConverterComponent } from './components/currency-unit-converter/currency-unit-converter.component';
import { ClipboardDirective } from './directive/clipboard.directive'; import { ClipboardDirective } from './directive/clipboard.directive';
import { RemoveLeadingZerosPipe, CurrencyUnitConvertPipe } from './pipes/app.pipe'; import { AutoFocusDirective } from './directive/auto-focus.directive';
import { RemoveLeadingZerosPipe } from './pipes/app.pipe';
import { CommonService } from './services/common.service'; import { CommonService } from './services/common.service';
@NgModule({ @NgModule({
@ -125,10 +126,10 @@ import { CommonService } from './services/common.service';
ServerConfigComponent, ServerConfigComponent,
CurrencyUnitConverterComponent, CurrencyUnitConverterComponent,
ClipboardDirective, ClipboardDirective,
AutoFocusDirective,
QRCodeModule, QRCodeModule,
NgxChartsModule, NgxChartsModule,
RemoveLeadingZerosPipe, RemoveLeadingZerosPipe
CurrencyUnitConvertPipe
], ],
declarations: [ declarations: [
AppSettingsComponent, AppSettingsComponent,
@ -146,8 +147,8 @@ import { CommonService } from './services/common.service';
CurrencyUnitConverterComponent, CurrencyUnitConverterComponent,
ErrorComponent, ErrorComponent,
ClipboardDirective, ClipboardDirective,
RemoveLeadingZerosPipe, AutoFocusDirective,
CurrencyUnitConvertPipe RemoveLeadingZerosPipe
], ],
entryComponents: [ entryComponents: [
InvoiceInformationComponent, InvoiceInformationComponent,
@ -158,7 +159,7 @@ import { CommonService } from './services/common.service';
providers: [ providers: [
{ provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: { hasBackdrop: true, autoFocus: true, disableClose: true, role: 'dialog', width: '700px' } }, { provide: MAT_DIALOG_DEFAULT_OPTIONS, useValue: { hasBackdrop: true, autoFocus: true, disableClose: true, role: 'dialog', width: '700px' } },
{ provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 3000, verticalPosition: 'bottom', panelClass: 'rtl-snack-bar' } }, { provide: MAT_SNACK_BAR_DEFAULT_OPTIONS, useValue: { duration: 3000, verticalPosition: 'bottom', panelClass: 'rtl-snack-bar' } },
CommonService, CurrencyUnitConvertPipe, DecimalPipe CommonService, DecimalPipe
] ]
}) })
export class SharedModule { } export class SharedModule { }

View file

@ -2,7 +2,7 @@
@import '~@angular/material/theming'; @import '~@angular/material/theming';
@include mat-core(); @include mat-core();
$purple-primary: mat-palette($purple-primary, 500, 400, 700); $purple-primary: mat-palette($purple-primary, 500, 200, 800);
$purple-accent: mat-palette($mat-gray, 800, 600, 900); $purple-accent: mat-palette($mat-gray, 800, 600, 900);
$purple-warn: mat-palette($mat-red); $purple-warn: mat-palette($mat-red);

View file

@ -228,4 +228,17 @@
font-size: $large-font-size; font-size: $large-font-size;
} }
} }
.icon-medium.mat-icon:focus, .icon-medium.mat-icon:hover {
outline: none;
@include mat-elevation(1);
}
.mat-raised-button.mat-primary:focus, .mat-raised-button.mat-primary:hover {
@include mat-elevation(8);
}
.mat-raised-button.mat-primary:disabled {
cursor: not-allowed;
}
} }

View file

@ -42,6 +42,9 @@
} }
} }
&.day { &.day {
.mat-stroked-button.mat-primary {
border-color: $primary-color;
}
.ng-fa-icon, .mat-nested-tree-node-parent .mat-icon, .mat-form-field-suffix { .ng-fa-icon, .mat-nested-tree-node-parent .mat-icon, .mat-form-field-suffix {
color: $foreground-secondary-text; color: $foreground-secondary-text;
} }
@ -186,10 +189,6 @@
color: $primary-darker; color: $primary-darker;
} }
.mat-stroked-button.mat-accent:hover {
color: $primary-darker;
}
.cc-data-block { .cc-data-block {
margin-right: 3.2rem; margin-right: 3.2rem;
& .cc-data-title { & .cc-data-title {

View file

@ -19,4 +19,8 @@ $icon-size: 3.6rem;
$pubkey-info-height: 15px; $pubkey-info-height: 15px;
$tree-node-height:48px; $tree-node-height:48px;
$fa-icon-small-size: 2rem; $fa-icon-small-size: 2rem;
$fa-icon-regular-size: 4rem; $fa-icon-regular-size: 4rem;
$yellow-color: #ffbd2e;
$green-color: #28ca43;
$dot-size: 1.2rem;

View file

@ -658,7 +658,7 @@ a {
.mat-tree-node div:focus, .mat-tree-node div:active, .mat-nested-tree-node-parent div:focus, .mat-nested-tree-node-parent div:active, .mat-tree-node div:focus, .mat-tree-node div:active, .mat-nested-tree-node-parent div:focus, .mat-nested-tree-node-parent div:active,
.mat-tree-node .mat-icon:focus, .mat-tree-node .mat-icon:active, .mat-nested-tree-node-parent .mat-icon:focus, .mat-nested-tree-node-parent .mat-icon:active { .mat-tree-node .mat-icon:focus, .mat-tree-node .mat-icon:active, .mat-nested-tree-node-parent .mat-icon:focus, .mat-nested-tree-node-parent .mat-icon:active {
outline: none; outline: none;
} }
.lnd-info { .lnd-info {
height: $sidenav-info-height; height: $sidenav-info-height;
@ -742,6 +742,24 @@ table {
width:100%; width:100%;
} }
.mat-button-focus-overlay { // .mat-button-focus-overlay {
background-color: transparent!important; // background-color: transparent!important;
// }
.green-dot {
display: inline-flex;
width: $dot-size;
height: $dot-size;
border-radius: $dot-size;
margin-right: 1rem;
background-color: $green-color;
} }
.yellow-dot {
display: inline-flex;
width: $dot-size;
height: $dot-size;
border-radius: $dot-size;
margin-right: 1rem;
background-color: $yellow-color;
}