Compare commits

..

16 Commits

Author SHA1 Message Date
wiz
541555051b Merge branch 'master' into knorrium/update-node-matrix 2025-01-20 19:26:56 +09:00
wiz
5aeaa68259 ops: Enable stratum in FOSS prod frontend config 2025-01-20 17:56:56 +09:00
nymkappa
e01898a4c5 Merge pull request #5640 from mempool/nymkappa/square-errors
[accelerator] display payment errors, auto reload after 10 secs instead of 3 secs
2025-01-20 17:47:18 +09:00
nymkappa
0568a8c6c1 Merge branch 'master' into nymkappa/square-errors 2025-01-20 17:36:31 +09:00
wiz
e53e810a55 ops: Fix stratum server URL path in prod config 2025-01-20 17:34:19 +09:00
nymkappa
e2c44b6c62 Merge branch 'master' into nymkappa/square-errors 2025-01-20 17:23:15 +09:00
wiz
36b691e25b ops: Enable stratum in prod config via localhost nginx proxy 2025-01-20 17:20:38 +09:00
Felipe Knorr Kuhn
5f5e96984a Merge branch 'master' into knorrium/update-node-matrix 2025-01-19 23:41:46 -08:00
wiz
4a14e8d921 Merge pull request #5736 from mempool/mononaut/fix-stratum-trees
fix stratum tree rendering with different branch lengths
2025-01-20 16:39:56 +09:00
Mononaut
4e735cc8b0 fix stratum tree rendering with different branch lengths 2025-01-20 07:30:27 +00:00
softsimon
4520e3fdf2 Merge pull request #5735 from mempool/nymkappa/new-fa-icon
add new fa icon
2025-01-20 14:01:37 +07:00
nymkappa
390bbf1097 add new fa icon 2025-01-20 15:20:29 +09:00
Felipe Knorr Kuhn
f5a54ae62b Update the local nvmrc to node 22 2025-01-15 21:52:54 -08:00
Felipe Knorr Kuhn
4da145ff5c Update the node version to run e2e tests 2025-01-15 21:52:38 -08:00
Felipe Knorr Kuhn
a898701830 Update node matrix to v20 and v22 2025-01-15 21:33:25 -08:00
nymkappa
72ddb8c6a4 [accelerator] display payment errors, auto reload after 10 secs instead of 3 secs 2024-11-14 16:46:18 +01:00
13 changed files with 126 additions and 117 deletions

View File

@@ -9,7 +9,7 @@ jobs:
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
strategy: strategy:
matrix: matrix:
node: ["20", "21"] node: ["20", "22"]
flavor: ["dev", "prod"] flavor: ["dev", "prod"]
fail-fast: false fail-fast: false
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
@@ -160,7 +160,7 @@ jobs:
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
strategy: strategy:
matrix: matrix:
node: ["20", "21"] node: ["20", "22"]
flavor: ["dev", "prod"] flavor: ["dev", "prod"]
fail-fast: false fail-fast: false
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
@@ -263,7 +263,7 @@ jobs:
- name: Setup node - name: Setup node
uses: actions/setup-node@v3 uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 22
cache: "npm" cache: "npm"
cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json

2
.nvmrc
View File

@@ -1 +1 @@
v20.8.0 v22.13.0

View File

@@ -1,10 +1,18 @@
<div class="box card w-100 accelerate-checkout-inner" [class.input-disabled]="isCheckoutLocked > 0" style="background: var(--box-bg)" id=acceleratePreviewAnchor> <div class="box card w-100 accelerate-checkout-inner" [class.input-disabled]="isCheckoutLocked > 0" style="background: var(--box-bg)" id=acceleratePreviewAnchor>
@if (accelerateError) { @if (accelerateError) {
<div class="row mb-1 text-center"> @if (accelerateError.includes('Payment declined')) {
<div class="col-sm"> <div class="row mb-1 text-center">
<h1 style="font-size: larger;" i18n="accelerator.sorry-error-title">Sorry, something went wrong!</h1> <div class="col-sm">
<h1 style="font-size: larger;">{{ accelerateError }}</h1>
</div>
</div> </div>
</div> } @else {
<div class="row mb-1 text-center">
<div class="col-sm">
<h1 style="font-size: larger;" i18n="accelerator.sorry-error-title">Sorry, something went wrong!</h1>
</div>
</div>
}
<div class="row text-center mt-1"> <div class="row text-center mt-1">
<div class="col-sm"> <div class="col-sm">
<div class="d-flex flex-row justify-content-center align-items-center"> <div class="d-flex flex-row justify-content-center align-items-center">

View File

@@ -222,7 +222,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.loadingBtcpayInvoice = true; this.loadingBtcpayInvoice = true;
this.invoice = null; this.invoice = null;
this.requestBTCPayInvoice(); this.requestBTCPayInvoice();
this.scrollToElementWithTimeout('acceleratePreviewAnchor', 'start', 100);
} else if (this._step === 'cashapp' && this.cashappEnabled) { } else if (this._step === 'cashapp' && this.cashappEnabled) {
this.loadingCashapp = true; this.loadingCashapp = true;
this.setupSquare(); this.setupSquare();
@@ -560,7 +559,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
// Reset everything by reloading the page :D, can be improved // Reset everything by reloading the page :D, can be improved
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``)); window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``));
}, 3000); }, 10000);
} }
} }
}); });
@@ -687,7 +686,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
// Reset everything by reloading the page :D, can be improved // Reset everything by reloading the page :D, can be improved
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``)); window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``));
}, 3000); }, 10000);
} }
} }
}); });
@@ -786,7 +785,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
// Reset everything by reloading the page :D, can be improved // Reset everything by reloading the page :D, can be improved
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``)); window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``));
}, 3000); }, 10000);
} }
} }
}); });

View File

@@ -11,6 +11,12 @@
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="daysAvailable"> <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="daysAvailable">
<div class="btn-group btn-group-toggle" name="radioBasic"> <div class="btn-group btn-group-toggle" name="radioBasic">
<label class="btn btn-primary btn-sm" [class.active]="radioGroupForm.get('dateSpan').value === '24h'">
<input type="radio" [value]="'24h'" fragment="24h" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 24H
</label>
<label class="btn btn-primary btn-sm" *ngIf="daysAvailable >= 1" [class.active]="radioGroupForm.get('dateSpan').value === '3d'">
<input type="radio" [value]="'3d'" fragment="3d" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 3D
</label>
<label class="btn btn-primary btn-sm" *ngIf="daysAvailable >= 3" [class.active]="radioGroupForm.get('dateSpan').value === '1w'"> <label class="btn btn-primary btn-sm" *ngIf="daysAvailable >= 3" [class.active]="radioGroupForm.get('dateSpan').value === '1w'">
<input type="radio" [value]="'1w'" fragment="1w" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 1W <input type="radio" [value]="'1w'" fragment="1w" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" formControlName="dateSpan"> 1W
</label> </label>

View File

@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { echarts, EChartsOption } from '@app/graphs/echarts'; import { EChartsOption } from '@app/graphs/echarts';
import { Observable, Subject, Subscription, combineLatest, fromEvent, merge, share } from 'rxjs'; import { Observable, Subject, Subscription, combineLatest, fromEvent, merge, share } from 'rxjs';
import { startWith, switchMap, tap } from 'rxjs/operators'; import { startWith, switchMap, tap } from 'rxjs/operators';
import { SeoService } from '@app/services/seo.service'; import { SeoService } from '@app/services/seo.service';
@@ -12,6 +12,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { Acceleration } from '@interfaces/node-api.interface'; import { Acceleration } from '@interfaces/node-api.interface';
import { ServicesApiServices } from '@app/services/services-api.service'; import { ServicesApiServices } from '@app/services/services-api.service';
import { StateService } from '@app/services/state.service'; import { StateService } from '@app/services/state.service';
import { RelativeUrlPipe } from '@app/shared/pipes/relative-url/relative-url.pipe';
@Component({ @Component({
selector: 'app-acceleration-fees-graph', selector: 'app-acceleration-fees-graph',
@@ -30,9 +31,9 @@ import { StateService } from '@app/services/state.service';
export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDestroy { export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDestroy {
@Input() widget: boolean = false; @Input() widget: boolean = false;
@Input() height: number = 300; @Input() height: number = 300;
@Input() right: number | string = 70; @Input() right: number | string = 45;
@Input() left: number | string = 55; @Input() left: number | string = 75;
@Input() period: '24h' | '1w' | '1m' | '1y' | 'all' = '1y'; @Input() period: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
@Input() accelerations$: Observable<Acceleration[]>; @Input() accelerations$: Observable<Acceleration[]>;
miningWindowPreference: string; miningWindowPreference: string;
@@ -50,7 +51,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
isLoading = true; isLoading = true;
formatNumber = formatNumber; formatNumber = formatNumber;
timespan = ''; timespan = '';
periodSubject$: Subject<'24h' | '1w' | '1m' | '1y' | 'all'> = new Subject(); periodSubject$: Subject<'24h' | '3d' | '1w' | '1m' | 'all'> = new Subject();
chartInstance: any = undefined; chartInstance: any = undefined;
daysAvailable: number = 0; daysAvailable: number = 0;
@@ -63,7 +64,9 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
private miningService: MiningService, private miningService: MiningService,
private route: ActivatedRoute, private route: ActivatedRoute,
public stateService: StateService, public stateService: StateService,
private cd: ChangeDetectorRef private cd: ChangeDetectorRef,
private router: Router,
private zone: NgZone,
) { ) {
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1w' }); this.radioGroupForm = this.formBuilder.group({ dateSpan: '1w' });
this.radioGroupForm.controls.dateSpan.setValue('1w'); this.radioGroupForm.controls.dateSpan.setValue('1w');
@@ -80,7 +83,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
this.fragmentSubscription = this.route.fragment.subscribe((fragment) => { this.fragmentSubscription = this.route.fragment.subscribe((fragment) => {
if (['1w', '1m', '1y', 'all'].indexOf(fragment) > -1) { if (['24h', '3d', '1w', '1m', '3m', 'all'].indexOf(fragment) > -1) {
this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false });
} }
}); });
@@ -95,9 +98,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
if (!this.widget) { if (!this.widget) {
this.storageService.setValue('miningWindowPreference', timespan); this.storageService.setValue('miningWindowPreference', timespan);
} }
if (timespan !== this.timespan) { this.isLoading = true;
this.isLoading = true;
}
this.timespan = timespan; this.timespan = timespan;
return this.servicesApiService.getAggregatedAccelerationHistory$({timeframe: this.timespan}); return this.servicesApiService.getAggregatedAccelerationHistory$({timeframe: this.timespan});
}) })
@@ -119,9 +120,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
if (changes.period) { if (changes.period) {
if (this.period === '24h') {
this.period = '1m';
}
this.periodSubject$.next(this.period); this.periodSubject$.next(this.period);
} }
} }
@@ -143,19 +141,13 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
this.chartOptions = { this.chartOptions = {
title: title, title: title,
color: [ color: [
new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [ '#8F5FF6',
{ offset: 0, color: '#F4511E' }, '#6b6b6b',
{ offset: 0.25, color: '#FB8C00' },
{ offset: 0.5, color: '#FFB300' },
{ offset: 0.75, color: '#FDD835' },
{ offset: 1, color: '#7CB342' }
]),
'#ab2dce',
], ],
animation: false, animation: false,
grid: { grid: {
height: (this.widget && this.height) ? this.height - 50 : undefined, height: (this.widget && this.height) ? this.height - 30 : undefined,
top: this.widget ? 40 : 60, top: this.widget ? 20 : 40,
bottom: this.widget ? 30 : 80, bottom: this.widget ? 30 : 80,
right: this.right, right: this.right,
left: this.left, left: this.left,
@@ -177,18 +169,17 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
formatter: (ticks) => { formatter: (ticks) => {
let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}</b><br>`; let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}</b><br>`;
for (const tick of ticks) { if (ticks[0].data[1] > 10_000_000) {
if (tick.seriesName === 'Total bid boost') { tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1] / 100_000_000, this.locale, '1.0-8')} BTC<br>`;
if (tick.data[1] > 10_000_000) { } else {
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1] / 100_000_000, this.locale, '1.0-8')} BTC<br>`; tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.0-0')} sats<br>`;
} else { }
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')} sats<br>`;
} if (['24h', '3d'].includes(this.timespan)) {
} else if (tick && tick.seriesName === 'Accelerated') { tooltip += `<small>` + $localize`At block: ${ticks[0].data[2]}` + `</small>`;
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.0-0')}<br>`; } else {
} tooltip += `<small>` + $localize`Around block: ${ticks[0].data[2]}` + `</small>`;
} }
tooltip += `<small>` + $localize`Around block: ${ticks[0].data[2]}` + `</small>`;
return tooltip; return tooltip;
} }
@@ -220,17 +211,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
textStyle: { textStyle: {
color: 'white', color: 'white',
}, },
itemStyle: {
color: '#FFB300',
},
icon: 'roundRect',
},
{
name: 'Accelerated',
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
color: 'white',
},
icon: 'roundRect', icon: 'roundRect',
}, },
], ],
@@ -242,13 +222,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
yAxis: data.length === 0 ? undefined : [ yAxis: data.length === 0 ? undefined : [
{ {
type: 'value', type: 'value',
name: 'Total bid boost',
position: 'right',
nameTextStyle: {
align: 'right',
padding: [0, -65, 0, 0],
fontStyle: 'italic',
},
axisLabel: { axisLabel: {
color: 'rgb(110, 112, 121)', color: 'rgb(110, 112, 121)',
formatter: (val) => { formatter: (val) => {
@@ -259,20 +232,6 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
} }
} }
}, },
splitLine: null
},
{
type: 'value',
name: 'Accelerated',
position: 'left',
axisLabel: {
color: 'rgb(110, 112, 121)',
},
nameTextStyle: {
align: 'right',
padding: [0, -35, 0, 0],
fontStyle: 'italic',
},
splitLine: { splitLine: {
lineStyle: { lineStyle: {
type: 'dotted', type: 'dotted',
@@ -281,28 +240,33 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
} }
}, },
}, },
{
type: 'value',
position: 'right',
axisLabel: {
color: 'rgb(110, 112, 121)',
formatter: function(val) {
return `${val}`;
}.bind(this)
},
splitLine: {
show: false,
},
},
], ],
series: data.length === 0 ? undefined : [ series: data.length === 0 ? undefined : [
{ {
legendHoverLink: false,
zlevel: 1,
name: 'Total bid boost', name: 'Total bid boost',
data: data.map(h => { data: data.map(h => {
return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight] return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight]
}), }),
type: 'line', stack: 'Total',
symbol: 'none',
lineStyle: {
width: 1,
},
smooth: true,
},
{
name: 'Accelerated',
yAxisIndex: 1,
data: data.map(h => {
return [h.timestamp * 1000, h.count, h.avgHeight]
}),
type: 'bar', type: 'bar',
barWidth: '90%', barWidth: '90%',
large: true,
barMinHeight: 3,
}, },
], ],
dataZoom: (this.widget || data.length === 0 )? undefined : [{ dataZoom: (this.widget || data.length === 0 )? undefined : [{
@@ -335,6 +299,19 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
onChartInit(ec) { onChartInit(ec) {
this.chartInstance = ec; this.chartInstance = ec;
this.chartInstance.on('click', (e) => {
this.zone.run(() => {
if (['24h', '3d'].includes(this.timespan)) {
const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.data[2]}`);
if (e.event.event.shiftKey || e.event.event.ctrlKey || e.event.event.metaKey) {
window.open(url);
} else {
this.router.navigate([url]);
}
}
});
});
} }
isMobile() { isMobile() {

View File

@@ -16,7 +16,7 @@ export type AccelerationStats = {
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AccelerationStatsComponent implements OnInit, OnChanges { export class AccelerationStatsComponent implements OnInit, OnChanges {
@Input() timespan: '24h' | '1m' | '1y' | 'all' = '1y'; @Input() timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
accelerationStats$: Observable<AccelerationStats>; accelerationStats$: Observable<AccelerationStats>;
blocksInPeriod: number = 7 * 144; blocksInPeriod: number = 7 * 144;
@@ -38,11 +38,14 @@ export class AccelerationStatsComponent implements OnInit, OnChanges {
case '24h': case '24h':
this.blocksInPeriod = 144; this.blocksInPeriod = 144;
break; break;
case '1m': case '3d':
this.blocksInPeriod = 30.5 * 144; this.blocksInPeriod = 3 * 144;
break; break;
case '1y': case '1w':
this.blocksInPeriod = 30.5 * 144 * 365; this.blocksInPeriod = 7 * 144;
break;
case '1m':
this.blocksInPeriod = 30 * 144;
break; break;
case 'all': case 'all':
this.blocksInPeriod = Infinity; this.blocksInPeriod = Infinity;

View File

@@ -26,12 +26,12 @@
@case ('24h') { @case ('24h') {
<span style="font-size: xx-small" i18n="mining.1-day">(1 day)</span> <span style="font-size: xx-small" i18n="mining.1-day">(1 day)</span>
} }
@case ('1w') {
<span style="font-size: xx-small" i18n="mining.1-week">(1 week)</span>
}
@case ('1m') { @case ('1m') {
<span style="font-size: xx-small" i18n="mining.1-month">(1 month)</span> <span style="font-size: xx-small" i18n="mining.1-month">(1 month)</span>
} }
@case ('1y') {
<span style="font-size: xx-small" i18n="mining.1-year">(1 year)</span>
}
@case ('all') { @case ('all') {
<span style="font-size: xx-small" i18n="mining.all-time">(all time)</span> <span style="font-size: xx-small" i18n="mining.all-time">(all time)</span>
} }
@@ -45,12 +45,12 @@
<a href="" (click)="setTimespan('24h')" class="toggler-option" <a href="" (click)="setTimespan('24h')" class="toggler-option"
[ngClass]="{'inactive': timespan === '24h'}"><small>24h</small></a> [ngClass]="{'inactive': timespan === '24h'}"><small>24h</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span> <span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('1w')" class="toggler-option"
[ngClass]="{'inactive': timespan === '1w'}"><small>1w</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('1m')" class="toggler-option" <a href="" (click)="setTimespan('1m')" class="toggler-option"
[ngClass]="{'inactive': timespan === '1m'}"><small>1m</small></a> [ngClass]="{'inactive': timespan === '1m'}"><small>1m</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span> <span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('1y')" class="toggler-option"
[ngClass]="{'inactive': timespan === '1y'}"><small>1y</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('all')" class="toggler-option" <a href="" (click)="setTimespan('all')" class="toggler-option"
[ngClass]="{'inactive': timespan === 'all'}"><small>all</small></a> [ngClass]="{'inactive': timespan === 'all'}"><small>all</small></a>
</div> </div>
@@ -79,15 +79,13 @@
<div class="col" style="margin-bottom: 1.47rem"> <div class="col" style="margin-bottom: 1.47rem">
<div class="card graph-card"> <div class="card graph-card">
<div class="card-body pl-2 pr-2"> <div class="card-body pl-2 pr-2">
<h5 class="card-title" i18n="acceleration.historical-trend">Historical Trend</h5> <h5 class="card-title" i18n="acceleration.total-bid-boost">Total Bid Boost</h5>
<div class="mempool-graph"> <div class="mempool-graph">
<app-acceleration-fees-graph <app-acceleration-fees-graph
[height]="graphHeight" [height]="graphHeight"
[attr.data-cy]="'acceleration-fees'" [attr.data-cy]="'acceleration-fees'"
[widget]=true [widget]=true
[period]="timespan" [period]="timespan"
[right]="80"
[left]="50"
></app-acceleration-fees-graph> ></app-acceleration-fees-graph>
</div> </div>
<div class="mt-1"><a [attr.data-cy]="'acceleration-fees-view-more'" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" i18n="dashboard.view-more">View more &raquo;</a></div> <div class="mt-1"><a [attr.data-cy]="'acceleration-fees-view-more'" [routerLink]="['/graphs/acceleration/fees' | relativeUrl]" i18n="dashboard.view-more">View more &raquo;</a></div>

View File

@@ -37,7 +37,7 @@ export class AcceleratorDashboardComponent implements OnInit, OnDestroy {
webGlEnabled = true; webGlEnabled = true;
seen: Set<string> = new Set(); seen: Set<string> = new Set();
firstLoad = true; firstLoad = true;
timespan: '24h' | '1m' | '1y' | 'all' = '1y'; timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
accelerationDeltaSubscription: Subscription; accelerationDeltaSubscription: Subscription;

View File

@@ -8,8 +8,10 @@ import { SinglePoolStats } from '../../../interfaces/node-api.interface';
type MerkleCellType = ' ' | '┬' | '├' | '└' | '│' | '─' | 'leaf'; type MerkleCellType = ' ' | '┬' | '├' | '└' | '│' | '─' | 'leaf';
interface TaggedStratumJob extends StratumJob { interface TaggedStratumJob extends StratumJob {
tag: string; tag: string;
merkleBranchIds: string[];
} }
interface MerkleCell { interface MerkleCell {
@@ -46,6 +48,18 @@ function parseTag(scriptSig: string): string {
return (ascii.match(/\/.*\//)?.[0] || ascii).trim(); return (ascii.match(/\/.*\//)?.[0] || ascii).trim();
} }
function getMerkleBranchIds(merkleBranches: string[], numBranches: number): string[] {
let lastHash = '';
const ids: string[] = [];
for (let i = 0; i < numBranches; i++) {
if (merkleBranches[i]) {
lastHash = merkleBranches[i];
}
ids.push(`${i}-${lastHash}`);
}
return ids;
}
@Component({ @Component({
selector: 'app-stratum-list', selector: 'app-stratum-list',
templateUrl: './stratum-list.component.html', templateUrl: './stratum-list.component.html',
@@ -81,16 +95,15 @@ export class StratumList implements OnInit, OnDestroy {
} }
processJobs(rawJobs: Record<string, StratumJob>): PoolRow[] { processJobs(rawJobs: Record<string, StratumJob>): PoolRow[] {
const numBranches = Math.max(...Object.values(rawJobs).map(job => job.merkleBranches.length));
const jobs: Record<string, TaggedStratumJob> = {}; const jobs: Record<string, TaggedStratumJob> = {};
for (const [id, job] of Object.entries(rawJobs)) { for (const [id, job] of Object.entries(rawJobs)) {
jobs[id] = { ...job, tag: parseTag(job.scriptsig) }; jobs[id] = { ...job, tag: parseTag(job.scriptsig), merkleBranchIds: getMerkleBranchIds(job.merkleBranches, numBranches) };
} }
if (Object.keys(jobs).length === 0) { if (Object.keys(jobs).length === 0) {
return []; return [];
} }
const numBranches = Math.max(...Object.values(jobs).map(job => job.merkleBranches.length));
let trees: MerkleTree[] = Object.keys(jobs).map(job => ({ let trees: MerkleTree[] = Object.keys(jobs).map(job => ({
job, job,
size: 1, size: 1,
@@ -100,12 +113,13 @@ export class StratumList implements OnInit, OnDestroy {
for (let col = numBranches - 1; col >= 0; col--) { for (let col = numBranches - 1; col >= 0; col--) {
const groups: Record<string, MerkleTree[]> = {}; const groups: Record<string, MerkleTree[]> = {};
for (const tree of trees) { for (const tree of trees) {
const hash = jobs[tree.job].merkleBranches[col]; const branchId = jobs[tree.job].merkleBranchIds[col];
if (!groups[hash]) { if (!groups[branchId]) {
groups[hash] = []; groups[branchId] = [];
} }
groups[hash].push(tree); groups[branchId].push(tree);
} }
trees = Object.values(groups).map(group => ({ trees = Object.values(groups).map(group => ({
hash: jobs[group[0].job].merkleBranches[col], hash: jobs[group[0].job].merkleBranches[col],
job: group[0].job, job: group[0].job,

View File

@@ -7,7 +7,7 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft,
faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck,
faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced, faHourglassStart, faHourglassHalf, faHourglassEnd, faWandMagicSparkles, faFaucetDrip, faTimeline, faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced, faHourglassStart, faHourglassHalf, faHourglassEnd, faWandMagicSparkles, faFaucetDrip, faTimeline,
faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot } from '@fortawesome/free-solid-svg-icons'; faCircleXmark, faCalendarCheck, faMoneyBillTrendUp, faRobot, faShareNodes } from '@fortawesome/free-solid-svg-icons';
import { InfiniteScrollModule } from 'ngx-infinite-scroll'; import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { MenuComponent } from '@components/menu/menu.component'; import { MenuComponent } from '@components/menu/menu.component';
import { PreviewTitleComponent } from '@components/master-page-preview/preview-title.component'; import { PreviewTitleComponent } from '@components/master-page-preview/preview-title.component';
@@ -459,5 +459,6 @@ export class SharedModule {
library.addIcons(faCalendarCheck); library.addIcons(faCalendarCheck);
library.addIcons(faMoneyBillTrendUp); library.addIcons(faMoneyBillTrendUp);
library.addIcons(faRobot); library.addIcons(faRobot);
library.addIcons(faShareNodes);
} }
} }

View File

@@ -154,5 +154,9 @@
"WALLETS": { "WALLETS": {
"ENABLED": true, "ENABLED": true,
"WALLETS": ["BITB", "3350"] "WALLETS": ["BITB", "3350"]
},
"STRATUM": {
"ENABLED": true,
"API": "http://127.0.0.1:81/api/v1/stratum/ws"
} }
} }

View File

@@ -4,8 +4,7 @@
"TESTNET4_ENABLED": true, "TESTNET4_ENABLED": true,
"LIQUID_ENABLED": false, "LIQUID_ENABLED": false,
"LIQUID_TESTNET_ENABLED": false, "LIQUID_TESTNET_ENABLED": false,
"BISQ_ENABLED": true, "STRATUM_ENABLED": true,
"BISQ_SEPARATE_BACKEND": true,
"SIGNET_ENABLED": true, "SIGNET_ENABLED": true,
"MEMPOOL_WEBSITE_URL": "https://mempool.space", "MEMPOOL_WEBSITE_URL": "https://mempool.space",
"LIQUID_WEBSITE_URL": "https://liquid.network", "LIQUID_WEBSITE_URL": "https://liquid.network",