Nodes per ISP list component
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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: ''
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user