Nodes per ISP list component

This commit is contained in:
nymkappa
2022-07-17 22:57:29 +02:00
parent cfad17d049
commit 51f0da04bd
10 changed files with 241 additions and 7 deletions

View File

@@ -20,6 +20,7 @@ import { NodesNetworksChartComponent } from './nodes-networks-chart/nodes-networ
import { ChannelsStatisticsComponent } from './channels-statistics/channels-statistics.component';
import { NodesPerAsChartComponent } from '../lightning/nodes-per-as-chart/nodes-per-as-chart.component';
import { NodesPerCountry } from './nodes-per-country/nodes-per-country.component';
import { NodesPerISP } from './nodes-per-isp/nodes-per-isp.component';
@NgModule({
declarations: [
LightningDashboardComponent,
@@ -37,6 +38,7 @@ import { NodesPerCountry } from './nodes-per-country/nodes-per-country.component
ChannelsStatisticsComponent,
NodesPerAsChartComponent,
NodesPerCountry,
NodesPerISP,
],
imports: [
CommonModule,

View File

@@ -5,6 +5,7 @@ import { LightningWrapperComponent } from './lightning-wrapper/lightning-wrapper
import { NodeComponent } from './node/node.component';
import { ChannelComponent } from './channel/channel.component';
import { NodesPerCountry } from './nodes-per-country/nodes-per-country.component';
import { NodesPerISP } from './nodes-per-isp/nodes-per-isp.component';
const routes: Routes = [
{
@@ -27,6 +28,10 @@ const routes: Routes = [
path: 'nodes/country/:country',
component: NodesPerCountry,
},
{
path: 'nodes/isp/:isp',
component: NodesPerISP,
},
{
path: '**',
redirectTo: ''

View File

@@ -25,7 +25,7 @@
<thead>
<tr>
<th *ngIf="!isMobile()" i18n="mining.rank">Rank</th>
<th i18n="lightning.as-name">Name</th>
<th i18n="lightning.isp">ISP</th>
<th *ngIf="!isMobile()" i18n="lightning.share">Share</th>
<th i18n="lightning.nodes-count">Nodes</th>
<th i18n="lightning.capacity">Capacity</th>
@@ -34,7 +34,9 @@
<tbody [attr.data-cy]="'pools-table'" *ngIf="(nodesPerAsObservable$ | async) as asList">
<tr *ngFor="let asEntry of asList">
<td *ngIf="!isMobile()">{{ asEntry.rank }}</td>
<td class="text-truncate" style="max-width: 100px">{{ asEntry.name }}</td>
<td class="text-truncate" style="max-width: 100px">
<a [routerLink]="[('/lightning/nodes/isp/' + asEntry.ispId) | relativeUrl]">{{ asEntry.name }}</a>
</td>
<td *ngIf="!isMobile()">{{ asEntry.share }}%</td>
<td>{{ asEntry.count }}</td>
<td><app-amount [satoshis]="asEntry.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount></td>

View File

@@ -1,11 +1,14 @@
import { ChangeDetectionStrategy, Component, OnInit, HostBinding } from '@angular/core';
import { ChangeDetectionStrategy, Component, OnInit, HostBinding, NgZone } from '@angular/core';
import { Router } from '@angular/router';
import { EChartsOption, PieSeriesOption } from 'echarts';
import { map, Observable, share, tap } from 'rxjs';
import { chartColors } from 'src/app/app.constants';
import { ApiService } from 'src/app/services/api.service';
import { SeoService } from 'src/app/services/seo.service';
import { StateService } from 'src/app/services/state.service';
import { download } from 'src/app/shared/graphs.utils';
import { AmountShortenerPipe } from 'src/app/shared/pipes/amount-shortener.pipe';
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
@Component({
selector: 'app-nodes-per-as-chart',
@@ -31,7 +34,10 @@ export class NodesPerAsChartComponent implements OnInit {
constructor(
private apiService: ApiService,
private seoService: SeoService,
private amountShortenerPipe: AmountShortenerPipe
private amountShortenerPipe: AmountShortenerPipe,
private router: Router,
private zone: NgZone,
private stateService: StateService,
) {
}
@@ -96,7 +102,7 @@ export class NodesPerAsChartComponent implements OnInit {
;
}
},
data: as.slug,
data: as.ispId,
} as PieSeriesOption);
});
@@ -126,6 +132,7 @@ export class NodesPerAsChartComponent implements OnInit {
totalNodeOther.toString() + ` nodes`;
}
},
data: 9999 as any,
} as PieSeriesOption);
return data;
@@ -149,7 +156,7 @@ export class NodesPerAsChartComponent implements OnInit {
{
zlevel: 0,
minShowLabelAngle: 3.6,
name: 'Mining pool',
name: 'Lightning nodes',
type: 'pie',
radius: pieSize,
data: this.generateChartSerieData(as),
@@ -193,6 +200,16 @@ export class NodesPerAsChartComponent implements OnInit {
return;
}
this.chartInstance = ec;
this.chartInstance.on('click', (e) => {
if (e.data.data === 9999) { // "Other"
return;
}
this.zone.run(() => {
const url = new RelativeUrlPipe(this.stateService).transform(`/lightning/nodes/isp/${e.data.data}`);
this.router.navigate([url]);
});
});
}
onSaveChart() {

View File

@@ -0,0 +1,42 @@
<div class="container-xl full-height" style="min-height: 335px">
<h1 class="float-left" i18n="lightning.nodes-for-isp">Lightning nodes on ISP: {{ isp?.name }} [AS {{isp?.id}}]</h1>
<div style="min-height: 295px">
<table class="table table-borderless">
<thead>
<th class="alias text-left" i18n="lightning.alias">Alias</th>
<th class="timestamp-first text-left" i18n="lightning.first_seen">First seen</th>
<th class="timestamp-update text-left" i18n="lightning.last_update">Last update</th>
<th class="capacity text-right" i18n="lightning.capacity">Capacity</th>
<th class="channels text-right" i18n="lightning.channels">Channels</th>
<th class="city text-right" i18n="lightning.city">City</th>
</thead>
<tbody *ngIf="nodes$ | async as nodes">
<tr *ngFor="let node of nodes; let i= index; trackBy: trackByPublicKey">
<td class="alias text-left text-truncate">
<a [routerLink]="['/lightning/node/' | relativeUrl, node.public_key]">{{ node.alias }}</a>
</td>
<td class="timestamp-first text-left">
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.first_seen"></app-timestamp>
</td>
<td class="timestamp-update text-left">
<app-timestamp [customFormat]="'yyyy-MM-dd'" [unixTime]="node.updated_at"></app-timestamp>
</td>
<td class="capacity text-right">
<app-amount *ngIf="node.capacity > 100000000; else smallchannel" [satoshis]="node.capacity" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount>
<ng-template #smallchannel>
{{ node.capacity | amountShortener: 1 }}
<span class="sats" i18n="shared.sats">sats</span>
</ng-template>
</td>
<td class="channels text-right">
{{ node.channels }}
</td>
<td class="city text-right text-truncate">
{{ node?.city?.en ?? '-' }}
</td>
</tbody>
</table>
</div>
</div>

View File

@@ -0,0 +1,62 @@
.container-xl {
max-width: 1400px;
padding-bottom: 100px;
}
.sats {
color: #ffffff66;
font-size: 12px;
top: 0px;
}
.alias {
width: 30%;
max-width: 400px;
padding-right: 70px;
@media (max-width: 576px) {
width: 50%;
max-width: 150px;
padding-right: 0px;
}
}
.timestamp-first {
width: 20%;
@media (max-width: 576px) {
display: none
}
}
.timestamp-update {
width: 16%;
@media (max-width: 576px) {
display: none
}
}
.capacity {
width: 10%;
@media (max-width: 576px) {
width: 25%;
}
}
.channels {
width: 10%;
@media (max-width: 576px) {
width: 25%;
}
}
.city {
max-width: 150px;
@media (max-width: 576px) {
display: none
}
}

View File

@@ -0,0 +1,40 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { map, Observable } from 'rxjs';
import { ApiService } from 'src/app/services/api.service';
import { SeoService } from 'src/app/services/seo.service';
@Component({
selector: 'app-nodes-per-isp',
templateUrl: './nodes-per-isp.component.html',
styleUrls: ['./nodes-per-isp.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NodesPerISP implements OnInit {
nodes$: Observable<any>;
isp: {name: string, id: number};
constructor(
private apiService: ApiService,
private seoService: SeoService,
private route: ActivatedRoute,
) { }
ngOnInit(): void {
this.nodes$ = this.apiService.getNodeForISP$(this.route.snapshot.params.isp)
.pipe(
map(response => {
this.isp = {
name: response.isp,
id: this.route.snapshot.params.isp
};
this.seoService.setTitle($localize`Lightning nodes on ISP: ${response.isp} [AS${this.route.snapshot.params.isp}]`);
return response.nodes;
})
);
}
trackByPublicKey(index: number, node: any) {
return node.public_key;
}
}

View File

@@ -258,4 +258,8 @@ export class ApiService {
getNodeForCountry$(country: string): Observable<any> {
return this.httpClient.get<any[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/country/' + country);
}
getNodeForISP$(isp: string): Observable<any> {
return this.httpClient.get<any[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/lightning/nodes/isp/' + isp);
}
}