Transaction details template refactor
This commit is contained in:
		
							parent
							
								
									eee2385d0d
								
							
						
					
					
						commit
						2df476406d
					
				@ -40,64 +40,39 @@
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="!isLoadingTx && !error">
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="tx?.status?.confirmed" [ngIfElse]="unconfirmedTemplate">
 | 
			
		||||
 | 
			
		||||
  @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>
 | 
			
		||||
                  <ng-container *ngTemplateOutlet="detailsLeft"></ng-container>
 | 
			
		||||
                  <ng-container *ngTemplateOutlet="detailsRight"></ng-container>
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
          </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>
 | 
			
		||||
        } @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>
 | 
			
		||||
          </div>
 | 
			
		||||
            <table class="table table-borderless table-striped">
 | 
			
		||||
              <tbody>
 | 
			
		||||
                  <ng-container *ngTemplateOutlet="detailsRight"></ng-container>
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
          </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>
 | 
			
		||||
      <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>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</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>
 | 
			
		||||
        </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 #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 #goggles>
 | 
			
		||||
  <tr *ngIf="((auditStatus && auditStatus.accelerated) || accelerationInfo || (tx && tx.acceleration)) || filters.length">
 | 
			
		||||
<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 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">
 | 
			
		||||
          <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>
 | 
			
		||||
          @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">
 | 
			
		||||
            @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>
 | 
			
		||||
@ -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