Merge branch 'master' into nymkappa/feature/preload-prev-block-summary
This commit is contained in:
		
						commit
						5373078a30
					
				@ -26,6 +26,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.loader-wrapper {
 | 
					.loader-wrapper {
 | 
				
			||||||
  position: absolute;
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  background: #181b2d7f;
 | 
				
			||||||
  left: 0;
 | 
					  left: 0;
 | 
				
			||||||
  right: 0;
 | 
					  right: 0;
 | 
				
			||||||
  top: 0;
 | 
					  top: 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -68,6 +68,21 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy {
 | 
				
			|||||||
    this.start();
 | 
					    this.start();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  destroy(): void {
 | 
				
			||||||
 | 
					    if (this.scene) {
 | 
				
			||||||
 | 
					      this.scene.destroy();
 | 
				
			||||||
 | 
					      this.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // initialize the scene without any entry transition
 | 
				
			||||||
 | 
					  setup(transactions: TransactionStripped[]): void {
 | 
				
			||||||
 | 
					    if (this.scene) {
 | 
				
			||||||
 | 
					      this.scene.setup(transactions);
 | 
				
			||||||
 | 
					      this.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enter(transactions: TransactionStripped[], direction: string): void {
 | 
					  enter(transactions: TransactionStripped[], direction: string): void {
 | 
				
			||||||
    if (this.scene) {
 | 
					    if (this.scene) {
 | 
				
			||||||
      this.scene.enter(transactions, direction);
 | 
					      this.scene.enter(transactions, direction);
 | 
				
			||||||
 | 
				
			|||||||
@ -29,10 +29,6 @@ export default class BlockScene {
 | 
				
			|||||||
    this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray });
 | 
					    this.init({ width, height, resolution, blockLimit, orientation, flip, vertexArray });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  destroy(): void {
 | 
					 | 
				
			||||||
    Object.values(this.txs).forEach(tx => tx.destroy());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  resize({ width = this.width, height = this.height }: { width?: number, height?: number}): void {
 | 
					  resize({ width = this.width, height = this.height }: { width?: number, height?: number}): void {
 | 
				
			||||||
    this.width = width;
 | 
					    this.width = width;
 | 
				
			||||||
    this.height = height;
 | 
					    this.height = height;
 | 
				
			||||||
@ -46,6 +42,36 @@ export default class BlockScene {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Destroy the current layout and clean up graphics sprites without any exit animation
 | 
				
			||||||
 | 
					  destroy(): void {
 | 
				
			||||||
 | 
					    Object.values(this.txs).forEach(tx => tx.destroy());
 | 
				
			||||||
 | 
					    this.txs = {};
 | 
				
			||||||
 | 
					    this.layout = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // set up the scene with an initial set of transactions, without any transition animation
 | 
				
			||||||
 | 
					  setup(txs: TransactionStripped[]) {
 | 
				
			||||||
 | 
					    // clean up any old transactions
 | 
				
			||||||
 | 
					    Object.values(this.txs).forEach(tx => {
 | 
				
			||||||
 | 
					      tx.destroy();
 | 
				
			||||||
 | 
					      delete this.txs[tx.txid];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight });
 | 
				
			||||||
 | 
					    txs.forEach(tx => {
 | 
				
			||||||
 | 
					      const txView = new TxView(tx, this.vertexArray);
 | 
				
			||||||
 | 
					      this.txs[tx.txid] = txView;
 | 
				
			||||||
 | 
					      this.place(txView);
 | 
				
			||||||
 | 
					      this.saveGridToScreenPosition(txView);
 | 
				
			||||||
 | 
					      this.applyTxUpdate(txView, {
 | 
				
			||||||
 | 
					        display: {
 | 
				
			||||||
 | 
					          position: txView.screenPosition,
 | 
				
			||||||
 | 
					          color: txView.getColor()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        duration: 0
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Animate new block entering scene
 | 
					  // Animate new block entering scene
 | 
				
			||||||
  enter(txs: TransactionStripped[], direction) {
 | 
					  enter(txs: TransactionStripped[], direction) {
 | 
				
			||||||
    this.replace(txs, direction);
 | 
					    this.replace(txs, direction);
 | 
				
			||||||
 | 
				
			|||||||
@ -2,9 +2,9 @@ import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/co
 | 
				
			|||||||
import { Location } from '@angular/common';
 | 
					import { Location } from '@angular/common';
 | 
				
			||||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
 | 
					import { ActivatedRoute, ParamMap, Router } from '@angular/router';
 | 
				
			||||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
					import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
				
			||||||
import { switchMap, tap, debounceTime, catchError, map, shareReplay, startWith, pairwise } from 'rxjs/operators';
 | 
					import { switchMap, tap, throttleTime, catchError, map, shareReplay, startWith, pairwise } from 'rxjs/operators';
 | 
				
			||||||
import { Transaction, Vout } from '../../interfaces/electrs.interface';
 | 
					import { Transaction, Vout } from '../../interfaces/electrs.interface';
 | 
				
			||||||
import { Observable, of, Subscription } from 'rxjs';
 | 
					import { Observable, of, Subscription, asyncScheduler } from 'rxjs';
 | 
				
			||||||
import { StateService } from '../../services/state.service';
 | 
					import { StateService } from '../../services/state.service';
 | 
				
			||||||
import { SeoService } from 'src/app/services/seo.service';
 | 
					import { SeoService } from 'src/app/services/seo.service';
 | 
				
			||||||
import { WebsocketService } from 'src/app/services/websocket.service';
 | 
					import { WebsocketService } from 'src/app/services/websocket.service';
 | 
				
			||||||
@ -33,7 +33,6 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  strippedTransactions: TransactionStripped[];
 | 
					  strippedTransactions: TransactionStripped[];
 | 
				
			||||||
  overviewTransitionDirection: string;
 | 
					  overviewTransitionDirection: string;
 | 
				
			||||||
  isLoadingOverview = true;
 | 
					  isLoadingOverview = true;
 | 
				
			||||||
  isAwaitingOverview = true;
 | 
					 | 
				
			||||||
  error: any;
 | 
					  error: any;
 | 
				
			||||||
  blockSubsidy: number;
 | 
					  blockSubsidy: number;
 | 
				
			||||||
  fees: number;
 | 
					  fees: number;
 | 
				
			||||||
@ -127,6 +126,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
          return of(history.state.data.block);
 | 
					          return of(history.state.data.block);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          this.isLoadingBlock = true;
 | 
					          this.isLoadingBlock = true;
 | 
				
			||||||
 | 
					          this.isLoadingOverview = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          let blockInCache: BlockExtended;
 | 
					          let blockInCache: BlockExtended;
 | 
				
			||||||
          if (isBlockHeight) {
 | 
					          if (isBlockHeight) {
 | 
				
			||||||
@ -181,12 +181,9 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
        this.transactions = null;
 | 
					        this.transactions = null;
 | 
				
			||||||
        this.transactionsError = null;
 | 
					        this.transactionsError = null;
 | 
				
			||||||
        this.isLoadingOverview = true;
 | 
					        this.isLoadingOverview = true;
 | 
				
			||||||
        this.isAwaitingOverview = true;
 | 
					        this.overviewError = null;
 | 
				
			||||||
        this.overviewError = true;
 | 
					 | 
				
			||||||
        if (this.blockGraph) {
 | 
					 | 
				
			||||||
          this.blockGraph.exit(direction);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
 | 
					      throttleTime(300, asyncScheduler, { leading: true, trailing: true }),
 | 
				
			||||||
      shareReplay(1)
 | 
					      shareReplay(1)
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    this.transactionSubscription = block$.pipe(
 | 
					    this.transactionSubscription = block$.pipe(
 | 
				
			||||||
@ -204,11 +201,6 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      this.transactions = transactions;
 | 
					      this.transactions = transactions;
 | 
				
			||||||
      this.isLoadingTransactions = false;
 | 
					      this.isLoadingTransactions = false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (!this.isAwaitingOverview && this.blockGraph && this.strippedTransactions && this.overviewTransitionDirection) {
 | 
					 | 
				
			||||||
        this.isLoadingOverview = false;
 | 
					 | 
				
			||||||
        this.blockGraph.replace(this.strippedTransactions, this.overviewTransitionDirection, false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    (error) => {
 | 
					    (error) => {
 | 
				
			||||||
      this.error = error;
 | 
					      this.error = error;
 | 
				
			||||||
@ -236,18 +228,19 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
      ),
 | 
					      ),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .subscribe(({transactions, direction}: {transactions: TransactionStripped[], direction: string}) => {
 | 
					    .subscribe(({transactions, direction}: {transactions: TransactionStripped[], direction: string}) => {
 | 
				
			||||||
      this.isAwaitingOverview = false;
 | 
					 | 
				
			||||||
      this.strippedTransactions = transactions;
 | 
					      this.strippedTransactions = transactions;
 | 
				
			||||||
      this.overviewTransitionDirection = direction;
 | 
					      this.isLoadingOverview = false;
 | 
				
			||||||
      if (!this.isLoadingTransactions && this.blockGraph) {
 | 
					      if (this.blockGraph) {
 | 
				
			||||||
        this.isLoadingOverview = false;
 | 
					        this.blockGraph.destroy();
 | 
				
			||||||
        this.blockGraph.replace(this.strippedTransactions, this.overviewTransitionDirection, false);
 | 
					        this.blockGraph.setup(this.strippedTransactions);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    (error) => {
 | 
					    (error) => {
 | 
				
			||||||
      this.error = error;
 | 
					      this.error = error;
 | 
				
			||||||
      this.isLoadingOverview = false;
 | 
					      this.isLoadingOverview = false;
 | 
				
			||||||
      this.isAwaitingOverview = false;
 | 
					      if (this.blockGraph) {
 | 
				
			||||||
 | 
					        this.blockGraph.destroy();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.networkChangedSubscription = this.stateService.networkChanged$
 | 
					    this.networkChangedSubscription = this.stateService.networkChanged$
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
<div [formGroup]="languageForm" class="text-small text-center mt-4">
 | 
					<div [formGroup]="languageForm" class="text-small text-center">
 | 
				
			||||||
    <select formControlName="language" class="custom-select custom-select-sm form-control-secondary form-control mx-auto" style="width: 130px;" (change)="changeLanguage()">
 | 
					    <select formControlName="language" class="custom-select custom-select-sm form-control-secondary form-control mx-auto" style="width: 130px;" (change)="changeLanguage()">
 | 
				
			||||||
        <option *ngFor="let lang of languages" [value]="lang.code">{{ lang.name }}</option>
 | 
					        <option *ngFor="let lang of languages" [value]="lang.code">{{ lang.name }}</option>
 | 
				
			||||||
    </select>
 | 
					    </select>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<div class="container-xl dashboard-container">
 | 
					<div class="container-xl dashboard-container">
 | 
				
			||||||
  <div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
 | 
					  <div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
 | 
				
			||||||
    <ng-template [ngIf]="collapseLevel === 'three'" [ngIfElse]="expanded">
 | 
					    <ng-container *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
 | 
				
			||||||
      <div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
 | 
					      <div class="col card-wrapper">
 | 
				
			||||||
        <div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
 | 
					        <div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
 | 
				
			||||||
        <div class="card">
 | 
					        <div class="card">
 | 
				
			||||||
          <div class="card-body less-padding">
 | 
					          <div class="card-body less-padding">
 | 
				
			||||||
@ -10,172 +10,135 @@
 | 
				
			|||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="col" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
 | 
					      <div class="col">
 | 
				
			||||||
        <app-difficulty></app-difficulty>
 | 
					        <app-difficulty></app-difficulty>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="col">
 | 
					    </ng-container>
 | 
				
			||||||
        <div class="card">
 | 
					    <div class="col">
 | 
				
			||||||
          <div class="card-body">
 | 
					      <div class="card graph-card">
 | 
				
			||||||
 | 
					        <div class="card-body pl-0">
 | 
				
			||||||
 | 
					          <div style="padding-left: 1.25rem;">
 | 
				
			||||||
            <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? lbtcPegs : mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					            <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? lbtcPegs : mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div class="col">
 | 
					 | 
				
			||||||
        <div class="card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? mempoolTable : txPerSecond; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </ng-template>
 | 
					 | 
				
			||||||
    <ng-template #expanded>
 | 
					 | 
				
			||||||
      <ng-container *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
 | 
					 | 
				
			||||||
        <div class="col card-wrapper">
 | 
					 | 
				
			||||||
          <div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
 | 
					 | 
				
			||||||
          <div class="card">
 | 
					 | 
				
			||||||
            <div class="card-body less-padding">
 | 
					 | 
				
			||||||
              <app-fees-box class="d-block"></app-fees-box>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="col">
 | 
					 | 
				
			||||||
          <app-difficulty></app-difficulty>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </ng-container>
 | 
					 | 
				
			||||||
      <div class="col">
 | 
					 | 
				
			||||||
        <div class="card graph-card">
 | 
					 | 
				
			||||||
          <div class="card-body pl-0">
 | 
					 | 
				
			||||||
            <div style="padding-left: 1.25rem;">
 | 
					 | 
				
			||||||
              <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? lbtcPegs : mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					 | 
				
			||||||
              <hr>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <ng-template [ngIf]="(network$ | async) !== 'liquid'" [ngIfElse]="liquidPegs">
 | 
					 | 
				
			||||||
              <ng-container *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
					 | 
				
			||||||
                <div class="mempool-graph">
 | 
					 | 
				
			||||||
                  <app-mempool-graph
 | 
					 | 
				
			||||||
                  [template]="'widget'"
 | 
					 | 
				
			||||||
                  [limitFee]="150"
 | 
					 | 
				
			||||||
                  [limitFilterFee]="1"
 | 
					 | 
				
			||||||
                  [data]="mempoolStats.value?.mempool"
 | 
					 | 
				
			||||||
                  [windowPreferenceOverride]="'2h'"
 | 
					 | 
				
			||||||
                  ></app-mempool-graph>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
              </ng-container>
 | 
					 | 
				
			||||||
            </ng-template>
 | 
					 | 
				
			||||||
            <ng-template #liquidPegs>
 | 
					 | 
				
			||||||
              <app-lbtc-pegs-graph [data]="liquidPegsMonth$ | async"></app-lbtc-pegs-graph>
 | 
					 | 
				
			||||||
            </ng-template>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div class="col">
 | 
					 | 
				
			||||||
        <div class="card graph-card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? mempoolTable : txPerSecond; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
					 | 
				
			||||||
            <hr>
 | 
					            <hr>
 | 
				
			||||||
            <div class="mempool-graph" *ngIf="stateService.network === 'liquid'; else mempoolGraph">
 | 
					 | 
				
			||||||
              <table class="table table-borderless table-striped" *ngIf="(featuredAssets$ | async) as featuredAssets else loadingAssetsTable">
 | 
					 | 
				
			||||||
                <tbody>
 | 
					 | 
				
			||||||
                  <tr *ngFor="let group of featuredAssets">
 | 
					 | 
				
			||||||
                    <td class="asset-icon">
 | 
					 | 
				
			||||||
                      <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">
 | 
					 | 
				
			||||||
                        <img class="assetIcon" [src]="'/api/v1/asset/' + group.asset + '/icon'">
 | 
					 | 
				
			||||||
                      </a>
 | 
					 | 
				
			||||||
                    </td>
 | 
					 | 
				
			||||||
                    <td class="asset-title">
 | 
					 | 
				
			||||||
                      <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">{{ group.name }}</a>
 | 
					 | 
				
			||||||
                    </td>
 | 
					 | 
				
			||||||
                    <td class="circulating-amount"><app-asset-circulation [assetId]="group.asset"></app-asset-circulation></td>
 | 
					 | 
				
			||||||
                  </tr>
 | 
					 | 
				
			||||||
                </tbody>
 | 
					 | 
				
			||||||
              </table>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <ng-template #mempoolGraph>
 | 
					 | 
				
			||||||
              <div class="mempool-graph" *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
					 | 
				
			||||||
                <app-incoming-transactions-graph
 | 
					 | 
				
			||||||
                  [left]="50"
 | 
					 | 
				
			||||||
                  [data]="mempoolStats.value?.weightPerSecond"
 | 
					 | 
				
			||||||
                  [windowPreferenceOverride]="'2h'"
 | 
					 | 
				
			||||||
                  ></app-incoming-transactions-graph>
 | 
					 | 
				
			||||||
              </div>
 | 
					 | 
				
			||||||
            </ng-template>
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					          <ng-template [ngIf]="(network$ | async) !== 'liquid'" [ngIfElse]="liquidPegs">
 | 
				
			||||||
 | 
					            <ng-container *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
				
			||||||
 | 
					              <div class="mempool-graph">
 | 
				
			||||||
 | 
					                <app-mempool-graph
 | 
				
			||||||
 | 
					                [template]="'widget'"
 | 
				
			||||||
 | 
					                [limitFee]="150"
 | 
				
			||||||
 | 
					                [limitFilterFee]="1"
 | 
				
			||||||
 | 
					                [data]="mempoolStats.value?.mempool"
 | 
				
			||||||
 | 
					                [windowPreferenceOverride]="'2h'"
 | 
				
			||||||
 | 
					                ></app-mempool-graph>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					            </ng-container>
 | 
				
			||||||
 | 
					          </ng-template>
 | 
				
			||||||
 | 
					          <ng-template #liquidPegs>
 | 
				
			||||||
 | 
					            <app-lbtc-pegs-graph [data]="liquidPegsMonth$ | async"></app-lbtc-pegs-graph>
 | 
				
			||||||
 | 
					          </ng-template>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <ng-template [ngIf]="collapseLevel === 'one'">
 | 
					    </div>
 | 
				
			||||||
      <div class="col" style="max-height: 410px">
 | 
					    <div class="col">
 | 
				
			||||||
        <div class="card">
 | 
					      <div class="card graph-card">
 | 
				
			||||||
          <div class="card-body">
 | 
					        <div class="card-body">
 | 
				
			||||||
            <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]">
 | 
					          <ng-container *ngTemplateOutlet="stateService.network === 'liquid' ? mempoolTable : txPerSecond; context: { $implicit: mempoolInfoData }"></ng-container>
 | 
				
			||||||
              <h5 class="card-title d-inline" i18n="dashboard.latest-blocks">Latest blocks</h5>
 | 
					          <hr>
 | 
				
			||||||
              <span> </span>
 | 
					          <div class="mempool-graph" *ngIf="stateService.network === 'liquid'; else mempoolGraph">
 | 
				
			||||||
              <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
 | 
					            <table class="table table-borderless table-striped" *ngIf="(featuredAssets$ | async) as featuredAssets else loadingAssetsTable">
 | 
				
			||||||
            </a>
 | 
					 | 
				
			||||||
            <table class="table lastest-blocks-table">
 | 
					 | 
				
			||||||
              <thead>
 | 
					 | 
				
			||||||
                <th class="table-cell-height" i18n="dashboard.latest-blocks.height">Height</th>
 | 
					 | 
				
			||||||
                <th *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" i18n="dashboard.latest-blocks.mined">Mined</th>
 | 
					 | 
				
			||||||
                <th *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4" i18n="mining.pool-name">Pool</th>
 | 
					 | 
				
			||||||
                <th class="table-cell-transaction-count" i18n="dashboard.latest-blocks.transaction-count">TXs</th>
 | 
					 | 
				
			||||||
                <th class="table-cell-size" i18n="dashboard.latest-blocks.size">Size</th>
 | 
					 | 
				
			||||||
              </thead>
 | 
					 | 
				
			||||||
              <tbody>
 | 
					              <tbody>
 | 
				
			||||||
                <tr *ngFor="let block of blocks$ | async; let i = index; trackBy: trackByBlock">
 | 
					                <tr *ngFor="let group of featuredAssets">
 | 
				
			||||||
                  <td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
					                  <td class="asset-icon">
 | 
				
			||||||
                  <td *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" ><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></td>
 | 
					                    <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">
 | 
				
			||||||
                  <td *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4">
 | 
					                      <img class="assetIcon" [src]="'/api/v1/asset/' + group.asset + '/icon'">
 | 
				
			||||||
                    <a class="clear-link" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
 | 
					 | 
				
			||||||
                      <img width="22" height="22" src="{{ block.extras.pool['logo'] }}"
 | 
					 | 
				
			||||||
                        onError="this.src = './resources/mining-pools/default.svg'">
 | 
					 | 
				
			||||||
                      <span class="pool-name">{{ block.extras.pool.name }}</span>
 | 
					 | 
				
			||||||
                    </a>
 | 
					                    </a>
 | 
				
			||||||
                  </td>
 | 
					                  </td>
 | 
				
			||||||
                  <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td>
 | 
					                  <td class="asset-title">
 | 
				
			||||||
                  <td class="table-cell-size">
 | 
					                    <a [routerLink]="['/assets/asset/' | relativeUrl, group.asset]">{{ group.name }}</a>
 | 
				
			||||||
                    <div class="progress">
 | 
					 | 
				
			||||||
                      <div class="progress-bar progress-mempool {{ network$ | async }}" role="progressbar" [ngStyle]="{'width': (block.weight / stateService.env.BLOCK_WEIGHT_UNITS)*100 + '%' }"> </div>
 | 
					 | 
				
			||||||
                      <div class="progress-text" [innerHTML]="block.size | bytes: 2"></div>
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </td>
 | 
					                  </td>
 | 
				
			||||||
 | 
					                  <td class="circulating-amount"><app-asset-circulation [assetId]="group.asset"></app-asset-circulation></td>
 | 
				
			||||||
                </tr>
 | 
					                </tr>
 | 
				
			||||||
              </tbody>
 | 
					              </tbody>
 | 
				
			||||||
            </table>
 | 
					            </table>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					          <ng-template #mempoolGraph>
 | 
				
			||||||
 | 
					            <div class="mempool-graph" *ngIf="{ value: (mempoolStats$ | async) } as mempoolStats">
 | 
				
			||||||
 | 
					              <app-incoming-transactions-graph
 | 
				
			||||||
 | 
					                [left]="50"
 | 
				
			||||||
 | 
					                [data]="mempoolStats.value?.weightPerSecond"
 | 
				
			||||||
 | 
					                [windowPreferenceOverride]="'2h'"
 | 
				
			||||||
 | 
					                ></app-incoming-transactions-graph>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </ng-template>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="col" style="max-height: 410px">
 | 
					 | 
				
			||||||
        <div class="card">
 | 
					 | 
				
			||||||
          <div class="card-body">
 | 
					 | 
				
			||||||
            <h5 class="card-title" i18n="dashboard.latest-transactions">Latest transactions</h5>
 | 
					 | 
				
			||||||
            <table class="table latest-transactions">
 | 
					 | 
				
			||||||
              <thead>
 | 
					 | 
				
			||||||
                <th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
 | 
					 | 
				
			||||||
                <th class="table-cell-satoshis" i18n="dashboard.latest-transactions.amount">Amount</th>
 | 
					 | 
				
			||||||
                <th class="table-cell-fiat" *ngIf="(network$ | async) === ''" i18n="dashboard.latest-transactions.USD">USD</th>
 | 
					 | 
				
			||||||
                <th class="table-cell-fees" i18n="dashboard.latest-transactions.fee">Fee</th>
 | 
					 | 
				
			||||||
              </thead>
 | 
					 | 
				
			||||||
              <tbody>
 | 
					 | 
				
			||||||
                <tr *ngFor="let transaction of transactions$ | async; let i = index;">
 | 
					 | 
				
			||||||
                  <td class="table-cell-txid"><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
 | 
					 | 
				
			||||||
                  <td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
 | 
					 | 
				
			||||||
                  <td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
 | 
					 | 
				
			||||||
                  <td class="table-cell-fees">{{ transaction.fee / transaction.vsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
 | 
					 | 
				
			||||||
                </tr>
 | 
					 | 
				
			||||||
              </tbody>
 | 
					 | 
				
			||||||
            </table>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </ng-template>
 | 
					 | 
				
			||||||
    </ng-template>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <button type="button" class="btn btn-secondary btn-sm d-block mx-auto" (click)="toggleCollapsed()">
 | 
					 | 
				
			||||||
    <div [ngSwitch]="collapseLevel">
 | 
					 | 
				
			||||||
      <fa-icon *ngSwitchCase="'three'" [icon]="['fas', 'angle-down']" [fixedWidth]="true" i18n-title="dashboard.expand" title="Expand"></fa-icon>
 | 
					 | 
				
			||||||
      <fa-icon *ngSwitchDefault [icon]="['fas', 'angle-up']" [fixedWidth]="true" i18n-title="dashboard.collapse" title="Collapse"></fa-icon>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </button>
 | 
					    <div class="col" style="max-height: 410px">
 | 
				
			||||||
 | 
					      <div class="card">
 | 
				
			||||||
 | 
					        <div class="card-body">
 | 
				
			||||||
 | 
					          <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]">
 | 
				
			||||||
 | 
					            <h5 class="card-title d-inline" i18n="dashboard.latest-blocks">Latest blocks</h5>
 | 
				
			||||||
 | 
					            <span> </span>
 | 
				
			||||||
 | 
					            <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
 | 
				
			||||||
 | 
					          </a>
 | 
				
			||||||
 | 
					          <table class="table lastest-blocks-table">
 | 
				
			||||||
 | 
					            <thead>
 | 
				
			||||||
 | 
					              <th class="table-cell-height" i18n="dashboard.latest-blocks.height">Height</th>
 | 
				
			||||||
 | 
					              <th *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" i18n="dashboard.latest-blocks.mined">Mined</th>
 | 
				
			||||||
 | 
					              <th *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4" i18n="mining.pool-name">Pool</th>
 | 
				
			||||||
 | 
					              <th class="table-cell-transaction-count" i18n="dashboard.latest-blocks.transaction-count">TXs</th>
 | 
				
			||||||
 | 
					              <th class="table-cell-size" i18n="dashboard.latest-blocks.size">Size</th>
 | 
				
			||||||
 | 
					            </thead>
 | 
				
			||||||
 | 
					            <tbody>
 | 
				
			||||||
 | 
					              <tr *ngFor="let block of blocks$ | async; let i = index; trackBy: trackByBlock">
 | 
				
			||||||
 | 
					                <td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
				
			||||||
 | 
					                <td *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" ><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></td>
 | 
				
			||||||
 | 
					                <td *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4">
 | 
				
			||||||
 | 
					                  <a class="clear-link" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
 | 
				
			||||||
 | 
					                    <img width="22" height="22" src="{{ block.extras.pool['logo'] }}"
 | 
				
			||||||
 | 
					                      onError="this.src = './resources/mining-pools/default.svg'">
 | 
				
			||||||
 | 
					                    <span class="pool-name">{{ block.extras.pool.name }}</span>
 | 
				
			||||||
 | 
					                  </a>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td>
 | 
				
			||||||
 | 
					                <td class="table-cell-size">
 | 
				
			||||||
 | 
					                  <div class="progress">
 | 
				
			||||||
 | 
					                    <div class="progress-bar progress-mempool {{ network$ | async }}" role="progressbar" [ngStyle]="{'width': (block.weight / stateService.env.BLOCK_WEIGHT_UNITS)*100 + '%' }"> </div>
 | 
				
			||||||
 | 
					                    <div class="progress-text" [innerHTML]="block.size | bytes: 2"></div>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					          </table>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					    <div class="col" style="max-height: 410px">
 | 
				
			||||||
 | 
					      <div class="card">
 | 
				
			||||||
 | 
					        <div class="card-body">
 | 
				
			||||||
 | 
					          <h5 class="card-title" i18n="dashboard.latest-transactions">Latest transactions</h5>
 | 
				
			||||||
 | 
					          <table class="table latest-transactions">
 | 
				
			||||||
 | 
					            <thead>
 | 
				
			||||||
 | 
					              <th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
 | 
				
			||||||
 | 
					              <th class="table-cell-satoshis" i18n="dashboard.latest-transactions.amount">Amount</th>
 | 
				
			||||||
 | 
					              <th class="table-cell-fiat" *ngIf="(network$ | async) === ''" i18n="dashboard.latest-transactions.USD">USD</th>
 | 
				
			||||||
 | 
					              <th class="table-cell-fees" i18n="dashboard.latest-transactions.fee">Fee</th>
 | 
				
			||||||
 | 
					            </thead>
 | 
				
			||||||
 | 
					            <tbody>
 | 
				
			||||||
 | 
					              <tr *ngFor="let transaction of transactions$ | async; let i = index;">
 | 
				
			||||||
 | 
					                <td class="table-cell-txid"><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
 | 
				
			||||||
 | 
					                <td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
 | 
				
			||||||
 | 
					                <td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
 | 
				
			||||||
 | 
					                <td class="table-cell-fees">{{ transaction.fee / transaction.vsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
 | 
				
			||||||
 | 
					              </tr>
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					          </table>
 | 
				
			||||||
 | 
					          <div class=""> </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <app-language-selector></app-language-selector>
 | 
					  <app-language-selector></app-language-selector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,6 @@ interface MempoolStatsData {
 | 
				
			|||||||
  changeDetection: ChangeDetectionStrategy.OnPush
 | 
					  changeDetection: ChangeDetectionStrategy.OnPush
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class DashboardComponent implements OnInit {
 | 
					export class DashboardComponent implements OnInit {
 | 
				
			||||||
  collapseLevel: string;
 | 
					 | 
				
			||||||
  featuredAssets$: Observable<any>;
 | 
					  featuredAssets$: Observable<any>;
 | 
				
			||||||
  network$: Observable<string>;
 | 
					  network$: Observable<string>;
 | 
				
			||||||
  mempoolBlocksData$: Observable<MempoolBlocksData>;
 | 
					  mempoolBlocksData$: Observable<MempoolBlocksData>;
 | 
				
			||||||
@ -63,7 +62,6 @@ export class DashboardComponent implements OnInit {
 | 
				
			|||||||
    this.seoService.resetTitle();
 | 
					    this.seoService.resetTitle();
 | 
				
			||||||
    this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
 | 
					    this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
 | 
				
			||||||
    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
					    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
				
			||||||
    this.collapseLevel = this.storageService.getValue('dashboard-collapsed') || 'one';
 | 
					 | 
				
			||||||
    this.mempoolLoadingStatus$ = this.stateService.loadingIndicators$
 | 
					    this.mempoolLoadingStatus$ = this.stateService.loadingIndicators$
 | 
				
			||||||
      .pipe(
 | 
					      .pipe(
 | 
				
			||||||
        map((indicators) => indicators.mempool !== undefined ? indicators.mempool : 100)
 | 
					        map((indicators) => indicators.mempool !== undefined ? indicators.mempool : 100)
 | 
				
			||||||
@ -230,15 +228,4 @@ export class DashboardComponent implements OnInit {
 | 
				
			|||||||
  trackByBlock(index: number, block: BlockExtended) {
 | 
					  trackByBlock(index: number, block: BlockExtended) {
 | 
				
			||||||
    return block.height;
 | 
					    return block.height;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  toggleCollapsed() {
 | 
					 | 
				
			||||||
    if (this.collapseLevel === 'one') {
 | 
					 | 
				
			||||||
      this.collapseLevel = 'two';
 | 
					 | 
				
			||||||
    } else if (this.collapseLevel === 'two') {
 | 
					 | 
				
			||||||
      this.collapseLevel = 'three';
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      this.collapseLevel = 'one';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    this.storageService.setValue('dashboard-collapsed', this.collapseLevel);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user