Merge branch 'master' into run_tests_on_merge
This commit is contained in:
commit
40c250502e
@ -228,7 +228,7 @@ class NodesApi {
|
|||||||
nodes.capacity
|
nodes.capacity
|
||||||
FROM nodes
|
FROM nodes
|
||||||
ORDER BY capacity DESC
|
ORDER BY capacity DESC
|
||||||
LIMIT 100
|
LIMIT 6
|
||||||
`;
|
`;
|
||||||
|
|
||||||
[rows] = await DB.query(query);
|
[rows] = await DB.query(query);
|
||||||
@ -269,14 +269,26 @@ class NodesApi {
|
|||||||
let query: string;
|
let query: string;
|
||||||
if (full === false) {
|
if (full === false) {
|
||||||
query = `
|
query = `
|
||||||
SELECT nodes.public_key as publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
SELECT
|
||||||
nodes.channels
|
nodes.public_key as publicKey,
|
||||||
|
IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
||||||
|
nodes.channels,
|
||||||
|
geo_names_city.names as city, geo_names_country.names as country,
|
||||||
|
geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision
|
||||||
FROM nodes
|
FROM nodes
|
||||||
|
LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country'
|
||||||
|
LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city'
|
||||||
|
LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code'
|
||||||
|
LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division'
|
||||||
ORDER BY channels DESC
|
ORDER BY channels DESC
|
||||||
LIMIT 100;
|
LIMIT 6;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
[rows] = await DB.query(query);
|
[rows] = await DB.query(query);
|
||||||
|
for (let i = 0; i < rows.length; ++i) {
|
||||||
|
rows[i].country = JSON.parse(rows[i].country);
|
||||||
|
rows[i].city = JSON.parse(rows[i].city);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
query = `
|
query = `
|
||||||
SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias,
|
||||||
|
@ -267,6 +267,7 @@ export class StartComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
resetScroll(): void {
|
resetScroll(): void {
|
||||||
this.scrollToBlock(this.chainTip);
|
this.scrollToBlock(this.chainTip);
|
||||||
|
this.blockchainContainer.nativeElement.scrollLeft = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPageIndexOf(height: number): number {
|
getPageIndexOf(height: number): number {
|
||||||
|
@ -199,8 +199,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands);
|
this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands);
|
||||||
|
|
||||||
this.middle = {
|
this.middle = {
|
||||||
path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.25} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.25}`,
|
path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.5} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.5}`,
|
||||||
style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}`
|
style: `stroke-width: ${this.combinedWeight + 1}; stroke: ${this.gradient[1]}`
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false)
|
this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false)
|
||||||
@ -257,7 +257,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
const lineParams = weights.map((w, i) => {
|
const lineParams = weights.map((w, i) => {
|
||||||
return {
|
return {
|
||||||
weight: w,
|
weight: w,
|
||||||
thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.min(this.combinedWeight + 0.5, Math.max(this.minWeight - 1, w) + 1),
|
thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.max(this.minWeight - 1, w) + 1,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
innerY: 0,
|
innerY: 0,
|
||||||
outerY: 0,
|
outerY: 0,
|
||||||
@ -269,7 +269,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
// bounds of the middle segment
|
// bounds of the middle segment
|
||||||
const innerTop = (this.height / 2) - (this.combinedWeight / 2);
|
const innerTop = (this.height / 2) - (this.combinedWeight / 2);
|
||||||
const innerBottom = innerTop + this.combinedWeight + 0.5;
|
const innerBottom = innerTop + this.combinedWeight;
|
||||||
// tracks the visual bottom of the endpoints of the previous line
|
// tracks the visual bottom of the endpoints of the previous line
|
||||||
let lastOuter = 0;
|
let lastOuter = 0;
|
||||||
let lastInner = innerTop;
|
let lastInner = innerTop;
|
||||||
@ -294,7 +294,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
// set the vertical position of the (center of the) outer side of the line
|
// set the vertical position of the (center of the) outer side of the line
|
||||||
line.outerY = lastOuter + (line.thickness / 2);
|
line.outerY = lastOuter + (line.thickness / 2);
|
||||||
line.innerY = Math.min(innerBottom - (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2)));
|
line.innerY = Math.min(innerBottom + (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2)));
|
||||||
|
|
||||||
// special case to center single input/outputs
|
// special case to center single input/outputs
|
||||||
if (xputs.length === 1) {
|
if (xputs.length === 1) {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top nodes per capacity -->
|
<!-- Top nodes per capacity -->
|
||||||
<div class="col">
|
<div class="col" style="max-height: 410px">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/liquidity' | relativeUrl]">
|
||||||
@ -69,7 +69,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top nodes per channels -->
|
<!-- Top nodes per channels -->
|
||||||
<div class="col">
|
<div class="col" style="max-height: 410px">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
<a class="title-link" href="" [routerLink]="['/lightning/nodes/rankings/connectivity' | relativeUrl]">
|
||||||
|
@ -1,71 +1,56 @@
|
|||||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
|
||||||
<h1 *ngIf="!widget" class="float-left">
|
|
||||||
<span i18n="lightning.top-100-liquidity">Top 100 nodes liquidity ranking</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div [class]="widget ? 'widget' : 'full'">
|
|
||||||
<table class="table table-borderless table-fixed">
|
<div class="container-xl" style="min-height: 335px" [ngClass]="{'widget': widget, 'full-height': !widget}">
|
||||||
|
<h1 *ngIf="!widget" class="float-left" i18n="lightning.liquidity-ranking">Liquidity Ranking</h1>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<div style="min-height: 295px">
|
||||||
|
<table class="table table-borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<th class="rank"></th>
|
<th class="text-left" i18n="nodes.alias">Alias</th>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="liquidity text-right" i18n="node.liquidity">Liquidity</th>
|
||||||
<th class="capacity text-right" i18n="node.liquidity">Liquidity</th>
|
<th class="d-table-cell fiat text-right" [class]="{'widget': widget}">{{ currency$ | async }}</th>
|
||||||
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell channels text-right" i18n="lightning.channels">Channels</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody *ngIf="topNodesPerCapacity$ | async as nodes; else skeleton">
|
<tbody *ngIf="topNodesPerCapacity$ | async as nodes">
|
||||||
<tr *ngFor="let node of nodes; let i = index;">
|
<tr *ngFor="let node of nodes;">
|
||||||
<td class="rank text-left">
|
<td class="pool text-left">
|
||||||
{{ i + 1 }}
|
<div class="tooltip-custom d-block w-100">
|
||||||
|
<a class="link d-block w-100" [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">
|
||||||
|
<span class="pool-name w-100">{{ node.alias }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="alias text-left">
|
<td class="text-right">
|
||||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">{{ node.alias }}</a>
|
|
||||||
</td>
|
|
||||||
<td class="capacity text-right">
|
|
||||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="channels text-right">
|
<td class="d-table-cell fiat text-right" [ngClass]="{'widget': widget}">
|
||||||
|
<app-fiat [value]="node.capacity"></app-fiat>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
{{ node.channels | number }}
|
{{ node.channels | number }}
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right text-truncate">
|
||||||
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<ng-template #skeleton>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let item of skeletonRows">
|
|
||||||
<td class="rank text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="alias text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="capacity text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="channels text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</ng-template>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="!widget">
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<br>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
</div>
|
||||||
|
@ -1,91 +1,52 @@
|
|||||||
.container-xl {
|
.container-xl {
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
padding-bottom: 100px;
|
}
|
||||||
@media (min-width: 960px) {
|
.container-xl.widget {
|
||||||
padding-left: 50px;
|
padding-right: 0px;
|
||||||
padding-right: 50px;
|
padding-left: 0px;
|
||||||
}
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td, .table th {
|
tr, td, th {
|
||||||
padding: 0.5rem;
|
border: 0px;
|
||||||
|
padding-top: 0.65rem !important;
|
||||||
|
padding-bottom: 0.7rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .rank {
|
.clear-link {
|
||||||
width: 5%;
|
color: white;
|
||||||
}
|
|
||||||
.widget .rank {
|
|
||||||
@media (min-width: 960px) {
|
|
||||||
width: 13%;
|
|
||||||
}
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .alias {
|
.pool {
|
||||||
width: 20%;
|
width: 15%;
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
white-space: nowrap;
|
||||||
@media (max-width: 960px) {
|
max-width: 160px;
|
||||||
width: 40%;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.widget .alias {
|
.pool-name {
|
||||||
width: 60%;
|
display: inline-block;
|
||||||
overflow: hidden;
|
vertical-align: text-top;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
overflow: hidden;
|
||||||
@media (max-width: 960px) {
|
|
||||||
max-width: 175px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .capacity {
|
.liquidity {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 575px) {
|
||||||
width: 30%;
|
width: 25%;
|
||||||
}
|
|
||||||
}
|
|
||||||
.widget .capacity {
|
|
||||||
width: 32%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .channels {
|
.fiat {
|
||||||
width: 15%;
|
width: 15%;
|
||||||
padding-right: 50px;
|
@media (min-width: 768px) and (max-width: 991px) {
|
||||||
@media (max-width: 960px) {
|
display: none !important;
|
||||||
display: none;
|
}
|
||||||
|
@media (max-width: 575px) {
|
||||||
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .timestamp-first {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .timestamp-update {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .location {
|
|
||||||
width: 15%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,8 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { INodesRanking, ITopNodesPerCapacity } from '../../../interfaces/node-api.interface';
|
import { INodesRanking, ITopNodesPerCapacity } from '../../../interfaces/node-api.interface';
|
||||||
import { SeoService } from '../../../services/seo.service';
|
import { SeoService } from '../../../services/seo.service';
|
||||||
import { isMobile } from '../../../shared/common.utils';
|
|
||||||
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
||||||
import { LightningApiService } from '../../lightning-api.service';
|
import { LightningApiService } from '../../lightning-api.service';
|
||||||
|
|
||||||
@ -18,18 +18,22 @@ export class TopNodesPerCapacity implements OnInit {
|
|||||||
|
|
||||||
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
||||||
skeletonRows: number[] = [];
|
skeletonRows: number[] = [];
|
||||||
|
currency$: Observable<string>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: LightningApiService,
|
private apiService: LightningApiService,
|
||||||
private seoService: SeoService
|
private seoService: SeoService,
|
||||||
|
private stateService: StateService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.currency$ = this.stateService.fiatCurrency$;
|
||||||
|
|
||||||
if (!this.widget) {
|
if (!this.widget) {
|
||||||
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
this.seoService.setTitle($localize`:@@2d9883d230a47fbbb2ec969e32a186597ea27405:Liquidity Ranking`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
||||||
this.skeletonRows.push(i);
|
this.skeletonRows.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +54,7 @@ export class TopNodesPerCapacity implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
||||||
map((ranking) => {
|
map((ranking) => {
|
||||||
return ranking.topByCapacity.slice(0, isMobile() ? 8 : 7);
|
return ranking.topByCapacity.slice(0, 6);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,56 @@
|
|||||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
|
||||||
<h1 *ngIf="!widget" class="float-left">
|
|
||||||
<span i18n="lightning.top-100-connectivity">Top 100 nodes connectivity ranking</span>
|
|
||||||
</h1>
|
|
||||||
|
|
||||||
<div [class]="widget ? 'widget' : 'full'">
|
|
||||||
|
<div class="container-xl" style="min-height: 335px" [ngClass]="{'widget': widget, 'full-height': !widget}">
|
||||||
|
<h1 *ngIf="!widget" class="float-left" i18n="lightning.liquidity-ranking">Liquidity Ranking</h1>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<div style="min-height: 295px">
|
||||||
<table class="table table-borderless">
|
<table class="table table-borderless">
|
||||||
<thead>
|
<thead>
|
||||||
<th class="rank"></th>
|
<th class="pool text-left" i18n="nodes.alias" [ngClass]="{'widget': widget}">Alias</th>
|
||||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
<th class="liquidity text-right" i18n="node.channels">Channels</th>
|
||||||
<th class="channels text-right" i18n="node.channels">Channels</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell channels text-right" i18n="lightning.channels">Capacity</th>
|
||||||
<th *ngIf="!widget" class="capacity text-right" i18n="lightning.liquidity">Liquidity</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell text-right" i18n="node.liquidity">{{ currency$ | async }}</th>
|
||||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="transaction.first-seen|Transaction first seen">First seen</th>
|
||||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
<th *ngIf="!widget" class="d-none d-md-table-cell timestamp text-right" i18n="lightning.last_update">Last update</th>
|
||||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
<th class="geolocation d-table-cell text-right" i18n="lightning.location">Location</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody *ngIf="topNodesPerChannels$ | async as nodes; else skeleton">
|
<tbody *ngIf="topNodesPerChannels$ | async as nodes">
|
||||||
<tr *ngFor="let node of nodes; let i = index;">
|
<tr *ngFor="let node of nodes;">
|
||||||
<td class="rank text-left">
|
<td class="pool text-left">
|
||||||
{{ i + 1 }}
|
<div class="tooltip-custom d-block w-100">
|
||||||
|
<a class="link d-block w-100" [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">
|
||||||
|
<span class="pool-name w-100">{{ node.alias }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="alias text-left">
|
<td class="text-right">
|
||||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">{{ node.alias }}</a>
|
{{ node.channels ? (node.channels | number) : '~' }}
|
||||||
</td>
|
</td>
|
||||||
<td class="channels text-right">
|
<td *ngIf="!widget" class="d-none d-md-table-cell capacity text-right">
|
||||||
{{ node.channels | number }}
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="capacity text-right">
|
|
||||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
<td *ngIf="!widget" class="fiat d-none d-md-table-cell text-right">
|
||||||
|
<app-fiat [value]="node.capacity"></app-fiat>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
<td *ngIf="!widget" class="d-none d-md-table-cell text-right">
|
||||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt" [hideTimeSince]="true"></app-timestamp>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
<td class="geolocation d-table-cell text-right text-truncate">
|
||||||
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
<app-geolocation [data]="node.geolocation" [type]="'list-isp'"></app-geolocation>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<ng-template #skeleton>
|
|
||||||
<tbody>
|
|
||||||
<tr *ngFor="let item of skeletonRows">
|
|
||||||
<td class="rank text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="alias text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td class="channels text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="capacity text-right">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
|
||||||
<span class="skeleton-loader"></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</ng-template>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="!widget">
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
<br>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
</div>
|
||||||
|
@ -1,91 +1,54 @@
|
|||||||
.container-xl {
|
.container-xl {
|
||||||
max-width: 1400px;
|
max-width: 1400px;
|
||||||
padding-bottom: 100px;
|
}
|
||||||
@media (min-width: 960px) {
|
.container-xl.widget {
|
||||||
padding-left: 50px;
|
padding-right: 0px;
|
||||||
padding-right: 50px;
|
padding-left: 0px;
|
||||||
}
|
padding-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table td, .table th {
|
tr, td, th {
|
||||||
padding: 0.5rem;
|
border: 0px;
|
||||||
|
padding-top: 0.65rem !important;
|
||||||
|
padding-bottom: 0.7rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .rank {
|
.clear-link {
|
||||||
width: 5%;
|
color: white;
|
||||||
}
|
|
||||||
.widget .rank {
|
|
||||||
@media (min-width: 960px) {
|
|
||||||
width: 13%;
|
|
||||||
}
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .alias {
|
.pool {
|
||||||
width: 20%;
|
width: 15%;
|
||||||
|
@media (max-width: 576px) {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
white-space: nowrap;
|
||||||
@media (max-width: 960px) {
|
max-width: 160px;
|
||||||
width: 40%;
|
|
||||||
max-width: 500px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.widget .alias {
|
.pool-name {
|
||||||
width: 60%;
|
display: inline-block;
|
||||||
overflow: hidden;
|
vertical-align: text-top;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: 350px;
|
overflow: hidden;
|
||||||
@media (max-width: 960px) {
|
}
|
||||||
max-width: 175px;
|
.pool.widget {
|
||||||
}
|
width: 45%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .capacity {
|
.liquidity {
|
||||||
width: 10%;
|
width: 10%;
|
||||||
@media (max-width: 960px) {
|
@media (max-width: 576px) {
|
||||||
width: 30%;
|
width: 25%;
|
||||||
}
|
|
||||||
}
|
|
||||||
.widget .capacity {
|
|
||||||
width: 32%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
padding-left: 0px;
|
|
||||||
padding-right: 0px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.full .channels {
|
.geolocation {
|
||||||
width: 15%;
|
@media (min-width: 768px) and (max-width: 991px) {
|
||||||
padding-right: 50px;
|
display: none !important;
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
@media (max-width: 575px) {
|
||||||
|
display: none !important;
|
||||||
.full .timestamp-first {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .timestamp-update {
|
|
||||||
width: 10%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.full .location {
|
|
||||||
width: 15%;
|
|
||||||
@media (max-width: 960px) {
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface';
|
||||||
import { isMobile } from '../../../shared/common.utils';
|
|
||||||
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component';
|
||||||
import { LightningApiService } from '../../lightning-api.service';
|
import { LightningApiService } from '../../lightning-api.service';
|
||||||
|
|
||||||
@ -17,13 +17,17 @@ export class TopNodesPerChannels implements OnInit {
|
|||||||
|
|
||||||
topNodesPerChannels$: Observable<ITopNodesPerChannels[]>;
|
topNodesPerChannels$: Observable<ITopNodesPerChannels[]>;
|
||||||
skeletonRows: number[] = [];
|
skeletonRows: number[] = [];
|
||||||
|
currency$: Observable<string>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: LightningApiService,
|
private apiService: LightningApiService,
|
||||||
|
private stateService: StateService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
for (let i = 1; i <= (this.widget ? (isMobile() ? 8 : 7) : 100); ++i) {
|
this.currency$ = this.stateService.fiatCurrency$;
|
||||||
|
|
||||||
|
for (let i = 1; i <= (this.widget ? 6 : 100); ++i) {
|
||||||
this.skeletonRows.push(i);
|
this.skeletonRows.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +48,15 @@ export class TopNodesPerChannels implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
this.topNodesPerChannels$ = this.nodes$.pipe(
|
this.topNodesPerChannels$ = this.nodes$.pipe(
|
||||||
map((ranking) => {
|
map((ranking) => {
|
||||||
return ranking.topByChannels.slice(0, isMobile() ? 8 : 7);
|
for (const i in ranking.topByChannels) {
|
||||||
|
ranking.topByChannels[i].geolocation = <GeolocationData>{
|
||||||
|
country: ranking.topByChannels[i].country?.en,
|
||||||
|
city: ranking.topByChannels[i].city?.en,
|
||||||
|
subdivision: ranking.topByChannels[i].subdivision?.en,
|
||||||
|
iso: ranking.topByChannels[i].iso_code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ranking.topByChannels.slice(0, 6);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ export class CacheService {
|
|||||||
|
|
||||||
txCache: { [txid: string]: Transaction } = {};
|
txCache: { [txid: string]: Transaction } = {};
|
||||||
|
|
||||||
|
network: string;
|
||||||
blockCache: { [height: number]: BlockExtended } = {};
|
blockCache: { [height: number]: BlockExtended } = {};
|
||||||
blockLoading: { [height: number]: boolean } = {};
|
blockLoading: { [height: number]: boolean } = {};
|
||||||
copiesInBlockQueue: { [height: number]: number } = {};
|
copiesInBlockQueue: { [height: number]: number } = {};
|
||||||
@ -33,6 +34,10 @@ export class CacheService {
|
|||||||
this.stateService.chainTip$.subscribe((height) => {
|
this.stateService.chainTip$.subscribe((height) => {
|
||||||
this.tip = height;
|
this.tip = height;
|
||||||
});
|
});
|
||||||
|
this.stateService.networkChanged$.subscribe((network) => {
|
||||||
|
this.network = network;
|
||||||
|
this.resetBlockCache();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setTxCache(transactions) {
|
setTxCache(transactions) {
|
||||||
@ -68,15 +73,17 @@ export class CacheService {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("failed to load blocks: ", e.message);
|
console.log("failed to load blocks: ", e.message);
|
||||||
}
|
}
|
||||||
for (let i = 0; i < chunkSize; i++) {
|
|
||||||
delete this.blockLoading[maxHeight - i];
|
|
||||||
}
|
|
||||||
if (result && result.length) {
|
if (result && result.length) {
|
||||||
result.forEach(block => {
|
result.forEach(block => {
|
||||||
this.addBlockToCache(block);
|
if (this.blockLoading[block.height]) {
|
||||||
this.loadedBlocks$.next(block);
|
this.addBlockToCache(block);
|
||||||
|
this.loadedBlocks$.next(block);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
for (let i = 0; i < chunkSize; i++) {
|
||||||
|
delete this.blockLoading[maxHeight - i];
|
||||||
|
}
|
||||||
this.clearBlocks();
|
this.clearBlocks();
|
||||||
} else {
|
} else {
|
||||||
this.bumpBlockPriority(height);
|
this.bumpBlockPriority(height);
|
||||||
@ -104,6 +111,14 @@ export class CacheService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove all blocks from the cache
|
||||||
|
resetBlockCache() {
|
||||||
|
this.blockCache = {};
|
||||||
|
this.blockLoading = {};
|
||||||
|
this.copiesInBlockQueue = {};
|
||||||
|
this.blockPriorities = [];
|
||||||
|
}
|
||||||
|
|
||||||
getCachedBlock(height) {
|
getCachedBlock(height) {
|
||||||
return this.blockCache[height];
|
return this.blockCache[height];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user