mirror of
https://github.com/mempool/mempool.git
synced 2025-02-28 16:58:32 +01:00
Fix default data to title tooltip MM/dd HH:mm. Add symbol to tx chart tooltip . Add accumulative total for tooltip information. Add 3th column to tooltip with a progress bar. Add and max span zoom span. Add feeRate limit input to mempool graph component. Add showZoom option to mempool graph component. Remove start animation to match the layout for future SSR. Remove mouse wheel zoom from small template. Fix small template style.
291 lines
15 KiB
HTML
291 lines
15 KiB
HTML
|
|
<div class="container-xl dashboard-container">
|
|
<div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
|
|
<ng-template [ngIf]="collapseLevel === 'three'" [ngIfElse]="expanded">
|
|
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
|
|
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<app-fees-box class="d-block"></app-fees-box>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
|
|
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
|
</div>
|
|
<div class="col">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<ng-container *ngTemplateOutlet="mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<ng-container *ngTemplateOutlet="txPerSecond; context: { $implicit: mempoolInfoData }"></ng-container>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
<ng-template #expanded>
|
|
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
|
|
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<app-fees-box class="d-block"></app-fees-box>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
|
|
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
|
</div>
|
|
<div class="col">
|
|
<div class="card graph-card">
|
|
<div class="card-body pl-0">
|
|
<div style="padding-left: 1.25rem;">
|
|
<ng-container *ngTemplateOutlet="mempoolTable; context: { $implicit: mempoolInfoData }"></ng-container>
|
|
<hr>
|
|
</div>
|
|
<div class="mempool-graph" *ngIf="(mempoolStats$ | async) as mempoolStats; else loadingSpinner">
|
|
<app-mempool-graph
|
|
[template]="'widget'"
|
|
[limitFee]="150"
|
|
[data]="mempoolStats.mempool"
|
|
></app-mempool-graph>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<div class="card graph-card">
|
|
<div class="card-body">
|
|
<ng-container *ngTemplateOutlet="txPerSecond; context: { $implicit: mempoolInfoData }"></ng-container>
|
|
<br>
|
|
<hr>
|
|
<div class="mempool-graph" *ngIf="(mempoolStats$ | async) as mempoolStats; else loadingSpinner">
|
|
<app-incoming-transactions-graph [data]="mempoolStats.weightPerSecond"></app-incoming-transactions-graph>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<ng-template [ngIf]="collapseLevel === 'one'">
|
|
<div class="col">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title" i18n="dashboard.latest-blocks">Latest blocks</h5>
|
|
<table class="table lastest-blocks-table">
|
|
<thead>
|
|
<th class="table-cell-height" i18n="dashboard.latest-blocks.height">Height</th>
|
|
<th class="table-cell-mined" i18n="dashboard.latest-blocks.mined">Mined</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 class="table-cell-mined" ><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></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 class=""><a href="" [routerLink]="['/blocks' | relativeUrl]" i18n="dashboard.view-all">View all »</a></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col">
|
|
<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'; 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>
|
|
</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>
|
|
</button>
|
|
|
|
<app-language-selector></app-language-selector>
|
|
|
|
<div class="terms-of-service">
|
|
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
|
|
|
|
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<ng-template #loadingTransactions>
|
|
<div class="skeleton-loader skeleton-loader-transactions"></div>
|
|
</ng-template>
|
|
|
|
<ng-template #loading>
|
|
<div class="skeleton-loader"></div>
|
|
</ng-template>
|
|
|
|
<ng-template #loadingbig>
|
|
<span class="skeleton-loader skeleton-loader-big" ></span>
|
|
</ng-template>
|
|
|
|
<ng-template #emptyBlock>
|
|
<div class="col">
|
|
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #mempoolTable let-mempoolInfoData>
|
|
<div class="mempool-info-data">
|
|
<div class="item">
|
|
<h5 *ngIf="!mempoolInfoData.value || mempoolInfoData.value.memPoolInfo.mempoolminfee === 0.00001 || (stateService.env.BASE_MODULE === 'liquid' && mempoolInfoData.value.memPoolInfo.mempoolminfee === 0.000001) else purgingText" class="card-title" i18n="dashboard.minimum-fee|Minimum mempool fee">Minimum fee</h5>
|
|
<ng-template #purgingText><h5 class="card-title" i18n="dashboard.purging|Purgin below fee">Purging</h5></ng-template>
|
|
<p class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loading">
|
|
<ng-template [ngIf]="mempoolInfoData.value.memPoolInfo.mempoolminfee > 0.00001">< </ng-template>{{ mempoolInfoData.value.memPoolInfo.mempoolminfee * 100000 | feeRounding }} <span><ng-container i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container></span>
|
|
</p>
|
|
</div>
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="dashboard.unconfirmed|Unconfirmed count">Unconfirmed</h5>
|
|
<p class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loading">
|
|
{{ mempoolInfoData.value.memPoolInfo.size | number }} <span i18n="dashboard.txs">TXs</span>
|
|
</p>
|
|
</div>
|
|
<div class="item bar">
|
|
<h5 class="card-title" i18n="dashboard.memory-usage|Memory usage">Memory usage</h5>
|
|
<div class="card-text" *ngIf="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value; else loadingbig">
|
|
<div class="progress">
|
|
<div class="progress-bar {{ mempoolInfoData.value.mempoolSizeProgress }}" role="progressbar" [ngStyle]="{'width': (mempoolInfoData.value.memPoolInfo.usage / mempoolInfoData.value.memPoolInfo.maxmempool * 100) + '%' }"> </div>
|
|
<div class="progress-text"><span [innerHTML]="mempoolInfoData.value.memPoolInfo.usage | bytes"></span> / <span [innerHTML]="mempoolInfoData.value.memPoolInfo.maxmempool | bytes"></span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #txPerSecond let-mempoolInfoData>
|
|
<h5 class="card-title" i18n="dashboard.incoming-transactions">Incoming transactions</h5>
|
|
<ng-template [ngIf]="(isLoadingWebSocket$ | async) === false && mempoolInfoData.value" [ngIfElse]="loadingTransactions">
|
|
<span *ngIf="(mempoolLoadingStatus$ | async) !== 100; else inSync">
|
|
<span class="badge badge-pill badge-warning"><ng-container i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</ng-container> ({{ mempoolLoadingStatus$ | async }}%)</span>
|
|
</span>
|
|
<ng-template #inSync>
|
|
<div class="progress inc-tx-progress-bar">
|
|
<div class="progress-bar" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth, 'background-color': mempoolInfoData.value.progressColor}"> </div>
|
|
<div class="progress-text">{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-container i18n="shared.vbytes-per-second|vB/s">vB/s</ng-container></div>
|
|
</div>
|
|
</ng-template>
|
|
</ng-template>
|
|
</ng-template>
|
|
|
|
|
|
<ng-template #difficultyEpoch>
|
|
<div class="main-title" i18n="dashboard.difficulty-adjustment">Difficulty Adjustment</div>
|
|
<div class="card-wrapper">
|
|
<div class="card">
|
|
<div class="card-body more-padding">
|
|
<div class="difficulty-adjustment-container" *ngIf="(isLoadingWebSocket$ | async) === false && (difficultyEpoch$ | async) as epochData; else loadingDifficulty">
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.remaining">Remaining</h5>
|
|
<div class="card-text">
|
|
<ng-container *ngTemplateOutlet="epochData.remainingBlocks === 1 ? blocksSingular : blocksPlural; context: {$implicit: epochData.remainingBlocks }"></ng-container>
|
|
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} <span class="shared-block">blocks</span></ng-template>
|
|
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} <span class="shared-block">block</span></ng-template>
|
|
</div>
|
|
<div class="symbol"><app-time-until [time]="epochData.remainingTime" [fastRender]="true"></app-time-until></div>
|
|
</div>
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.estimate">Estimate</h5>
|
|
<div class="card-text" [ngStyle]="{'color': epochData.colorAdjustments}">
|
|
<span *ngIf="epochData.change > 0; else arrowDownDifficulty" >
|
|
<fa-icon class="retarget-sign" [icon]="['fas', 'caret-up']" [fixedWidth]="true"></fa-icon>
|
|
</span>
|
|
<ng-template #arrowDownDifficulty >
|
|
<fa-icon class="retarget-sign" [icon]="['fas', 'caret-down']" [fixedWidth]="true"></fa-icon>
|
|
</ng-template>
|
|
{{ epochData.change | absolute | number: '1.2-2' }}
|
|
<span class="symbol">%</span>
|
|
</div>
|
|
<div class="symbol">
|
|
<span i18n="difficulty-box.previous">Previous</span>:
|
|
<span [ngStyle]="{'color': epochData.colorPreviousAdjustments}">
|
|
<span *ngIf="epochData.previousRetarget > 0; else arrowDownPreviousDifficulty" >
|
|
<fa-icon class="previous-retarget-sign" [icon]="['fas', 'caret-up']" [fixedWidth]="true"></fa-icon>
|
|
</span>
|
|
<ng-template #arrowDownPreviousDifficulty >
|
|
<fa-icon class="previous-retarget-sign" [icon]="['fas', 'caret-down']" [fixedWidth]="true"></fa-icon>
|
|
</ng-template>
|
|
{{ epochData.previousRetarget | absolute | number: '1.2-2' }} </span> %
|
|
</div>
|
|
</div>
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5>
|
|
<div class="card-text">{{ epochData.progress | number: '1.2-2' }} <span class="symbol">%</span></div>
|
|
<div class="progress small-bar">
|
|
<div class="progress-bar" role="progressbar" style="width: 15%; background-color: #105fb0" [ngStyle]="{'width': epochData.base}"> </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
|
|
<ng-template #loadingSpinner>
|
|
<div class="text-center loadingGraphs">
|
|
<div class="spinner-border text-light"></div>
|
|
</div>
|
|
</ng-template>
|
|
|
|
<ng-template #loadingDifficulty>
|
|
<div class="difficulty-skeleton loading-container">
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.remaining">Remaining</h5>
|
|
<div class="card-text">
|
|
<div class="skeleton-loader"></div>
|
|
<div class="skeleton-loader"></div>
|
|
</div>
|
|
</div>
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.estimate">Estimate</h5>
|
|
<div class="card-text">
|
|
<div class="skeleton-loader"></div>
|
|
<div class="skeleton-loader"></div>
|
|
</div>
|
|
</div>
|
|
<div class="item">
|
|
<h5 class="card-title" i18n="difficulty-box.current-period">Current Period</h5>
|
|
<div class="card-text">
|
|
<div class="skeleton-loader"></div>
|
|
<div class="skeleton-loader"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</ng-template>
|