Merge pull request #1596 from mempool/nymkappa/feature/indexing-progress
Create indexing progress sticky notification
This commit is contained in:
		
						commit
						61a054b40f
					
				| @ -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 totalIndexed = 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; | ||||||
| @ -246,16 +247,17 @@ class Blocks { | |||||||
|             break; |             break; | ||||||
|           } |           } | ||||||
|           ++indexedThisRun; |           ++indexedThisRun; | ||||||
|           ++totaIndexed; |           ++totalIndexed; | ||||||
|           const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); |           const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); | ||||||
|           if (elapsedSeconds > 5 || blockHeight === lastBlockToIndex) { |           if (elapsedSeconds > 5 || blockHeight === lastBlockToIndex) { | ||||||
|             const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); |             const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); | ||||||
|             const blockPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); |             const blockPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); | ||||||
|             const progress = Math.round(totaIndexed / indexingBlockAmount * 100); |             const progress = Math.round(totalIndexed / indexingBlockAmount * 10000) / 100; | ||||||
|             const timeLeft = Math.round((indexingBlockAmount - totaIndexed) / blockPerSeconds); |             const timeLeft = Math.round((indexingBlockAmount - totalIndexed) / blockPerSeconds); | ||||||
|             logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds} blocks/sec | total: ${totaIndexed}/${indexingBlockAmount} (${progress}%) | elapsed: ${runningFor} seconds | left: ~${timeLeft} seconds`); |             logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds.toFixed(2)} blocks/sec | total: ${totalIndexed}/${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, false); | ||||||
|           } |           } | ||||||
|           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; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -12,8 +12,8 @@ class LoadingIndicators { | |||||||
|     this.progressChangedCallback = fn; |     this.progressChangedCallback = fn; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public setProgress(name: string, progressPercent: number) { |   public setProgress(name: string, progressPercent: number, rounded: boolean = true) { | ||||||
|     const newProgress = Math.round(progressPercent); |     const newProgress = rounded === true ? Math.round(progressPercent) : progressPercent; | ||||||
|     if (newProgress >= 100) { |     if (newProgress >= 100) { | ||||||
|       delete this.loadingIndicators[name]; |       delete this.loadingIndicators[name]; | ||||||
|     } else { |     } else { | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import bitcoinClient from './bitcoin/bitcoin-client'; | |||||||
| import logger from '../logger'; | import logger from '../logger'; | ||||||
| import blocks from './blocks'; | import blocks from './blocks'; | ||||||
| import { Common } from './common'; | import { Common } from './common'; | ||||||
|  | import loadingIndicators from './loading-indicators'; | ||||||
| 
 | 
 | ||||||
| class Mining { | class Mining { | ||||||
|   hashrateIndexingStarted = false; |   hashrateIndexingStarted = false; | ||||||
| @ -131,7 +132,7 @@ class Mining { | |||||||
|    * [INDEXING] Generate weekly mining pool hashrate history |    * [INDEXING] Generate weekly mining pool hashrate history | ||||||
|    */ |    */ | ||||||
|   public async $generatePoolHashrateHistory(): Promise<void> { |   public async $generatePoolHashrateHistory(): Promise<void> { | ||||||
|     if (!blocks.blockIndexingCompleted || this.weeklyHashrateIndexingStarted) { |     if (!blocks.blockIndexingCompleted || this.hashrateIndexingStarted || this.weeklyHashrateIndexingStarted) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -167,7 +168,10 @@ class Mining { | |||||||
|       let indexedThisRun = 0; |       let indexedThisRun = 0; | ||||||
|       let totalIndexed = 0; |       let totalIndexed = 0; | ||||||
|       let newlyIndexed = 0; |       let newlyIndexed = 0; | ||||||
|       let startedAt = new Date().getTime(); |       const startedAt = new Date().getTime() / 1000; | ||||||
|  |       let timer = new Date().getTime() / 1000; | ||||||
|  | 
 | ||||||
|  |       loadingIndicators.setProgress('weekly-hashrate-indexing', 0); | ||||||
| 
 | 
 | ||||||
|       while (toTimestamp > genesisTimestamp) { |       while (toTimestamp > genesisTimestamp) { | ||||||
|         const fromTimestamp = toTimestamp - 604800000; |         const fromTimestamp = toTimestamp - 604800000; | ||||||
| @ -214,14 +218,17 @@ class Mining { | |||||||
|         await HashratesRepository.$saveHashrates(hashrates); |         await HashratesRepository.$saveHashrates(hashrates); | ||||||
|         hashrates.length = 0; |         hashrates.length = 0; | ||||||
| 
 | 
 | ||||||
|         const elapsedSeconds = Math.max(1, Math.round((new Date().getTime()) - startedAt)) / 1000; |         const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); | ||||||
|         if (elapsedSeconds > 1) { |         if (elapsedSeconds > 1) { | ||||||
|           const weeksPerSeconds = (indexedThisRun / elapsedSeconds).toFixed(2); |           const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); | ||||||
|  |           const weeksPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); | ||||||
|  |           const progress = Math.round(totalIndexed / totalWeekIndexed * 10000) / 100; | ||||||
|  |           const timeLeft = Math.round((totalWeekIndexed - totalIndexed) / weeksPerSeconds); | ||||||
|           const formattedDate = new Date(fromTimestamp).toUTCString(); |           const formattedDate = new Date(fromTimestamp).toUTCString(); | ||||||
|           const weeksLeft = Math.round(totalWeekIndexed - totalIndexed); |           logger.debug(`Getting weekly pool hashrate for ${formattedDate} | ~${weeksPerSeconds.toFixed(2)} weeks/sec | total: ~${totalIndexed}/${Math.round(totalWeekIndexed)} (${progress}%) | elapsed: ${runningFor} seconds | left: ~${timeLeft} seconds`); | ||||||
|           logger.debug(`Getting weekly pool hashrate for ${formattedDate} | ~${weeksPerSeconds} weeks/sec | ~${weeksLeft} weeks left to index`); |           timer = new Date().getTime() / 1000; | ||||||
|           startedAt = new Date().getTime(); |  | ||||||
|           indexedThisRun = 0; |           indexedThisRun = 0; | ||||||
|  |           loadingIndicators.setProgress('weekly-hashrate-indexing', progress, false); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         toTimestamp -= 604800000; |         toTimestamp -= 604800000; | ||||||
| @ -233,7 +240,9 @@ class Mining { | |||||||
|       if (newlyIndexed > 0) { |       if (newlyIndexed > 0) { | ||||||
|         logger.info(`Indexed ${newlyIndexed} pools weekly hashrate`); |         logger.info(`Indexed ${newlyIndexed} pools weekly hashrate`); | ||||||
|       } |       } | ||||||
|  |       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|  |       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); | ||||||
|       this.weeklyHashrateIndexingStarted = false; |       this.weeklyHashrateIndexingStarted = false; | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
| @ -273,7 +282,10 @@ class Mining { | |||||||
|       let indexedThisRun = 0; |       let indexedThisRun = 0; | ||||||
|       let totalIndexed = 0; |       let totalIndexed = 0; | ||||||
|       let newlyIndexed = 0; |       let newlyIndexed = 0; | ||||||
|       let startedAt = new Date().getTime(); |       const startedAt = new Date().getTime() / 1000; | ||||||
|  |       let timer = new Date().getTime() / 1000; | ||||||
|  | 
 | ||||||
|  |       loadingIndicators.setProgress('daily-hashrate-indexing', 0); | ||||||
| 
 | 
 | ||||||
|       while (toTimestamp > genesisTimestamp) { |       while (toTimestamp > genesisTimestamp) { | ||||||
|         const fromTimestamp = toTimestamp - 86400000; |         const fromTimestamp = toTimestamp - 86400000; | ||||||
| @ -312,15 +324,17 @@ class Mining { | |||||||
|           hashrates.length = 0; |           hashrates.length = 0; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const elapsedSeconds = Math.max(1, Math.round(new Date().getTime() - startedAt)) / 1000; |         const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); | ||||||
|         if (elapsedSeconds > 1) { |         if (elapsedSeconds > 1) { | ||||||
|           const daysPerSeconds = (indexedThisRun / elapsedSeconds).toFixed(2); |           const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); | ||||||
|  |           const daysPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); | ||||||
|  |           const progress = Math.round(totalIndexed / totalDayIndexed * 10000) / 100; | ||||||
|  |           const timeLeft = Math.round((totalDayIndexed - totalIndexed) / daysPerSeconds); | ||||||
|           const formattedDate = new Date(fromTimestamp).toUTCString(); |           const formattedDate = new Date(fromTimestamp).toUTCString(); | ||||||
|           const daysLeft = Math.round(totalDayIndexed - totalIndexed); |           logger.debug(`Getting network daily hashrate for ${formattedDate} | ~${daysPerSeconds.toFixed(2)} days/sec | total: ~${totalIndexed}/${Math.round(totalDayIndexed)} (${progress}%) | elapsed: ${runningFor} seconds | left: ~${timeLeft} seconds`); | ||||||
|           logger.debug(`Getting network daily hashrate for ${formattedDate} | ~${daysPerSeconds} days/sec | ` + |           timer = new Date().getTime() / 1000; | ||||||
|             `~${daysLeft} days left to index`); |  | ||||||
|           startedAt = new Date().getTime(); |  | ||||||
|           indexedThisRun = 0; |           indexedThisRun = 0; | ||||||
|  |           loadingIndicators.setProgress('daily-hashrate-indexing', progress); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         toTimestamp -= 86400000; |         toTimestamp -= 86400000; | ||||||
| @ -346,7 +360,9 @@ class Mining { | |||||||
|       if (newlyIndexed > 0) { |       if (newlyIndexed > 0) { | ||||||
|         logger.info(`Indexed ${newlyIndexed} day of network hashrate`); |         logger.info(`Indexed ${newlyIndexed} day of network hashrate`); | ||||||
|       } |       } | ||||||
|  |       loadingIndicators.setProgress('daily-hashrate-indexing', 100); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|  |       loadingIndicators.setProgress('daily-hashrate-indexing', 100); | ||||||
|       this.hashrateIndexingStarted = false; |       this.hashrateIndexingStarted = false; | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -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 | ||||||
|    */ |    */ | ||||||
|  | |||||||
| @ -76,6 +76,8 @@ 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'; | ||||||
|  | import { IndexingProgressComponent } from './components/indexing-progress/indexing-progress.component'; | ||||||
| 
 | 
 | ||||||
| @NgModule({ | @NgModule({ | ||||||
|   declarations: [ |   declarations: [ | ||||||
| @ -132,6 +134,8 @@ import { BlockFeeRatesGraphComponent } from './components/block-fee-rates-graph/ | |||||||
|     BlockFeesGraphComponent, |     BlockFeesGraphComponent, | ||||||
|     BlockRewardsGraphComponent, |     BlockRewardsGraphComponent, | ||||||
|     BlockFeeRatesGraphComponent, |     BlockFeeRatesGraphComponent, | ||||||
|  |     LoadingIndicatorComponent, | ||||||
|  |     IndexingProgressComponent, | ||||||
|   ], |   ], | ||||||
|   imports: [ |   imports: [ | ||||||
|     BrowserModule.withServerTransition({ appId: 'serverApp' }), |     BrowserModule.withServerTransition({ appId: 'serverApp' }), | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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> | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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> | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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"> | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress *ngIf="!widget"></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress *ngIf="!widget"></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <div [class]="widget === false ? 'full-container' : ''"> | <div [class]="widget === false ? 'full-container' : ''"> | ||||||
| 
 | 
 | ||||||
|   <div *ngIf="widget"> |   <div *ngIf="widget"> | ||||||
|  | |||||||
| @ -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' | ||||||
|       }; |       }; | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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"> | ||||||
|  | |||||||
| @ -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', | ||||||
|       }; |       }; | ||||||
|  | |||||||
| @ -0,0 +1,3 @@ | |||||||
|  | <app-loading-indicator [name]="'block-indexing'" i18n-label label="Indexing blocks"></app-loading-indicator> | ||||||
|  | <app-loading-indicator [name]="'daily-hashrate-indexing'" i18n-label label="Indexing network hashrate"></app-loading-indicator> | ||||||
|  | <app-loading-indicator [name]="'weekly-hashrate-indexing'" i18n-label label="Indexing pools hashrate"></app-loading-indicator> | ||||||
| @ -0,0 +1,14 @@ | |||||||
|  | import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; | ||||||
|  | 
 | ||||||
|  | @Component({ | ||||||
|  |   selector: 'app-indexing-progress', | ||||||
|  |   templateUrl: './indexing-progress.component.html', | ||||||
|  |   changeDetection: ChangeDetectionStrategy.OnPush | ||||||
|  | }) | ||||||
|  | export class IndexingProgressComponent implements OnInit { | ||||||
|  |   constructor( | ||||||
|  |   ) {} | ||||||
|  | 
 | ||||||
|  |   ngOnInit() { | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -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">{{ this.label }} ({{ progress }}%)</span> | ||||||
|  | </div> | ||||||
| @ -0,0 +1,18 @@ | |||||||
|  | .sticky-loading { | ||||||
|  |   position: absolute; | ||||||
|  |   right: 10px; | ||||||
|  |   z-index: 100; | ||||||
|  |   font-size: 14px; | ||||||
|  |   @media (width >= 992px) { | ||||||
|  |     left: 32px; | ||||||
|  |     top: 55px; | ||||||
|  |   } | ||||||
|  |   @media (576px <= width < 992px ) { | ||||||
|  |     left: 18px; | ||||||
|  |     top: 55px; | ||||||
|  |   } | ||||||
|  |   @media (width <= 575px) { | ||||||
|  |     left: 18px; | ||||||
|  |     top: 100px; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | 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; | ||||||
|  |   @Input() label: 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) | ||||||
|  |       ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <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"> | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress *ngIf="!widget"></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <div [class]="widget === false ? 'full-container' : ''"> | <div [class]="widget === false ? 'full-container' : ''"> | ||||||
| 
 | 
 | ||||||
|   <div *ngIf="widget"> |   <div *ngIf="widget"> | ||||||
|  | |||||||
| @ -1,3 +1,5 @@ | |||||||
|  | <app-indexing-progress></app-indexing-progress> | ||||||
|  | 
 | ||||||
| <div class="container-xl"> | <div class="container-xl"> | ||||||
| 
 | 
 | ||||||
|   <!-- Pool overview --> |   <!-- Pool overview --> | ||||||
|  | |||||||
| @ -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', | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user