Merge pull request #1254 from nymkappa/feature/mining-dashboard
Create mining dashboard page
This commit is contained in:
		
						commit
						49dd475b4e
					
				@ -198,7 +198,7 @@ class Blocks {
 | 
			
		||||
      logger.info(`Indexing blocks from #${currentBlockHeight} to #${lastBlockToIndex}`);
 | 
			
		||||
 | 
			
		||||
      const chunkSize = 10000;
 | 
			
		||||
      let totaIndexed = 0;
 | 
			
		||||
      let totaIndexed = await blocksRepository.$blockCount(null, null);
 | 
			
		||||
      let indexedThisRun = 0;
 | 
			
		||||
      while (currentBlockHeight >= lastBlockToIndex) {
 | 
			
		||||
        const endBlock = Math.max(0, lastBlockToIndex, currentBlockHeight - chunkSize + 1);
 | 
			
		||||
@ -208,11 +208,9 @@ class Blocks {
 | 
			
		||||
        if (missingBlockHeights.length <= 0) {
 | 
			
		||||
          logger.debug(`No missing blocks between #${currentBlockHeight} to #${endBlock}`);
 | 
			
		||||
          currentBlockHeight -= chunkSize;
 | 
			
		||||
          totaIndexed += chunkSize;
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        totaIndexed += chunkSize - missingBlockHeights.length;
 | 
			
		||||
        logger.debug(`Indexing ${missingBlockHeights.length} blocks from #${currentBlockHeight} to #${endBlock}`);
 | 
			
		||||
 | 
			
		||||
        for (const blockHeight of missingBlockHeights) {
 | 
			
		||||
@ -220,7 +218,8 @@ class Blocks {
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          try {
 | 
			
		||||
            if (totaIndexed % 100 === 0 || blockHeight === lastBlockToIndex) {
 | 
			
		||||
            ++indexedThisRun;
 | 
			
		||||
            if (++totaIndexed % 100 === 0 || blockHeight === lastBlockToIndex) {
 | 
			
		||||
              const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt));
 | 
			
		||||
              const blockPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds));
 | 
			
		||||
              const progress = Math.round(totaIndexed / indexingBlockAmount * 100);
 | 
			
		||||
@ -232,8 +231,6 @@ class Blocks {
 | 
			
		||||
            const transactions = await this.$getTransactionsExtended(blockHash, block.height, true, true);
 | 
			
		||||
            const blockExtended = await this.$getBlockExtended(block, transactions);
 | 
			
		||||
            await blocksRepository.$saveBlockInDatabase(blockExtended);
 | 
			
		||||
            ++totaIndexed;
 | 
			
		||||
            ++indexedThisRun;
 | 
			
		||||
          } catch (e) {
 | 
			
		||||
            logger.err(`Something went wrong while indexing blocks.` + e);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
@ -27,6 +27,7 @@ import { AssetGroupComponent } from './components/assets/asset-group/asset-group
 | 
			
		||||
import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component';
 | 
			
		||||
import { AssetsComponent } from './components/assets/assets.component';
 | 
			
		||||
import { PoolComponent } from './components/pool/pool.component';
 | 
			
		||||
import { MiningDashboardComponent } from './components/mining-dashboard/mining-dashboard.component';
 | 
			
		||||
import { DifficultyChartComponent } from './components/difficulty-chart/difficulty-chart.component';
 | 
			
		||||
 | 
			
		||||
let routes: Routes = [
 | 
			
		||||
@ -58,6 +59,10 @@ let routes: Routes = [
 | 
			
		||||
            path: 'mempool-block/:id',
 | 
			
		||||
            component: MempoolBlockComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'mining',
 | 
			
		||||
            component: MiningDashboardComponent,
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
@ -154,6 +159,10 @@ let routes: Routes = [
 | 
			
		||||
                path: 'mempool-block/:id',
 | 
			
		||||
                component: MempoolBlockComponent
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                path: 'mining',
 | 
			
		||||
                component: MiningDashboardComponent,
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
@ -244,6 +253,10 @@ let routes: Routes = [
 | 
			
		||||
                path: 'mempool-block/:id',
 | 
			
		||||
                component: MempoolBlockComponent
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                path: 'mining',
 | 
			
		||||
                component: MiningDashboardComponent,
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
 | 
			
		||||
@ -68,6 +68,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra
 | 
			
		||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component';
 | 
			
		||||
import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component';
 | 
			
		||||
import { MiningDashboardComponent } from './components/mining-dashboard/mining-dashboard.component';
 | 
			
		||||
import { DifficultyChartComponent } from './components/difficulty-chart/difficulty-chart.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
@ -119,6 +120,7 @@ import { DifficultyChartComponent } from './components/difficulty-chart/difficul
 | 
			
		||||
    AssetsNavComponent,
 | 
			
		||||
    AssetsFeaturedComponent,
 | 
			
		||||
    AssetGroupComponent,
 | 
			
		||||
    MiningDashboardComponent,
 | 
			
		||||
    DifficultyChartComponent,
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,13 @@
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="time-difference"><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    <div class="" *ngIf="showMiningInfo === true">
 | 
			
		||||
      <a class="badge badge-primary" [routerLink]="[('/mining/pool/' + block.extras.pool.id) | relativeUrl]">
 | 
			
		||||
        {{ block.extras.pool.name}}</a>
 | 
			
		||||
    </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div [hidden]="!arrowVisible" id="arrow-up" [style.transition]="transition" [ngStyle]="{'left': arrowLeftPx + 'px' }"></div>
 | 
			
		||||
<div [hidden]="!arrowVisible" id="arrow-up" [style.transition]="transition" [ngStyle]="{'left': arrowLeftPx + 'px' }"></div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<ng-template #loadingBlocksTemplate>
 | 
			
		||||
 | 
			
		||||
@ -124,3 +124,9 @@
 | 
			
		||||
  50% {opacity: 1.0;}
 | 
			
		||||
  100% {opacity: 0.7;}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.badge {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 15px;
 | 
			
		||||
  z-index: 101;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
 | 
			
		||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input } from '@angular/core';
 | 
			
		||||
import { Observable, Subscription } from 'rxjs';
 | 
			
		||||
import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
@ -12,6 +12,7 @@ import { BlockExtended } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
  @Input() showMiningInfo: boolean = false;
 | 
			
		||||
  specialBlocks = specialBlocks;
 | 
			
		||||
  network = '';
 | 
			
		||||
  blocks: BlockExtended[] = [];
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
<div class="text-center" class="blockchain-wrapper">
 | 
			
		||||
<div class="text-center" class="blockchain-wrapper animate" #container>
 | 
			
		||||
  <div class="position-container {{ network }}">
 | 
			
		||||
    <span>
 | 
			
		||||
      <app-mempool-blocks></app-mempool-blocks>
 | 
			
		||||
      <app-blockchain-blocks></app-blockchain-blocks>
 | 
			
		||||
      <app-blockchain-blocks [showMiningInfo]="showMiningInfo"></app-blockchain-blocks>
 | 
			
		||||
      <div id="divider"></div>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,6 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.blockchain-wrapper {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  height: 250px;
 | 
			
		||||
 | 
			
		||||
  -webkit-user-select: none; /* Safari */        
 | 
			
		||||
@ -60,4 +59,14 @@
 | 
			
		||||
  width: 300px;
 | 
			
		||||
  left: -150px;
 | 
			
		||||
  top: 0px;
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.animate {
 | 
			
		||||
  transition: all 1s ease-in-out;
 | 
			
		||||
}
 | 
			
		||||
.move-left {
 | 
			
		||||
  transform: translate(-40%, 0);
 | 
			
		||||
	@media (max-width: 767.98px) {
 | 
			
		||||
    transform: translate(-85%, 0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,11 @@ import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class BlockchainComponent implements OnInit {
 | 
			
		||||
  showMiningInfo: boolean = false;
 | 
			
		||||
  network: string;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
    public stateService: StateService,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
<div [class]="widget === false ? 'container-xl' : ''">
 | 
			
		||||
 | 
			
		||||
  <div *ngIf="difficultyObservable$ | async" class="" echarts [initOpts]="chartInitOptions" [options]="chartOptions"></div>
 | 
			
		||||
  <div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
			
		||||
    <div class="spinner-border text-light"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4">
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4" [style]="widget ? 'display:none' : ''">
 | 
			
		||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(difficultyObservable$ | async) as diffChanges">
 | 
			
		||||
      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/difficulty' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 90">
 | 
			
		||||
@ -30,7 +30,7 @@
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <table class="table table-borderless table-sm text-center">
 | 
			
		||||
  <table class="table table-borderless table-sm text-center" *ngIf="!widget">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th i18n="mining.rank">Block</th>
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
.main-title {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  color: #ffffff91;
 | 
			
		||||
  margin-top: -13px;
 | 
			
		||||
  font-size: 10px;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  padding-bottom: 3px;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Component, Inject, LOCALE_ID, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
 | 
			
		||||
import { EChartsOption } from 'echarts';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
 | 
			
		||||
@ -21,6 +21,8 @@ import { FormBuilder, FormGroup } from '@angular/forms';
 | 
			
		||||
  `],
 | 
			
		||||
})
 | 
			
		||||
export class DifficultyChartComponent implements OnInit {
 | 
			
		||||
  @Input() widget: boolean = false;
 | 
			
		||||
 | 
			
		||||
  radioGroupForm: FormGroup;
 | 
			
		||||
 | 
			
		||||
  chartOptions: EChartsOption = {};
 | 
			
		||||
@ -99,7 +101,7 @@ export class DifficultyChartComponent implements OnInit {
 | 
			
		||||
  prepareChartOptions(data) {
 | 
			
		||||
    this.chartOptions = {
 | 
			
		||||
      title: {
 | 
			
		||||
        text: $localize`:@@mining.difficulty:Difficulty`,
 | 
			
		||||
        text: this.widget? '' : $localize`:@@mining.difficulty:Difficulty`,
 | 
			
		||||
        left: 'center',
 | 
			
		||||
        textStyle: {
 | 
			
		||||
          color: '#FFF',
 | 
			
		||||
@ -112,15 +114,13 @@ export class DifficultyChartComponent implements OnInit {
 | 
			
		||||
      axisPointer: {
 | 
			
		||||
        type: 'line',
 | 
			
		||||
      },
 | 
			
		||||
      xAxis: [
 | 
			
		||||
        {
 | 
			
		||||
          type: 'time',
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      xAxis: {
 | 
			
		||||
        type: 'time',
 | 
			
		||||
        splitNumber: this.isMobile() ? 5 : 10,
 | 
			
		||||
      },
 | 
			
		||||
      yAxis: {
 | 
			
		||||
        type: 'value',
 | 
			
		||||
        axisLabel: {
 | 
			
		||||
          fontSize: 11,
 | 
			
		||||
          formatter: (val) => {
 | 
			
		||||
            const diff = val / Math.pow(10, 12); // terra
 | 
			
		||||
            return diff.toString() + 'T';
 | 
			
		||||
@ -148,4 +148,7 @@ export class DifficultyChartComponent implements OnInit {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isMobile() {
 | 
			
		||||
    return (window.innerWidth <= 767.98);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@
 | 
			
		||||
        <a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.dashboard" title="Dashboard"></fa-icon></a>
 | 
			
		||||
      </li>
 | 
			
		||||
      <li class="nav-item" routerLinkActive="active" id="btn-pools" *ngIf="stateService.env.MINING_DASHBOARD">
 | 
			
		||||
        <a class="nav-link" [routerLink]="['/mining/pools' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'hammer']" [fixedWidth]="true" i18n-title="master-page.mining-pools" title="Mining Pools"></fa-icon></a>
 | 
			
		||||
        <a class="nav-link" [routerLink]="['/mining' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'hammer']" [fixedWidth]="true" i18n-title="master-page.mining-dashboard" title="Mining Dashboard"></fa-icon></a>
 | 
			
		||||
      </li>
 | 
			
		||||
      <li class="nav-item" routerLinkActive="active" id="btn-blocks" *ngIf="!stateService.env.MINING_DASHBOARD">
 | 
			
		||||
        <a class="nav-link" [routerLink]="['/blocks' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'cubes']" [fixedWidth]="true" i18n-title="master-page.blocks" title="Blocks"></fa-icon></a>
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
<div class="container-xl dashboard-container">
 | 
			
		||||
  
 | 
			
		||||
  <div class="row row-cols-1 row-cols-md-2">
 | 
			
		||||
 | 
			
		||||
    <!-- pool distribution -->
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="main-title" i18n="mining.pool-share">Mining Pools Share (1w)</div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <app-pool-ranking [widget]=true></app-pool-ranking>
 | 
			
		||||
          <div class="text-center"><a href="" [routerLink]="['/mining/pools' | relativeUrl]" i18n="dashboard.view-more">View more
 | 
			
		||||
              »</a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- difficulty -->
 | 
			
		||||
    <div class="col">
 | 
			
		||||
      <div class="main-title" i18n="mining.difficulty">Difficulty (1y)</div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <app-difficulty-chart [widget]=true></app-difficulty-chart>
 | 
			
		||||
          <div class="text-center"><a href="" [routerLink]="['/mining/difficulty' | relativeUrl]" i18n="dashboard.view-more">View more
 | 
			
		||||
              »</a></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,57 @@
 | 
			
		||||
.dashboard-container {
 | 
			
		||||
  padding-bottom: 60px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-top: 0.5rem;
 | 
			
		||||
  @media (min-width: 992px) {
 | 
			
		||||
    padding-bottom: 0px;
 | 
			
		||||
  }
 | 
			
		||||
  .col {
 | 
			
		||||
    margin-bottom: 1.5rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card {
 | 
			
		||||
  background-color: #1d1f31;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card-wrapper {
 | 
			
		||||
  .card {
 | 
			
		||||
    height: auto !important;
 | 
			
		||||
  }
 | 
			
		||||
  .card-body {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex: inherit;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: space-around;
 | 
			
		||||
    padding: 22px 20px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#blockchain-container {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow-x: scroll;
 | 
			
		||||
  overflow-y: hidden;
 | 
			
		||||
  scrollbar-width: none;
 | 
			
		||||
  -ms-overflow-style: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#blockchain-container::-webkit-scrollbar {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.fade-border {
 | 
			
		||||
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 80%, transparent 100%)
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
.main-title {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  color: #ffffff91;
 | 
			
		||||
  margin-top: -13px;
 | 
			
		||||
  font-size: 10px;
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  padding-bottom: 3px;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,16 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-mining-dashboard',
 | 
			
		||||
  templateUrl: './mining-dashboard.component.html',
 | 
			
		||||
  styleUrls: ['./mining-dashboard.component.scss'],
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class MiningDashboardComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,49 +1,48 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
  <!-- <app-difficulty [showProgress]=false [showHalving]=true></app-difficulty>  -->
 | 
			
		||||
<div [class]="widget === false ? 'container-xl' : ''">
 | 
			
		||||
 | 
			
		||||
  <div class="hashrate-pie" echarts [initOpts]="chartInitOptions" [options]="chartOptions" (chartInit)="onChartInit($event)"></div>
 | 
			
		||||
  <div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
			
		||||
    <div class="spinner-border text-light"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4">
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4" [style]="widget === true ? 'display:none' : ''">
 | 
			
		||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(miningStatsObservable$ | async) as miningStats">
 | 
			
		||||
      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 1">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'24h'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="24h"> 24h
 | 
			
		||||
          <input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 3">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3d'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="3d"> 3D
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 7">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1w'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="1w"> 1W
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 30">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1m'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="1m"> 1M
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 90">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3m'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="3m"> 3M
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 180">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'6m'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="6m"> 6M
 | 
			
		||||
          <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 365">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1y'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="1y"> 1Y
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 730">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'2y'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="2y"> 2Y
 | 
			
		||||
          <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 1095">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3y'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="3y"> 3Y
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'all'" [routerLink]="['/mining/pools' | relativeUrl]" fragment="all"> ALL
 | 
			
		||||
          <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
 | 
			
		||||
        </label>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <table class="table table-borderless text-center pools-table">
 | 
			
		||||
  <table *ngIf="widget === false" class="table table-borderless text-center pools-table">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th class="d-none d-md-block" i18n="mining.rank">Rank</th>
 | 
			
		||||
@ -64,8 +63,8 @@
 | 
			
		||||
        <td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
 | 
			
		||||
      </tr>
 | 
			
		||||
      <tr style="border-top: 1px solid #555">
 | 
			
		||||
        <td class="d-none d-md-block">-</td>
 | 
			
		||||
        <td class="text-right"><img width="25" height="25" src="./resources/mining-pools/default.svg"></td>
 | 
			
		||||
        <td class="d-none d-md-block"></td>
 | 
			
		||||
        <td class="text-right"></td>
 | 
			
		||||
        <td class="" i18n="mining.all-miners"><b>All miners</b></td>
 | 
			
		||||
        <td class="" *ngIf="this.poolsWindowPreference === '24h'"><b>{{ miningStats.lastEstimatedHashrate}} {{ miningStats.miningUnits.hashrateUnit }}</b></td>
 | 
			
		||||
        <td class=""><b>{{ miningStats.blockCount }}</b></td>
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { FormBuilder, FormGroup } from '@angular/forms';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { EChartsOption, PieSeriesOption } from 'echarts';
 | 
			
		||||
@ -25,6 +25,8 @@ import { chartColors } from 'src/app/app.constants';
 | 
			
		||||
  `],
 | 
			
		||||
})
 | 
			
		||||
export class PoolRankingComponent implements OnInit {
 | 
			
		||||
  @Input() widget: boolean = false;
 | 
			
		||||
 | 
			
		||||
  poolsWindowPreference: string;
 | 
			
		||||
  radioGroupForm: FormGroup;
 | 
			
		||||
 | 
			
		||||
@ -46,12 +48,17 @@ export class PoolRankingComponent implements OnInit {
 | 
			
		||||
    private router: Router,
 | 
			
		||||
  ) {
 | 
			
		||||
    this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
 | 
			
		||||
    this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
 | 
			
		||||
    this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
 | 
			
		||||
    this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    if (this.widget) {
 | 
			
		||||
      this.poolsWindowPreference = '1w';
 | 
			
		||||
    } else {
 | 
			
		||||
      this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';    
 | 
			
		||||
    }
 | 
			
		||||
    this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
 | 
			
		||||
    this.radioGroupForm.controls.dateSpan.setValue(this.poolsWindowPreference);
 | 
			
		||||
 | 
			
		||||
    // When...
 | 
			
		||||
    this.miningStatsObservable$ = combineLatest([
 | 
			
		||||
      // ...a new block is mined
 | 
			
		||||
@ -65,7 +72,9 @@ export class PoolRankingComponent implements OnInit {
 | 
			
		||||
        .pipe(
 | 
			
		||||
          startWith(this.poolsWindowPreference), // (trigger when the page loads)
 | 
			
		||||
          tap((value) => {
 | 
			
		||||
            this.storageService.setValue('poolsWindowPreference', value);
 | 
			
		||||
            if (!this.widget) {
 | 
			
		||||
              this.storageService.setValue('poolsWindowPreference', value);
 | 
			
		||||
            }
 | 
			
		||||
            this.poolsWindowPreference = value;
 | 
			
		||||
          })
 | 
			
		||||
        )
 | 
			
		||||
@ -146,8 +155,7 @@ export class PoolRankingComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
    this.chartOptions = {
 | 
			
		||||
      title: {
 | 
			
		||||
        text: $localize`:@@mining.pool-chart-title:${network}:NETWORK: mining pools share`,
 | 
			
		||||
        subtext: $localize`:@@mining.pool-chart-sub-title:Estimated from the # of blocks mined`,
 | 
			
		||||
        text: this.widget ? '' : $localize`:@@mining.pool-chart-title:${network}:NETWORK: mining pools share`,
 | 
			
		||||
        left: 'center',
 | 
			
		||||
        textStyle: {
 | 
			
		||||
          color: '#FFF',
 | 
			
		||||
@ -162,10 +170,11 @@ export class PoolRankingComponent implements OnInit {
 | 
			
		||||
      },
 | 
			
		||||
      series: [
 | 
			
		||||
        {
 | 
			
		||||
          top: this.isMobile() ? '5%' : '20%',
 | 
			
		||||
          top: this.widget ? '0%' : (this.isMobile() ? '5%' : '10%'),
 | 
			
		||||
          bottom: this.widget ? '0%' : (this.isMobile() ? '0%' : '5%'),
 | 
			
		||||
          name: 'Mining pool',
 | 
			
		||||
          type: 'pie',
 | 
			
		||||
          radius: this.isMobile() ? ['10%', '50%'] : ['20%', '80%'],
 | 
			
		||||
          radius: this.widget ? ['20%', '60%'] : (this.isMobile() ? ['10%', '50%'] : ['20%', '70%']),
 | 
			
		||||
          data: this.generatePoolsChartSerieData(miningStats),
 | 
			
		||||
          labelLine: {
 | 
			
		||||
            lineStyle: {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user