Dashboard with Pie Chart

Dashboard with Pie Chart
This commit is contained in:
Shahana Farooqui 2019-12-04 18:14:34 -05:00
parent 92b01b1761
commit 9f676f7468
29 changed files with 368 additions and 167 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

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="16x16" href="assets/images/favicon/favicon-16x16.png">
<link rel="manifest" href="assets/images/favicon/site.webmanifest">
<link rel="stylesheet" href="styles.f3946135b912b44b7ab0.css"></head>
<link rel="stylesheet" href="styles.2854cf815b8f6666c61c.css"></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.bd1f2742607d74fabe48.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.c3537a1c742904e625c2.js"></script></body>
<script src="runtime.32f66eb87b7f21a182be.js"></script><script src="polyfills-es5.92f4069201c83f4833ef.js" nomodule></script><script src="polyfills.5ddcccdb990eb395f306.js"></script><script src="main.ec8cc621bd3cf505ae93.js"></script></body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,72 +3,98 @@ var common = require('../../common');
var logger = require('../logger');
var options = {};
getAliasForChannel = (channel, channelType) => {
getAliasForChannel = (channel) => {
return new Promise(function(resolve, reject) {
if (undefined === channelType || channelType === 'all') {
options.url = common.getSelLNServerUrl() + '/graph/node/' + channel.remote_pubkey;
} else {
options.url = common.getSelLNServerUrl() + '/graph/node/' + channel.channel.remote_node_pub;
}
options.url = common.getSelLNServerUrl() + '/graph/node/' + channel.remote_pubkey;
request(options).then(function(aliasBody) {
logger.info({fileName: 'Channels', msg: 'Alias: ' + JSON.stringify(aliasBody.node.alias)});
if (undefined === channelType || channelType === 'all') {
channel.remote_alias = aliasBody.node.alias;
resolve(aliasBody.node.alias);
} else {
channel.channel.remote_alias = aliasBody.node.alias;
resolve(aliasBody.node.alias);
}
channel.remote_alias = aliasBody.node.alias;
resolve(aliasBody.node.alias);
})
.catch(err => resolve(''));
});
}
exports.getChannels = (req, res, next) => {
exports.getAllChannels = (req, res, next) => {
options = common.getOptions();
if (undefined === req.params.channelType || req.params.channelType === 'all') {
options.url = common.getSelLNServerUrl() + '/channels';
} else {
options.url = common.getSelLNServerUrl() + '/channels/' + req.params.channelType; // active_only, inactive_only, public_only, private_only, Not Implemented in Frontend yet
}
options.url = common.getSelLNServerUrl() + '/channels';
options.qs = req.query;
request(options).then(function (body) {
let channels = [];
if (undefined === req.params.channelType || req.params.channelType === 'all') {
channels = (undefined === body.channels) ? [] : body.channels;
if(body.channels) {
let channels = body.channels;
Promise.all(
channels.map(channel => {
return getAliasForChannel(channel, req.params.channelType);
return getAliasForChannel(channel);
})
)
.then(function(values) {
logger.info({fileName: 'Channels', msg: 'Channels with Alias: ' + JSON.stringify(body)});
logger.info({fileName: 'Channels', msg: 'All Channels with Alias: ' + JSON.stringify(body)});
body.channels = common.sortAscByKey(body.channels, 'capacity');
res.status(200).json(body);
}).catch(err => {
console.error(err.error);
logger.error({fileName: 'Channels', lineNum: 49, msg: 'Get All Channel Alias: ' + JSON.stringify(err)});
res.status(500).json({
message: 'Fetching Channels Alias Failed!',
error: err.error
});
});
} else {
if (undefined === body.total_limbo_balance) {
body.total_limbo_balance = 0;
body.btc_total_limbo_balance = 0;
} else {
body.btc_total_limbo_balance = common.convertToBTC(body.total_limbo_balance);
}
if (req.params.channelType === 'closed' && body.channels && body.channels.length > 0) {
body.channels.forEach(channel => {
channel.close_type = (undefined === channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type;
});
body.channels = common.sortDescByKey(body.channels, 'close_type');
}
logger.info({fileName: 'Channels', msg: 'Pending/Closed Channels: ' + JSON.stringify(body)});
body.channels = [];
res.status(200).json(body);
}
})
.catch(function (err) {
logger.error({fileName: 'Channels', lineNum: 68, msg: 'Get Channel: ' + JSON.stringify(err)});
logger.error({fileName: 'Channels', lineNum: 68, msg: 'Get All Channel: ' + JSON.stringify(err)});
return res.status(500).json({
message: 'Fetching Channels Failed!',
message: 'Fetching All Channels Failed!',
error: err.error
});
});
};
exports.getPendingChannels = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/channels/pending';
options.qs = req.query;
request(options).then(function (body) {
let channels = [];
if (undefined === body.total_limbo_balance) {
body.total_limbo_balance = 0;
body.btc_total_limbo_balance = 0;
} else {
body.btc_total_limbo_balance = common.convertToBTC(body.total_limbo_balance);
}
logger.info({fileName: 'Channels', msg: 'Pending Channels: ' + JSON.stringify(body)});
res.status(200).json(body);
})
.catch(function (err) {
logger.error({fileName: 'Channels', lineNum: 68, msg: 'Get Pending Channel: ' + JSON.stringify(err)});
return res.status(500).json({
message: 'Fetching Pending Channels Failed!',
error: err.error
});
});
};
exports.getClosedChannels = (req, res, next) => {
options = common.getOptions();
options.url = common.getSelLNServerUrl() + '/channels/closed';
options.qs = req.query;
request(options).then(function (body) {
let channels = [];
if (body.channels && body.channels.length > 0) {
body.channels.forEach(channel => {
channel.close_type = (undefined === channel.close_type) ? 'COOPERATIVE_CLOSE' : channel.close_type;
});
body.channels = common.sortDescByKey(body.channels, 'close_type');
}
logger.info({fileName: 'Channels', msg: 'Closed Channels: ' + JSON.stringify(body)});
res.status(200).json(body);
})
.catch(function (err) {
logger.error({fileName: 'Channels', lineNum: 68, msg: 'Get Closed Channel: ' + JSON.stringify(err)});
return res.status(500).json({
message: 'Fetching Closed Channels Failed!',
error: err.error
});
});

View file

@ -3,9 +3,10 @@ const express = require("express");
const router = express.Router();
const authCheck = require("../authCheck");
router.get("/", authCheck, ChannelsController.getChannels);
router.get("/", authCheck, ChannelsController.getAllChannels);
router.get("/pending", authCheck, ChannelsController.getPendingChannels);
router.get("/closed", authCheck, ChannelsController.getClosedChannels);
router.post("/", authCheck, ChannelsController.postChannel);
router.get("/:channelType", authCheck, ChannelsController.getChannels);
router.post("/transactions", authCheck, ChannelsController.postTransactions);
router.delete("/:channelPoint", authCheck, ChannelsController.closeChannel);
router.post("/chanPolicy", authCheck, ChannelsController.postChanPolicy);

View file

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start start">
<!-- <div fxLayout="column" fxFlex="100" fxLayoutAlign="start start">
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Lightning</h4>
<div class="foreground-secondary-text">{{balances.lightning | number}} (Sats)</div>
@ -7,11 +7,55 @@
<h4 fxLayoutAlign="start" class="font-bold-500">On-chain</h4>
<div class="foreground-secondary-text">{{balances.onchain | number}} (Sats)</div>
</div>
<div fxFlex="43" fxLayoutAlign="start start" style="margin-left: -2rem;">
<div fxFlex="43" fxLayoutAlign="start start" style="margin-left: -1.4rem;">
<div *ngIf="flgBalanceUpdated">
<ngx-charts-bar-horizontal
[view]="[360, 80]"
[scheme]="colorScheme"
[results]="totalBalances">
[yAxis]="true"
[showDataLabel]="true"
[tooltipDisabled]="true"
[view]="[360, 80]"
[results]="totalBalances">
</ngx-charts-bar-horizontal>
</div>
</div>
</div> -->
<!-- <div fxLayout="column" fxFlex="40" fxLayoutAlign="start start">
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Lightning</h4>
<div class="foreground-secondary-text">{{balances.lightning | number}} (Sats)</div>
</div>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">On-chain</h4>
<div class="foreground-secondary-text">{{balances.onchain | number}} (Sats)</div>
</div>
<div fxFlex="34" fxLayoutAlign="start start"></div>
</div>
<div fxLayout="column" fxFlex="60" fxLayoutAlign="start start">
<div *ngIf="flgBalanceUpdated">
<ngx-charts-bar-vertical
[xAxis]="true"
[showDataLabel]="true"
[tooltipDisabled]="true"
[view]="[190, 240]"
[results]="totalBalances">
</ngx-charts-bar-vertical>
</div>
</div> -->
<div fxLayout="column" fxFlex="40" fxLayoutAlign="start start">
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Lightning</h4>
<div class="foreground-secondary-text">{{balances.lightning | number}} (Sats)</div>
</div>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">On-chain</h4>
<div class="foreground-secondary-text">{{balances.onchain | number}} (Sats)</div>
</div>
<div fxFlex="34" fxLayoutAlign="start start"></div>
</div>
<div fxLayout="column" fxFlex="60" fxLayoutAlign="start start" *ngIf="flgInfoUpdate">
<ngx-charts-pie-chart class="balances-info-pie-chart" style="margin-top: -2.5rem;"
[explodeSlices]="true"
[view]="[190, 190]"
[results]="totalBalances">
</ngx-charts-pie-chart>
</div>

View file

@ -7,20 +7,18 @@ import { Component, OnChanges, Input } from '@angular/core';
})
export class BalancesInfoComponent implements OnChanges {
@Input() balances = { onchain: 0, lightning: 0 };
@Input() flgInfoUpdate = false;
flgBalanceUpdated = false;
totalBalances = [{'name': 'Lightning ', 'value': 45850609}, {'name': 'On-chain', 'value': 44755091}];
maxBalanceValue = 150;
totalBalances = [{'name': 'Lightning ', 'value': 0}, {'name': 'On-chain', 'value': 0}];
maxBalanceValue = 0;
xAxisLabel = 'Balance';
colorScheme = {domain: ['#FFFFFF']};
constructor() {}
ngOnChanges() {
// this.totalBalances = [{'name': 'Lightning ', 'value': this.balances.lightning}, {'name': 'On-chain', 'value': this.balances.onchain}];
// this.maxBalanceValue = (this.balances.lightning > this.balances.onchain) ? this.balances.lightning : this.balances.onchain;
// Object.assign(this, this.totalBalances);
this.flgBalanceUpdated = true;
console.warn(this.totalBalances);
this.totalBalances = [{'name': 'Lightning ', 'value': this.balances.lightning}, {'name': 'On-chain', 'value': this.balances.onchain}];
this.maxBalanceValue = (this.balances.lightning > this.balances.onchain) ? this.balances.lightning : this.balances.onchain;
Object.assign(this, this.totalBalances);
}
}

View file

@ -8,13 +8,18 @@
<mat-divider class="w-100 dashboard-divider"></mat-divider>
</div>
<div fxLayout="column" fxFlex="92" fxFlex.lt-md="85" fxLayoutAlign="start start" class="channels-capacity-scroll" perfectScrollbar>
<div fxLayout="column" fxFlex="100" class="w-100 mt-2" *ngFor="let channel of allChannels">
<h4>{{(channel.remote_alias || channel.remote_pubkey) | slice:0:24}}{{(channel.remote_alias || channel.remote_pubkey).length > 25 ? '...' : ''}}</h4>
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint fxFlex="50" fxLayoutAlign="start center" class="font-size-80"><strong class="font-weight-900">Local:</strong>{{channel.local_balance || 0 | number}} Sats</mat-hint>
<mat-hint fxFlex="50" fxLayoutAlign="end center" class="font-size-80"><strong class="font-weight-900">Remote:</strong>{{channel.remote_balance || 0 | number}} Sats</mat-hint>
<div fxLayout="column" fxFlex="100" class="w-100" *ngIf="allChannels && allChannels.length > 0; else noChannelBlock">
<div *ngFor="let channel of allChannels" class="mt-2">
<h4>{{(channel.remote_alias || channel.remote_pubkey) | slice:0:24}}{{(channel.remote_alias || channel.remote_pubkey).length > 25 ? '...' : ''}}</h4>
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint fxFlex="50" fxLayoutAlign="start center" class="font-size-80"><strong class="font-weight-900">Local:</strong>{{channel.local_balance || 0 | number}} Sats</mat-hint>
<mat-hint fxFlex="50" fxLayoutAlign="end center" class="font-size-80"><strong class="font-weight-900">Remote:</strong>{{channel.remote_balance || 0 | number}} Sats</mat-hint>
</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.local_balance && channel.local_balance > 0 ? ((+channel.local_balance/((+channel.local_balance)+(+channel.remote_balance)))*100) : 0}}"></mat-progress-bar>
</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.local_balance && channel.local_balance > 0 ? ((+channel.local_balance/((+channel.local_balance)+(+channel.remote_balance)))*100) : 0}}"></mat-progress-bar>
</div>
</div>
</div>
<ng-template #noChannelBlock>
<div fxLayout="column" fxFlex="100" class="w-100 mt-2">No channels available.</div>
</ng-template>

View file

@ -1,4 +1,4 @@
<div fxLayout="column" fxFlex="50" fxLayoutAlign="center start">
<div fxLayout="column" fxFlex="60" fxLayoutAlign="center start">
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Daily</h4>
<div class="foreground-secondary-text">{{fees?.day_fee_sum | number}} (Sats)</div>
@ -12,4 +12,11 @@
<div class="foreground-secondary-text">{{fees?.month_fee_sum | number}} (Sats)</div>
</div>
</div>
<div fxLayout="column" fxFlex="50" fxLayoutAlign="center center" style="background-color:#afa7d2;height:67%;border-radius: 500px;">Pie Chart</div>
<div fxLayout="column" fxFlex="60" fxLayoutAlign="start start" *ngIf="flgInfoUpdate">
<ngx-charts-gauge class="fee-info-gauge-chart" style="margin-top: -2.5rem;margin-left: -8rem;"
[showText]="false"
[max]="maxFeeValue"
[view]="[300, 300]"
[results]="totalFees">
</ngx-charts-gauge>
</div>

View file

@ -8,9 +8,24 @@ import { Fees } from '../../../shared/models/lndModels';
})
export class FeeInfoComponent implements OnChanges {
@Input() fees: Fees;
@Input() flgInfoUpdate = false;
totalFees = [{'name': 'Monthly', 'value': 0}, {'name': 'Weekly', 'value': 0}, {'name': 'Daily', 'value': 0}];
maxFeeValue = 100;
constructor() {}
ngOnChanges() {}
ngOnChanges() {
if(this.fees.month_fee_sum) {
this.totalFees = [{'name': 'Monthly', 'value': this.fees.month_fee_sum}, {'name': 'Weekly', 'value': this.fees.week_fee_sum}, {'name': 'Daily ', 'value': this.fees.day_fee_sum}];
let e = Math.ceil(Math.log(this.fees.month_fee_sum + 1) / Math.LN10);
let m = Math.pow(10, e - 1);
this.maxFeeValue = Math.ceil(this.fees.month_fee_sum / m) * m || 100;
Object.assign(this, this.totalFees);
} else {
this.totalFees = [{'name': 'Monthly', 'value': 0}, {'name': 'Weekly', 'value': 0}, {'name': 'Daily', 'value': 0}];
this.maxFeeValue = 100;
Object.assign(this, this.totalFees);
}
}
}

View file

@ -20,11 +20,11 @@
</mat-card-header>
<mat-card-content class="dashboard-card-content w-100" fxFlex="95">
<div [ngSwitch]="card.id" fxLayout="column" fxFlex="100">
<rtl-node-info fxFlex="100" *ngSwitchCase="'node'" [information]="information"></rtl-node-info>
<rtl-balances-info fxFlex="100" *ngSwitchCase="'balance'" [balances]="balances"></rtl-balances-info>
<rtl-channel-capacity-info fxFlex="100" *ngSwitchCase="'capacity'" [channelBalances]="channelBalances" [allChannels]="allChannels"></rtl-channel-capacity-info>
<rtl-fee-info fxFlex="100" *ngSwitchCase="'fee'" [fees]="fees"></rtl-fee-info>
<rtl-channel-status-info fxFlex="100" *ngSwitchCase="'status'" [channelsStatus]="channelsStatus"></rtl-channel-status-info>
<rtl-node-info fxFlex="100" *ngSwitchCase="'node'" [information]="information" [ngClass]="{'error-border': flgLoading[0]==='error'}"></rtl-node-info>
<rtl-balances-info fxFlex="100" *ngSwitchCase="'balance'" [flgInfoUpdate]="flgChildInfoUpdated" [balances]="balances" [ngClass]="{'error-border': flgLoading[2]==='error' || flgLoading[5]==='error'}"></rtl-balances-info>
<rtl-channel-capacity-info fxFlex="100" *ngSwitchCase="'capacity'" [channelBalances]="channelBalances" [allChannels]="allChannels" [ngClass]="{'error-border': flgLoading[5]==='error'}"></rtl-channel-capacity-info>
<rtl-fee-info fxFlex="100" *ngSwitchCase="'fee'" [flgInfoUpdate]="flgChildInfoUpdated" [fees]="fees" [ngClass]="{'error-border': flgLoading[1]==='error'}"></rtl-fee-info>
<rtl-channel-status-info fxFlex="100" *ngSwitchCase="'status'" [channelsStatus]="channelsStatus" [ngClass]="{'error-border': flgLoading[5]==='error' || flgLoading[6]==='error'}"></rtl-channel-status-info>
<h3 *ngSwitchDefault>Error! Unable to find information!</h3>
</div>
</mat-card-content>

View file

@ -2,14 +2,16 @@ import { Component, OnInit, OnDestroy } from '@angular/core';
import { map } from 'rxjs/operators';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faSmile } from '@fortawesome/free-regular-svg-icons';
import { LoggerService } from '../../shared/services/logger.service';
import { ChannelsStatus, GetInfo, Fees, Peer } from '../../shared/models/lndModels';
import { SelNodeChild } from '../../shared/models/RTLconfig';
import * as fromRTLReducer from '../../store/rtl.reducers';
import * as RTLActions from '../../store/rtl.actions';
@Component({
selector: 'rtl-home',
@ -18,14 +20,15 @@ import * as fromRTLReducer from '../../store/rtl.reducers';
})
export class HomeComponent implements OnInit, OnDestroy {
public faSmile = faSmile;
public flgChildInfoUpdated = false;
public activeChannels = 0;
public inactiveChannels = 0;
public pendingChannels = 0;
public channelBalances = {localBalance: -1, remoteBalance: -1};
public channelBalances = {localBalance: 0, remoteBalance: 0};
public selNode: SelNodeChild = {};
public fees: Fees;
public information: GetInfo = {};
public balances = { onchain: -1, lightning: -1 };
public balances = { onchain: 0, lightning: 0 };
public allChannels = [];
public flgLoading: Array<Boolean | 'error'> = [true, true, true, true, true, true, true, true]; // 0: Info, 1: Fee, 2: Wallet, 3: Channel, 4: Network
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@ -53,8 +56,7 @@ export class HomeComponent implements OnInit, OnDestroy {
})
);
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private breakpointObserver: BreakpointObserver) {}
constructor(private logger: LoggerService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private breakpointObserver: BreakpointObserver) {}
ngOnInit() {
this.store.select('lnd')
@ -75,6 +77,8 @@ export class HomeComponent implements OnInit, OnDestroy {
}
if (effectsErr.action === 'FetchChannels/all') {
this.flgLoading[5] = 'error';
}
if (effectsErr.action === 'FetchChannels/pending') {
this.flgLoading[6] = 'error';
}
});
@ -88,18 +92,18 @@ export class HomeComponent implements OnInit, OnDestroy {
if (this.flgLoading[1] !== 'error') {
this.flgLoading[1] = (undefined !== this.fees.day_fee_sum) ? false : true;
}
this.balances.onchain = rtlStore.blockchainBalance.total_balance;
this.balances.onchain = (+rtlStore.blockchainBalance.total_balance >= 0) ? +rtlStore.blockchainBalance.total_balance : 0;
if (this.flgLoading[2] !== 'error') {
this.flgLoading[2] = (this.balances.onchain >= 0) ? false : true;
this.flgLoading[2] = false;
}
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0) {
this.channelBalances = { localBalance: rtlStore.totalLocalBalance, remoteBalance: rtlStore.totalRemoteBalance };
this.balances.lightning = rtlStore.totalLocalBalance;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
this.channelBalances = { localBalance: rtlStore.totalLocalBalance, remoteBalance: rtlStore.totalRemoteBalance };
this.balances.lightning = rtlStore.totalLocalBalance;
if (this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
this.balances = Object.assign({}, this.balances);
this.activeChannels = rtlStore.numberOfActiveChannels;
this.inactiveChannels = rtlStore.numberOfInactiveChannels;
this.pendingChannels = (undefined !== rtlStore.pendingChannels.pending_open_channels) ? rtlStore.pendingChannels.pending_open_channels.length : 0;
@ -112,12 +116,22 @@ export class HomeComponent implements OnInit, OnDestroy {
pending: { channels: this.pendingChannels, capacity: rtlStore.pendingChannels.total_limbo_balance },
closed: { channels: (rtlStore.closedChannels && rtlStore.closedChannels.length) ? rtlStore.closedChannels.length : 0, capacity: 0 }
};
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0 && this.flgLoading[6] !== 'error') {
this.flgLoading[6] = false;
if (rtlStore.totalLocalBalance >= 0 && rtlStore.totalRemoteBalance >= 0 && this.flgLoading[5] !== 'error') {
this.flgLoading[5] = false;
}
this.allChannels = rtlStore.allChannels.filter(channel => channel.active === true);
this.logger.info(rtlStore);
});
this.actions$.pipe(takeUntil(this.unSubs[2]),
filter((action) => action.type === RTLActions.FETCH_FEES || action.type === RTLActions.SET_FEES))
.subscribe(action => {
if(action.type === RTLActions.FETCH_FEES) {
this.flgChildInfoUpdated = false;
}
if(action.type === RTLActions.SET_FEES) {
this.flgChildInfoUpdated = true;
}
});
}
ngOnDestroy() {

View file

@ -14,7 +14,6 @@ export class NodeInfoComponent implements OnChanges {
constructor(private commonService: CommonService) { }
ngOnChanges() {
console.warn(this.information);
if(this.information && this.information.chains && this.information.chains.length > 0) {
this.chains = [''];
this.information.chains.forEach(chain => {

View file

@ -71,8 +71,8 @@ export class ChannelBackupTableComponent implements OnInit, OnDestroy {
this.actions$
.pipe(
takeUntil(this.unSubs[1]),
filter((action) => action.type === RTLActions.SET_CHANNELS)
).subscribe((setchannels: RTLActions.SetChannels) => {
filter((action) => action.type === RTLActions.SET_ALL_CHANNELS)
).subscribe((setchannels: RTLActions.SetAllChannels) => {
this.selChannel = undefined;
});
}

View file

@ -59,7 +59,7 @@ export class ChannelClosedTableComponent implements OnInit, OnDestroy {
ngOnInit() {
this.actions$.pipe(takeUntil(this.unsub[2]), filter((action) => action.type === RTLActions.RESET_LND_STORE)).subscribe((resetLndStore: RTLActions.ResetLNDStore) => {
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'}));
this.store.dispatch(new RTLActions.FetchClosedChannels());
});
this.store.select('lnd')
.pipe(takeUntil(this.unsub[0]))

View file

@ -231,11 +231,10 @@ export class LNDEffects implements OnDestroy {
this.logger.info(postRes);
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' }));
this.store.dispatch(new RTLActions.FetchAllChannels());
this.store.dispatch(new RTLActions.BackupChannels({ channelPoint: 'ALL', showMessage: 'Channel Added Successfully!' }));
return {
type: RTLActions.FETCH_CHANNELS,
payload: { routeParam: 'pending', channelStatus: '' }
type: RTLActions.FETCH_PENDING_CHANNELS
};
}),
catchError((err: any) => {
@ -258,8 +257,7 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.OpenAlert({ width: '55%', data: { type: AlertTypeEnum.SUCCESS, alertTitle: 'Channel Updated', titleMessage: 'Channel Updated Successfully!' }}));
return {
type: RTLActions.FETCH_CHANNELS,
payload: { routeParam: 'all', channelStatus: '' }
type: RTLActions.FETCH_ALL_CHANNELS
};
}),
catchError((err: any) => {
@ -281,11 +279,11 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.CloseSpinner());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchBalance('blockchain'));
this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' }));
this.store.dispatch(new RTLActions.FetchAllChannels());
if (action.payload.forcibly) {
this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'pending' }));
this.store.dispatch(new RTLActions.FetchPendingChannels());
} else {
this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'closed' }));
this.store.dispatch(new RTLActions.FetchClosedChannels());
}
this.store.dispatch(new RTLActions.BackupChannels({ channelPoint: 'ALL', showMessage: 'Channel Closed Successfully!' }));
return {
@ -444,50 +442,82 @@ export class LNDEffects implements OnDestroy {
));
@Effect()
channelsFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_CHANNELS),
mergeMap((action: RTLActions.FetchChannels) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchChannels/' + action.payload.routeParam));
return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/' + action.payload.routeParam)
channelsAllFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_ALL_CHANNELS),
mergeMap((action: RTLActions.FetchAllChannels) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchChannels/all'));
return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API)
.pipe(
map((channels: any) => {
this.logger.info(channels);
if (action.payload.routeParam === 'pending') {
let pendingChannels = -1;
if (channels) {
pendingChannels = 0;
if (channels.pending_closing_channels) {
pendingChannels = pendingChannels + channels.pending_closing_channels.length;
}
if (channels.pending_force_closing_channels) {
pendingChannels = pendingChannels + channels.pending_force_closing_channels.length;
}
if (channels.pending_open_channels) {
pendingChannels = pendingChannels + channels.pending_open_channels.length;
}
if (channels.waiting_close_channels) {
pendingChannels = pendingChannels + channels.waiting_close_channels.length;
}
}
this.store.dispatch(new RTLActions.SetNodePendingChannelsData(pendingChannels));
return {
type: RTLActions.SET_PENDING_CHANNELS,
payload: channels ? { channels: channels, pendingChannels: pendingChannels } : {channels: {}, pendingChannels: pendingChannels}
};
} else if (action.payload.routeParam === 'closed') {
return {
type: RTLActions.SET_CLOSED_CHANNELS,
payload: (channels && channels.channels && channels.channels.length > 0) ? channels.channels : []
};
} else if (action.payload.routeParam === 'all') {
return {
type: RTLActions.SET_CHANNELS,
payload: (channels && channels.channels && channels.channels.length > 0) ? channels.channels : []
};
}
return {
type: RTLActions.SET_ALL_CHANNELS,
payload: (channels && channels.channels && channels.channels.length > 0) ? channels.channels : []
};
},
catchError((err: any) => {
this.handleErrorWithoutAlert('FetchChannels/' + action.payload.routeParam, err);
this.handleErrorWithoutAlert('FetchChannels/all', err);
return of({type: RTLActions.VOID});
})
));
}
));
@Effect()
channelsPendingFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_PENDING_CHANNELS),
mergeMap((action: RTLActions.FetchPendingChannels) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchChannels/pending'));
return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/pending')
.pipe(
map((channels: any) => {
this.logger.info(channels);
let pendingChannels = -1;
if (channels) {
pendingChannels = 0;
if (channels.pending_closing_channels) {
pendingChannels = pendingChannels + channels.pending_closing_channels.length;
}
if (channels.pending_force_closing_channels) {
pendingChannels = pendingChannels + channels.pending_force_closing_channels.length;
}
if (channels.pending_open_channels) {
pendingChannels = pendingChannels + channels.pending_open_channels.length;
}
if (channels.waiting_close_channels) {
pendingChannels = pendingChannels + channels.waiting_close_channels.length;
}
}
this.store.dispatch(new RTLActions.SetNodePendingChannelsData(pendingChannels));
return {
type: RTLActions.SET_PENDING_CHANNELS,
payload: channels ? { channels: channels, pendingChannels: pendingChannels } : {channels: {}, pendingChannels: pendingChannels}
};
},
catchError((err: any) => {
this.handleErrorWithoutAlert('FetchChannels/pending', err);
return of({type: RTLActions.VOID});
})
));
}
));
@Effect()
channelsClosedFetch = this.actions$.pipe(
ofType(RTLActions.FETCH_CLOSED_CHANNELS),
mergeMap((action: RTLActions.FetchClosedChannels) => {
this.store.dispatch(new RTLActions.ClearEffectErrorLnd('FetchChannels/closed'));
return this.httpClient.get(this.CHILD_API_URL + environment.CHANNELS_API + '/closed')
.pipe(
map((channels: any) => {
this.logger.info(channels);
return {
type: RTLActions.SET_CLOSED_CHANNELS,
payload: (channels && channels.channels && channels.channels.length > 0) ? channels.channels : []
};
},
catchError((err: any) => {
this.handleErrorWithoutAlert('FetchChannels/closed', err);
return of({type: RTLActions.VOID});
})
));
@ -626,7 +656,7 @@ export class LNDEffects implements OnDestroy {
titleMessage: 'Payment Sent Successfully!',
message: msg
}}));
this.store.dispatch(new RTLActions.FetchChannels({ routeParam: 'all' }));
this.store.dispatch(new RTLActions.FetchAllChannels());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchPayments());
return {
@ -1047,9 +1077,9 @@ export class LNDEffects implements OnDestroy {
this.store.dispatch(new RTLActions.FetchPeers());
this.store.dispatch(new RTLActions.FetchBalance('channels'));
this.store.dispatch(new RTLActions.FetchNetwork());
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'all'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'pending'}));
this.store.dispatch(new RTLActions.FetchChannels({routeParam: 'closed'}));
this.store.dispatch(new RTLActions.FetchAllChannels());
this.store.dispatch(new RTLActions.FetchPendingChannels());
this.store.dispatch(new RTLActions.FetchClosedChannels());
this.store.dispatch(new RTLActions.FetchInvoices({num_max_invoices: 10, reversed: true}));
this.store.dispatch(new RTLActions.FetchPayments());
let newRoute = this.location.path();

View file

@ -46,10 +46,10 @@ export const initLNDState: LNDState = {
numberOfActiveChannels: 0,
numberOfInactiveChannels: 0,
numberOfPendingChannels: -1,
totalCapacityActive: -1,
totalCapacityInactive: -1,
totalLocalBalance: -1,
totalRemoteBalance: -1,
totalCapacityActive: 0,
totalCapacityInactive: 0,
totalLocalBalance: 0,
totalRemoteBalance: 0,
totalInvoices: -1,
transactions: [],
payments: [],
@ -136,7 +136,7 @@ export function LNDReducer(state = initLNDState, action: RTLActions.RTLActions)
pendingChannels: action.payload.channels,
numberOfPendingChannels: action.payload.pendingChannels,
};
case RTLActions.SET_CHANNELS:
case RTLActions.SET_ALL_CHANNELS:
let localBal = 0, remoteBal = 0, activeChannels = 0, inactiveChannels = 0, totalCapacityActive = 0, totalCapacityInactive = 0;
if (action.payload) {
action.payload.filter(channel => {

View file

@ -1,5 +1,4 @@
import { Component, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@ -14,7 +13,6 @@ import { RTLConfiguration, LightningNode, Settings, GetInfoRoot } from '../../..
import { LoggerService } from '../../../services/logger.service';
import { SessionService } from '../../../services/session.service';
import { GetInfoChain } from '../../../models/lndModels';
import { ShowPubkeyComponent } from '../../../components/data-modal/show-pubkey/show-pubkey.component';
import { MenuChildNode, MENU_DATA } from '../../../models/navMenu';
import { RTLEffects } from '../../../../store/rtl.effects';
@ -52,7 +50,7 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
navMenusLogout = new MatTreeNestedDataSource<MenuChildNode>();
navMenusShowData = new MatTreeNestedDataSource<MenuChildNode>();
constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects, private router: Router, private activatedRoute: ActivatedRoute) {
constructor(private logger: LoggerService, private sessionService: SessionService, private store: Store<fromRTLReducer.RTLState>, private actions$: Actions, private rtlEffects: RTLEffects) {
this.version = environment.VERSION;
if (MENU_DATA.LNDChildren[MENU_DATA.LNDChildren.length - 1].id === 200) {
MENU_DATA.LNDChildren.pop();

View file

@ -341,4 +341,59 @@
.mat-drawer-inner-container {
overflow: hidden;
}
.balances-info-pie-chart .ngx-charts .ng-star-inserted:nth-child(1) {
& .arc {
fill: mat-color($primary, 400);
}
& .arc.active, .arc:hover {
fill: mat-color($primary, 300);
}
}
.balances-info-pie-chart .ngx-charts .ng-star-inserted:nth-child(2) {
& .arc {
fill: mat-color($primary, 600);
}
& .arc.active, .arc:hover {
fill: mat-color($primary, 700);
}
}
.ngx-charts .arc.active, .ngx-charts .arc:hover {
opacity: 1;
transform: scale(1.03);
-webkit-transition: transform 200ms linear;
transition: transform 200ms linear;
}
.fee-info-gauge-chart .ngx-charts .gauge .ng-star-inserted:nth-child(1) g g:nth-child(2) {
& .arc {
fill: mat-color($primary, 700);
}
& .arc.active, .arc:hover {
fill: mat-color($primary, 900);
}
}
.fee-info-gauge-chart .ngx-charts .gauge .ng-star-inserted:nth-child(2) g g:nth-child(2) {
& .arc {
fill: mat-color($primary, 500);
}
& .arc.active, .arc:hover {
fill: mat-color($primary, 900);
}
}
.fee-info-gauge-chart .ngx-charts .gauge .ng-star-inserted:nth-child(3) g g:nth-child(2) {
& .arc {
fill: mat-color($primary, 300);
}
& .arc.active, .arc:hover {
fill: mat-color($primary, 900);
}
}
}

View file

@ -50,11 +50,13 @@ export const FETCH_BALANCE = 'FETCH_BALANCE';
export const SET_BALANCE = 'SET_BALANCE';
export const FETCH_NETWORK = 'FETCH_NETWORK';
export const SET_NETWORK = 'SET_NETWORK';
export const FETCH_CHANNELS = 'FETCH_CHANNELS';
export const SET_CHANNELS = 'SET_CHANNELS';
export const UPDATE_CHANNELS = 'UPDATE_CHANNELS';
export const FETCH_ALL_CHANNELS = 'FETCH_ALL_CHANNELS';
export const FETCH_PENDING_CHANNELS = 'FETCH_PENDING_CHANNELS';
export const FETCH_CLOSED_CHANNELS = 'FETCH_CLOSED_CHANNELS';
export const SET_ALL_CHANNELS = 'SET_ALL_CHANNELS';
export const SET_PENDING_CHANNELS = 'SET_PENDING_CHANNELS';
export const SET_CLOSED_CHANNELS = 'SET_CLOSED_CHANNELS';
export const UPDATE_CHANNELS = 'UPDATE_CHANNELS';
export const SAVE_NEW_CHANNEL = 'SAVE_NEW_CHANNEL';
export const CLOSE_CHANNEL = 'CLOSE_CHANNEL';
export const REMOVE_CHANNEL = 'REMOVE_CHANNEL';
@ -347,19 +349,17 @@ export class SetNetwork implements Action {
constructor(public payload: NetworkInfo) {}
}
export class FetchChannels implements Action {
readonly type = FETCH_CHANNELS;
constructor(public payload: {routeParam: string}) {}
export class FetchAllChannels implements Action {
readonly type = FETCH_ALL_CHANNELS;
}
export class SetChannels implements Action {
readonly type = SET_CHANNELS;
export class SetAllChannels implements Action {
readonly type = SET_ALL_CHANNELS;
constructor(public payload: Channel[]) {}
}
export class UpdateChannels implements Action {
readonly type = UPDATE_CHANNELS;
constructor(public payload: any) {}
export class FetchPendingChannels implements Action {
readonly type = FETCH_PENDING_CHANNELS;
}
export class SetPendingChannels implements Action {
@ -367,11 +367,20 @@ export class SetPendingChannels implements Action {
constructor(public payload: {channels: PendingChannels, pendingChannels: number}) {}
}
export class FetchClosedChannels implements Action {
readonly type = FETCH_CLOSED_CHANNELS;
}
export class SetClosedChannels implements Action {
readonly type = SET_CLOSED_CHANNELS;
constructor(public payload: ClosedChannel[]) {}
}
export class UpdateChannels implements Action {
readonly type = UPDATE_CHANNELS;
constructor(public payload: any) {}
}
export class SaveNewChannel implements Action {
readonly type = SAVE_NEW_CHANNEL;
constructor(public payload: {selectedPeerPubkey: string, fundingAmount: number, private: boolean, transType: string, transTypeValue: string, spendUnconfirmed: boolean}) {}
@ -824,7 +833,7 @@ export type RTLActions =
FetchFees | SetFees |
FetchBalance | SetBalance |
FetchNetwork | SetNetwork |
FetchChannels | SetChannels | SetPendingChannels | SetClosedChannels | UpdateChannels |
FetchAllChannels | SetAllChannels | FetchPendingChannels | SetPendingChannels | FetchClosedChannels | SetClosedChannels | UpdateChannels |
SaveNewChannel | CloseChannel | RemoveChannel |
BackupChannels | VerifyChannels | BackupChannelsRes | VerifyChannelsRes |
RestoreChannels | RestoreChannelsRes | RestoreChannelsList | SetRestoreChannelsList |