|
-
- {{ acceleration.feePaid | number }} sat
+ |
+ {{ (acceleration.feePaid - acceleration.baseFee - acceleration.vsizeFee) | number }} sat
+ |
+
+ ~
|
{{ acceleration.feeDelta | number }} sat
diff --git a/frontend/src/app/components/accelerations-list/accelerations-list.component.scss b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
similarity index 100%
rename from frontend/src/app/components/accelerations-list/accelerations-list.component.scss
rename to frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
diff --git a/frontend/src/app/components/accelerations-list/accelerations-list.component.ts b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
similarity index 68%
rename from frontend/src/app/components/accelerations-list/accelerations-list.component.ts
rename to frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
index efc900bd5..0c0002782 100644
--- a/frontend/src/app/components/accelerations-list/accelerations-list.component.ts
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
@@ -1,9 +1,9 @@
import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef } from '@angular/core';
-import { Observable, catchError, of, switchMap } from 'rxjs';
-import { Acceleration, BlockExtended } from '../../interfaces/node-api.interface';
-import { ApiService } from '../../services/api.service';
-import { StateService } from '../../services/state.service';
-import { WebsocketService } from '../../services/websocket.service';
+import { Observable, catchError, of, switchMap, tap } from 'rxjs';
+import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
+import { ApiService } from '../../../services/api.service';
+import { StateService } from '../../../services/state.service';
+import { WebsocketService } from '../../../services/websocket.service';
@Component({
selector: 'app-accelerations-list',
@@ -13,8 +13,9 @@ import { WebsocketService } from '../../services/websocket.service';
})
export class AccelerationsListComponent implements OnInit {
@Input() widget: boolean = false;
+ @Input() accelerations$: Observable;
- accelerations$: Observable = undefined;
+ accelerationList$: Observable = undefined;
isLoading = true;
paginationMaxSize: number;
@@ -39,7 +40,7 @@ export class AccelerationsListComponent implements OnInit {
this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5;
- this.accelerations$ = this.apiService.getAccelerationHistory$().pipe(
+ this.accelerationList$ = (this.apiService.getAccelerationHistory$({ timeframe: '1m' }) || this.accelerations$).pipe(
switchMap(accelerations => {
if (this.widget) {
return of(accelerations.slice(-6).reverse());
@@ -50,6 +51,9 @@ export class AccelerationsListComponent implements OnInit {
catchError((err) => {
this.isLoading = false;
return of([]);
+ }),
+ tap(() => {
+ this.isLoading = false;
})
);
}
diff --git a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
similarity index 92%
rename from frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.html
rename to frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
index def01fc00..b43d27f05 100644
--- a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.html
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
@@ -4,7 +4,7 @@
-
+
Pending accelerations
@@ -12,7 +12,7 @@
@@ -27,7 +27,7 @@
@@ -37,7 +37,7 @@
diff --git a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.scss b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
similarity index 97%
rename from frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.scss
rename to frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
index 1171846fe..6d863fb60 100644
--- a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.scss
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
@@ -120,6 +120,10 @@
text-align: left;
width: 30%;
+ @media (max-width: 875px) {
+ display: none;
+ }
+
.pool-name {
margin-left: 1em;
}
diff --git a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
similarity index 72%
rename from frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.ts
rename to frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
index 3a3b3f384..00b3d303b 100644
--- a/frontend/src/app/components/accelerator-dashboard/accelerator-dashboard.component.ts
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
@@ -1,10 +1,10 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { SeoService } from '../../services/seo.service';
-import { WebsocketService } from '../../services/websocket.service';
-import { Acceleration, BlockExtended } from '../../interfaces/node-api.interface';
-import { StateService } from '../../services/state.service';
-import { Observable, catchError, combineLatest, of, switchMap } from 'rxjs';
-import { ApiService } from '../../services/api.service';
+import { SeoService } from '../../../services/seo.service';
+import { WebsocketService } from '../../../services/websocket.service';
+import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
+import { StateService } from '../../../services/state.service';
+import { Observable, Subject, catchError, combineLatest, distinctUntilChanged, of, share, switchMap, tap } from 'rxjs';
+import { ApiService } from '../../../services/api.service';
interface AccelerationBlock extends BlockExtended {
accelerationCount: number,
@@ -18,7 +18,7 @@ interface AccelerationBlock extends BlockExtended {
})
export class AcceleratorDashboardComponent implements OnInit {
blocks$: Observable ;
-
+ accelerations$: Observable;
loadingBlocks: boolean = true;
constructor(
@@ -33,7 +33,19 @@ export class AcceleratorDashboardComponent implements OnInit {
ngOnInit(): void {
this.websocketService.want(['blocks', 'mempool-blocks', 'stats']);
+ this.accelerations$ = this.stateService.chainTip$.pipe(
+ distinctUntilChanged(),
+ switchMap((chainTip) => {
+ return this.apiService.getAccelerationHistory$({ timeframe: '1w' });
+ }),
+ catchError((e) => {
+ return of([]);
+ }),
+ share(),
+ );
+
this.blocks$ = combineLatest([
+ this.accelerations$,
this.stateService.blocks$.pipe(
switchMap((blocks) => {
if (this.stateService.env.MINING_DASHBOARD === true) {
@@ -44,16 +56,13 @@ export class AcceleratorDashboardComponent implements OnInit {
}
}
return of(blocks as AccelerationBlock[]);
- })
- ),
- this.apiService.getAccelerationHistory$('24h').pipe(
- catchError((err) => {
+ }),
+ tap(() => {
this.loadingBlocks = false;
- return of([]);
})
)
]).pipe(
- switchMap(([blocks, accelerations]) => {
+ switchMap(([accelerations, blocks]) => {
const blockMap = {};
for (const block of blocks) {
blockMap[block.id] = block;
diff --git a/frontend/src/app/components/acceleration-stats/acceleration-stats.component.html b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
similarity index 60%
rename from frontend/src/app/components/acceleration-stats/acceleration-stats.component.html
rename to frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
index 2180a1ad6..5b7bc356a 100644
--- a/frontend/src/app/components/acceleration-stats/acceleration-stats.component.html
+++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
@@ -8,22 +8,15 @@
- Fee delta
+ Avg Max Bid
- {{ stats.totalFeeDelta / 100_000_000 | amountShortener: 4 }} BTC
+ {{ stats.avgFeeDelta / 100_000_000 | amountShortener: 4 }} BTC
-
+
-
- Success rate
-
- {{ stats.successRate.toFixed(2) }} %
- mined in the next block
-
-
-
+
- Fee delta
+ Avg Max Bid
-
-
+
Total vsize
diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss
new file mode 100644
index 000000000..fcc5564a8
--- /dev/null
+++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss
@@ -0,0 +1,88 @@
+.card-title {
+ color: #4a68b9;
+ font-size: 10px;
+ margin-bottom: 4px;
+ font-size: 1rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.card-text {
+ font-size: 22px;
+ span {
+ font-size: 11px;
+ position: relative;
+ top: -2px;
+ display: inline-flex;
+ }
+ .green-color {
+ display: block;
+ }
+}
+
+.stats-container {
+ display: flex;
+ justify-content: space-between;
+ @media (min-width: 376px) {
+ flex-direction: row;
+ }
+ .item {
+ max-width: 150px;
+ margin: 0;
+ width: -webkit-fill-available;
+ @media (min-width: 376px) {
+ margin: 0 auto 0px;
+ }
+ &:first-child{
+ display: none;
+ @media (min-width: 485px) {
+ display: block;
+ }
+ @media (min-width: 768px) {
+ display: none;
+ }
+ @media (min-width: 992px) {
+ display: block;
+ }
+ }
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .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;
+ }
+ }
+}
+
+.loading-container{
+ min-height: 76px;
+}
+
+.card-text {
+ .skeleton-loader {
+ width: 100%;
+ display: block;
+ &:first-child {
+ max-width: 90px;
+ margin: 15px auto 3px;
+ }
+ &:last-child {
+ margin: 10px auto 3px;
+ max-width: 55px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts
new file mode 100644
index 000000000..dd3adacf8
--- /dev/null
+++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts
@@ -0,0 +1,39 @@
+import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
+import { Observable, of } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
+import { ApiService } from '../../../services/api.service';
+
+@Component({
+ selector: 'app-pending-stats',
+ templateUrl: './pending-stats.component.html',
+ styleUrls: ['./pending-stats.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class PendingStatsComponent implements OnInit {
+ public accelerationStats$: Observable ;
+
+ constructor(
+ private apiService: ApiService,
+ ) { }
+
+ ngOnInit(): void {
+ this.accelerationStats$ = this.apiService.getAccelerations$().pipe(
+ switchMap(accelerations => {
+ let totalAccelerations = 0;
+ let totalFeeDelta = 0;
+ let totalVsize = 0;
+ for (const acceleration of accelerations) {
+ totalAccelerations++;
+ totalFeeDelta += acceleration.feeDelta || 0;
+ totalVsize += acceleration.effectiveVsize || 0;
+ }
+ return of({
+ count: totalAccelerations,
+ totalFeeDelta,
+ avgFeeDelta: totalAccelerations ? totalFeeDelta / totalAccelerations : 0,
+ totalVsize,
+ });
+ })
+ );
+ }
+}
diff --git a/frontend/src/app/graphs/graphs.module.ts b/frontend/src/app/graphs/graphs.module.ts
index 81a1f0c06..85905d1f1 100644
--- a/frontend/src/app/graphs/graphs.module.ts
+++ b/frontend/src/app/graphs/graphs.module.ts
@@ -3,7 +3,7 @@ import { NgxEchartsModule } from 'ngx-echarts';
import { GraphsRoutingModule } from './graphs.routing.module';
import { SharedModule } from '../shared/shared.module';
-import { AccelerationFeesGraphComponent } from '../components/acceleration-fees-graph/acceleration-fees-graph.component';
+import { AccelerationFeesGraphComponent } from '../components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component';
import { BlockFeesGraphComponent } from '../components/block-fees-graph/block-fees-graph.component';
import { BlockRewardsGraphComponent } from '../components/block-rewards-graph/block-rewards-graph.component';
import { BlockFeeRatesGraphComponent } from '../components/block-fee-rates-graph/block-fee-rates-graph.component';
@@ -20,7 +20,7 @@ import { PoolComponent } from '../components/pool/pool.component';
import { TelevisionComponent } from '../components/television/television.component';
import { DashboardComponent } from '../dashboard/dashboard.component';
import { MiningDashboardComponent } from '../components/mining-dashboard/mining-dashboard.component';
-import { AcceleratorDashboardComponent } from '../components/accelerator-dashboard/accelerator-dashboard.component';
+import { AcceleratorDashboardComponent } from '../components/acceleration/accelerator-dashboard/accelerator-dashboard.component';
import { HashrateChartComponent } from '../components/hashrate-chart/hashrate-chart.component';
import { HashrateChartPoolsComponent } from '../components/hashrates-chart-pools/hashrate-chart-pools.component';
import { BlockHealthGraphComponent } from '../components/block-health-graph/block-health-graph.component';
diff --git a/frontend/src/app/graphs/graphs.routing.module.ts b/frontend/src/app/graphs/graphs.routing.module.ts
index 12eeb6e4c..0f217eb6e 100644
--- a/frontend/src/app/graphs/graphs.routing.module.ts
+++ b/frontend/src/app/graphs/graphs.routing.module.ts
@@ -10,15 +10,15 @@ import { HashrateChartComponent } from '../components/hashrate-chart/hashrate-ch
import { HashrateChartPoolsComponent } from '../components/hashrates-chart-pools/hashrate-chart-pools.component';
import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component';
import { MiningDashboardComponent } from '../components/mining-dashboard/mining-dashboard.component';
-import { AcceleratorDashboardComponent } from '../components/accelerator-dashboard/accelerator-dashboard.component';
+import { AcceleratorDashboardComponent } from '../components/acceleration/accelerator-dashboard/accelerator-dashboard.component';
import { PoolRankingComponent } from '../components/pool-ranking/pool-ranking.component';
import { PoolComponent } from '../components/pool/pool.component';
import { StartComponent } from '../components/start/start.component';
import { StatisticsComponent } from '../components/statistics/statistics.component';
import { TelevisionComponent } from '../components/television/television.component';
import { DashboardComponent } from '../dashboard/dashboard.component';
-import { AccelerationFeesGraphComponent } from '../components/acceleration-fees-graph/acceleration-fees-graph.component';
-import { AccelerationsListComponent } from '../components/accelerations-list/accelerations-list.component';
+import { AccelerationFeesGraphComponent } from '../components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component';
+import { AccelerationsListComponent } from '../components/acceleration/accelerations-list/accelerations-list.component';
const routes: Routes = [
{
diff --git a/frontend/src/app/shared/components/btc/btc.component.html b/frontend/src/app/shared/components/btc/btc.component.html
new file mode 100644
index 000000000..c13a8ff31
--- /dev/null
+++ b/frontend/src/app/shared/components/btc/btc.component.html
@@ -0,0 +1,8 @@
+{{ valueOverride }}
+{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ value | number }}
+
+ L-
+ tL-
+ t-
+ s-{{ unit }}
+
\ No newline at end of file
diff --git a/frontend/src/app/shared/components/btc/btc.component.scss b/frontend/src/app/shared/components/btc/btc.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/frontend/src/app/shared/components/btc/btc.component.ts b/frontend/src/app/shared/components/btc/btc.component.ts
new file mode 100644
index 000000000..4e62b07ff
--- /dev/null
+++ b/frontend/src/app/shared/components/btc/btc.component.ts
@@ -0,0 +1,44 @@
+import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
+import { Subscription } from 'rxjs';
+import { StateService } from '../../../services/state.service';
+
+@Component({
+ selector: 'app-btc',
+ templateUrl: './btc.component.html',
+ styleUrls: ['./btc.component.scss']
+})
+export class BtcComponent implements OnInit, OnChanges {
+ @Input() satoshis: number;
+ @Input() addPlus = false;
+ @Input() valueOverride: string | undefined = undefined;
+
+ value: number;
+ unit: string;
+
+ network = '';
+ stateSubscription: Subscription;
+
+ constructor(
+ private stateService: StateService,
+ ) { }
+
+ ngOnInit() {
+ this.stateSubscription = this.stateService.networkChanged$.subscribe((network) => this.network = network);
+ }
+
+ ngOnDestroy() {
+ if (this.stateSubscription) {
+ this.stateSubscription.unsubscribe();
+ }
+ }
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if (this.satoshis >= 1_000_000) {
+ this.value = (this.satoshis / 100_000_000);
+ this.unit = 'BTC'
+ } else {
+ this.value = Math.round(this.satoshis);
+ this.unit = 'sats'
+ }
+ }
+}
diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts
index bd897ba99..52123f995 100644
--- a/frontend/src/app/shared/shared.module.ts
+++ b/frontend/src/app/shared/shared.module.ts
@@ -73,6 +73,7 @@ import { IndexingProgressComponent } from '../components/indexing-progress/index
import { SvgImagesComponent } from '../components/svg-images/svg-images.component';
import { ChangeComponent } from '../components/change/change.component';
import { SatsComponent } from './components/sats/sats.component';
+import { BtcComponent } from './components/btc/btc.component';
import { FeeRateComponent } from './components/fee-rate/fee-rate.component';
import { TruncateComponent } from './components/truncate/truncate.component';
import { SearchResultsComponent } from '../components/search-form/search-results/search-results.component';
@@ -85,8 +86,9 @@ import { GlobalFooterComponent } from './components/global-footer/global-footer.
import { AcceleratePreviewComponent } from '../components/accelerate-preview/accelerate-preview.component';
import { AccelerateFeeGraphComponent } from '../components/accelerate-preview/accelerate-fee-graph.component';
import { MempoolErrorComponent } from './components/mempool-error/mempool-error.component';
-import { AccelerationsListComponent } from '../components/accelerations-list/accelerations-list.component';
-import { AccelerationStatsComponent } from '../components/acceleration-stats/acceleration-stats.component';
+import { AccelerationsListComponent } from '../components/acceleration/accelerations-list/accelerations-list.component';
+import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component';
+import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
import { BlockViewComponent } from '../components/block-view/block-view.component';
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
@@ -169,6 +171,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
SvgImagesComponent,
ChangeComponent,
SatsComponent,
+ BtcComponent,
FeeRateComponent,
TruncateComponent,
SearchResultsComponent,
@@ -194,6 +197,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
MempoolErrorComponent,
AccelerationsListComponent,
AccelerationStatsComponent,
+ PendingStatsComponent,
],
imports: [
CommonModule,
@@ -291,6 +295,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
SvgImagesComponent,
ChangeComponent,
SatsComponent,
+ BtcComponent,
FeeRateComponent,
TruncateComponent,
SearchResultsComponent,
@@ -306,6 +311,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
MempoolErrorComponent,
AccelerationsListComponent,
AccelerationStatsComponent,
+ PendingStatsComponent,
MempoolBlockOverviewComponent,
ClockchainComponent,
From 42f6f0c1224fc0bf56f566c6a1025c1d9ef4b8d5 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Thu, 7 Dec 2023 11:12:20 +0000
Subject: [PATCH 21/23] Redesign accelerator dashboard
---
.../accelerations-list.component.html | 14 ++-
.../accelerations-list.component.scss | 10 ++
.../accelerations-list.component.ts | 9 +-
.../accelerator-dashboard.component.html | 69 ++++-------
.../accelerator-dashboard.component.scss | 13 +++
.../accelerator-dashboard.component.ts | 38 ++++++-
.../pending-stats.component.html | 2 +-
.../pending-stats/pending-stats.component.ts | 4 +-
.../block-overview-graph.component.ts | 9 +-
.../block-overview-graph/block-scene.ts | 107 ++++++++++++++++--
.../block-overview-graph/tx-view.ts | 86 +-------------
.../components/block-overview-graph/utils.ts | 29 +++++
.../mempool-block-overview.component.html | 1 +
.../mempool-block-overview.component.ts | 3 +
14 files changed, 243 insertions(+), 151 deletions(-)
create mode 100644 frontend/src/app/components/block-overview-graph/utils.ts
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
index 0ac963446..a64c4724b 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
@@ -1,20 +1,18 @@
-
-
Accelerations
-
-
+
+
TXID |
Final Fee |
Max Bid |
Status |
-
+
@@ -62,5 +60,11 @@
+
+
+
+ There are no accelerations show here yet!
+
+
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
index d49ac2609..55cecdcbd 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
@@ -105,3 +105,13 @@ tr, td, th {
max-width: 50vw;
text-align: left;
}
+
+.no-data {
+ color: rgba(255, 255, 255, 0.4);
+ display: flex;
+ height: 280px;
+ width: 100%;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
index 0c0002782..ddd89d31c 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts
@@ -13,6 +13,7 @@ import { WebsocketService } from '../../../services/websocket.service';
})
export class AccelerationsListComponent implements OnInit {
@Input() widget: boolean = false;
+ @Input() pending: boolean = false;
@Input() accelerations$: Observable;
accelerationList$: Observable = undefined;
@@ -40,8 +41,14 @@ export class AccelerationsListComponent implements OnInit {
this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5;
- this.accelerationList$ = (this.apiService.getAccelerationHistory$({ timeframe: '1m' }) || this.accelerations$).pipe(
+ const accelerationObservable$ = this.accelerations$ || (this.pending ? this.apiService.getAccelerations$() : this.apiService.getAccelerationHistory$({ timeframe: '1m' }));
+ this.accelerationList$ = accelerationObservable$.pipe(
switchMap(accelerations => {
+ if (this.pending) {
+ for (const acceleration of accelerations) {
+ acceleration.status = acceleration.status || 'accelerating';
+ }
+ }
if (this.widget) {
return of(accelerations.slice(-6).reverse());
} else {
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
index b43d27f05..0dbba3219 100644
--- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
@@ -12,7 +12,7 @@
@@ -27,7 +27,18 @@
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+ Pending Accelerations
+
-
+
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
index 6d863fb60..0d1c3b1c0 100644
--- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss
@@ -132,4 +132,17 @@
text-align: right;
width: 20%;
}
+}
+
+.card {
+ height: 385px;
+}
+.list-card {
+ height: 410px;
+}
+
+.mempool-block-wrapper {
+ max-height: 380px;
+ max-width: 380px;
+ margin: auto;
}
\ No newline at end of file
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
index 00b3d303b..c3a40730b 100644
--- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
@@ -3,8 +3,15 @@ import { SeoService } from '../../../services/seo.service';
import { WebsocketService } from '../../../services/websocket.service';
import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
import { StateService } from '../../../services/state.service';
-import { Observable, Subject, catchError, combineLatest, distinctUntilChanged, of, share, switchMap, tap } from 'rxjs';
+import { Observable, Subject, catchError, combineLatest, distinctUntilChanged, interval, map, of, share, startWith, switchMap, tap } from 'rxjs';
import { ApiService } from '../../../services/api.service';
+import { Color } from '../../block-overview-graph/sprite-types';
+import { hexToColor } from '../../block-overview-graph/utils';
+import TxView from '../../block-overview-graph/tx-view';
+import { feeLevels, mempoolFeeColors } from '../../../app.constants';
+
+const acceleratedColor: Color = hexToColor('8F5FF6');
+const normalColors = mempoolFeeColors.map(hex => hexToColor(hex + '5F'));
interface AccelerationBlock extends BlockExtended {
accelerationCount: number,
@@ -19,6 +26,8 @@ interface AccelerationBlock extends BlockExtended {
export class AcceleratorDashboardComponent implements OnInit {
blocks$: Observable ;
accelerations$: Observable;
+ pendingAccelerations$: Observable;
+ minedAccelerations$: Observable;
loadingBlocks: boolean = true;
constructor(
@@ -33,6 +42,17 @@ export class AcceleratorDashboardComponent implements OnInit {
ngOnInit(): void {
this.websocketService.want(['blocks', 'mempool-blocks', 'stats']);
+ this.pendingAccelerations$ = interval(30000).pipe(
+ startWith(true),
+ switchMap(() => {
+ return this.apiService.getAccelerations$();
+ }),
+ catchError((e) => {
+ return of([]);
+ }),
+ share(),
+ );
+
this.accelerations$ = this.stateService.chainTip$.pipe(
distinctUntilChanged(),
switchMap((chainTip) => {
@@ -44,6 +64,12 @@ export class AcceleratorDashboardComponent implements OnInit {
share(),
);
+ this.minedAccelerations$ = this.accelerations$.pipe(
+ map(accelerations => {
+ return accelerations.filter(acc => ['mined', 'completed'].includes(acc.status))
+ })
+ );
+
this.blocks$ = combineLatest([
this.accelerations$,
this.stateService.blocks$.pipe(
@@ -83,4 +109,14 @@ export class AcceleratorDashboardComponent implements OnInit {
})
);
}
+
+ getAcceleratorColor(tx: TxView): Color {
+ if (tx.status === 'accelerated' || tx.acc) {
+ return acceleratedColor;
+ } else {
+ const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
+ const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1;
+ return normalColors[feeLevelIndex] || normalColors[mempoolFeeColors.length - 1];
+ }
+ }
}
diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
index 5b7bc356a..c94bbf43a 100644
--- a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
+++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html
@@ -20,7 +20,7 @@
Total vsize
- {{ (stats.totalVsize / 1_000_000).toFixed(2) }}% of next block
+ {{ (stats.totalVsize / 1_000_000 * 100).toFixed(2) }}% of next block
diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts
index dd3adacf8..f344c37a0 100644
--- a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts
+++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts
@@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ApiService } from '../../../services/api.service';
+import { Acceleration } from '../../../interfaces/node-api.interface';
@Component({
selector: 'app-pending-stats',
@@ -10,6 +11,7 @@ import { ApiService } from '../../../services/api.service';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PendingStatsComponent implements OnInit {
+ @Input() accelerations$: Observable;
public accelerationStats$: Observable;
constructor(
@@ -17,7 +19,7 @@ export class PendingStatsComponent implements OnInit {
) { }
ngOnInit(): void {
- this.accelerationStats$ = this.apiService.getAccelerations$().pipe(
+ this.accelerationStats$ = (this.accelerations$ || this.apiService.getAccelerations$()).pipe(
switchMap(accelerations => {
let totalAccelerations = 0;
let totalFeeDelta = 0;
diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
index 68d2a1bf3..1fc173a2d 100644
--- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
+++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts
@@ -4,7 +4,7 @@ import { FastVertexArray } from './fast-vertex-array';
import BlockScene from './block-scene';
import TxSprite from './tx-sprite';
import TxView from './tx-view';
-import { Position } from './sprite-types';
+import { Color, Position } from './sprite-types';
import { Price } from '../../services/price.service';
import { StateService } from '../../services/state.service';
import { Subscription } from 'rxjs';
@@ -27,6 +27,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
@Input() unavailable: boolean = false;
@Input() auditHighlighting: boolean = false;
@Input() blockConversion: Price;
+ @Input() overrideColors: ((tx: TxView) => Color) | null = null;
@Output() txClickEvent = new EventEmitter<{ tx: TransactionStripped, keyModifier: boolean}>();
@Output() txHoverEvent = new EventEmitter();
@Output() readyEvent = new EventEmitter();
@@ -91,6 +92,9 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
if (changes.auditHighlighting) {
this.setHighlightingEnabled(this.auditHighlighting);
}
+ if (changes.overrideColor) {
+ this.scene.setColorFunction(this.overrideColors);
+ }
}
ngOnDestroy(): void {
@@ -228,7 +232,8 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
} else {
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,
blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray,
- highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset });
+ highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset,
+ colorFunction: this.overrideColors });
this.start();
}
}
diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts
index 2569a3bb2..77b7c2e05 100644
--- a/frontend/src/app/components/block-overview-graph/block-scene.ts
+++ b/frontend/src/app/components/block-overview-graph/block-scene.ts
@@ -1,12 +1,26 @@
import { FastVertexArray } from './fast-vertex-array';
import TxView from './tx-view';
import { TransactionStripped } from '../../interfaces/websocket.interface';
-import { Position, Square, ViewUpdateParams } from './sprite-types';
+import { Color, Position, Square, ViewUpdateParams } from './sprite-types';
+import { feeLevels, mempoolFeeColors } from '../../app.constants';
+import { darken, desaturate, hexToColor } from './utils';
+
+const feeColors = mempoolFeeColors.map(hexToColor);
+const auditFeeColors = feeColors.map((color) => darken(desaturate(color, 0.3), 0.9));
+const marginalFeeColors = feeColors.map((color) => darken(desaturate(color, 0.8), 1.1));
+const auditColors = {
+ censored: hexToColor('f344df'),
+ missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7),
+ added: hexToColor('0099ff'),
+ selected: darken(desaturate(hexToColor('0099ff'), 0.3), 0.7),
+ accelerated: hexToColor('8F5FF6'),
+};
export default class BlockScene {
scene: { count: number, offset: { x: number, y: number}};
vertexArray: FastVertexArray;
txs: { [key: string]: TxView };
+ getColor: ((tx: TxView) => Color) = defaultColorFunction;
orientation: string;
flip: boolean;
animationDuration: number = 1000;
@@ -26,11 +40,11 @@ export default class BlockScene {
animateUntil = 0;
dirty: boolean;
- constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting }:
+ constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction }:
{ width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number,
- orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean }
+ orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null }
) {
- this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting });
+ this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction });
}
resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void {
@@ -63,6 +77,14 @@ export default class BlockScene {
}
}
+ setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void {
+ this.getColor = colorFunction;
+ this.dirty = true;
+ if (this.initialised && this.scene) {
+ this.updateColors(performance.now(), 50);
+ }
+ }
+
// Destroy the current layout and clean up graphics sprites without any exit animation
destroy(): void {
Object.values(this.txs).forEach(tx => tx.destroy());
@@ -86,7 +108,7 @@ export default class BlockScene {
this.applyTxUpdate(txView, {
display: {
position: txView.screenPosition,
- color: txView.getColor()
+ color: this.getColor(txView)
},
duration: 0
});
@@ -217,9 +239,9 @@ export default class BlockScene {
this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value));
}
- private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting }:
+ private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, highlighting, colorFunction }:
{ width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number,
- orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean }
+ orientation: string, flip: boolean, vertexArray: FastVertexArray, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null }
): void {
this.animationDuration = animationDuration || 1000;
this.configAnimationOffset = animationOffset;
@@ -228,6 +250,7 @@ export default class BlockScene {
this.flip = flip;
this.vertexArray = vertexArray;
this.highlightingEnabled = highlighting;
+ this.getColor = colorFunction || defaultColorFunction;
this.scene = {
count: 0,
@@ -261,9 +284,23 @@ export default class BlockScene {
}
}
+ private updateColor(tx: TxView, startTime: number, delay: number, animate: boolean = true, duration: number = 500): void {
+ if (tx.dirty || this.dirty) {
+ const txColor = this.getColor(tx);
+ this.applyTxUpdate(tx, {
+ display: {
+ color: txColor,
+ },
+ start: startTime,
+ delay,
+ duration: animate ? duration : 0,
+ });
+ }
+ }
+
private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void {
if (!tx.initialised) {
- const txColor = tx.getColor();
+ const txColor = this.getColor(tx);
this.applyTxUpdate(tx, {
display: {
position: {
@@ -321,6 +358,15 @@ export default class BlockScene {
this.dirty = false;
}
+ private updateColors(startTime: number, delay: number = 50, animate: boolean = true, duration: number = 500): void {
+ const ids = this.getTxList();
+ startTime = startTime || performance.now();
+ for (const id of ids) {
+ this.updateColor(this.txs[id], startTime, delay, animate, duration);
+ }
+ this.dirty = false;
+ }
+
private remove(id: string, startTime: number, direction: string = 'left'): TxView | void {
const tx = this.txs[id];
if (tx) {
@@ -858,3 +904,48 @@ class BlockLayout {
function feeRateDescending(a: TxView, b: TxView) {
return b.feerate - a.feerate;
}
+
+function defaultColorFunction(tx: TxView): Color {
+ const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate
+ const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1;
+ const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1];
+ // Normal mode
+ if (!tx.scene?.highlightingEnabled) {
+ if (tx.acc) {
+ return auditColors.accelerated;
+ } else {
+ return feeLevelColor;
+ }
+ return feeLevelColor;
+ }
+ // Block audit
+ switch(tx.status) {
+ case 'censored':
+ return auditColors.censored;
+ case 'missing':
+ case 'sigop':
+ case 'rbf':
+ return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
+ case 'fresh':
+ case 'freshcpfp':
+ return auditColors.missing;
+ case 'added':
+ return auditColors.added;
+ case 'selected':
+ return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
+ case 'accelerated':
+ return auditColors.accelerated;
+ case 'found':
+ if (tx.context === 'projected') {
+ return auditFeeColors[feeLevelIndex] || auditFeeColors[mempoolFeeColors.length - 1];
+ } else {
+ return feeLevelColor;
+ }
+ default:
+ if (tx.acc) {
+ return auditColors.accelerated;
+ } else {
+ return feeLevelColor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts
index db2c4f6ae..4e2d855e6 100644
--- a/frontend/src/app/components/block-overview-graph/tx-view.ts
+++ b/frontend/src/app/components/block-overview-graph/tx-view.ts
@@ -2,24 +2,13 @@ import TxSprite from './tx-sprite';
import { FastVertexArray } from './fast-vertex-array';
import { TransactionStripped } from '../../interfaces/websocket.interface';
import { SpriteUpdateParams, Square, Color, ViewUpdateParams } from './sprite-types';
-import { feeLevels, mempoolFeeColors } from '../../app.constants';
+import { hexToColor } from './utils';
import BlockScene from './block-scene';
const hoverTransitionTime = 300;
const defaultHoverColor = hexToColor('1bd8f4');
const defaultHighlightColor = hexToColor('800080');
-const feeColors = mempoolFeeColors.map(hexToColor);
-const auditFeeColors = feeColors.map((color) => darken(desaturate(color, 0.3), 0.9));
-const marginalFeeColors = feeColors.map((color) => darken(desaturate(color, 0.8), 1.1));
-const auditColors = {
- censored: hexToColor('f344df'),
- missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7),
- added: hexToColor('0099ff'),
- selected: darken(desaturate(hexToColor('0099ff'), 0.3), 0.7),
- accelerated: hexToColor('8F5FF6'),
-};
-
// convert from this class's update format to TxSprite's update format
function toSpriteUpdate(params: ViewUpdateParams): SpriteUpdateParams {
return {
@@ -195,77 +184,4 @@ export default class TxView implements TransactionStripped {
this.dirty = false;
return performance.now() + hoverTransitionTime;
}
-
- getColor(): Color {
- const rate = this.fee / this.vsize; // color by simple single-tx fee rate
- const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1;
- const feeLevelColor = feeColors[feeLevelIndex] || feeColors[mempoolFeeColors.length - 1];
- // Normal mode
- if (!this.scene?.highlightingEnabled) {
- if (this.acc) {
- return auditColors.accelerated;
- } else {
- return feeLevelColor;
- }
- return feeLevelColor;
- }
- // Block audit
- switch(this.status) {
- case 'censored':
- return auditColors.censored;
- case 'missing':
- case 'sigop':
- case 'rbf':
- return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
- case 'fresh':
- case 'freshcpfp':
- return auditColors.missing;
- case 'added':
- return auditColors.added;
- case 'selected':
- return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1];
- case 'accelerated':
- return auditColors.accelerated;
- case 'found':
- if (this.context === 'projected') {
- return auditFeeColors[feeLevelIndex] || auditFeeColors[mempoolFeeColors.length - 1];
- } else {
- return feeLevelColor;
- }
- default:
- if (this.acc) {
- return auditColors.accelerated;
- } else {
- return feeLevelColor;
- }
- }
- }
-}
-
-function hexToColor(hex: string): Color {
- return {
- r: parseInt(hex.slice(0, 2), 16) / 255,
- g: parseInt(hex.slice(2, 4), 16) / 255,
- b: parseInt(hex.slice(4, 6), 16) / 255,
- a: 1
- };
-}
-
-function desaturate(color: Color, amount: number): Color {
- const gray = (color.r + color.g + color.b) / 6;
- return {
- r: color.r + ((gray - color.r) * amount),
- g: color.g + ((gray - color.g) * amount),
- b: color.b + ((gray - color.b) * amount),
- a: color.a,
- };
-}
-
-function darken(color: Color, amount: number): Color {
- return {
- r: color.r * amount,
- g: color.g * amount,
- b: color.b * amount,
- a: color.a,
- }
}
diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts
new file mode 100644
index 000000000..a0bb8e868
--- /dev/null
+++ b/frontend/src/app/components/block-overview-graph/utils.ts
@@ -0,0 +1,29 @@
+import { Color } from './sprite-types';
+
+export function hexToColor(hex: string): Color {
+ return {
+ r: parseInt(hex.slice(0, 2), 16) / 255,
+ g: parseInt(hex.slice(2, 4), 16) / 255,
+ b: parseInt(hex.slice(4, 6), 16) / 255,
+ a: hex.length > 6 ? parseInt(hex.slice(6, 8), 16) / 255 : 1
+ };
+}
+
+export function desaturate(color: Color, amount: number): Color {
+ const gray = (color.r + color.g + color.b) / 6;
+ return {
+ r: color.r + ((gray - color.r) * amount),
+ g: color.g + ((gray - color.g) * amount),
+ b: color.b + ((gray - color.b) * amount),
+ a: color.a,
+ };
+}
+
+export function darken(color: Color, amount: number): Color {
+ return {
+ r: color.r * amount,
+ g: color.g * amount,
+ b: color.b * amount,
+ a: color.a,
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html
index 503f2e38d..1e0cba48c 100644
--- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html
+++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.html
@@ -5,5 +5,6 @@
[blockLimit]="stateService.blockVSize"
[orientation]="timeLtr ? 'right' : 'left'"
[flip]="true"
+ [overrideColors]="overrideColors"
(txClickEvent)="onTxClick($event)"
>
diff --git a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts
index 226be5210..09eac989e 100644
--- a/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts
+++ b/frontend/src/app/components/mempool-block-overview/mempool-block-overview.component.ts
@@ -8,6 +8,8 @@ import { switchMap, filter } from 'rxjs/operators';
import { WebsocketService } from '../../services/websocket.service';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
import { Router } from '@angular/router';
+import { Color } from '../block-overview-graph/sprite-types';
+import TxView from '../block-overview-graph/tx-view';
@Component({
selector: 'app-mempool-block-overview',
@@ -16,6 +18,7 @@ import { Router } from '@angular/router';
})
export class MempoolBlockOverviewComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit {
@Input() index: number;
+ @Input() overrideColors: ((tx: TxView) => Color) | null = null;
@Output() txPreviewEvent = new EventEmitter();
@ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent;
From aff44d90d5ebc678f86e9caeadd5e82376c33e09 Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 8 Dec 2023 13:03:08 +0000
Subject: [PATCH 22/23] Rerefactor acceleration dashboard
---
.../acceleration-fees-graph.component.html | 33 +---
.../acceleration-fees-graph.component.scss | 57 +------
.../acceleration-fees-graph.component.ts | 145 ++++++++++--------
.../acceleration-stats.component.ts | 2 +-
.../accelerations-list.component.html | 57 ++++---
.../accelerations-list.component.scss | 14 +-
.../accelerator-dashboard.component.html | 24 ++-
.../accelerator-dashboard.component.ts | 2 +-
8 files changed, 158 insertions(+), 176 deletions(-)
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html
index 0c15f9f44..9ae0ddade 100644
--- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html
+++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html
@@ -28,19 +28,8 @@
-
-
- Avg Out-of-band Fees (24h)
-
-
-
-
-
- Avg Out-of-band Fees (1w)
-
-
-
-
+
+ Out-of-band Fees Per Block
@@ -50,22 +39,4 @@
-
-
-
-
- Avg Out-of-band Fees (24h)
-
-
-
-
-
-
-
- Avg Out-of-band Fees (1w)
-
-
-
-
-
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss
index 2ffcc6374..c4b4335ee 100644
--- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss
+++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss
@@ -56,61 +56,16 @@
.chart-widget {
width: 100%;
height: 100%;
- max-height: 238px;
+ max-height: 290px;
}
-.acceleration-fees {
- min-height: 56px;
- display: block;
- @media (min-width: 485px) {
- display: flex;
- flex-direction: row;
- }
- h5 {
- margin-bottom: 10px;
- }
- .item {
- width: 50%;
- display: inline-block;
- margin: 0px auto 20px;
- &:nth-child(2) {
- order: 2;
- @media (min-width: 485px) {
- order: 3;
- }
- }
- &:nth-child(3) {
- order: 3;
- @media (min-width: 485px) {
- order: 2;
- display: block;
- }
- @media (min-width: 768px) {
- display: none;
- }
- @media (min-width: 992px) {
- display: block;
- }
- }
- .card-title {
- font-size: 1rem;
- color: #4a68b9;
- }
- .card-text {
- font-size: 18px;
- span {
- color: #ffffff66;
- font-size: 12px;
- }
- }
- }
+h5 {
+ margin-bottom: 10px;
}
-.skeleton-loader {
- width: 100%;
- display: block;
- max-width: 80px;
- margin: 15px auto 3px;
+.card-title {
+ font-size: 1rem;
+ color: #4a68b9;
}
.disabled {
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts
index b5dc21eb6..d27b10690 100644
--- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts
+++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts
@@ -1,12 +1,12 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnDestroy, OnInit } from '@angular/core';
import { EChartsOption, graphic } from 'echarts';
-import { Observable, combineLatest } from 'rxjs';
-import { map, startWith, switchMap, tap } from 'rxjs/operators';
+import { Observable, Subscription, combineLatest } from 'rxjs';
+import { map, max, startWith, switchMap, tap } from 'rxjs/operators';
import { ApiService } from '../../../services/api.service';
import { SeoService } from '../../../services/seo.service';
import { formatNumber } from '@angular/common';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
-import { download, formatterXAxis } from '../../../shared/graphs.utils';
+import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from '../../../shared/graphs.utils';
import { StorageService } from '../../../services/storage.service';
import { MiningService } from '../../../services/mining.service';
import { ActivatedRoute } from '@angular/router';
@@ -26,7 +26,7 @@ import { Acceleration } from '../../../interfaces/node-api.interface';
`],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class AccelerationFeesGraphComponent implements OnInit {
+export class AccelerationFeesGraphComponent implements OnInit, OnDestroy {
@Input() widget: boolean = false;
@Input() right: number | string = 45;
@Input() left: number | string = 75;
@@ -42,6 +42,7 @@ export class AccelerationFeesGraphComponent implements OnInit {
hrStatsObservable$: Observable;
statsObservable$: Observable;
+ statsSubscription: Subscription;
isLoading = true;
formatNumber = formatNumber;
timespan = '';
@@ -66,26 +67,17 @@ export class AccelerationFeesGraphComponent implements OnInit {
ngOnInit(): void {
this.seoService.setTitle($localize`:@@6c453b11fd7bd159ae30bc381f367bc736d86909:Acceleration Fees`);
+ this.isLoading = true;
if (this.widget) {
- this.miningWindowPreference = '1w';
- this.isLoading = true;
+ this.miningWindowPreference = '1m';
this.timespan = this.miningWindowPreference;
- this.hrStatsObservable$ = (this.accelerations$ || this.apiService.getAccelerationHistory$({ timeframe: '24h' })).pipe(
- map((accelerations) => {
- return {
- avgFeesPaid: accelerations.filter(acc => acc.status === 'completed' && acc.lastUpdated < (Date.now() - (24 * 60 * 60 * 1000))).reduce((total, acc) => total + acc.feePaid, 0) / accelerations.length
- };
- })
- );
-
this.statsObservable$ = combineLatest([
(this.accelerations$ || this.apiService.getAccelerationHistory$({ timeframe: this.miningWindowPreference })),
this.apiService.getHistoricalBlockFees$(this.miningWindowPreference),
]).pipe(
tap(([accelerations, blockFeesResponse]) => {
this.prepareChartOptions(accelerations, blockFeesResponse.body);
- this.isLoading = false;
}),
map(([accelerations, blockFeesResponse]) => {
return {
@@ -121,11 +113,13 @@ export class AccelerationFeesGraphComponent implements OnInit {
]).pipe(
tap(([accelerations, blockFeesResponse]) => {
this.prepareChartOptions(accelerations, blockFeesResponse.body);
- this.isLoading = false;
- this.cd.markForCheck();
})
);
}
+ this.statsSubscription = this.statsObservable$.subscribe(() => {
+ this.isLoading = false;
+ this.cd.markForCheck();
+ });
}
prepareChartOptions(accelerations, blockFees) {
@@ -143,6 +137,8 @@ export class AccelerationFeesGraphComponent implements OnInit {
}
let last = null;
+ let minValue = Infinity;
+ let maxValue = 0;
const data = [];
for (const val of blockFees) {
if (last == null) {
@@ -151,31 +147,29 @@ export class AccelerationFeesGraphComponent implements OnInit {
let totalFeeDelta = 0;
let totalFeePaid = 0;
let totalCount = 0;
+ let blockCount = 0;
while (last <= val.avgHeight) {
+ blockCount++;
totalFeeDelta += (blockAccelerations[last] || []).reduce((total, acc) => total + acc.feeDelta, 0);
totalFeePaid += (blockAccelerations[last] || []).reduce((total, acc) => total + acc.feePaid, 0);
totalCount += (blockAccelerations[last] || []).length;
last++;
}
+ minValue = Math.min(minValue, val.avgFees);
+ maxValue = Math.max(maxValue, val.avgFees);
data.push({
...val,
feeDelta: totalFeeDelta,
- feePaid: totalFeePaid,
- accelerations: totalCount,
+ avgFeePaid: (totalFeePaid / blockCount),
+ accelerations: totalCount / blockCount,
});
}
this.chartOptions = {
title: title,
color: [
- '#1E88E5',
- new graphic.LinearGradient(0, 0, 0, 0.65, [
- { offset: 0, color: '#F4511E' },
- { offset: 0.25, color: '#FB8C00' },
- { offset: 0.5, color: '#FFB300' },
- { offset: 0.75, color: '#FDD835' },
- { offset: 1, color: '#7CB342' }
- ]),
+ '#8F5FF6',
+ '#6b6b6b',
],
animation: false,
grid: {
@@ -205,11 +199,11 @@ export class AccelerationFeesGraphComponent implements OnInit {
let tooltip = `
${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))} `;
- for (const tick of data) {
- if (tick.seriesIndex === 1) {
+ for (const tick of data.reverse()) {
+ if (tick.data[1] >= 1_000_000) {
+ tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1] / 100_000_000, this.locale, '1.0-3')} BTC `;
+ } else {
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')} sats `;
- } else if (tick.seriesIndex === 0) {
- tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')} `;
}
}
@@ -224,24 +218,35 @@ export class AccelerationFeesGraphComponent implements OnInit {
},
xAxis: data.length === 0 ? undefined :
{
- type: 'time',
- splitNumber: this.isMobile() ? 5 : 10,
+ name: this.widget ? undefined : formatterXAxisLabel(this.locale, this.timespan),
+ nameLocation: 'middle',
+ nameTextStyle: {
+ padding: [10, 0, 0, 0],
+ },
+ type: 'category',
+ boundaryGap: false,
+ axisLine: { onZero: true },
axisLabel: {
+ formatter: val => formatterXAxisTimeCategory(this.locale, this.timespan, parseInt(val, 10)),
+ align: 'center',
+ fontSize: 11,
+ lineHeight: 12,
hideOverlap: true,
- }
+ padding: [0, 5],
+ },
},
- legend: (this.widget || data.length === 0) ? undefined : {
+ legend: {
data: [
{
- name: 'Total accelerations',
+ name: 'In-band fees per block',
inactiveColor: 'rgb(110, 112, 121)',
- textStyle: {
+ textStyle: {
color: 'white',
},
icon: 'roundRect',
},
{
- name: 'Out-of-band fees paid',
+ name: 'Out-of-band fees per block',
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
color: 'white',
@@ -249,6 +254,11 @@ export class AccelerationFeesGraphComponent implements OnInit {
icon: 'roundRect',
},
],
+ selected: {
+ 'In-band fees per block': false,
+ 'Out-of-band fees per block': true,
+ },
+ show: !this.widget,
},
yAxis: data.length === 0 ? undefined : [
{
@@ -288,35 +298,23 @@ export class AccelerationFeesGraphComponent implements OnInit {
series: data.length === 0 ? undefined : [
{
legendHoverLink: false,
- zlevel: 0,
- yAxisIndex: 1,
- name: 'Total accelerations',
- data: data.map(block => [block.timestamp * 1000, block.accelerations, block.avgHeight]),
- type: 'line',
- symbol: 'none',
- areaStyle: {
- color: '#1E88E5',
- opacity: 0.5
- },
- lineStyle: {
- width: 1,
- opacity: 1,
- },
- step: 'middle',
+ zlevel: 1,
+ name: 'Out-of-band fees per block',
+ data: data.map(block => [block.timestamp * 1000, block.avgFeePaid, block.avgHeight]),
+ stack: 'Total',
+ type: 'bar',
+ barWidth: '100%',
+ large: true,
},
{
legendHoverLink: false,
- zlevel: 1,
- yAxisIndex: 0,
- name: 'Out-of-band fees paid',
- data: data.map(block => [block.timestamp * 1000, block.feePaid, block.avgHeight]),
- type: 'line',
- smooth: 0.25,
- symbol: 'none',
- lineStyle: {
- width: 2,
- opacity: 1,
- }
+ zlevel: 0,
+ name: 'In-band fees per block',
+ data: data.map(block => [block.timestamp * 1000, block.avgFees, block.avgHeight]),
+ stack: 'Total',
+ type: 'bar',
+ barWidth: '100%',
+ large: true,
},
],
dataZoom: (this.widget || data.length === 0 )? undefined : [{
@@ -344,6 +342,17 @@ export class AccelerationFeesGraphComponent implements OnInit {
}
},
}],
+ visualMap: {
+ type: 'continuous',
+ min: minValue,
+ max: maxValue,
+ dimension: 1,
+ seriesIndex: 1,
+ show: false,
+ inRange: {
+ color: ['#F4511E7f', '#FB8C007f', '#FFB3007f', '#FDD8357f', '#7CB3427f'].reverse() // Gradient color range
+ }
+ },
};
}
@@ -372,4 +381,10 @@ export class AccelerationFeesGraphComponent implements OnInit {
this.chartOptions.backgroundColor = 'none';
this.chartInstance.setOption(this.chartOptions);
}
+
+ ngOnDestroy(): void {
+ if (this.statsSubscription) {
+ this.statsSubscription.unsubscribe();
+ }
+ }
}
diff --git a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts
index 51f7360e1..d83303619 100644
--- a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts
+++ b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts
@@ -12,7 +12,7 @@ import { Acceleration } from '../../../interfaces/node-api.interface';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AccelerationStatsComponent implements OnInit {
- @Input() timespan: '24h' | '1w' = '24h';
+ @Input() timespan: '24h' | '1w' | '1m' = '24h';
@Input() accelerations$: Observable;
public accelerationStats$: Observable;
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
index a64c4724b..4a864b024 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
@@ -8,9 +8,16 @@
TXID |
- Final Fee |
- Max Bid |
- Status |
+
+ Fee Rate |
+ Acceleration Bid |
+ Requested |
+
+
+ Out-of-band Fee |
+ Block |
+ Status |
+
@@ -19,20 +26,33 @@
-
- {{ (acceleration.feePaid - acceleration.baseFee - acceleration.vsizeFee) | number }} sat
- |
-
- ~
- |
-
- {{ acceleration.feeDelta | number }} sat
- |
-
- Pending
- Mined
- Canceled
- |
+
+
+
+ |
+
+ {{ (acceleration.feeDelta) | number }} sat
+ |
+
+
+ |
+
+
+
+ {{ (acceleration.feePaid) | number }} sat
+ |
+
+ ~
+ |
+
+ {{ acceleration.blockHeight }}
+ |
+
+ Pending
+ Mined
+ Canceled
+ |
+
@@ -63,7 +83,8 @@
- There are no accelerations show here yet!
+ There are no active accelerations yet!
+ There are no accelerations show here yet!
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
index 55cecdcbd..69aae18cc 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss
@@ -50,7 +50,7 @@ tr, td, th {
}
.txid {
- width: 30%;
+ width: 25%;
@media (max-width: 1100px) {
padding-right: 10px;
}
@@ -64,10 +64,18 @@ tr, td, th {
}
.fee {
- width: 25%;
+ width: 35%;
}
-.fee-delta {
+.block {
+ width: 20%;
+}
+
+.bid {
+ width: 30%;
+}
+
+.time {
width: 25%;
}
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
index 0dbba3219..91b721db6 100644
--- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html
@@ -7,7 +7,7 @@
- Pending accelerations
+ Active accelerations
-
+
Acceleration stats
- (1008 blocks)
+ (1 month)
@@ -54,11 +54,23 @@
-
+
+
+
+
- Pending Accelerations
+
+ Active Accelerations
+
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
index c3a40730b..79a77a600 100644
--- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
+++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts
@@ -56,7 +56,7 @@ export class AcceleratorDashboardComponent implements OnInit {
this.accelerations$ = this.stateService.chainTip$.pipe(
distinctUntilChanged(),
switchMap((chainTip) => {
- return this.apiService.getAccelerationHistory$({ timeframe: '1w' });
+ return this.apiService.getAccelerationHistory$({ timeframe: '1m' });
}),
catchError((e) => {
return of([]);
From 2cddc5fdd8d55d15e6ca2ea436d111671b67af7c Mon Sep 17 00:00:00 2001
From: Mononaut
Date: Fri, 8 Dec 2023 13:23:51 +0000
Subject: [PATCH 23/23] accelerations: not yet
---
.../accelerations-list/accelerations-list.component.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
index 4a864b024..32012d363 100644
--- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
+++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html
@@ -83,8 +83,8 @@
- There are no active accelerations yet!
- There are no accelerations show here yet!
+ There are no active accelerations
+ There are no recent accelerations
| |