Merge pull request #5681 from mempool/mononaut/wallet-preview
wallet unfurler preview
This commit is contained in:
commit
e58579ed8a
@ -45,14 +45,17 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
@Input() left: number | string = 70;
|
@Input() left: number | string = 70;
|
||||||
@Input() widget: boolean = false;
|
@Input() widget: boolean = false;
|
||||||
@Input() defaultFiat: boolean = false;
|
@Input() defaultFiat: boolean = false;
|
||||||
|
@Input() showLegend: boolean = true;
|
||||||
|
@Input() showYAxis: boolean = true;
|
||||||
|
|
||||||
|
adjustedLeft: number;
|
||||||
|
adjustedRight: number;
|
||||||
data: any[] = [];
|
data: any[] = [];
|
||||||
fiatData: any[] = [];
|
fiatData: any[] = [];
|
||||||
hoverData: any[] = [];
|
hoverData: any[] = [];
|
||||||
conversions: any;
|
conversions: any;
|
||||||
allowZoom: boolean = false;
|
allowZoom: boolean = false;
|
||||||
initialRight = this.right;
|
|
||||||
initialLeft = this.left;
|
|
||||||
selected = { [$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`]: true, 'Fiat': false };
|
selected = { [$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`]: true, 'Fiat': false };
|
||||||
|
|
||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
@ -181,8 +184,8 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
const maxValue = this.data.reduce((acc, d) => Math.max(acc, Math.abs(d[1] ?? d.value[1])), 0);
|
const maxValue = this.data.reduce((acc, d) => Math.max(acc, Math.abs(d[1] ?? d.value[1])), 0);
|
||||||
const minValue = this.data.reduce((acc, d) => Math.min(acc, Math.abs(d[1] ?? d.value[1])), maxValue);
|
const minValue = this.data.reduce((acc, d) => Math.min(acc, Math.abs(d[1] ?? d.value[1])), maxValue);
|
||||||
|
|
||||||
this.right = this.selected['Fiat'] ? +this.initialRight + 40 : this.initialRight;
|
this.adjustedRight = this.selected['Fiat'] ? +this.right + 40 : +this.right;
|
||||||
this.left = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? this.initialLeft : +this.initialLeft - 40;
|
this.adjustedLeft = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? +this.left : +this.left - 40;
|
||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
color: [
|
color: [
|
||||||
@ -199,10 +202,10 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
grid: {
|
grid: {
|
||||||
top: 20,
|
top: 20,
|
||||||
bottom: this.allowZoom ? 65 : 20,
|
bottom: this.allowZoom ? 65 : 20,
|
||||||
right: this.right,
|
right: this.adjustedRight,
|
||||||
left: this.left,
|
left: this.adjustedLeft,
|
||||||
},
|
},
|
||||||
legend: !this.stateService.isAnyTestnet() ? {
|
legend: (this.showLegend && !this.stateService.isAnyTestnet()) ? {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: $localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`,
|
name: $localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`,
|
||||||
@ -313,6 +316,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
type: 'value',
|
type: 'value',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
|
show: this.showYAxis,
|
||||||
color: 'rgb(110, 112, 121)',
|
color: 'rgb(110, 112, 121)',
|
||||||
formatter: (val): string => {
|
formatter: (val): string => {
|
||||||
let valSpan = maxValue - (this.period === 'all' ? 0 : minValue);
|
let valSpan = maxValue - (this.period === 'all' ? 0 : minValue);
|
||||||
@ -343,6 +347,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
{
|
{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
|
show: this.showYAxis,
|
||||||
color: 'rgb(110, 112, 121)',
|
color: 'rgb(110, 112, 121)',
|
||||||
formatter: function(val) {
|
formatter: function(val) {
|
||||||
return `$${this.amountShortenerPipe.transform(val, 0, undefined, true)}`;
|
return `$${this.amountShortenerPipe.transform(val, 0, undefined, true)}`;
|
||||||
@ -399,8 +404,8 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
type: 'slider',
|
type: 'slider',
|
||||||
brushSelect: false,
|
brushSelect: false,
|
||||||
realtime: true,
|
realtime: true,
|
||||||
left: this.left,
|
left: this.adjustedLeft,
|
||||||
right: this.right,
|
right: this.adjustedRight,
|
||||||
selectedDataBackground: {
|
selectedDataBackground: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
@ -430,23 +435,23 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
|||||||
|
|
||||||
onLegendSelectChanged(e) {
|
onLegendSelectChanged(e) {
|
||||||
this.selected = e.selected;
|
this.selected = e.selected;
|
||||||
this.right = this.selected['Fiat'] ? +this.initialRight + 40 : this.initialRight;
|
this.adjustedRight = this.selected['Fiat'] ? +this.right + 40 : +this.right;
|
||||||
this.left = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? this.initialLeft : +this.initialLeft - 40;
|
this.adjustedLeft = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? +this.left : +this.left - 40;
|
||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
grid: {
|
grid: {
|
||||||
right: this.right,
|
right: this.adjustedRight,
|
||||||
left: this.left,
|
left: this.adjustedLeft,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
selected: this.selected,
|
selected: this.selected,
|
||||||
},
|
},
|
||||||
dataZoom: this.allowZoom ? [{
|
dataZoom: this.allowZoom ? [{
|
||||||
left: this.left,
|
left: this.adjustedLeft,
|
||||||
right: this.right,
|
right: this.adjustedRight,
|
||||||
}, {
|
}, {
|
||||||
left: this.left,
|
left: this.adjustedLeft,
|
||||||
right: this.right,
|
right: this.adjustedRight,
|
||||||
}] : undefined
|
}] : undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
<div class="box preview-box" *ngIf="(walletAddresses$ | async) as walletAddresses">
|
||||||
|
<app-preview-title>
|
||||||
|
<span i18n="shared.wallet">Wallet</span>
|
||||||
|
</app-preview-title>
|
||||||
|
<div>
|
||||||
|
<div class="table-col">
|
||||||
|
<table class="table table-borderless dual-col-striped table-fixed wallet-table" *ngIf="(walletStats$ | async) as walletStats">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td i18n="address.number-addresses">Addresses</td>
|
||||||
|
<td class="wrap-cell">{{ addressStrings.length }}</td>
|
||||||
|
<td class="spacer"></td>
|
||||||
|
<td i18n="address.utxos">UTXOs</td>
|
||||||
|
<td class="wrap-cell">{{ walletStats.utxos }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td i18n="wallet.balance-btc">Balance (BTC)</td>
|
||||||
|
<td class="wrap-cell"><app-amount [satoshis]="walletStats.balance" [noFiat]="true" [digitsInfo]="walletStats.balance > 1_000_000_000 ? '1.4-4' : '1.8-8'"></app-amount></td>
|
||||||
|
<td class="spacer"></td>
|
||||||
|
<td i18n="wallet.balance-usd">Balance (USD)</td>
|
||||||
|
<td class="wrap-cell"><span class="fiat"><app-fiat [value]="walletStats.balance"></app-fiat></span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="w-100 d-block d-md-none"></div>
|
||||||
|
<div class="col-md graph-col">
|
||||||
|
<app-address-graph [addressSummary$]="walletSummary$" period="all" [widget]="true" [defaultFiat]="true" [height]="330" [left]="-40" [right]="-40" [showLegend]="false" [showYAxis]="false"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,31 @@
|
|||||||
|
.title-wrapper {
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.graph-col {
|
||||||
|
height: 350px;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-col {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
font-size: 32px;
|
||||||
|
|
||||||
|
::ng-deep .symbol {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacer {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiat {
|
||||||
|
display: block;
|
||||||
|
}
|
245
frontend/src/app/components/wallet/wallet-preview.component.ts
Normal file
245
frontend/src/app/components/wallet/wallet-preview.component.ts
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
|
import { ActivatedRoute, ParamMap } from '@angular/router';
|
||||||
|
import { switchMap, catchError, map, tap, shareReplay, startWith, scan } from 'rxjs/operators';
|
||||||
|
import { Address, AddressTxSummary, ChainStats, Transaction } from '@interfaces/electrs.interface';
|
||||||
|
import { StateService } from '@app/services/state.service';
|
||||||
|
import { ApiService } from '@app/services/api.service';
|
||||||
|
import { of, Observable, Subscription } from 'rxjs';
|
||||||
|
import { SeoService } from '@app/services/seo.service';
|
||||||
|
import { seoDescriptionNetwork } from '@app/shared/common.utils';
|
||||||
|
import { WalletAddress } from '@interfaces/node-api.interface';
|
||||||
|
import { OpenGraphService } from '../../services/opengraph.service';
|
||||||
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
|
|
||||||
|
class WalletStats implements ChainStats {
|
||||||
|
addresses: string[];
|
||||||
|
funded_txo_count: number;
|
||||||
|
funded_txo_sum: number;
|
||||||
|
spent_txo_count: number;
|
||||||
|
spent_txo_sum: number;
|
||||||
|
tx_count: number;
|
||||||
|
|
||||||
|
constructor (stats: ChainStats[], addresses: string[]) {
|
||||||
|
Object.assign(this, stats.reduce((acc, stat) => {
|
||||||
|
acc.funded_txo_count += stat.funded_txo_count;
|
||||||
|
acc.funded_txo_sum += stat.funded_txo_sum;
|
||||||
|
acc.spent_txo_count += stat.spent_txo_count;
|
||||||
|
acc.spent_txo_sum += stat.spent_txo_sum;
|
||||||
|
return acc;
|
||||||
|
}, {
|
||||||
|
funded_txo_count: 0,
|
||||||
|
funded_txo_sum: 0,
|
||||||
|
spent_txo_count: 0,
|
||||||
|
spent_txo_sum: 0,
|
||||||
|
tx_count: 0,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addTx(tx: Transaction): void {
|
||||||
|
for (const vin of tx.vin) {
|
||||||
|
if (this.addresses.includes(vin.prevout?.scriptpubkey_address)) {
|
||||||
|
this.spendTxo(vin.prevout.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const vout of tx.vout) {
|
||||||
|
if (this.addresses.includes(vout.scriptpubkey_address)) {
|
||||||
|
this.fundTxo(vout.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tx_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeTx(tx: Transaction): void {
|
||||||
|
for (const vin of tx.vin) {
|
||||||
|
if (this.addresses.includes(vin.prevout?.scriptpubkey_address)) {
|
||||||
|
this.unspendTxo(vin.prevout.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const vout of tx.vout) {
|
||||||
|
if (this.addresses.includes(vout.scriptpubkey_address)) {
|
||||||
|
this.unfundTxo(vout.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tx_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
private fundTxo(value: number): void {
|
||||||
|
this.funded_txo_sum += value;
|
||||||
|
this.funded_txo_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unfundTxo(value: number): void {
|
||||||
|
this.funded_txo_sum -= value;
|
||||||
|
this.funded_txo_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
private spendTxo(value: number): void {
|
||||||
|
this.spent_txo_sum += value;
|
||||||
|
this.spent_txo_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unspendTxo(value: number): void {
|
||||||
|
this.spent_txo_sum -= value;
|
||||||
|
this.spent_txo_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
get balance(): number {
|
||||||
|
return this.funded_txo_sum - this.spent_txo_sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
get totalReceived(): number {
|
||||||
|
return this.funded_txo_sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
get utxos(): number {
|
||||||
|
return this.funded_txo_count - this.spent_txo_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-wallet-preview',
|
||||||
|
templateUrl: './wallet-preview.component.html',
|
||||||
|
styleUrls: ['./wallet-preview.component.scss']
|
||||||
|
})
|
||||||
|
export class WalletPreviewComponent implements OnInit, OnDestroy {
|
||||||
|
network = '';
|
||||||
|
|
||||||
|
addresses: Address[] = [];
|
||||||
|
addressStrings: string[] = [];
|
||||||
|
walletName: string;
|
||||||
|
isLoadingWallet = true;
|
||||||
|
wallet$: Observable<Record<string, WalletAddress>>;
|
||||||
|
walletAddresses$: Observable<Record<string, Address>>;
|
||||||
|
walletSummary$: Observable<AddressTxSummary[]>;
|
||||||
|
walletStats$: Observable<WalletStats>;
|
||||||
|
error: any;
|
||||||
|
walletSubscription: Subscription;
|
||||||
|
|
||||||
|
collapseAddresses: boolean = true;
|
||||||
|
|
||||||
|
fullyLoaded = false;
|
||||||
|
txCount = 0;
|
||||||
|
received = 0;
|
||||||
|
sent = 0;
|
||||||
|
chainBalance = 0;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private stateService: StateService,
|
||||||
|
private apiService: ApiService,
|
||||||
|
private seoService: SeoService,
|
||||||
|
private websocketService: WebsocketService,
|
||||||
|
private openGraphService: OpenGraphService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.websocketService.want(['blocks', 'stats']);
|
||||||
|
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
||||||
|
this.wallet$ = this.route.paramMap.pipe(
|
||||||
|
map((params: ParamMap) => params.get('wallet') as string),
|
||||||
|
tap((walletName: string) => {
|
||||||
|
this.walletName = walletName;
|
||||||
|
this.openGraphService.waitFor('wallet-addresses-' + this.walletName);
|
||||||
|
this.openGraphService.waitFor('wallet-data-' + this.walletName);
|
||||||
|
this.openGraphService.waitFor('wallet-txs-' + this.walletName);
|
||||||
|
this.seoService.setTitle($localize`:@@wallet.component.browser-title:Wallet: ${walletName}:INTERPOLATION:`);
|
||||||
|
this.seoService.setDescription($localize`:@@meta.description.bitcoin.wallet:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} wallet ${walletName}:INTERPOLATION:.`);
|
||||||
|
}),
|
||||||
|
switchMap((walletName: string) => this.apiService.getWallet$(walletName).pipe(
|
||||||
|
catchError((err) => {
|
||||||
|
this.error = err;
|
||||||
|
this.seoService.logSoft404();
|
||||||
|
console.log(err);
|
||||||
|
this.openGraphService.fail('wallet-addresses-' + this.walletName);
|
||||||
|
this.openGraphService.fail('wallet-data-' + this.walletName);
|
||||||
|
this.openGraphService.fail('wallet-txs-' + this.walletName);
|
||||||
|
return of({});
|
||||||
|
})
|
||||||
|
)),
|
||||||
|
shareReplay(1),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.walletAddresses$ = this.wallet$.pipe(
|
||||||
|
map(wallet => {
|
||||||
|
const walletInfo: Record<string, Address> = {};
|
||||||
|
for (const address of Object.keys(wallet)) {
|
||||||
|
walletInfo[address] = {
|
||||||
|
address,
|
||||||
|
chain_stats: wallet[address].stats,
|
||||||
|
mempool_stats: {
|
||||||
|
funded_txo_count: 0,
|
||||||
|
funded_txo_sum: 0,
|
||||||
|
spent_txo_count: 0, spent_txo_sum: 0, tx_count: 0
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return walletInfo;
|
||||||
|
}),
|
||||||
|
tap(() => {
|
||||||
|
this.isLoadingWallet = false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.walletSubscription = this.walletAddresses$.subscribe(wallet => {
|
||||||
|
this.addressStrings = Object.keys(wallet);
|
||||||
|
this.addresses = Object.values(wallet);
|
||||||
|
this.openGraphService.waitOver('wallet-addresses-' + this.walletName);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.walletSummary$ = this.wallet$.pipe(
|
||||||
|
map(wallet => this.deduplicateWalletTransactions(Object.values(wallet).flatMap(address => address.transactions))),
|
||||||
|
tap(() => {
|
||||||
|
this.openGraphService.waitOver('wallet-txs-' + this.walletName);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.walletStats$ = this.wallet$.pipe(
|
||||||
|
switchMap(wallet => {
|
||||||
|
const walletStats = new WalletStats(Object.values(wallet).map(w => w.stats), Object.keys(wallet));
|
||||||
|
return this.stateService.walletTransactions$.pipe(
|
||||||
|
startWith([]),
|
||||||
|
scan((stats, newTransactions) => {
|
||||||
|
for (const tx of newTransactions) {
|
||||||
|
stats.addTx(tx);
|
||||||
|
}
|
||||||
|
return stats;
|
||||||
|
}, walletStats),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
tap(() => {
|
||||||
|
this.openGraphService.waitOver('wallet-data-' + this.walletName);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
deduplicateWalletTransactions(walletTransactions: AddressTxSummary[]): AddressTxSummary[] {
|
||||||
|
const transactions = new Map<string, AddressTxSummary>();
|
||||||
|
for (const tx of walletTransactions) {
|
||||||
|
if (transactions.has(tx.txid)) {
|
||||||
|
transactions.get(tx.txid).value += tx.value;
|
||||||
|
} else {
|
||||||
|
transactions.set(tx.txid, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(transactions.values()).sort((a, b) => {
|
||||||
|
if (a.height === b.height) {
|
||||||
|
return b.tx_position - a.tx_position;
|
||||||
|
}
|
||||||
|
return b.height - a.height;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizeAddress(address: string): string {
|
||||||
|
if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(address)) {
|
||||||
|
return address.toLowerCase();
|
||||||
|
} else {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.walletSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ import { HashrateChartPoolsComponent } from '@components/hashrates-chart-pools/h
|
|||||||
import { BlockHealthGraphComponent } from '@components/block-health-graph/block-health-graph.component';
|
import { BlockHealthGraphComponent } from '@components/block-health-graph/block-health-graph.component';
|
||||||
import { AddressComponent } from '@components/address/address.component';
|
import { AddressComponent } from '@components/address/address.component';
|
||||||
import { WalletComponent } from '@components/wallet/wallet.component';
|
import { WalletComponent } from '@components/wallet/wallet.component';
|
||||||
|
import { WalletPreviewComponent } from '@components/wallet/wallet-preview.component';
|
||||||
import { AddressGraphComponent } from '@components/address-graph/address-graph.component';
|
import { AddressGraphComponent } from '@components/address-graph/address-graph.component';
|
||||||
import { UtxoGraphComponent } from '@components/utxo-graph/utxo-graph.component';
|
import { UtxoGraphComponent } from '@components/utxo-graph/utxo-graph.component';
|
||||||
import { ActiveAccelerationBox } from '@components/acceleration/active-acceleration-box/active-acceleration-box.component';
|
import { ActiveAccelerationBox } from '@components/acceleration/active-acceleration-box/active-acceleration-box.component';
|
||||||
@ -49,6 +50,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
MempoolBlockComponent,
|
MempoolBlockComponent,
|
||||||
AddressComponent,
|
AddressComponent,
|
||||||
WalletComponent,
|
WalletComponent,
|
||||||
|
WalletPreviewComponent,
|
||||||
|
|
||||||
MiningDashboardComponent,
|
MiningDashboardComponent,
|
||||||
AcceleratorDashboardComponent,
|
AcceleratorDashboardComponent,
|
||||||
|
@ -3,6 +3,7 @@ import { RouterModule, Routes } from '@angular/router';
|
|||||||
import { TransactionPreviewComponent } from '@components/transaction/transaction-preview.component';
|
import { TransactionPreviewComponent } from '@components/transaction/transaction-preview.component';
|
||||||
import { BlockPreviewComponent } from '@components/block/block-preview.component';
|
import { BlockPreviewComponent } from '@components/block/block-preview.component';
|
||||||
import { AddressPreviewComponent } from '@components/address/address-preview.component';
|
import { AddressPreviewComponent } from '@components/address/address-preview.component';
|
||||||
|
import { WalletPreviewComponent } from '@components/wallet/wallet-preview.component';
|
||||||
import { PoolPreviewComponent } from '@components/pool/pool-preview.component';
|
import { PoolPreviewComponent } from '@components/pool/pool-preview.component';
|
||||||
import { MasterPagePreviewComponent } from '@components/master-page-preview/master-page-preview.component';
|
import { MasterPagePreviewComponent } from '@components/master-page-preview/master-page-preview.component';
|
||||||
|
|
||||||
@ -20,6 +21,11 @@ const routes: Routes = [
|
|||||||
children: [],
|
children: [],
|
||||||
component: AddressPreviewComponent
|
component: AddressPreviewComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'wallet/:wallet',
|
||||||
|
children: [],
|
||||||
|
component: WalletPreviewComponent
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'tx/:id',
|
path: 'tx/:id',
|
||||||
children: [],
|
children: [],
|
||||||
|
@ -85,6 +85,13 @@ const routes = {
|
|||||||
return `Address: ${path[0]}`;
|
return `Address: ${path[0]}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
wallet: {
|
||||||
|
render: true,
|
||||||
|
params: 1,
|
||||||
|
getTitle(path) {
|
||||||
|
return `Wallet: ${path[0]}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
blocks: {
|
blocks: {
|
||||||
title: "Blocks",
|
title: "Blocks",
|
||||||
fallbackImg: '/resources/previews/blocks.jpg',
|
fallbackImg: '/resources/previews/blocks.jpg',
|
||||||
@ -289,6 +296,7 @@ export const networks = {
|
|||||||
routes: { // only dynamic routes supported
|
routes: { // only dynamic routes supported
|
||||||
block: routes.block,
|
block: routes.block,
|
||||||
address: routes.address,
|
address: routes.address,
|
||||||
|
wallet: routes.wallet,
|
||||||
tx: routes.tx,
|
tx: routes.tx,
|
||||||
mining: {
|
mining: {
|
||||||
title: "Mining",
|
title: "Mining",
|
||||||
@ -309,6 +317,7 @@ export const networks = {
|
|||||||
routes: { // only dynamic routes supported
|
routes: { // only dynamic routes supported
|
||||||
block: routes.block,
|
block: routes.block,
|
||||||
address: routes.address,
|
address: routes.address,
|
||||||
|
wallet: routes.wallet,
|
||||||
tx: routes.tx,
|
tx: routes.tx,
|
||||||
mining: {
|
mining: {
|
||||||
title: "Mining",
|
title: "Mining",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user