From 1318c4aa369d9517a4bc2cc30032f5e2d3dd096d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 7 Mar 2022 18:42:47 +0100 Subject: [PATCH 1/3] Fix broken navigation when clicking on pie chart --- .../app/components/pool-ranking/pool-ranking.component.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts index 64641c31d..01b36ab74 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, NgZone, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { EChartsOption, PieSeriesOption } from 'echarts'; @@ -41,6 +41,7 @@ export class PoolRankingComponent implements OnInit { private miningService: MiningService, private seoService: SeoService, private router: Router, + private zone: NgZone, ) { } @@ -293,7 +294,9 @@ export class PoolRankingComponent implements OnInit { if (e.data.data === 9999) { // "Other" return; } - this.router.navigate(['/mining/pool/', e.data.data]); + this.zone.run(() => { + this.router.navigate(['/mining/pool/', e.data.data]); + }); }); } From 6f3443faba091a90c3247877b532d120c04add74 Mon Sep 17 00:00:00 2001 From: softsimon Date: Mon, 7 Mar 2022 19:45:09 +0100 Subject: [PATCH 2/3] UTXO spent tracking refactor refs #1301 --- backend/src/api/websocket-handler.ts | 18 +++-- .../transactions-list.component.html | 8 +-- .../transactions-list.component.ts | 71 +++++++++++-------- .../src/app/interfaces/websocket.interface.ts | 2 +- frontend/src/app/services/state.service.ts | 2 +- .../src/app/services/websocket.service.ts | 2 +- 6 files changed, 59 insertions(+), 44 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index a2ae6d0c9..92abaab6d 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -332,11 +332,18 @@ class WebsocketHandler { } if (client['track-tx']) { - const utxoSpent = newTransactions.some((tx) => { - return tx.vin.some((vin) => vin.txid === client['track-tx']); - }); - if (utxoSpent) { - response['utxoSpent'] = true; + const outspends: object = {}; + newTransactions.forEach((tx) => tx.vin.forEach((vin, i) => { + if (vin.txid === client['track-tx']) { + outspends[vin.vout] = { + vin: i, + txid: tx.txid, + }; + } + })); + + if (Object.keys(outspends).length) { + response['utxoSpent'] = outspends; } if (rbfTransactions[client['track-tx']]) { @@ -414,7 +421,6 @@ class WebsocketHandler { } if (client['track-tx'] && txIds.indexOf(client['track-tx']) > -1) { - client['track-tx'] = null; response['txConfirmed'] = true; } diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 200356ffd..1470e6211 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -186,16 +186,16 @@ - - + + - + - + diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index fd3cf0241..7d3c5d0e4 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -1,11 +1,11 @@ -import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, Output, EventEmitter } from '@angular/core'; +import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; import { StateService } from '../../services/state.service'; -import { Observable, forkJoin, ReplaySubject, BehaviorSubject, merge } from 'rxjs'; +import { Observable, forkJoin, ReplaySubject, BehaviorSubject, merge, of, Subject, Subscription } from 'rxjs'; import { Outspend, Transaction } from '../../interfaces/electrs.interface'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { environment } from 'src/environments/environment'; import { AssetsService } from 'src/app/services/assets.service'; -import { map, share, switchMap } from 'rxjs/operators'; +import { map, share, switchMap, tap } from 'rxjs/operators'; import { BlockExtended } from 'src/app/interfaces/node-api.interface'; @Component({ @@ -27,41 +27,18 @@ export class TransactionsListComponent implements OnInit, OnChanges { @Output() loadMore = new EventEmitter(); latestBlock$: Observable; - outspends$: Observable; + outspendsSubscription: Subscription; refreshOutspends$: ReplaySubject = new ReplaySubject(); showDetails$ = new BehaviorSubject(false); - _outspends: Outspend[] = []; + outspends: Outspend[][] = []; assetsMinimal: any; constructor( public stateService: StateService, private electrsApiService: ElectrsApiService, private assetsService: AssetsService, - ) { - this.outspends$ = merge( - this.refreshOutspends$, - this.stateService.utxoSpent$ - .pipe( - map(() => { - this._outspends = []; - return { 0: this.electrsApiService.getOutspends$(this.transactions[0].txid) }; - }), - ) - ).pipe( - switchMap((observableObject) => forkJoin(observableObject)), - map((outspends: any) => { - const newOutspends = []; - for (const i in outspends) { - if (outspends.hasOwnProperty(i)) { - newOutspends.push(outspends[i]); - } - } - this._outspends = this._outspends.concat(newOutspends); - return this._outspends; - }), - share(), - ); - } + private ref: ChangeDetectorRef, + ) { } ngOnInit() { this.latestBlock$ = this.stateService.blocks$.pipe(map(([block]) => block)); @@ -72,6 +49,34 @@ export class TransactionsListComponent implements OnInit, OnChanges { this.assetsMinimal = assets; }); } + + this.outspendsSubscription = merge( + this.refreshOutspends$ + .pipe( + switchMap((observableObject) => forkJoin(observableObject)), + map((outspends: any) => { + const newOutspends: Outspend[] = []; + for (const i in outspends) { + if (outspends.hasOwnProperty(i)) { + newOutspends.push(outspends[i]); + } + } + this.outspends = this.outspends.concat(newOutspends); + }), + ), + this.stateService.utxoSpent$ + .pipe( + map((utxoSpent) => { + for (const i in utxoSpent) { + this.outspends[0][i] = { + spent: true, + txid: utxoSpent[i].txid, + vin: utxoSpent[i].vin, + }; + } + }), + ) + ).subscribe(() => this.ref.markForCheck()); } ngOnChanges() { @@ -90,7 +95,7 @@ export class TransactionsListComponent implements OnInit, OnChanges { this.transactions.forEach((tx, i) => { tx['@voutLimit'] = true; tx['@vinLimit'] = true; - if (this._outspends[i]) { + if (this.outspends[i]) { return; } observableObject[i] = this.electrsApiService.getOutspends$(tx.txid); @@ -149,4 +154,8 @@ export class TransactionsListComponent implements OnInit, OnChanges { this.showDetails$.next(true); } } + + ngOnDestroy() { + this.outspendsSubscription.unsubscribe(); + } } diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index cb867ffb3..d82d9a618 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -16,7 +16,7 @@ export interface WebsocketResponse { data?: string[]; tx?: Transaction; rbfTransaction?: Transaction; - utxoSpent?: boolean; + utxoSpent?: object; transactions?: TransactionStripped[]; loadingIndicators?: ILoadingIndicators; backendInfo?: IBackendInfo; diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 238cf227c..85ce7b567 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -81,7 +81,7 @@ export class StateService { mempoolInfo$ = new ReplaySubject(1); mempoolBlocks$ = new ReplaySubject(1); txReplaced$ = new Subject(); - utxoSpent$ = new Subject(); + utxoSpent$ = new Subject(); mempoolTransactions$ = new Subject(); blockTransactions$ = new Subject(); isLoadingWebSocket$ = new ReplaySubject(1); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 4d294ae2d..f99524197 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -252,7 +252,7 @@ export class WebsocketService { } if (response.utxoSpent) { - this.stateService.utxoSpent$.next(); + this.stateService.utxoSpent$.next(response.utxoSpent); } if (response.backendInfo) { From 2b91ced4d675f32001711447b77744e46d1d8317 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Mon, 7 Mar 2022 19:54:17 +0100 Subject: [PATCH 3/3] Add skeleton in the mining dashboard page --- .../hashrate-chart.component.html | 4 +- .../hashrate-chart.component.ts | 2 +- .../hashrate-chart-pools.component.html | 2 +- .../mining-dashboard.component.html | 30 ++++- .../mining-dashboard.component.scss | 104 +++++++----------- .../pool-ranking/pool-ranking.component.html | 62 ++++++++--- .../pool-ranking/pool-ranking.component.scss | 9 +- 7 files changed, 122 insertions(+), 91 deletions(-) diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html index eaa9fa809..c58861d36 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.html @@ -25,13 +25,13 @@ -
-
+
diff --git a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts index a5f2b63b8..b5db5bb65 100644 --- a/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts +++ b/frontend/src/app/components/hashrate-chart/hashrate-chart.component.ts @@ -15,7 +15,7 @@ import { selectPowerOfTen } from 'src/app/bitcoin.utils'; styles: [` .loadingGraphs { position: absolute; - top: 38%; + top: 50%; left: calc(50% - 15px); z-index: 100; } diff --git a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html index 8750caa56..69da008d2 100644 --- a/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html +++ b/frontend/src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html @@ -25,7 +25,7 @@ -
diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html index 6dbb541c3..38d3284ac 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.html @@ -2,11 +2,12 @@
+
Reward stats
-
+
Miners Reward
@@ -34,6 +35,31 @@
+ +
+
+
Miners Reward
+
+
+
+
+
+
+
Reward Per Tx
+
+
+
+
+
+
+
Average Fee
+
+
+
+
+
+
+
@@ -96,4 +122,4 @@
-
\ No newline at end of file +
diff --git a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss index 828ee7ed0..fb2663812 100644 --- a/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss +++ b/frontend/src/app/components/mining-dashboard/mining-dashboard.component.scss @@ -44,7 +44,7 @@ .fade-border { -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 80%, transparent 100%) } - + .main-title { position: relative; color: #ffffff91; @@ -56,39 +56,22 @@ padding-bottom: 3px; } -.general-stats { - min-height: 56px; - display: block; - @media (min-width: 485px) { - display: flex; +.fee-estimation-container { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { flex-direction: row; } - h5 { - margin-bottom: 10px; - } .item { - width: 50%; - margin: 0px auto 10px; - display: inline-block; - @media (min-width: 485px) { - margin: 0px auto 10px; + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; } - @media (min-width: 785px) { - margin: 0px auto 0px; - } - &:last-child { - margin: 0px auto 0px; - } - &:nth-child(2) { - order: 2; + &:first-child{ + display: none; @media (min-width: 485px) { - order: 3; - } - } - &:nth-child(3) { - order: 3; - @media (min-width: 485px) { - order: 2; display: block; } @media (min-width: 768px) { @@ -98,48 +81,37 @@ display: block; } } - .card-title { - font-size: 1rem; - color: #4a68b9; + &:last-child { + margin-bottom: 0; } - .card-text { - font-size: 18px; - span { - color: #ffffff66; - font-size: 12px; - } + .card-text span { + color: #ffffff66; + font-size: 12px; + top: 0px; + } + .fee-text{ + border-bottom: 1px solid #ffffff1c; + width: fit-content; + margin: auto; + line-height: 1.45; + padding: 0px 2px; + } + .fiat { + display: block; + font-size: 14px !important; } } } -.difficulty-adjustment-container { - display: flex; - flex-direction: row; - justify-content: space-around; - height: 76px; - .shared-block { - color: #ffffff66; - font-size: 12px; +.skeleton-loader { + width: 100%; + display: block; + &:first-child { + max-width: 90px; + margin: 15px auto 3px; } - .item { - padding: 0 5px; - width: 100%; - &:nth-child(1) { - display: none; - @media (min-width: 485px) { - display: table-cell; - } - @media (min-width: 768px) { - display: none; - } - @media (min-width: 992px) { - display: table-cell; - } - } - } - .card-text { - font-size: 22px; - margin-top: -9px; - position: relative; + &:last-child { + margin: 10px auto 3px; + max-width: 55px; } } diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index 6bba39df4..9a1dc01b2 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -1,23 +1,25 @@
-
-
-
Pools luck (1w)
-

- {{ miningStats['minersLuck'] }}% -

-
-
-
Blocks (1w)
-

- {{ miningStats.blockCount }} -

-
-
-
Pools count (1w)
-

- {{ miningStats.pools.length }} -

+
+
+
+
Pools luck (1w)
+

+ {{ miningStats['minersLuck'] }}% +

+
+
+
Blocks (1w)
+

+ {{ miningStats.blockCount }} +

+
+
+
Pools count (1w)
+

+ {{ miningStats.pools.length }} +

+
@@ -96,3 +98,27 @@
+ + + +
+
+
Pools luck (1w)
+

+ +

+
+
+
Blocks (1w)
+

+ +

+
+
+
Pools count (1w)
+

+ +

+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss index f73486395..d25148df1 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.scss +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.scss @@ -102,4 +102,11 @@ } } } -} \ No newline at end of file +} + +.skeleton-loader { + width: 100%; + display: block; + max-width: 80px; + margin: 15px auto 3px; +}