diff --git a/backend/src/api/explorer/nodes.api.ts b/backend/src/api/explorer/nodes.api.ts index 9e57e7802..e1949a17c 100644 --- a/backend/src/api/explorer/nodes.api.ts +++ b/backend/src/api/explorer/nodes.api.ts @@ -228,7 +228,7 @@ class NodesApi { nodes.capacity FROM nodes ORDER BY capacity DESC - LIMIT 100 + LIMIT 6 `; [rows] = await DB.query(query); @@ -269,14 +269,26 @@ class NodesApi { let query: string; if (full === false) { query = ` - SELECT nodes.public_key as publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, - nodes.channels + SELECT + 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 + 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 - LIMIT 100; + LIMIT 6; `; [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 { query = ` SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index c7b8a83bc..0855cad05 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -267,6 +267,7 @@ export class StartComponent implements OnInit, OnDestroy { resetScroll(): void { this.scrollToBlock(this.chainTip); + this.blockchainContainer.nativeElement.scrollLeft = 0; } getPageIndexOf(height: number): number { diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts index 9c4991590..6be475243 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts @@ -199,8 +199,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands); 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}`, - style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}` + 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 + 1}; stroke: ${this.gradient[1]}` }; 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) => { return { 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, innerY: 0, outerY: 0, @@ -269,7 +269,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { // bounds of the middle segment 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 let lastOuter = 0; 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 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 if (xputs.length === 1) { diff --git a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html index c12565d6d..b73d21bcd 100644 --- a/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html +++ b/frontend/src/app/lightning/lightning-dashboard/lightning-dashboard.component.html @@ -55,7 +55,7 @@ -
+
-
+
diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss index 59151f6b2..3547c447f 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.scss @@ -1,91 +1,52 @@ .container-xl { max-width: 1400px; - padding-bottom: 100px; - @media (min-width: 960px) { - padding-left: 50px; - padding-right: 50px; - } +} +.container-xl.widget { + padding-right: 0px; + padding-left: 0px; + padding-bottom: 0px; } -.table td, .table th { - padding: 0.5rem; +tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.7rem !important; } -.full .rank { - width: 5%; -} -.widget .rank { - @media (min-width: 960px) { - width: 13%; - } - @media (max-width: 960px) { - padding-left: 0px; - padding-right: 0px; - } +.clear-link { + color: white; } -.full .alias { - width: 20%; +.pool { + width: 15%; + @media (max-width: 575px) { + width: 75%; + } overflow: hidden; text-overflow: ellipsis; - max-width: 350px; - @media (max-width: 960px) { - width: 40%; - max-width: 500px; - } + white-space: nowrap; + max-width: 160px; } -.widget .alias { - width: 60%; - overflow: hidden; +.pool-name { + display: inline-block; + vertical-align: text-top; text-overflow: ellipsis; - max-width: 350px; - @media (max-width: 960px) { - max-width: 175px; - } + overflow: hidden; } -.full .capacity { +.liquidity { width: 10%; - @media (max-width: 960px) { - width: 30%; - } -} -.widget .capacity { - width: 32%; - @media (max-width: 960px) { - padding-left: 0px; - padding-right: 0px; + @media (max-width: 575px) { + width: 25%; } } -.full .channels { +.fiat { width: 15%; - padding-right: 50px; - @media (max-width: 960px) { - display: none; + @media (min-width: 768px) and (max-width: 991px) { + display: none !important; + } + @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; - } -} \ No newline at end of file diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts index 766e7f090..4925256c0 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-capacity/top-nodes-per-capacity.component.ts @@ -1,8 +1,8 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { map, Observable } from 'rxjs'; +import { StateService } from 'src/app/services/state.service'; import { INodesRanking, ITopNodesPerCapacity } from '../../../interfaces/node-api.interface'; import { SeoService } from '../../../services/seo.service'; -import { isMobile } from '../../../shared/common.utils'; import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component'; import { LightningApiService } from '../../lightning-api.service'; @@ -18,18 +18,22 @@ export class TopNodesPerCapacity implements OnInit { topNodesPerCapacity$: Observable; skeletonRows: number[] = []; + currency$: Observable; constructor( private apiService: LightningApiService, - private seoService: SeoService + private seoService: SeoService, + private stateService: StateService, ) {} ngOnInit(): void { + this.currency$ = this.stateService.fiatCurrency$; + if (!this.widget) { 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); } @@ -50,7 +54,7 @@ export class TopNodesPerCapacity implements OnInit { } else { this.topNodesPerCapacity$ = this.nodes$.pipe( map((ranking) => { - return ranking.topByCapacity.slice(0, isMobile() ? 8 : 7); + return ranking.topByCapacity.slice(0, 6); }) ); } diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.html b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.html index 7d02e510f..4bab712a8 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.html +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.html @@ -1,71 +1,56 @@ -
-

- Top 100 nodes connectivity ranking -

-
+ +
+

Liquidity Ranking

+ +
+ +
- - - - - - - + + + + + + + - - - + + - - - - + - - - + - - - - - - - - - - - - -
AliasChannelsLiquidityFirst seenLast updateLocationAliasChannelsCapacity{{ currency$ | async }}First seenLast updateLocation
- {{ i + 1 }} +
+ - {{ node.alias }} + + {{ node.channels ? (node.channels | number) : '~' }} - {{ node.channels | number }} - + + + + + +
- - - - - - - - - - - - - -
+ + +
+
+
-
\ No newline at end of file + +
diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss index 59151f6b2..a42599d69 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.scss @@ -1,91 +1,54 @@ .container-xl { max-width: 1400px; - padding-bottom: 100px; - @media (min-width: 960px) { - padding-left: 50px; - padding-right: 50px; - } +} +.container-xl.widget { + padding-right: 0px; + padding-left: 0px; + padding-bottom: 0px; } -.table td, .table th { - padding: 0.5rem; +tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.7rem !important; } -.full .rank { - width: 5%; -} -.widget .rank { - @media (min-width: 960px) { - width: 13%; - } - @media (max-width: 960px) { - padding-left: 0px; - padding-right: 0px; - } +.clear-link { + color: white; } -.full .alias { - width: 20%; +.pool { + width: 15%; + @media (max-width: 576px) { + width: 75%; + } overflow: hidden; text-overflow: ellipsis; - max-width: 350px; - @media (max-width: 960px) { - width: 40%; - max-width: 500px; - } + white-space: nowrap; + max-width: 160px; } -.widget .alias { - width: 60%; - overflow: hidden; +.pool-name { + display: inline-block; + vertical-align: text-top; text-overflow: ellipsis; - max-width: 350px; - @media (max-width: 960px) { - max-width: 175px; - } + overflow: hidden; +} +.pool.widget { + width: 45%; } -.full .capacity { +.liquidity { width: 10%; - @media (max-width: 960px) { - width: 30%; - } -} -.widget .capacity { - width: 32%; - @media (max-width: 960px) { - padding-left: 0px; - padding-right: 0px; + @media (max-width: 576px) { + width: 25%; } } -.full .channels { - width: 15%; - padding-right: 50px; - @media (max-width: 960px) { - display: none; +.geolocation { + @media (min-width: 768px) and (max-width: 991px) { + 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; + @media (max-width: 575px) { + display: none !important; } } \ No newline at end of file diff --git a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts index 2c88e4bae..ce6436ce3 100644 --- a/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts +++ b/frontend/src/app/lightning/nodes-ranking/top-nodes-per-channels/top-nodes-per-channels.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { map, Observable } from 'rxjs'; +import { StateService } from 'src/app/services/state.service'; import { INodesRanking, ITopNodesPerChannels } from '../../../interfaces/node-api.interface'; -import { isMobile } from '../../../shared/common.utils'; import { GeolocationData } from '../../../shared/components/geolocation/geolocation.component'; import { LightningApiService } from '../../lightning-api.service'; @@ -17,13 +17,17 @@ export class TopNodesPerChannels implements OnInit { topNodesPerChannels$: Observable; skeletonRows: number[] = []; + currency$: Observable; constructor( private apiService: LightningApiService, + private stateService: StateService, ) {} 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); } @@ -44,7 +48,15 @@ export class TopNodesPerChannels implements OnInit { } else { this.topNodesPerChannels$ = this.nodes$.pipe( map((ranking) => { - return ranking.topByChannels.slice(0, isMobile() ? 8 : 7); + for (const i in ranking.topByChannels) { + ranking.topByChannels[i].geolocation = { + 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); }) ); } diff --git a/frontend/src/app/services/cache.service.ts b/frontend/src/app/services/cache.service.ts index 15ef99859..5eefd6e0a 100644 --- a/frontend/src/app/services/cache.service.ts +++ b/frontend/src/app/services/cache.service.ts @@ -17,6 +17,7 @@ export class CacheService { txCache: { [txid: string]: Transaction } = {}; + network: string; blockCache: { [height: number]: BlockExtended } = {}; blockLoading: { [height: number]: boolean } = {}; copiesInBlockQueue: { [height: number]: number } = {}; @@ -33,6 +34,10 @@ export class CacheService { this.stateService.chainTip$.subscribe((height) => { this.tip = height; }); + this.stateService.networkChanged$.subscribe((network) => { + this.network = network; + this.resetBlockCache(); + }); } setTxCache(transactions) { @@ -68,15 +73,17 @@ export class CacheService { } catch (e) { console.log("failed to load blocks: ", e.message); } - for (let i = 0; i < chunkSize; i++) { - delete this.blockLoading[maxHeight - i]; - } if (result && result.length) { result.forEach(block => { - this.addBlockToCache(block); - this.loadedBlocks$.next(block); + if (this.blockLoading[block.height]) { + this.addBlockToCache(block); + this.loadedBlocks$.next(block); + } }); } + for (let i = 0; i < chunkSize; i++) { + delete this.blockLoading[maxHeight - i]; + } this.clearBlocks(); } else { 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) { return this.blockCache[height]; }