Merge branch 'master' into mononaut/fix-mobile-bottom-nav

This commit is contained in:
wiz
2023-01-27 03:49:07 +09:00
committed by GitHub
92 changed files with 37829 additions and 16586 deletions

View File

@@ -4,7 +4,7 @@
</app-preview-title>
<div class="row d-flex justify-content-between full-width-row">
<div class="title-wrapper">
<h1 class="title truncated"><span class="first">{{txId.slice(0,-4)}}</span><span class="last-four">{{txId.slice(-4)}}</span></h1>
<h1 class="title truncated"><app-truncate [text]="txId"></app-truncate></h1>
</div>
<div *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" class="features">
<app-tx-features [tx]="tx"></app-tx-features>

View File

@@ -3,21 +3,25 @@
<div class="title-block">
<div *ngIf="rbfTransaction" class="alert alert-mempool" role="alert">
<span i18n="transaction.rbf.replacement|RBF replacement">This transaction has been replaced by:</span>
<a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]">
<span class="d-inline d-lg-none">{{ rbfTransaction.txid | shortenString : 24 }}</span>
<span class="d-none d-lg-inline">{{ rbfTransaction.txid }}</span>
</a>
<app-truncate [text]="rbfTransaction.txid" [lastChars]="12" [link]="['/tx/' | relativeUrl, rbfTransaction.txid]"></app-truncate>
</div>
<ng-container *ngIf="!rbfTransaction || rbfTransaction?.size">
<div *ngIf="rbfReplaces?.length" class="alert alert-mempool" role="alert">
<span i18n="transaction.rbf.replaced|RBF replaced">This transaction replaced:</span>
<div class="tx-list">
<app-truncate [text]="replaced" [lastChars]="12" *ngFor="let replaced of rbfReplaces" [link]="['/tx/' | relativeUrl, replaced]"></app-truncate>
</div>
</div>
<ng-container *ngIf="!rbfTransaction || rbfTransaction?.size || tx">
<h1 i18n="shared.transaction">Transaction</h1>
<span class="tx-link float-left">
<a [routerLink]="['/tx/' | relativeUrl, txId]">
<span class="d-inline d-lg-none">{{ txId | shortenString : 24 }}</span>
<span class="d-none d-lg-inline">{{ txId }}</span>
</a>
<app-clipboard [text]="txId"></app-clipboard>
<span class="tx-link">
<span class="txid">
<app-truncate [text]="txId" [lastChars]="12" [link]="['/tx/' | relativeUrl, txId]">
<app-clipboard [text]="txId"></app-clipboard>
</app-truncate>
</span>
</span>
<div class="container-buttons">
@@ -28,7 +32,10 @@
<ng-template #confirmationPlural let-i i18n="shared.confirmation-count.plural|Transaction plural confirmation count">{{ i }} confirmations</ng-template>
</button>
</ng-template>
<ng-template [ngIf]="tx && !tx?.status.confirmed">
<ng-template [ngIf]="tx && !tx?.status?.confirmed && replaced">
<button type="button" class="btn btn-sm btn-danger" i18n="transaction.unconfirmed|Transaction unconfirmed state">Replaced</button>
</ng-template>
<ng-template [ngIf]="tx && !tx?.status?.confirmed && !replaced">
<button type="button" class="btn btn-sm btn-danger" i18n="transaction.unconfirmed|Transaction unconfirmed state">Unconfirmed</button>
</ng-template>
</div>
@@ -91,7 +98,7 @@
<div class="col-sm">
<table class="table table-borderless table-striped">
<tbody>
<ng-template [ngIf]="transactionTime !== 0">
<ng-template [ngIf]="transactionTime !== 0 && !replaced">
<tr *ngIf="transactionTime === -1; else firstSeenTmpl">
<td><span class="skeleton-loader"></span></td>
<td><span class="skeleton-loader"></span></td>
@@ -103,7 +110,7 @@
</tr>
</ng-template>
</ng-template>
<tr>
<tr *ngIf="!replaced">
<td class="td-width" i18n="transaction.eta|Transaction ETA">ETA</td>
<td>
<ng-template [ngIf]="txInBlockIndex === undefined" [ngIfElse]="estimationTmpl">
@@ -144,12 +151,12 @@
<br>
<h2 class="text-left">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true" size="xs"></fa-icon></h2>
<div class="box">
<table class="table table-borderless table-striped">
<div class="box cpfp-details">
<table class="table table-fixed table-borderless table-striped">
<thead>
<tr>
<th i18n="transactions-list.vout.scriptpubkey-type">Type</th>
<th i18n="dashboard.latest-transactions.txid">TXID</th>
<th class="txids" i18n="dashboard.latest-transactions.txid">TXID</th>
<th class="d-none d-lg-table-cell" i18n="transaction.vsize|Transaction Virtual Size">Virtual size</th>
<th i18n="transaction.fee-rate|Transaction fee rate">Fee rate</th>
<th class="d-none d-lg-table-cell"></th>
@@ -159,10 +166,8 @@
<ng-template [ngIf]="cpfpInfo?.descendants?.length">
<tr *ngFor="let cpfpTx of cpfpInfo.descendants">
<td><span class="badge badge-primary" i18n="transaction.descendant|Descendant">Descendant</span></td>
<td><a [routerLink]="['/tx' | relativeUrl, cpfpTx.txid]">
<span class="d-inline d-lg-none">{{ cpfpTx.txid | shortenString : 8 }}</span>
<span class="d-none d-lg-inline">{{ cpfpTx.txid }}</span>
</a>
<td>
<app-truncate [text]="cpfpTx.txid" [link]="['/tx' | relativeUrl, cpfpTx.txid]"></app-truncate>
</td>
<td class="d-none d-lg-table-cell" [innerHTML]="cpfpTx.weight / 4 | vbytes: 2"></td>
<td>{{ cpfpTx.fee / (cpfpTx.weight / 4) | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
@@ -172,11 +177,8 @@
<ng-template [ngIf]="cpfpInfo?.bestDescendant">
<tr>
<td><span class="badge badge-success" i18n="transaction.descendant|Descendant">Descendant</span></td>
<td>
<a [routerLink]="['/tx' | relativeUrl, cpfpInfo.bestDescendant.txid]">
<span class="d-inline d-lg-none">{{ cpfpInfo.bestDescendant.txid | shortenString : 8 }}</span>
<span class="d-none d-lg-inline">{{ cpfpInfo.bestDescendant.txid }}</span>
</a>
<td class="txids">
<app-truncate [text]="cpfpInfo.bestDescendant.txid" [link]="['/tx' | relativeUrl, cpfpInfo.bestDescendant.txid]"></app-truncate>
</td>
<td class="d-none d-lg-table-cell" [innerHTML]="cpfpInfo.bestDescendant.weight / 4 | vbytes: 2"></td>
<td>{{ cpfpInfo.bestDescendant.fee / (cpfpInfo.bestDescendant.weight / 4) | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
@@ -186,10 +188,8 @@
<ng-template [ngIf]="cpfpInfo?.ancestors?.length">
<tr *ngFor="let cpfpTx of cpfpInfo.ancestors">
<td><span class="badge badge-primary" i18n="transaction.ancestor|Transaction Ancestor">Ancestor</span></td>
<td><a [routerLink]="['/tx' | relativeUrl, cpfpTx.txid]">
<span class="d-inline d-lg-none">{{ cpfpTx.txid | shortenString : 8 }}</span>
<span class="d-none d-lg-inline">{{ cpfpTx.txid }}</span>
</a>
<td class="txids">
<app-truncate [text]="cpfpTx.txid" [link]="['/tx' | relativeUrl, cpfpTx.txid]"></app-truncate>
</td>
<td class="d-none d-lg-table-cell" [innerHTML]="cpfpTx.weight / 4 | vbytes: 2"></td>
<td>{{ cpfpTx.fee / (cpfpTx.weight / 4) | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>

View File

@@ -19,22 +19,32 @@
}
}
.tx-link {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: baseline;
width: 0;
max-width: 100%;
margin-right: 0px;
margin-bottom: 0px;
margin-top: 8px;
display: inline-block;
width: 100%;
flex-shrink: 0;
@media (min-width: 651px) {
display: flex;
width: auto;
flex-grow: 1;
margin-bottom: 0px;
margin-right: 1em;
top: 1px;
position: relative;
}
@media (max-width: 650px) {
width: 100%;
order: 3;
}
.txid {
width: 200px;
min-width: 200px;
flex-grow: 1;
}
}
.td-width {
@@ -188,4 +198,16 @@
margin-left: 8px;
}
}
}
.cpfp-details {
.txids {
width: 60%;
}
}
.tx-list {
.alert-link {
display: block;
}
}

View File

@@ -40,15 +40,21 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
transactionTime = -1;
subscription: Subscription;
fetchCpfpSubscription: Subscription;
fetchRbfSubscription: Subscription;
fetchCachedTxSubscription: Subscription;
txReplacedSubscription: Subscription;
blocksSubscription: Subscription;
queryParamsSubscription: Subscription;
urlFragmentSubscription: Subscription;
fragmentParams: URLSearchParams;
rbfTransaction: undefined | Transaction;
replaced: boolean = false;
rbfReplaces: string[];
cpfpInfo: CpfpInfo | null;
showCpfpDetails = false;
fetchCpfp$ = new Subject<string>();
fetchRbfHistory$ = new Subject<string>();
fetchCachedTx$ = new Subject<string>();
now = new Date().getTime();
timeAvg$: Observable<number>;
liquidUnblinding = new LiquidUnblinding();
@@ -122,7 +128,11 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
}),
delay(2000)
)))
)),
catchError(() => {
return of(null);
})
)
),
catchError(() => {
return of(null);
@@ -155,6 +165,49 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.cpfpInfo = cpfpInfo;
});
this.fetchRbfSubscription = this.fetchRbfHistory$
.pipe(
switchMap((txId) =>
this.apiService
.getRbfHistory$(txId)
),
catchError(() => {
return of([]);
})
).subscribe((replaces) => {
this.rbfReplaces = replaces;
});
this.fetchCachedTxSubscription = this.fetchCachedTx$
.pipe(
switchMap((txId) =>
this.apiService
.getRbfCachedTx$(txId)
),
catchError(() => {
return of(null);
})
).subscribe((tx) => {
if (!tx) {
return;
}
this.tx = tx;
if (tx.fee === undefined) {
this.tx.fee = 0;
}
this.tx.feePerVsize = tx.fee / (tx.weight / 4);
this.isLoadingTx = false;
this.error = undefined;
this.waitingForTransaction = false;
this.graphExpanded = false;
this.setupGraph();
if (!this.tx?.status?.confirmed) {
this.fetchRbfHistory$.next(this.tx.txid);
}
});
this.subscription = this.route.paramMap
.pipe(
switchMap((params: ParamMap) => {
@@ -268,6 +321,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
} else {
this.fetchCpfp$.next(this.tx.txid);
}
this.fetchRbfHistory$.next(this.tx.txid);
}
setTimeout(() => { this.applyFragment(); }, 0);
},
@@ -299,6 +353,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.rbfTransaction = rbfTransaction;
this.cacheService.setTxCache([this.rbfTransaction]);
this.replaced = true;
if (rbfTransaction && !this.tx) {
this.fetchCachedTx$.next(this.txId);
}
});
this.queryParamsSubscription = this.route.queryParams.subscribe((params) => {
@@ -364,8 +422,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.waitingForTransaction = false;
this.isLoadingTx = true;
this.rbfTransaction = undefined;
this.replaced = false;
this.transactionTime = -1;
this.cpfpInfo = null;
this.rbfReplaces = [];
this.showCpfpDetails = false;
document.body.scrollTo(0, 0);
this.leaveTransaction();
@@ -431,6 +491,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
ngOnDestroy() {
this.subscription.unsubscribe();
this.fetchCpfpSubscription.unsubscribe();
this.fetchRbfSubscription.unsubscribe();
this.fetchCachedTxSubscription.unsubscribe();
this.txReplacedSubscription.unsubscribe();
this.blocksSubscription.unsubscribe();
this.queryParamsSubscription.unsubscribe();