Transaction details template refactor
This commit is contained in:
		
							parent
							
								
									eee2385d0d
								
							
						
					
					
						commit
						2df476406d
					
				| @ -40,64 +40,39 @@ | |||||||
|   </div> |   </div> | ||||||
|   <div class="clearfix"></div> |   <div class="clearfix"></div> | ||||||
| 
 | 
 | ||||||
|   <ng-template [ngIf]="!isLoadingTx && !error"> |   @if (!error) { | ||||||
| 
 |  | ||||||
|     <ng-template [ngIf]="tx?.status?.confirmed" [ngIfElse]="unconfirmedTemplate"> |  | ||||||
| 
 |  | ||||||
|     <div class="box"> |     <div class="box"> | ||||||
|       <div class="row"> |       <div class="row"> | ||||||
|  |         @if (isMobile) { | ||||||
|           <div class="col-sm"> |           <div class="col-sm"> | ||||||
|             <table class="table table-borderless table-striped"> |             <table class="table table-borderless table-striped"> | ||||||
|               <tbody> |               <tbody> | ||||||
|                 <tr> |                   <ng-container *ngTemplateOutlet="detailsLeft"></ng-container> | ||||||
|                   <td i18n="block.timestamp">Timestamp</td> |                   <ng-container *ngTemplateOutlet="detailsRight"></ng-container> | ||||||
|                   <td> |               </tbody> | ||||||
|                     ‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }} |             </table> | ||||||
|                     <div class="lg-inline"> |  | ||||||
|                       <i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i> |  | ||||||
|           </div> |           </div> | ||||||
|                   </td> |         } @else { | ||||||
|                 </tr> |           <div class="col-sm"> | ||||||
|                 <ng-template [ngIf]="transactionTime > 0"> |             <table class="table table-borderless table-striped"> | ||||||
|                   <tr> |               <tbody> | ||||||
|                     <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td> |                   <ng-container *ngTemplateOutlet="detailsLeft"></ng-container> | ||||||
|                     <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> |  | ||||||
|               </tbody> |               </tbody> | ||||||
|             </table> |             </table> | ||||||
|           </div> |           </div> | ||||||
|           <div class="col-sm"> |           <div class="col-sm"> | ||||||
|             <ng-container *ngTemplateOutlet="feeTable"></ng-container> |             <table class="table table-borderless table-striped"> | ||||||
|           </div> |               <tbody> | ||||||
|  |                   <ng-container *ngTemplateOutlet="detailsRight"></ng-container> | ||||||
|  |               </tbody> | ||||||
|  |             </table> | ||||||
|  |           </div> | ||||||
|  |         } | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|     </ng-template> |   <ng-template [ngIf]="!isLoadingTx && !error"> | ||||||
| 
 | 
 | ||||||
|     <!-- Accelerator --> |     <!-- Accelerator --> | ||||||
|     <ng-container *ngIf="!tx?.status?.confirmed && showAccelerationSummary"> |     <ng-container *ngIf="!tx?.status?.confirmed && showAccelerationSummary"> | ||||||
| @ -113,69 +88,6 @@ | |||||||
|       </div> |       </div> | ||||||
|     </ng-container> |     </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"> |     <ng-template [ngIf]="showCpfpDetails"> | ||||||
|       <br> |       <br> | ||||||
| 
 | 
 | ||||||
| @ -364,42 +276,7 @@ | |||||||
|   </ng-template> |   </ng-template> | ||||||
| 
 | 
 | ||||||
|   <ng-template [ngIf]="(isLoadingTx && !error) || loadingCachedTx"> |   <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> |     <br> | ||||||
| 
 |  | ||||||
|     <ng-container *ngIf="flowEnabled"> |     <ng-container *ngIf="flowEnabled"> | ||||||
|       <div class="title"> |       <div class="title"> | ||||||
|         <h2 i18n="transaction.flow|Transaction flow">Flow</h2> |         <h2 i18n="transaction.flow|Transaction flow">Flow</h2> | ||||||
| @ -525,65 +402,264 @@ | |||||||
| 
 | 
 | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <ng-template #feeTable> | <ng-template #detailsLeft> | ||||||
|   <table class="table table-borderless table-striped"> |   @if (tx?.status?.confirmed) { | ||||||
|     <tbody> |     <ng-container *ngTemplateOutlet="timestampRow"></ng-container> | ||||||
|       <tr *ngIf="isMobile && (network === 'liquid' || network === 'liquidtestnet' || !featuresEnabled || network === '')"></tr> |     <ng-container *ngTemplateOutlet="confirmedAfterRow"></ng-container> | ||||||
|       <tr> |   } @else { | ||||||
|         <td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td> |     <ng-container *ngTemplateOutlet="firstSeenRow"></ng-container> | ||||||
|         <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> |     <ng-container *ngTemplateOutlet="etaRow"></ng-container> | ||||||
|       </tr> |   } | ||||||
|       <tr> |   <ng-container *ngTemplateOutlet="featuresRow"></ng-container> | ||||||
|         <td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td> |   @if (tx?.status?.confirmed) { | ||||||
|         <td> |     <ng-container *ngTemplateOutlet="auditRow"></ng-container> | ||||||
|           <app-fee-rate [fee]="tx.feePerVsize"></app-fee-rate> |   } | ||||||
|           <ng-template [ngIf]="tx?.status?.confirmed"> |   <ng-container *ngTemplateOutlet="gogglesRow"></ng-container> | ||||||
|               |  | ||||||
|             <app-tx-fee-rating *ngIf="tx.fee && !hasEffectiveFeeRate && !accelerationInfo" [tx]="tx"></app-tx-fee-rating> |  | ||||||
|           </ng-template> |  | ||||||
|         </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> |  | ||||||
|         <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> |  | ||||||
| 
 |  | ||||||
|             <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> |  | ||||||
|           </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> |  | ||||||
|         </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> |  | ||||||
| </ng-template> | </ng-template> | ||||||
| 
 | 
 | ||||||
| <ng-template #goggles> | <ng-template #detailsRight> | ||||||
|   <tr *ngIf="((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length"> |   <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 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 class="td-width align-items-center align-middle" i18n="transaction.eta|Transaction ETA">ETA</td> | ||||||
|  |         <td> | ||||||
|  |           @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> | ||||||
|  |     } | ||||||
|  |   } @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"> |         <td class="td-width"> | ||||||
|           <span class="goggles-icon"><app-svg-images name="goggles" width="100%" height="100%"></app-svg-images></span> |           <span class="goggles-icon"><app-svg-images name="goggles" width="100%" height="100%"></app-svg-images></span> | ||||||
|         </td> |         </td> | ||||||
|         <td class="wrap-cell"> |         <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> |           @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;"> |           <ng-container *ngFor="let filter of filters;"> | ||||||
|             <span class="badge badge-primary filter-tag mr-1">{{ filter.label }}</span> |             <span class="badge badge-primary filter-tag mr-1">{{ filter.label }}</span> | ||||||
|           </ng-container> |           </ng-container> | ||||||
|         </td> |         </td> | ||||||
|       </tr> |       </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"> | ||||||
|  |             @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> | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @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> | ||||||
|  |           @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> | ||||||
|  |     } | ||||||
|  |   } @else { | ||||||
|  |     <ng-container *ngTemplateOutlet="skeletonDetailsRow"></ng-container> | ||||||
|  |   } | ||||||
|  | </ng-template> | ||||||
|  | 
 | ||||||
|  | <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> | </ng-template> | ||||||
| @ -87,6 +87,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|   rbfReplaces: string[]; |   rbfReplaces: string[]; | ||||||
|   rbfInfo: RbfTree; |   rbfInfo: RbfTree; | ||||||
|   cpfpInfo: CpfpInfo | null; |   cpfpInfo: CpfpInfo | null; | ||||||
|  |   hasCpfp: boolean = false; | ||||||
|   accelerationInfo: Acceleration | null = null; |   accelerationInfo: Acceleration | null = null; | ||||||
|   sigops: number | null; |   sigops: number | null; | ||||||
|   adjustedVsize: number | null; |   adjustedVsize: number | null; | ||||||
| @ -491,10 +492,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|                 txFeePerVSize: tx.effectiveFeePerVsize, |                 txFeePerVSize: tx.effectiveFeePerVsize, | ||||||
|                 mempoolPosition: this.mempoolPosition, |                 mempoolPosition: this.mempoolPosition, | ||||||
|               }); |               }); | ||||||
|               this.cpfpInfo = { |               this.setCpfpInfo({ | ||||||
|                 ancestors: tx.ancestors, |                 ancestors: tx.ancestors, | ||||||
|                 bestDescendant: tx.bestDescendant, |                 bestDescendant: tx.bestDescendant, | ||||||
|               }; |               }); | ||||||
|               const hasRelatives = !!(tx.ancestors?.length || tx.bestDescendant); |               const hasRelatives = !!(tx.ancestors?.length || tx.bestDescendant); | ||||||
|               this.hasEffectiveFeeRate = hasRelatives || (tx.effectiveFeePerVsize && (Math.abs(tx.effectiveFeePerVsize - tx.feePerVsize) > 0.01)); |               this.hasEffectiveFeeRate = hasRelatives || (tx.effectiveFeePerVsize && (Math.abs(tx.effectiveFeePerVsize - tx.feePerVsize) > 0.01)); | ||||||
|             } else { |             } else { | ||||||
| @ -646,6 +647,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|   setCpfpInfo(cpfpInfo: CpfpInfo): void { |   setCpfpInfo(cpfpInfo: CpfpInfo): void { | ||||||
|     if (!cpfpInfo || !this.tx) { |     if (!cpfpInfo || !this.tx) { | ||||||
|       this.cpfpInfo = null; |       this.cpfpInfo = null; | ||||||
|  |       this.hasCpfp = false; | ||||||
|       this.hasEffectiveFeeRate = false; |       this.hasEffectiveFeeRate = false; | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @ -675,6 +677,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { | |||||||
|       this.sigops = this.cpfpInfo.sigops; |       this.sigops = this.cpfpInfo.sigops; | ||||||
|       this.adjustedVsize = this.cpfpInfo.adjustedVsize; |       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)); |     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