mirror of
https://github.com/mempool/mempool.git
synced 2025-02-22 06:21:46 +01:00
Add basic transaction link previews
This commit is contained in:
parent
a6b1d4059f
commit
e0ea47b8ee
6 changed files with 447 additions and 0 deletions
|
@ -2,6 +2,7 @@ import { NgModule } from '@angular/core';
|
||||||
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
|
import { Routes, RouterModule, PreloadAllModules } from '@angular/router';
|
||||||
import { StartComponent } from './components/start/start.component';
|
import { StartComponent } from './components/start/start.component';
|
||||||
import { TransactionComponent } from './components/transaction/transaction.component';
|
import { TransactionComponent } from './components/transaction/transaction.component';
|
||||||
|
import { TransactionPreviewComponent } from './components/transaction/transaction-preview.component';
|
||||||
import { BlockComponent } from './components/block/block.component';
|
import { BlockComponent } from './components/block/block.component';
|
||||||
import { BlockAuditComponent } from './components/block-audit/block-audit.component';
|
import { BlockAuditComponent } from './components/block-audit/block-audit.component';
|
||||||
import { BlockPreviewComponent } from './components/block/block-preview.component';
|
import { BlockPreviewComponent } from './components/block/block-preview.component';
|
||||||
|
@ -366,6 +367,21 @@ let routes: Routes = [
|
||||||
children: [],
|
children: [],
|
||||||
component: AddressPreviewComponent
|
component: AddressPreviewComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'tx/:id',
|
||||||
|
children: [],
|
||||||
|
component: TransactionPreviewComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'testnet/tx/:id',
|
||||||
|
children: [],
|
||||||
|
component: TransactionPreviewComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'signet/tx/:id',
|
||||||
|
children: [],
|
||||||
|
component: TransactionPreviewComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'lightning',
|
path: 'lightning',
|
||||||
loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule)
|
loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule)
|
||||||
|
@ -643,6 +659,16 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
||||||
children: [],
|
children: [],
|
||||||
component: AddressPreviewComponent
|
component: AddressPreviewComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'tx/:id',
|
||||||
|
children: [],
|
||||||
|
component: TransactionPreviewComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'testnet/tx/:id',
|
||||||
|
children: [],
|
||||||
|
component: TransactionPreviewComponent
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
<div class="box preview-box" *ngIf="tx && !error">
|
||||||
|
|
||||||
|
<div class="page-title">
|
||||||
|
<h1 i18n="shared.transaction">Transaction</h1>
|
||||||
|
<div *ngIf="network !== 'liquid' && network !== 'liquidtestnet'" class="features">
|
||||||
|
<app-tx-features [tx]="tx"></app-tx-features>
|
||||||
|
<span *ngIf="cpfpInfo && cpfpInfo.bestDescendant" class="badge badge-primary mr-1">
|
||||||
|
CPFP
|
||||||
|
</span>
|
||||||
|
<span *ngIf="cpfpInfo && !cpfpInfo.bestDescendant && cpfpInfo.ancestors.length" class="badge badge-info mr-1">
|
||||||
|
CPFP
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a [routerLink]="['/tx/' | relativeUrl, txId]" class="tx-link">
|
||||||
|
{{ txId }}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm">
|
||||||
|
<table class="table table-borderless table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr *ngIf="tx.status.confirmed; else firstSeen">
|
||||||
|
<td i18n="block.timestamp">Timestamp</td>
|
||||||
|
<td>
|
||||||
|
‎{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<ng-template #firstSeen>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.first-seen|Transaction first seen">First seen</td>
|
||||||
|
<td *ngIf="transactionTime > 0; else notSeen">
|
||||||
|
‎{{ transactionTime * 1000 | date:'yyyy-MM-dd HH:mm' }}
|
||||||
|
</td>
|
||||||
|
<ng-template #notSeen>
|
||||||
|
<td>?</td>
|
||||||
|
</ng-template>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
<tr>
|
||||||
|
<td class="td-width" i18n="dashboard.latest-transactions.amount">Amount</td>
|
||||||
|
<td>
|
||||||
|
<ng-template [ngIf]="(network === 'liquid' || network === 'liquidtestnet') && haveBlindedOutputValues(tx)" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
|
||||||
|
<ng-template #defaultAmount>
|
||||||
|
<app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
|
||||||
|
</ng-template>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="block.size">Size</td>
|
||||||
|
<td [innerHTML]="'‎' + (tx.size | bytes: 2)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="block.weight">Weight</td>
|
||||||
|
<td [innerHTML]="'‎' + (tx.weight | wuBytes: 2)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.inputs">Inputs</td>
|
||||||
|
<td *ngIf="!isCoinbase(tx); else coinbaseInputs">{{ tx.vin.length }}</td>
|
||||||
|
<ng-template #coinbaseInputs>
|
||||||
|
<td i18n="transactions-list.coinbase">Coinbase</td>
|
||||||
|
</ng-template>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm">
|
||||||
|
<table class="table table-borderless table-striped">
|
||||||
|
<tbody>
|
||||||
|
<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></td>
|
||||||
|
</tr>
|
||||||
|
<tr *ngIf="!cpfpInfo || (!cpfpInfo.bestDescendant && !cpfpInfo.ancestors.length); else cpfpFee">
|
||||||
|
<td i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td>
|
||||||
|
<td>
|
||||||
|
{{ tx.feePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
|
<ng-template [ngIf]="tx.status.confirmed">
|
||||||
|
|
||||||
|
<app-tx-fee-rating *ngIf="tx.fee && ((cpfpInfo && !cpfpInfo.bestDescendant && !cpfpInfo.ancestors.length) || !cpfpInfo)" [tx]="tx"></app-tx-fee-rating>
|
||||||
|
</ng-template>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<ng-template #cpfpFee>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.effective-fee-rate|Effective transaction fee rate">Effective fee rate</td>
|
||||||
|
<td>
|
||||||
|
<div class="effective-fee-container">
|
||||||
|
{{ tx.effectiveFeePerVsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
|
<ng-template [ngIf]="tx.status.confirmed">
|
||||||
|
<app-tx-fee-rating class="d-none d-lg-inline ml-2" *ngIf="tx.fee" [tx]="tx"></app-tx-fee-rating>
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</ng-template>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.vsize|Transaction Virtual Size">Virtual size</td>
|
||||||
|
<td [innerHTML]="'‎' + (tx.weight / 4 | vbytes: 2)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.locktime">Locktime</td>
|
||||||
|
<td [innerHTML]="'‎' + (tx.locktime | number)"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="transaction.outputs">Outputs</td>
|
||||||
|
<td>{{ tx.vout.length }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,75 @@
|
||||||
|
.adjust-btn-padding {
|
||||||
|
padding: 0.55rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.td-width {
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .badge {
|
||||||
|
font-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-small-height {
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-green {
|
||||||
|
color: #1a9436;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow-red {
|
||||||
|
color: #dc3545;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.effective-fee-container {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
h2 {
|
||||||
|
line-height: 1;
|
||||||
|
margin: 0;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-outline-info {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 52px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
font-size: 32px;
|
||||||
|
|
||||||
|
::ng-deep .symbol {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tx-link {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 28px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { ElectrsApiService } from '../../services/electrs-api.service';
|
||||||
|
import { ActivatedRoute, ParamMap } from '@angular/router';
|
||||||
|
import {
|
||||||
|
switchMap,
|
||||||
|
filter,
|
||||||
|
catchError,
|
||||||
|
retryWhen,
|
||||||
|
delay,
|
||||||
|
map
|
||||||
|
} from 'rxjs/operators';
|
||||||
|
import { Transaction, Vout } from '../../interfaces/electrs.interface';
|
||||||
|
import { of, merge, Subscription, Observable, Subject, timer, combineLatest, from } from 'rxjs';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { OpenGraphService } from 'src/app/services/opengraph.service';
|
||||||
|
import { ApiService } from 'src/app/services/api.service';
|
||||||
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
|
import { CpfpInfo } from 'src/app/interfaces/node-api.interface';
|
||||||
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-transaction-preview',
|
||||||
|
templateUrl: './transaction-preview.component.html',
|
||||||
|
styleUrls: ['./transaction-preview.component.scss'],
|
||||||
|
})
|
||||||
|
export class TransactionPreviewComponent implements OnInit, OnDestroy {
|
||||||
|
network = '';
|
||||||
|
tx: Transaction;
|
||||||
|
txId: string;
|
||||||
|
isLoadingTx = true;
|
||||||
|
error: any = undefined;
|
||||||
|
errorUnblinded: any = undefined;
|
||||||
|
transactionTime = -1;
|
||||||
|
subscription: Subscription;
|
||||||
|
fetchCpfpSubscription: Subscription;
|
||||||
|
cpfpInfo: CpfpInfo | null;
|
||||||
|
showCpfpDetails = false;
|
||||||
|
fetchCpfp$ = new Subject<string>();
|
||||||
|
liquidUnblinding = new LiquidUnblinding();
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private electrsApiService: ElectrsApiService,
|
||||||
|
private stateService: StateService,
|
||||||
|
private apiService: ApiService,
|
||||||
|
private seoService: SeoService,
|
||||||
|
private openGraphService: OpenGraphService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.stateService.networkChanged$.subscribe(
|
||||||
|
(network) => (this.network = network)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.fetchCpfpSubscription = this.fetchCpfp$
|
||||||
|
.pipe(
|
||||||
|
switchMap((txId) =>
|
||||||
|
this.apiService
|
||||||
|
.getCpfpinfo$(txId)
|
||||||
|
.pipe(retryWhen((errors) => errors.pipe(delay(2000))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.subscribe((cpfpInfo) => {
|
||||||
|
if (!this.tx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lowerFeeParents = cpfpInfo.ancestors.filter(
|
||||||
|
(parent) => parent.fee / (parent.weight / 4) < this.tx.feePerVsize
|
||||||
|
);
|
||||||
|
let totalWeight =
|
||||||
|
this.tx.weight +
|
||||||
|
lowerFeeParents.reduce((prev, val) => prev + val.weight, 0);
|
||||||
|
let totalFees =
|
||||||
|
this.tx.fee +
|
||||||
|
lowerFeeParents.reduce((prev, val) => prev + val.fee, 0);
|
||||||
|
|
||||||
|
if (cpfpInfo.bestDescendant) {
|
||||||
|
totalWeight += cpfpInfo.bestDescendant.weight;
|
||||||
|
totalFees += cpfpInfo.bestDescendant.fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4);
|
||||||
|
this.stateService.markBlock$.next({
|
||||||
|
txFeePerVSize: this.tx.effectiveFeePerVsize,
|
||||||
|
});
|
||||||
|
this.cpfpInfo = cpfpInfo;
|
||||||
|
this.openGraphService.waitOver('cpfp-data');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.subscription = this.route.paramMap
|
||||||
|
.pipe(
|
||||||
|
switchMap((params: ParamMap) => {
|
||||||
|
this.openGraphService.waitFor('tx-data');
|
||||||
|
const urlMatch = (params.get('id') || '').split(':');
|
||||||
|
this.txId = urlMatch[0];
|
||||||
|
this.seoService.setTitle(
|
||||||
|
$localize`:@@bisq.transaction.browser-title:Transaction: ${this.txId}:INTERPOLATION:`
|
||||||
|
);
|
||||||
|
this.resetTransaction();
|
||||||
|
return merge(
|
||||||
|
of(true),
|
||||||
|
this.stateService.connectionState$.pipe(
|
||||||
|
filter(
|
||||||
|
(state) => state === 2 && this.tx && !this.tx.status.confirmed
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
switchMap(() => {
|
||||||
|
let transactionObservable$: Observable<Transaction>;
|
||||||
|
if (history.state.data && history.state.data.fee !== -1) {
|
||||||
|
transactionObservable$ = of(history.state.data);
|
||||||
|
} else {
|
||||||
|
transactionObservable$ = this.electrsApiService
|
||||||
|
.getTransaction$(this.txId)
|
||||||
|
.pipe(
|
||||||
|
catchError(error => {
|
||||||
|
this.error = error;
|
||||||
|
this.isLoadingTx = false;
|
||||||
|
return of(null);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return merge(
|
||||||
|
transactionObservable$,
|
||||||
|
this.stateService.mempoolTransactions$
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
switchMap((tx) => {
|
||||||
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
|
return from(this.liquidUnblinding.checkUnblindedTx(tx))
|
||||||
|
.pipe(
|
||||||
|
catchError((error) => {
|
||||||
|
this.errorUnblinded = error;
|
||||||
|
return of(tx);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return of(tx);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe((tx: Transaction) => {
|
||||||
|
if (!tx) {
|
||||||
|
this.openGraphService.fail('tx-data');
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (!tx.status.confirmed && tx.firstSeen) {
|
||||||
|
this.transactionTime = tx.firstSeen;
|
||||||
|
} else {
|
||||||
|
this.getTransactionTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.tx.status.confirmed) {
|
||||||
|
if (tx.cpfpChecked) {
|
||||||
|
this.cpfpInfo = {
|
||||||
|
ancestors: tx.ancestors,
|
||||||
|
bestDescendant: tx.bestDescendant,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.openGraphService.waitFor('cpfp-data');
|
||||||
|
this.fetchCpfp$.next(this.tx.txid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.openGraphService.waitOver('tx-data');
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
this.openGraphService.fail('tx-data');
|
||||||
|
this.error = error;
|
||||||
|
this.isLoadingTx = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTransactionTime() {
|
||||||
|
this.openGraphService.waitFor('tx-time');
|
||||||
|
this.apiService
|
||||||
|
.getTransactionTimes$([this.tx.txid])
|
||||||
|
.pipe(
|
||||||
|
catchError((err) => {
|
||||||
|
return of(0);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe((transactionTimes) => {
|
||||||
|
this.transactionTime = transactionTimes[0];
|
||||||
|
this.openGraphService.waitOver('tx-time');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTransaction() {
|
||||||
|
this.error = undefined;
|
||||||
|
this.tx = null;
|
||||||
|
this.isLoadingTx = true;
|
||||||
|
this.transactionTime = -1;
|
||||||
|
this.cpfpInfo = null;
|
||||||
|
this.showCpfpDetails = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCoinbase(tx: Transaction): boolean {
|
||||||
|
return tx.vin.some((v: any) => v.is_coinbase === true);
|
||||||
|
}
|
||||||
|
|
||||||
|
haveBlindedOutputValues(tx: Transaction): boolean {
|
||||||
|
return tx.vout.some((v: any) => v.value === undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTotalTxOutput(tx: Transaction) {
|
||||||
|
return tx.vout.map((v: Vout) => v.value || 0).reduce((a: number, b: number) => a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
this.fetchCpfpSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@ import { RouterModule } from '@angular/router';
|
||||||
import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
|
import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
|
||||||
import { StartComponent } from '../components/start/start.component';
|
import { StartComponent } from '../components/start/start.component';
|
||||||
import { TransactionComponent } from '../components/transaction/transaction.component';
|
import { TransactionComponent } from '../components/transaction/transaction.component';
|
||||||
|
import { TransactionPreviewComponent } from '../components/transaction/transaction-preview.component';
|
||||||
import { TransactionsListComponent } from '../components/transactions-list/transactions-list.component';
|
import { TransactionsListComponent } from '../components/transactions-list/transactions-list.component';
|
||||||
import { BlockComponent } from '../components/block/block.component';
|
import { BlockComponent } from '../components/block/block.component';
|
||||||
import { BlockPreviewComponent } from '../components/block/block-preview.component';
|
import { BlockPreviewComponent } from '../components/block/block-preview.component';
|
||||||
|
@ -118,6 +119,7 @@ import { ToggleComponent } from './components/toggle/toggle.component';
|
||||||
LiquidMasterPageComponent,
|
LiquidMasterPageComponent,
|
||||||
StartComponent,
|
StartComponent,
|
||||||
TransactionComponent,
|
TransactionComponent,
|
||||||
|
TransactionPreviewComponent,
|
||||||
BlockComponent,
|
BlockComponent,
|
||||||
BlockPreviewComponent,
|
BlockPreviewComponent,
|
||||||
BlockAuditComponent,
|
BlockAuditComponent,
|
||||||
|
@ -220,6 +222,7 @@ import { ToggleComponent } from './components/toggle/toggle.component';
|
||||||
AmountComponent,
|
AmountComponent,
|
||||||
StartComponent,
|
StartComponent,
|
||||||
TransactionComponent,
|
TransactionComponent,
|
||||||
|
TransactionPreviewComponent,
|
||||||
BlockComponent,
|
BlockComponent,
|
||||||
BlockPreviewComponent,
|
BlockPreviewComponent,
|
||||||
BlockAuditComponent,
|
BlockAuditComponent,
|
||||||
|
|
|
@ -157,6 +157,9 @@ class Server {
|
||||||
case 'address':
|
case 'address':
|
||||||
ogTitle = `Address: ${parts[1]}`;
|
ogTitle = `Address: ${parts[1]}`;
|
||||||
break;
|
break;
|
||||||
|
case 'tx':
|
||||||
|
ogTitle = `Transaction: ${parts[1]}`;
|
||||||
|
break;
|
||||||
case 'lightning':
|
case 'lightning':
|
||||||
switch (parts[1]) {
|
switch (parts[1]) {
|
||||||
case 'node':
|
case 'node':
|
||||||
|
|
Loading…
Add table
Reference in a new issue