Create indexing sticky notification that show indexing progress in all mining dashboard related pages

This commit is contained in:
nymkappa 2022-05-02 17:28:58 +09:00
parent 11cdbb3118
commit 802e10e0a9
No known key found for this signature in database
GPG key ID: E155910B16E8BD04
19 changed files with 95 additions and 20 deletions

View file

@ -221,9 +221,10 @@ class Blocks {
const lastBlockToIndex = Math.max(0, currentBlockHeight - indexingBlockAmount + 1); const lastBlockToIndex = Math.max(0, currentBlockHeight - indexingBlockAmount + 1);
logger.debug(`Indexing blocks from #${currentBlockHeight} to #${lastBlockToIndex}`); logger.debug(`Indexing blocks from #${currentBlockHeight} to #${lastBlockToIndex}`);
loadingIndicators.setProgress('block-indexing', 0);
const chunkSize = 10000; const chunkSize = 10000;
let totaIndexed = await blocksRepository.$blockCount(null, null); let totaIndexed = await blocksRepository.$blockCountBetweenHeight(currentBlockHeight, lastBlockToIndex);
let indexedThisRun = 0; let indexedThisRun = 0;
let newlyIndexed = 0; let newlyIndexed = 0;
const startedAt = new Date().getTime() / 1000; const startedAt = new Date().getTime() / 1000;
@ -256,6 +257,7 @@ class Blocks {
logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds} blocks/sec | total: ${totaIndexed}/${indexingBlockAmount} (${progress}%) | elapsed: ${runningFor} seconds | left: ~${timeLeft} seconds`); logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds} blocks/sec | total: ${totaIndexed}/${indexingBlockAmount} (${progress}%) | elapsed: ${runningFor} seconds | left: ~${timeLeft} seconds`);
timer = new Date().getTime() / 1000; timer = new Date().getTime() / 1000;
indexedThisRun = 0; indexedThisRun = 0;
loadingIndicators.setProgress('block-indexing', progress);
} }
const blockHash = await bitcoinApi.$getBlockHash(blockHeight); const blockHash = await bitcoinApi.$getBlockHash(blockHeight);
const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash)); const block = BitcoinApi.convertBlock(await bitcoinClient.getBlock(blockHash));
@ -269,9 +271,11 @@ class Blocks {
currentBlockHeight -= chunkSize; currentBlockHeight -= chunkSize;
} }
logger.info(`Indexed ${newlyIndexed} blocks`); logger.info(`Indexed ${newlyIndexed} blocks`);
loadingIndicators.setProgress('block-indexing', 100);
} catch (e) { } catch (e) {
logger.err('Block indexing failed. Trying again later. Reason: ' + (e instanceof Error ? e.message : e)); logger.err('Block indexing failed. Trying again later. Reason: ' + (e instanceof Error ? e.message : e));
this.blockIndexingStarted = false; this.blockIndexingStarted = false;
loadingIndicators.setProgress('block-indexing', 100);
return; return;
} }

View file

@ -188,6 +188,24 @@ class BlocksRepository {
} }
} }
/**
* Get blocks count for a period
*/
public async $blockCountBetweenHeight(startHeight: number, endHeight: number): Promise<number> {
const params: any[] = [];
let query = `SELECT count(height) as blockCount
FROM blocks
WHERE height <= ${startHeight} AND height >= ${endHeight}`;
try {
const [rows] = await DB.query(query, params);
return <number>rows[0].blockCount;
} catch (e) {
logger.err(`Cannot count blocks for this pool (using offset). Reason: ` + (e instanceof Error ? e.message : e));
throw e;
}
}
/** /**
* Get the oldest indexed block * Get the oldest indexed block
*/ */

View file

@ -76,6 +76,7 @@ import { DataCyDirective } from './data-cy.directive';
import { BlockFeesGraphComponent } from './components/block-fees-graph/block-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 { BlockRewardsGraphComponent } from './components/block-rewards-graph/block-rewards-graph.component';
import { BlockFeeRatesGraphComponent } from './components/block-fee-rates-graph/block-fee-rates-graph.component'; import { BlockFeeRatesGraphComponent } from './components/block-fee-rates-graph/block-fee-rates-graph.component';
import { LoadingIndicatorComponent } from './components/loading-indicator/loading-indicator.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -132,6 +133,7 @@ import { BlockFeeRatesGraphComponent } from './components/block-fee-rates-graph/
BlockFeesGraphComponent, BlockFeesGraphComponent,
BlockRewardsGraphComponent, BlockRewardsGraphComponent,
BlockFeeRatesGraphComponent, BlockFeeRatesGraphComponent,
LoadingIndicatorComponent,
], ],
imports: [ imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }), BrowserModule.withServerTransition({ appId: 'serverApp' }),

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="full-container"> <div class="full-container">
<div class="card-header mb-0 mb-md-4"> <div class="card-header mb-0 mb-md-4">
<span i18n="mining.block-fee-rates">Block fee rates</span> <span i18n="mining.block-fee-rates">Block fee rates</span>

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="full-container"> <div class="full-container">
<div class="card-header mb-0 mb-md-4"> <div class="card-header mb-0 mb-md-4">
<span i18n="mining.block-fees">Block fees</span> <span i18n="mining.block-fees">Block fees</span>

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="full-container"> <div class="full-container">
<div class="card-header mb-0 mb-md-4"> <div class="card-header mb-0 mb-md-4">

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="container-xl" [class]="widget ? 'widget' : 'full-height'"> <div class="container-xl" [class]="widget ? 'widget' : 'full-height'">
<h1 *ngIf="!widget" class="float-left" i18n="latest-blocks.blocks">Blocks</h1> <h1 *ngIf="!widget" class="float-left" i18n="latest-blocks.blocks">Blocks</h1>

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div [class]="widget === false ? 'full-container' : ''"> <div [class]="widget === false ? 'full-container' : ''">
<div *ngIf="widget"> <div *ngIf="widget">

View file

@ -136,16 +136,12 @@ export class HashrateChartComponent implements OnInit {
prepareChartOptions(data) { prepareChartOptions(data) {
let title: object; let title: object;
if (data.hashrates.length === 0) { if (data.hashrates.length === 0) {
const lastBlock = new Date(data.timestamp * 1000);
const dd = String(lastBlock.getDate()).padStart(2, '0');
const mm = String(lastBlock.getMonth() + 1).padStart(2, '0'); // January is 0!
const yyyy = lastBlock.getFullYear();
title = { title = {
textStyle: { textStyle: {
color: 'grey', color: 'grey',
fontSize: 15 fontSize: 15
}, },
text: `Indexing in progess - ${yyyy}-${mm}-${dd}`, text: `Indexing in progess`,
left: 'center', left: 'center',
top: 'center' top: 'center'
}; };

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="full-container"> <div class="full-container">
<div class="card-header mb-0 mb-md-4"> <div class="card-header mb-0 mb-md-4">

View file

@ -150,16 +150,12 @@ export class HashrateChartPoolsComponent implements OnInit {
prepareChartOptions(data) { prepareChartOptions(data) {
let title: object; let title: object;
if (data.series.length === 0) { if (data.series.length === 0) {
const lastBlock = new Date(data.timestamp * 1000);
const dd = String(lastBlock.getDate()).padStart(2, '0');
const mm = String(lastBlock.getMonth() + 1).padStart(2, '0'); // January is 0!
const yyyy = lastBlock.getFullYear();
title = { title = {
textStyle: { textStyle: {
color: 'grey', color: 'grey',
fontSize: 15 fontSize: 15
}, },
text: `Indexing in progess - ${yyyy}-${mm}-${dd}`, text: `Indexing in progess`,
left: 'center', left: 'center',
top: 'center', top: 'center',
}; };

View file

@ -0,0 +1,3 @@
<div *ngIf="this.indexingProgress$ | async as progress" class="sticky-loading">
<span *ngIf="progress >= 0" class="mr-auto badge badge-pill badge-warning">Indexing blocks ({{ progress }}%)</span>
</div>

View file

@ -0,0 +1,14 @@
.sticky-loading {
position: fixed;
right: 10px;
z-index: 100;
@media (width > 991px) {
bottom: 15px;
}
@media (576px <= width <= 991px) {
bottom: 60px;
}
@media (width <= 575px) {
top: 17px;
}
}

View file

@ -0,0 +1,29 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { StateService } from 'src/app/services/state.service';
import { WebsocketService } from 'src/app/services/websocket.service';
@Component({
selector: 'app-loading-indicator',
templateUrl: './loading-indicator.component.html',
styleUrls: ['./loading-indicator.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class LoadingIndicatorComponent implements OnInit {
@Input() name: string;
public indexingProgress$: Observable<number>;
constructor(
private stateService: StateService,
private websocketService: WebsocketService
) {}
ngOnInit() {
this.indexingProgress$ = this.stateService.loadingIndicators$
.pipe(
map((indicators) => indicators[this.name] ?? -1)
);
}
}

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="container-xl dashboard-container"> <div class="container-xl dashboard-container">
<div class="row row-cols-1 row-cols-md-2"> <div class="row row-cols-1 row-cols-md-2">

View file

@ -1,8 +1,5 @@
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { map } from 'rxjs/operators';
import { SeoService } from 'src/app/services/seo.service'; import { SeoService } from 'src/app/services/seo.service';
import { StateService } from 'src/app/services/state.service';
import { Observable } from 'rxjs';
import { WebsocketService } from 'src/app/services/websocket.service'; import { WebsocketService } from 'src/app/services/websocket.service';
@Component({ @Component({
@ -12,8 +9,6 @@ import { WebsocketService } from 'src/app/services/websocket.service';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class MiningDashboardComponent implements OnInit { export class MiningDashboardComponent implements OnInit {
private blocks = [];
constructor( constructor(
private seoService: SeoService, private seoService: SeoService,
private websocketService: WebsocketService, private websocketService: WebsocketService,

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div [class]="widget === false ? 'full-container' : ''"> <div [class]="widget === false ? 'full-container' : ''">
<div *ngIf="widget"> <div *ngIf="widget">

View file

@ -1,3 +1,5 @@
<app-loading-indicator [name]="'block-indexing'"></app-loading-indicator>
<div class="container-xl"> <div class="container-xl">
<!-- Pool overview --> <!-- Pool overview -->

View file

@ -111,7 +111,7 @@ export class PoolComponent implements OnInit {
color: 'grey', color: 'grey',
fontSize: 15 fontSize: 15
}, },
text: `No data`, text: `Indexing in progress`,
left: 'center', left: 'center',
top: 'center' top: 'center'
}; };
@ -164,14 +164,14 @@ export class PoolComponent implements OnInit {
`; `;
}.bind(this) }.bind(this)
}, },
xAxis: { xAxis: data.length === 0 ? undefined : {
type: 'time', type: 'time',
splitNumber: (this.isMobile()) ? 5 : 10, splitNumber: (this.isMobile()) ? 5 : 10,
axisLabel: { axisLabel: {
hideOverlap: true, hideOverlap: true,
} }
}, },
yAxis: [ yAxis: data.length === 0 ? undefined : [
{ {
min: (value) => { min: (value) => {
return value.min * 0.9; return value.min * 0.9;
@ -190,7 +190,7 @@ export class PoolComponent implements OnInit {
} }
}, },
], ],
series: [ series: data.length === 0 ? undefined : [
{ {
zlevel: 0, zlevel: 0,
name: 'Hashrate', name: 'Hashrate',