Create top 100 node per capacity component
This commit is contained in:
@@ -159,9 +159,14 @@ export interface ITopNodesPerChannels {
|
||||
}
|
||||
|
||||
export interface ITopNodesPerCapacity {
|
||||
public_key: string,
|
||||
publicKey: string,
|
||||
alias: string,
|
||||
capacity: number,
|
||||
channels?: number,
|
||||
firstSeen?: number,
|
||||
updatedAt?: number,
|
||||
city?: any,
|
||||
country?: any,
|
||||
}
|
||||
|
||||
export interface INodesRanking {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StateService } from '../services/state.service';
|
||||
import { INodesRanking } from '../interfaces/node-api.interface';
|
||||
import { INodesRanking, ITopNodesPerCapacity } from '../interfaces/node-api.interface';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -63,4 +63,10 @@ export class LightningApiService {
|
||||
(interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
|
||||
);
|
||||
}
|
||||
|
||||
getTopNodesByCapacity$(): Observable<ITopNodesPerCapacity[]> {
|
||||
return this.httpClient.get<ITopNodesPerCapacity[]>(
|
||||
this.apiBasePath + '/api/v1/lightning/nodes/rankings/capacity'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/ranking' | relativeUrl]">
|
||||
<h5 class="card-title d-inline" i18n="lightning.top-capacity-nodes">Top Capacity Nodes</h5>
|
||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/top-capacity' | relativeUrl]">
|
||||
<h5 class="card-title d-inline" i18n="lightning.top-capacity-nodes">Top capacity nodes</h5>
|
||||
<span> </span>
|
||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||
</a>
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/ranking' | relativeUrl]">
|
||||
<a class="title-link" href="" [routerLink]="['/lightning/nodes/top-channels' | relativeUrl]">
|
||||
<h5 class="card-title d-inline" i18n="lightning.top-channels-nodes">Most connected nodes</h5>
|
||||
<span> </span>
|
||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
|
||||
|
||||
@@ -24,6 +24,7 @@ import { NodesPerISP } from './nodes-per-isp/nodes-per-isp.component';
|
||||
import { NodesPerCountryChartComponent } from '../lightning/nodes-per-country-chart/nodes-per-country-chart.component';
|
||||
import { NodesMap } from '../lightning/nodes-map/nodes-map.component';
|
||||
import { NodesChannelsMap } from '../lightning/nodes-channels-map/nodes-channels-map.component';
|
||||
import { NodesRanking } from '../lightning/nodes-ranking/nodes-ranking.component';
|
||||
import { TopNodesPerChannels } from '../lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component';
|
||||
import { TopNodesPerCapacity } from '../lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component';
|
||||
@NgModule({
|
||||
@@ -47,6 +48,7 @@ import { TopNodesPerCapacity } from '../lightning/nodes-ranking/top-nodes-per-ca
|
||||
NodesPerCountryChartComponent,
|
||||
NodesMap,
|
||||
NodesChannelsMap,
|
||||
NodesRanking,
|
||||
TopNodesPerChannels,
|
||||
TopNodesPerCapacity,
|
||||
],
|
||||
@@ -77,6 +79,7 @@ import { TopNodesPerCapacity } from '../lightning/nodes-ranking/top-nodes-per-ca
|
||||
NodesPerCountryChartComponent,
|
||||
NodesMap,
|
||||
NodesChannelsMap,
|
||||
NodesRanking,
|
||||
TopNodesPerChannels,
|
||||
TopNodesPerCapacity,
|
||||
],
|
||||
|
||||
@@ -34,8 +34,11 @@ const routes: Routes = [
|
||||
component: NodesPerISP,
|
||||
},
|
||||
{
|
||||
path: 'nodes/ranking',
|
||||
path: 'nodes/top-capacity',
|
||||
component: NodesRanking,
|
||||
data: {
|
||||
type: 'capacity'
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
|
||||
@@ -1,29 +1,2 @@
|
||||
<div style="width: 100%">
|
||||
|
||||
<table class="table table-borderless" style="width: 100%">
|
||||
<thead>
|
||||
<th class="" i18n="" style="width: 33%">Rank</th>
|
||||
<th class="" i18n="" style="width: 33%">Alias</th>
|
||||
<th class="" i18n="" style="width: 33%">Placeholder</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ng-template #skeleton>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
|
||||
<td class="">
|
||||
<span class="skeleton-loader"></span>
|
||||
</td>
|
||||
<td class="">
|
||||
<span class="skeleton-loader"></span>
|
||||
</td>
|
||||
<td class="">
|
||||
<span class="skeleton-loader"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</ng-template>
|
||||
|
||||
</div>
|
||||
<app-top-nodes-per-capacity [nodes$]="null" [widget]="false" *ngIf="type === 'capacity'">
|
||||
</app-top-nodes-per-capacity>
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nodes-ranking',
|
||||
@@ -7,9 +8,13 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NodesRanking implements OnInit {
|
||||
type: string;
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
console.log('hi');
|
||||
this.route.data.subscribe(data => {
|
||||
this.type = data.type;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,37 +1,59 @@
|
||||
<div>
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<th class="rank"></th>
|
||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||
<th class="capacity text-right" i18n="node.capacity">Capacity</th>
|
||||
</thead>
|
||||
<tbody *ngIf="topNodesPerCapacity$ | async as nodes; else skeleton">
|
||||
<tr *ngFor="let node of nodes; let i = index;">
|
||||
<td class="rank text-left">
|
||||
{{ i + 1 }}
|
||||
</td>
|
||||
<td class="alias text-left">
|
||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.public_key]">{{ node.alias }}</a>
|
||||
</td>
|
||||
<td class="capacity text-right">
|
||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<ng-template #skeleton>
|
||||
<tbody>
|
||||
<tr *ngFor="let item of skeletonRows">
|
||||
<div [class]="!widget ? 'container-xl full-height' : ''">
|
||||
<h1 *ngIf="!widget" class="float-left" i18n="lightning.top-100-capacity">
|
||||
<span>Top 100 nodes by capacity</span>
|
||||
</h1>
|
||||
|
||||
<div [class]="widget ? 'widget' : 'full'">
|
||||
<table class="table table-borderless">
|
||||
<thead>
|
||||
<th class="rank"></th>
|
||||
<th class="alias text-left" i18n="nodes.alias">Alias</th>
|
||||
<th class="capacity text-right" i18n="node.capacity">Capacity</th>
|
||||
<th *ngIf="!widget" class="channels text-right" i18n="lightning.channels">Channels</th>
|
||||
<th *ngIf="!widget" class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
|
||||
<th *ngIf="!widget" class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
|
||||
<th *ngIf="!widget" class="location text-right" i18n="lightning.location">Location</th>
|
||||
</thead>
|
||||
<tbody *ngIf="topNodesPerCapacity$ | async as nodes; else skeleton">
|
||||
<tr *ngFor="let node of nodes; let i = index;">
|
||||
<td class="rank text-left">
|
||||
<span class="skeleton-loader"></span>
|
||||
{{ i + 1 }}
|
||||
</td>
|
||||
<td class="alias text-left">
|
||||
<span class="skeleton-loader"></span>
|
||||
<a [routerLink]="['/lightning/node' | relativeUrl, node.publicKey]">{{ node.alias }}</a>
|
||||
</td>
|
||||
<td class="capacity text-right">
|
||||
<span class="skeleton-loader"></span>
|
||||
<app-amount [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
|
||||
</td>
|
||||
<td *ngIf="!widget" class="channels text-right">
|
||||
{{ node.channels | number }}
|
||||
</td>
|
||||
<td *ngIf="!widget" class="timestamp-first text-left">
|
||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.firstSeen"></app-timestamp>
|
||||
</td>
|
||||
<td *ngIf="!widget" class="timestamp-update text-left">
|
||||
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updatedAt"></app-timestamp>
|
||||
</td>
|
||||
<td *ngIf="!widget" class="location text-right text-truncate">
|
||||
{{ node?.city?.en ?? '-' }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</ng-template>
|
||||
</table>
|
||||
<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>
|
||||
</tr>
|
||||
</tbody>
|
||||
</ng-template>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,8 +1,20 @@
|
||||
.container-xl {
|
||||
max-width: 1400px;
|
||||
padding-bottom: 100px;
|
||||
@media (min-width: 767.98px) {
|
||||
padding-left: 50px;
|
||||
padding-right: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
.table td, .table th {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.rank {
|
||||
.full .rank {
|
||||
width: 5%;
|
||||
}
|
||||
.widget .rank {
|
||||
@media (min-width: 767.98px) {
|
||||
width: 13%;
|
||||
}
|
||||
@@ -12,7 +24,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
.full .alias {
|
||||
width: 10%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 350px;
|
||||
@media (max-width: 767.98px) {
|
||||
max-width: 175px;
|
||||
}
|
||||
}
|
||||
.widget .alias {
|
||||
width: 55%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -21,10 +42,43 @@
|
||||
max-width: 175px;
|
||||
}
|
||||
}
|
||||
.capacity {
|
||||
|
||||
.full .capacity {
|
||||
width: 10%;
|
||||
}
|
||||
.widget .capacity {
|
||||
width: 32%;
|
||||
@media (max-width: 767.98px) {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.full .channels {
|
||||
width: 15%;
|
||||
padding-right: 50px;
|
||||
@media (max-width: 767.98px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.full .timestamp-first {
|
||||
width: 15%;
|
||||
@media (max-width: 767.98px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.full .timestamp-update {
|
||||
width: 15%;
|
||||
@media (max-width: 767.98px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.full .location {
|
||||
width: 10%;
|
||||
@media (max-width: 767.98px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { map, Observable } from 'rxjs';
|
||||
import { INodesRanking, ITopNodesPerCapacity } from 'src/app/interfaces/node-api.interface';
|
||||
import { LightningApiService } from '../../lightning-api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-top-nodes-per-capacity',
|
||||
@@ -15,20 +16,24 @@ export class TopNodesPerCapacity implements OnInit {
|
||||
topNodesPerCapacity$: Observable<ITopNodesPerCapacity[]>;
|
||||
skeletonRows: number[] = [];
|
||||
|
||||
constructor(private apiService: LightningApiService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
for (let i = 1; i <= (this.widget ? 10 : 100); ++i) {
|
||||
this.skeletonRows.push(i);
|
||||
}
|
||||
|
||||
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
||||
map((ranking) => {
|
||||
if (this.widget === true) {
|
||||
console.log(this.widget);
|
||||
|
||||
if (this.widget === false) {
|
||||
this.topNodesPerCapacity$ = this.apiService.getTopNodesByCapacity$();
|
||||
} else {
|
||||
this.topNodesPerCapacity$ = this.nodes$.pipe(
|
||||
map((ranking) => {
|
||||
return ranking.topByCapacity.slice(0, 10);
|
||||
} else {
|
||||
return ranking.topByCapacity;
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user