Merge pull request #4891 from mempool/mononaut/tx-details-stripes
Transaction details template refactor
This commit is contained in:
		
						commit
						e55898b414
					
				| @ -40,64 +40,39 @@ | ||||
|   </div> | ||||
|   <div class="clearfix"></div> | ||||
| 
 | ||||
|   <ng-template [ngIf]="!isLoadingTx && !error"> | ||||
| 
 | ||||
|     <ng-template [ngIf]="tx?.status?.confirmed" [ngIfElse]="unconfirmedTemplate"> | ||||
| 
 | ||||
|       <div class="box"> | ||||
|         <div class="row"> | ||||
|   @if (!error) { | ||||
|     <div class="box"> | ||||
|       <div class="row"> | ||||
|         @if (isMobile) { | ||||
|           <div class="col-sm"> | ||||
|             <table class="table table-borderless table-striped"> | ||||
|               <tbody> | ||||
|                 <tr> | ||||
|                   <td i18n="block.timestamp">Timestamp</td> | ||||
|                   <td> | ||||
|                     ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} | ||||
|                     <div class="lg-inline"> | ||||
|                       <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i> | ||||
|                     </div> | ||||
|                   </td> | ||||
|                 </tr> | ||||
|                 <ng-template [ngIf]="transactionTime > 0"> | ||||
|                   <tr> | ||||
|                     <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> | ||||
|                     <td><app-time kind="span" [time]="tx.status.block_time - transactionTime" [fastRender]="true" [relative]="true"></app-time></td> | ||||
|                   </tr> | ||||
|                 </ng-template> | ||||
|                 <tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet' && featuresEnabled"> | ||||
|                   <td class="td-width" i18n="transaction.features|Transaction features">Features</td> | ||||
|                   <td> | ||||
|                     <app-tx-features [tx]="tx"></app-tx-features> | ||||
|                   </td> | ||||
|                 </tr> | ||||
|                 <tr *ngIf="network === '' && auditStatus"> | ||||
|                   <td class="td-width" i18n="block.toggle-audit|Toggle Audit">Audit</td> | ||||
|                   <td *ngIf="pool" class="wrap-cell"> | ||||
|                     <ng-container> | ||||
|                       <span *ngIf="auditStatus.coinbase; else expected" class="badge badge-primary mr-1" i18n="transactions-list.coinbase">Coinbase</span> | ||||
|                       <ng-template #expected><span *ngIf="auditStatus.expected; else seen" class="badge badge-success mr-1" i18n-ngbTooltip="Expected in block tooltip" ngbTooltip="This transaction was projected to be included in the block" placement="bottom" i18n="tx-features.tag.expected|Expected in Block">Expected in Block</span></ng-template> | ||||
|                       <ng-template #seen><span *ngIf="auditStatus.seen; else notSeen" class="badge badge-success mr-1" i18n-ngbTooltip="Seen in mempool tooltip" ngbTooltip="This transaction was seen in the mempool prior to mining" placement="bottom" i18n="tx-features.tag.seen|Seen in Mempool">Seen in Mempool</span></ng-template> | ||||
|                       <ng-template #notSeen><span *ngIf="!auditStatus.conflict" class="badge badge-warning mr-1" i18n-ngbTooltip="Not seen in mempool tooltip" ngbTooltip="This transaction was missing from our mempool prior to mining" placement="bottom" i18n="tx-features.tag.not-seen|Not seen in Mempool">Not seen in Mempool</span></ng-template> | ||||
|                       <span *ngIf="auditStatus.added" class="badge badge-warning mr-1" i18n-ngbTooltip="Added transaction tooltip" ngbTooltip="This transaction may have been added out-of-band" placement="bottom" i18n="tx-features.tag.added|Added">Added</span> | ||||
|                       <span *ngIf="auditStatus.prioritized" class="badge badge-warning mr-1" i18n-ngbTooltip="Prioritized transaction tooltip" ngbTooltip="This transaction may have been prioritized out-of-band" placement="bottom" i18n="tx-features.tag.prioritized|Prioritized">Prioritized</span> | ||||
|                       <span *ngIf="auditStatus.conflict" class="badge badge-warning mr-1" i18n-ngbTooltip="Conflict in mempool tooltip" ngbTooltip="This transaction conflicted with another version in our mempool" placement="bottom" i18n="tx-features.tag.conflict|Conflict">Conflict</span> | ||||
|                     </ng-container> | ||||
|                   </td> | ||||
|                   <td *ngIf="!pool"> | ||||
|                     <span class="skeleton-loader"></span> | ||||
|                   </td> | ||||
|                 </tr> | ||||
|                 <ng-container *ngTemplateOutlet="goggles"></ng-container> | ||||
|                   <ng-container *ngTemplateOutlet="detailsLeft"></ng-container> | ||||
|                   <ng-container *ngTemplateOutlet="detailsRight"></ng-container> | ||||
|               </tbody> | ||||
|             </table> | ||||
|           </div> | ||||
|         } @else { | ||||
|           <div class="col-sm"> | ||||
|             <table class="table table-borderless table-striped"> | ||||
|               <tbody> | ||||
|                   <ng-container *ngTemplateOutlet="detailsLeft"></ng-container> | ||||
|               </tbody> | ||||
|             </table> | ||||
|           </div> | ||||
|           <div class="col-sm"> | ||||
|             <ng-container *ngTemplateOutlet="feeTable"></ng-container> | ||||
|             <table class="table table-borderless table-striped"> | ||||
|               <tbody> | ||||
|                   <ng-container *ngTemplateOutlet="detailsRight"></ng-container> | ||||
|               </tbody> | ||||
|             </table> | ||||
|           </div> | ||||
|         </div> | ||||
|         } | ||||
|       </div> | ||||
|     </div> | ||||
|   } | ||||
| 
 | ||||
|     </ng-template> | ||||
|   <ng-template [ngIf]="!isLoadingTx && !error"> | ||||
| 
 | ||||
|     <!-- Accelerator --> | ||||
|     <ng-container *ngIf="!tx?.status?.confirmed && showAccelerationSummary"> | ||||
| @ -113,69 +88,6 @@ | ||||
|       </div> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <ng-template #unconfirmedTemplate> | ||||
| 
 | ||||
|       <div class="box"> | ||||
|         <div class="row"> | ||||
|           <div class="col-sm"> | ||||
|             <table class="table table-borderless table-striped"> | ||||
|               <tbody> | ||||
|                 <ng-template [ngIf]="transactionTime !== 0"> | ||||
|                   <tr *ngIf="transactionTime === -1; else firstSeenTmpl"> | ||||
|                     <td><span class="skeleton-loader"></span></td> | ||||
|                     <td><span class="skeleton-loader"></span></td> | ||||
|                   </tr> | ||||
|                   <ng-template #firstSeenTmpl> | ||||
|                     <tr> | ||||
|                       <td i18n="transaction.first-seen|Transaction first seen">First seen</td> | ||||
|                       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i></td> | ||||
|                     </tr> | ||||
|                   </ng-template> | ||||
|                 </ng-template> | ||||
|                 <tr *ngIf="!replaced && !isCached"> | ||||
|                   <td class="td-width align-items-center align-middle" i18n="transaction.eta|Transaction ETA">ETA</td> | ||||
|                   <td> | ||||
|                     <ng-template [ngIf]="this.mempoolPosition?.block == null" [ngIfElse]="estimationTmpl"> | ||||
|                       <span class="skeleton-loader"></span> | ||||
|                     </ng-template> | ||||
|                     <ng-template #estimationTmpl> | ||||
|                       <ng-template [ngIf]="this.mempoolPosition.block >= 7" [ngIfElse]="belowBlockLimit"> | ||||
|                         <span [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''"> | ||||
|                           <span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span> | ||||
|                           <a *ngIf="!tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration" [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a> | ||||
|                         </span> | ||||
|                       </ng-template> | ||||
|                       <ng-template #belowBlockLimit> | ||||
|                         <ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeEstimateDefault"> | ||||
|                           <app-time kind="until" [time]="(60 * 1000 * this.mempoolPosition.block) + now" [fastRender]="false" [fixedRender]="true"></app-time> | ||||
|                         </ng-template> | ||||
|                         <ng-template #timeEstimateDefault> | ||||
|                           <span class="eta justify-content-end" [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'd-flex align-items-center' : ''"> | ||||
|                             <app-time kind="until" *ngIf="(da$ | async) as da;" [time]="da.adjustedTimeAvg * (this.mempoolPosition.block + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true"></app-time> | ||||
|                             <a *ngIf="!tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration" [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a> | ||||
|                           </span> | ||||
|                         </ng-template> | ||||
|                       </ng-template> | ||||
|                     </ng-template> | ||||
|                   </td> | ||||
|                 </tr> | ||||
|                 <tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" id="acceleratePreviewAnchor"> | ||||
|                   <td class="td-width" i18n="transaction.features|Transaction Features">Features</td> | ||||
|                   <td> | ||||
|                     <app-tx-features [tx]="tx"></app-tx-features> | ||||
|                   </td> | ||||
|                 </tr> | ||||
|                 <ng-container *ngTemplateOutlet="goggles"></ng-container> | ||||
|               </tbody> | ||||
|             </table> | ||||
|           </div> | ||||
|           <div class="col-sm"> | ||||
|             <ng-container *ngTemplateOutlet="feeTable"></ng-container> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </ng-template> | ||||
| 
 | ||||
|     <ng-template [ngIf]="showCpfpDetails"> | ||||
|       <br> | ||||
| 
 | ||||
| @ -364,42 +276,7 @@ | ||||
|   </ng-template> | ||||
| 
 | ||||
|   <ng-template [ngIf]="(isLoadingTx && !error) || loadingCachedTx"> | ||||
| 
 | ||||
|     <div class="box"> | ||||
|       <div class="row"> | ||||
|         <div class="col-sm"> | ||||
|           <table class="table table-borderless table-striped"> | ||||
|             <tbody> | ||||
|               <tr> | ||||
|                 <td class="td-width"><span class="skeleton-loader"></span></td> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|               </tr> | ||||
|               <tr> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|               </tr> | ||||
|             </tbody> | ||||
|           </table> | ||||
|         </div> | ||||
|         <div class="col-sm"> | ||||
|           <table class="table table-borderless table-striped"> | ||||
|             <tbody> | ||||
|               <tr> | ||||
|                 <td class="td-width"><span class="skeleton-loader"></span></td> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|               </tr> | ||||
|               <tr> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|                 <td><span class="skeleton-loader"></span></td> | ||||
|               </tr> | ||||
|             </tbody> | ||||
|           </table> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <br> | ||||
| 
 | ||||
|     <ng-container *ngIf="flowEnabled"> | ||||
|       <div class="title"> | ||||
|         <h2 i18n="transaction.flow|Transaction flow">Flow</h2> | ||||
| @ -525,65 +402,264 @@ | ||||
| 
 | ||||
| </div> | ||||
| 
 | ||||
| <ng-template #feeTable> | ||||
|   <table class="table table-borderless table-striped"> | ||||
|     <tbody> | ||||
|       <tr *ngIf="isMobile && (network === 'liquid' || network === 'liquidtestnet' || !featuresEnabled || network === '')"></tr> | ||||
| <ng-template #detailsLeft> | ||||
|   @if (tx?.status?.confirmed) { | ||||
|     <ng-container *ngTemplateOutlet="timestampRow"></ng-container> | ||||
|     <ng-container *ngTemplateOutlet="confirmedAfterRow"></ng-container> | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="firstSeenRow"></ng-container> | ||||
|     <ng-container *ngTemplateOutlet="etaRow"></ng-container> | ||||
|   } | ||||
|   <ng-container *ngTemplateOutlet="featuresRow"></ng-container> | ||||
|   @if (tx?.status?.confirmed) { | ||||
|     <ng-container *ngTemplateOutlet="auditRow"></ng-container> | ||||
|   } | ||||
|   <ng-container *ngTemplateOutlet="gogglesRow"></ng-container> | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #detailsRight> | ||||
|   <ng-container *ngTemplateOutlet="feeRow"></ng-container> | ||||
|   <ng-container *ngTemplateOutlet="feeRateRow"></ng-container> | ||||
|   <ng-container *ngTemplateOutlet="effectiveRateRow"></ng-container> | ||||
|   @if (tx?.status?.confirmed) { | ||||
|     <ng-container *ngTemplateOutlet="minerRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #timestampRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     <tr> | ||||
|       <td i18n="block.timestamp">Timestamp</td> | ||||
|       <td> | ||||
|         ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} | ||||
|         <div class="lg-inline"> | ||||
|           <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i> | ||||
|         </div> | ||||
|       </td> | ||||
|     </tr> | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #confirmedAfterRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     @if (transactionTime > 0) { | ||||
|       <tr> | ||||
|         <td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td> | ||||
|         <td>{{ tx.fee | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> <span class="fiat"><app-fiat [blockConversion]="tx.price" [value]="tx.fee"></app-fiat></span></td> | ||||
|         <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> | ||||
|         <td><app-time kind="span" [time]="tx.status.block_time - transactionTime" [fastRender]="true" [relative]="true"></app-time></td> | ||||
|       </tr> | ||||
|     } | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #firstSeenRow> | ||||
|   @if (!isLoadingTx && transactionTime !== -1) { | ||||
|     <tr> | ||||
|       <td i18n="transaction.first-seen|Transaction first seen">First seen</td> | ||||
|       <td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true"></app-time></i></td> | ||||
|     </tr> | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #featuresRow> | ||||
|   @if (network !== 'liquid' && network !== 'liquidtestnet') { | ||||
|     @if (!isLoadingTx) { | ||||
|       @if (featuresEnabled) { | ||||
|         <tr> | ||||
|           <td class="td-width" i18n="transaction.features|Transaction features">Features</td> | ||||
|           <td> | ||||
|             <app-tx-features [tx]="tx"></app-tx-features> | ||||
|           </td> | ||||
|         </tr> | ||||
|       } | ||||
|     } @else { | ||||
|       <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|     } | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #auditRow> | ||||
|   @if (network === '') { | ||||
|     @if (!isLoadingTx) { | ||||
|       @if (auditStatus) { | ||||
|         <tr> | ||||
|           <td class="td-width" i18n="block.toggle-audit|Toggle Audit">Audit</td> | ||||
|           <td class="wrap-cell"> | ||||
|             <ng-container> | ||||
|               @if (auditStatus.coinbase) { | ||||
|                 <span class="badge badge-primary mr-1" i18n="transactions-list.coinbase">Coinbase</span> | ||||
|               } @else if (auditStatus.expected) { | ||||
|                 <span class="badge badge-success mr-1" i18n-ngbTooltip="Expected in block tooltip" ngbTooltip="This transaction was projected to be included in the block" placement="bottom" i18n="tx-features.tag.expected|Expected in Block">Expected in Block</span> | ||||
|               } @else if (auditStatus.seen) { | ||||
|                 <span class="badge badge-success mr-1" i18n-ngbTooltip="Seen in mempool tooltip" ngbTooltip="This transaction was seen in the mempool prior to mining" placement="bottom" i18n="tx-features.tag.seen|Seen in Mempool">Seen in Mempool</span> | ||||
|               } @else if (!auditStatus.conflict) { | ||||
|                 <span class="badge badge-warning mr-1" i18n-ngbTooltip="Not seen in mempool tooltip" ngbTooltip="This transaction was missing from our mempool prior to mining" placement="bottom" i18n="tx-features.tag.not-seen|Not seen in Mempool">Not seen in Mempool</span> | ||||
|               } | ||||
|               @if (auditStatus.added) { | ||||
|                 <span class="badge badge-warning mr-1" i18n-ngbTooltip="Added transaction tooltip" ngbTooltip="This transaction may have been added out-of-band" placement="bottom" i18n="tx-features.tag.added|Added">Added</span> | ||||
|               } | ||||
|               @if (auditStatus.prioritized) { | ||||
|                 <span class="badge badge-warning mr-1" i18n-ngbTooltip="Prioritized transaction tooltip" ngbTooltip="This transaction may have been prioritized out-of-band" placement="bottom" i18n="tx-features.tag.prioritized|Prioritized">Prioritized</span> | ||||
|               } | ||||
|               @if (auditStatus.conflict) { | ||||
|                 <span class="badge badge-warning mr-1" i18n-ngbTooltip="Conflict in mempool tooltip" ngbTooltip="This transaction conflicted with another version in our mempool" placement="bottom" i18n="tx-features.tag.conflict|Conflict">Conflict</span> | ||||
|               } | ||||
|             </ng-container> | ||||
|           </td> | ||||
|         </tr> | ||||
|       } | ||||
|     } @else { | ||||
|       <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|     } | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #etaRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     @if (!replaced && !isCached) { | ||||
|       <tr> | ||||
|         <td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td> | ||||
|         <td class="td-width align-items-center align-middle" i18n="transaction.eta|Transaction ETA">ETA</td> | ||||
|         <td> | ||||
|           <app-fee-rate [fee]="tx.feePerVsize"></app-fee-rate> | ||||
|           <ng-template [ngIf]="tx?.status?.confirmed"> | ||||
|               | ||||
|             <app-tx-fee-rating *ngIf="tx.fee && !hasEffectiveFeeRate && !accelerationInfo" [tx]="tx"></app-tx-fee-rating> | ||||
|           </ng-template> | ||||
|           @if (this.mempoolPosition?.block == null) { | ||||
|             <span class="skeleton-loader"></span> | ||||
|           } @else if (this.mempoolPosition.block >= 7) { | ||||
|             <span [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''"> | ||||
|               <span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span> | ||||
|               @if (!tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) { | ||||
|                 <a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a> | ||||
|               } | ||||
|             </span> | ||||
|           } @else if (network === 'liquid' || network === 'liquidtestnet') { | ||||
|             <app-time kind="until" [time]="(60 * 1000 * this.mempoolPosition.block) + now" [fastRender]="false" [fixedRender]="true"></app-time> | ||||
|           } @else { | ||||
|             <span class="eta justify-content-end" [class]="(acceleratorAvailable && accelerateCtaType === 'button') ? 'd-flex align-items-center' : ''"> | ||||
|               <app-time kind="until" *ngIf="(da$ | async) as da;" [time]="da.adjustedTimeAvg * (this.mempoolPosition.block + 1) + now + da.timeOffset" [fastRender]="false" [fixedRender]="true"></app-time> | ||||
|               @if (!tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) { | ||||
|                 <a [href]="'/services/accelerator/accelerate?txid=' + tx.txid" class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a> | ||||
|               } | ||||
|             </span> | ||||
|           } | ||||
|         </td> | ||||
|       </tr> | ||||
|       <tr *ngIf="(cpfpInfo && hasEffectiveFeeRate) || accelerationInfo"> | ||||
|         <td *ngIf="tx.acceleration || accelerationInfo" i18n="transaction.accelerated-fee-rate|Accelerated transaction fee rate">Accelerated fee rate</td> | ||||
|         <td *ngIf="!(tx.acceleration || accelerationInfo)" i18n="transaction.effective-fee-rate|Effective transaction fee rate">Effective fee rate</td> | ||||
|     } | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #gogglesRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     @if (((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length) { | ||||
|       <tr> | ||||
|         <td class="td-width"> | ||||
|           <span class="goggles-icon"><app-svg-images name="goggles" width="100%" height="100%"></app-svg-images></span> | ||||
|         </td> | ||||
|         <td class="wrap-cell"> | ||||
|           @if ((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) { | ||||
|             <span class="badge badge-accelerated mr-1" i18n="transaction.audit.accelerated">Accelerated</span> | ||||
|           } | ||||
|           <ng-container *ngFor="let filter of filters;"> | ||||
|             <span class="badge badge-primary filter-tag mr-1">{{ filter.label }}</span> | ||||
|           </ng-container> | ||||
|         </td> | ||||
|       </tr> | ||||
|     } | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #feeRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     <tr> | ||||
|       <td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td> | ||||
|       <td>{{ tx.fee | number }} <span class="symbol" i18n="shared.sat|sat">sat</span> <span class="fiat"><app-fiat [blockConversion]="tx.price" [value]="tx.fee"></app-fiat></span></td> | ||||
|     </tr> | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #feeRateRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     <tr> | ||||
|       <td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td> | ||||
|       <td> | ||||
|         <app-fee-rate [fee]="tx.feePerVsize"></app-fee-rate> | ||||
|         @if (tx?.status?.confirmed && tx.fee && !hasEffectiveFeeRate && !accelerationInfo) { | ||||
|             | ||||
|           <app-tx-fee-rating [tx]="tx"></app-tx-fee-rating> | ||||
|         } | ||||
|       </td> | ||||
|     </tr> | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #effectiveRateRow> | ||||
|   @if (!isLoadingTx) { | ||||
|     @if ((cpfpInfo && hasEffectiveFeeRate) || accelerationInfo) { | ||||
|       <tr> | ||||
|         @if (tx.acceleration || accelerationInfo) { | ||||
|           <td i18n="transaction.accelerated-fee-rate|Accelerated transaction fee rate">Accelerated fee rate</td> | ||||
|         } @else { | ||||
|           <td i18n="transaction.effective-fee-rate|Effective transaction fee rate">Effective fee rate</td> | ||||
|         } | ||||
|         <td> | ||||
|           <div class="effective-fee-container"> | ||||
|             <app-fee-rate *ngIf="accelerationInfo" [fee]="accelerationInfo.acceleratedFee" [weight]="accelerationInfo.effectiveVsize * 4"></app-fee-rate> | ||||
|             <app-fee-rate *ngIf="!accelerationInfo" [fee]="tx.effectiveFeePerVsize"></app-fee-rate> | ||||
|             @if (accelerationInfo) { | ||||
|               <app-fee-rate [fee]="accelerationInfo.acceleratedFee" [weight]="accelerationInfo.effectiveVsize * 4"></app-fee-rate> | ||||
|             } @else { | ||||
|               <app-fee-rate [fee]="tx.effectiveFeePerVsize"></app-fee-rate> | ||||
|             } | ||||
| 
 | ||||
|             <ng-template [ngIf]="tx?.status?.confirmed || tx.acceleration || accelerationInfo"> | ||||
|               <app-tx-fee-rating *ngIf="!(tx.acceleration || accelerationInfo) && (tx.fee || tx.effectiveFeePerVsize)" class="ml-2 mr-2 effective-fee-rating" [tx]="tx"></app-tx-fee-rating> | ||||
|             </ng-template> | ||||
|             @if (tx?.status?.confirmed && !tx.acceleration && !accelerationInfo && tx.fee && tx.effectiveFeePerVsize) { | ||||
|               <app-tx-fee-rating class="ml-2 mr-2 effective-fee-rating" [tx]="tx"></app-tx-fee-rating> | ||||
|             } | ||||
|           </div> | ||||
|           <button *ngIf="cpfpInfo?.bestDescendant || cpfpInfo?.descendants?.length || cpfpInfo?.ancestors?.length" type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button> | ||||
|           @if (hasCpfp) { | ||||
|             <button type="button" class="btn btn-outline-info btn-sm btn-small-height float-right" (click)="showCpfpDetails = !showCpfpDetails">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button> | ||||
|           } | ||||
|         </td> | ||||
|       </tr> | ||||
|       <tr *ngIf="network === '' && tx?.status?.confirmed"> | ||||
|         <td class="td-width" i18n="block.miner">Miner</td> | ||||
|         <td *ngIf="pool" class="wrap-cell"> | ||||
|           <a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, pool.slug]" class="badge mr-1" | ||||
|             [class]="pool.slug === 'unknown' ? 'badge-secondary' : 'badge-primary'"> | ||||
|             {{ pool.name }} | ||||
|           </a> | ||||
|         </td> | ||||
|         <td *ngIf="!pool"> | ||||
|           <span class="skeleton-loader"></span> | ||||
|         </td> | ||||
|       </tr> | ||||
|     </tbody> | ||||
|   </table> | ||||
|     } | ||||
|   } @else { | ||||
|     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #goggles> | ||||
|   <tr *ngIf="((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length"> | ||||
|     <td class="td-width"> | ||||
|       <span class="goggles-icon"><app-svg-images name="goggles" width="100%" height="100%"></app-svg-images></span> | ||||
|     </td> | ||||
|     <td class="wrap-cell"> | ||||
|       <span *ngIf="((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration))" class="badge badge-accelerated mr-1" i18n="transaction.audit.accelerated">Accelerated</span> | ||||
|       <ng-container *ngFor="let filter of filters;"> | ||||
|         <span class="badge badge-primary filter-tag mr-1">{{ filter.label }}</span> | ||||
|       </ng-container> | ||||
|     </td> | ||||
|   </tr> | ||||
| <ng-template #minerRow> | ||||
|   @if (network === '') { | ||||
|     @if (!isLoadingTx) { | ||||
|       <tr> | ||||
|         <td class="td-width" i18n="block.miner">Miner</td> | ||||
|         @if (pool) { | ||||
|           <td class="wrap-cell"> | ||||
|             <a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, pool.slug]" class="badge mr-1" | ||||
|               [class]="pool.slug === 'unknown' ? 'badge-secondary' : 'badge-primary'"> | ||||
|               {{ pool.name }} | ||||
|             </a> | ||||
|           </td> | ||||
|         } @else { | ||||
|           <td> | ||||
|             <span class="skeleton-loader"></span> | ||||
|           </td> | ||||
|         } | ||||
|       </tr> | ||||
|     } @else { | ||||
|       <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||
|     } | ||||
|   } | ||||
| </ng-template> | ||||
| 
 | ||||
| <ng-template #skeletonDetailsRow> | ||||
|   <tr> | ||||
|     <td><span class="skeleton-loader"></span></td> | ||||
|   </tr> | ||||
| </ng-template> | ||||
| @ -87,6 +87,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | ||||
|   rbfReplaces: string[]; | ||||
|   rbfInfo: RbfTree; | ||||
|   cpfpInfo: CpfpInfo | null; | ||||
|   hasCpfp: boolean = false; | ||||
|   accelerationInfo: Acceleration | null = null; | ||||
|   sigops: number | null; | ||||
|   adjustedVsize: number | null; | ||||
| @ -491,10 +492,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | ||||
|                 txFeePerVSize: tx.effectiveFeePerVsize, | ||||
|                 mempoolPosition: this.mempoolPosition, | ||||
|               }); | ||||
|               this.cpfpInfo = { | ||||
|               this.setCpfpInfo({ | ||||
|                 ancestors: tx.ancestors, | ||||
|                 bestDescendant: tx.bestDescendant, | ||||
|               }; | ||||
|               }); | ||||
|               const hasRelatives = !!(tx.ancestors?.length || tx.bestDescendant); | ||||
|               this.hasEffectiveFeeRate = hasRelatives || (tx.effectiveFeePerVsize && (Math.abs(tx.effectiveFeePerVsize - tx.feePerVsize) > 0.01)); | ||||
|             } else { | ||||
| @ -646,6 +647,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | ||||
|   setCpfpInfo(cpfpInfo: CpfpInfo): void { | ||||
|     if (!cpfpInfo || !this.tx) { | ||||
|       this.cpfpInfo = null; | ||||
|       this.hasCpfp = false; | ||||
|       this.hasEffectiveFeeRate = false; | ||||
|       return; | ||||
|     } | ||||
| @ -675,6 +677,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | ||||
|       this.sigops = this.cpfpInfo.sigops; | ||||
|       this.adjustedVsize = this.cpfpInfo.adjustedVsize; | ||||
|     } | ||||
|     this.hasCpfp =!!(this.cpfpInfo && (this.cpfpInfo.bestDescendant || this.cpfpInfo.descendants?.length || this.cpfpInfo.ancestors?.length)); | ||||
|     this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01)); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user