mirror of
https://github.com/mempool/mempool.git
synced 2025-09-27 22:57:07 +02:00
add pie chart to treasuries dashboard
This commit is contained in:
@@ -10,6 +10,12 @@ import { StateService } from '@app/services/state.service';
|
||||
import { FiatCurrencyPipe } from '@app/shared/pipes/fiat-currency.pipe';
|
||||
import { SeriesOption } from 'echarts';
|
||||
import { WalletStats } from '@app/shared/wallet-stats';
|
||||
import { chartColors } from '@app/app.constants';
|
||||
|
||||
|
||||
// export const treasuriesPalette = [
|
||||
// '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40',
|
||||
// ];
|
||||
|
||||
const periodSeconds = {
|
||||
'1d': (60 * 60 * 24),
|
||||
@@ -65,11 +71,6 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy {
|
||||
isLoading = true;
|
||||
chartInstance: any = undefined;
|
||||
|
||||
// Color palette for multiple wallets
|
||||
colorPalette = [
|
||||
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40',
|
||||
];
|
||||
|
||||
constructor(
|
||||
@Inject(LOCALE_ID) public locale: string,
|
||||
public stateService: StateService,
|
||||
@@ -215,7 +216,7 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}));
|
||||
|
||||
this.chartOptions = {
|
||||
color: this.colorPalette,
|
||||
color: chartColors,
|
||||
animation: false,
|
||||
grid: {
|
||||
top: 20,
|
||||
@@ -260,11 +261,12 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy {
|
||||
tooltip += `<div><b style="color: white; margin-left: 2px">${date}</b><br>`;
|
||||
|
||||
// Get all active wallet IDs from the selected wallets
|
||||
const activeWalletIds = Object.keys(this.selectedWallets)
|
||||
.filter(walletId => this.selectedWallets[walletId] && this.walletData[walletId]);
|
||||
const activeWalletIds: { walletId: string, index: number }[] = this.wallets
|
||||
.map((walletId, index) => ({ walletId, index }))
|
||||
.filter(({ walletId }) => this.selectedWallets[walletId] && this.walletData[walletId]);
|
||||
|
||||
// For each active wallet, find and display the most recent balance
|
||||
activeWalletIds.forEach((walletId, index) => {
|
||||
activeWalletIds.forEach(({ walletId, index }) => {
|
||||
const walletPoints = this.walletData[walletId];
|
||||
if (!walletPoints || !walletPoints.length) {
|
||||
return;
|
||||
@@ -293,11 +295,7 @@ export class TreasuriesGraphComponent implements OnInit, OnChanges, OnDestroy {
|
||||
(mostRecentPoint && typeof mostRecentPoint === 'object' && 'value' in mostRecentPoint ? mostRecentPoint.value[1] : null);
|
||||
|
||||
if (balance !== null && !isNaN(balance)) {
|
||||
// Create a marker for this series using the color from colorPalette
|
||||
const colorIndex = index % this.colorPalette.length;
|
||||
|
||||
// Get color for marker - use direct color from palette
|
||||
const markerColor = this.colorPalette[colorIndex];
|
||||
const markerColor = chartColors[index % chartColors.length];
|
||||
|
||||
const marker = `<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${markerColor};"></span>`;
|
||||
|
||||
|
@@ -0,0 +1,7 @@
|
||||
<div>
|
||||
<div class="container pb-lg-0">
|
||||
<div class="chart-widget" *browserOnly [style]="{ height: (height + 'px'), opacity: isLoading ? 0.5 : 1 }" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
|
||||
(chartInit)="onChartInit($event)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,135 @@
|
||||
.card-header {
|
||||
border-bottom: 0;
|
||||
font-size: 18px;
|
||||
@media (min-width: 465px) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.full-container {
|
||||
padding: 0px 15px;
|
||||
width: 100%;
|
||||
height: calc(100% - 140px);
|
||||
padding-bottom: 20px;
|
||||
@media (max-width: 992px) {
|
||||
height: calc(100% - 190px);
|
||||
};
|
||||
@media (max-width: 575px) {
|
||||
height: calc(100% - 230px);
|
||||
};
|
||||
}
|
||||
|
||||
.chart {
|
||||
max-height: 400px;
|
||||
@media (max-width: 767.98px) {
|
||||
max-height: 230px;
|
||||
}
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.chart-widget {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@media (max-width: 767px) {
|
||||
max-height: 240px;
|
||||
}
|
||||
@media (max-width: 485px) {
|
||||
max-height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.pools-table th,
|
||||
.pools-table td {
|
||||
padding: .3em !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.pool-name {
|
||||
max-width: 110px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.health-column {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.loadingGraphs {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: calc(50% - 15px);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.pool-distribution {
|
||||
min-height: 56px;
|
||||
display: block;
|
||||
@media (min-width: 485px) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
h5 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.item {
|
||||
max-width: 160px;
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
margin: 0px auto 20px;
|
||||
&:nth-child(2) {
|
||||
order: 2;
|
||||
@media (min-width: 485px) {
|
||||
order: 3;
|
||||
}
|
||||
}
|
||||
&:nth-child(3) {
|
||||
width: 50%;
|
||||
order: 3;
|
||||
@media (min-width: 485px) {
|
||||
order: 2;
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.card-title {
|
||||
font-size: 1rem;
|
||||
color: var(--title-fg);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.card-text {
|
||||
font-size: 18px;
|
||||
span {
|
||||
color: var(--transparent-fg);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.skeleton-loader {
|
||||
width: 100%;
|
||||
display: block;
|
||||
max-width: 80px;
|
||||
margin: 15px auto 3px;
|
||||
}
|
||||
|
||||
|
||||
td {
|
||||
.difference {
|
||||
&.positive {
|
||||
color: rgb(66, 183, 71);
|
||||
}
|
||||
&.negative {
|
||||
color: rgb(183, 66, 66);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,280 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, Input, NgZone, OnChanges, SimpleChanges, ChangeDetectorRef, EventEmitter, Output } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { EChartsOption, PieSeriesOption } from '@app/graphs/echarts';
|
||||
import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
import { RelativeUrlPipe } from '@app/shared/pipes/relative-url/relative-url.pipe';
|
||||
import { download } from '@app/shared/graphs.utils';
|
||||
import { isMobile } from '@app/shared/common.utils';
|
||||
import { WalletStats } from '@app/shared/wallet-stats';
|
||||
import { AddressTxSummary } from '@interfaces/electrs.interface';
|
||||
import { chartColors } from '@app/app.constants';
|
||||
import { formatNumber } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-treasuries-pie',
|
||||
templateUrl: './treasuries-pie.component.html',
|
||||
styleUrls: ['./treasuries-pie.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TreasuriesPieComponent implements OnChanges {
|
||||
@Input() height: number = 300;
|
||||
@Input() mode: 'relative' | 'all' = 'relative';
|
||||
@Input() walletStats: Record<string, WalletStats>;
|
||||
@Input() walletSummaries$: Observable<Record<string, AddressTxSummary[]>>;
|
||||
@Input() selectedWallets: Record<string, boolean> = {};
|
||||
@Input() wallets: string[] = [];
|
||||
@Output() navigateToWallet: EventEmitter<string> = new EventEmitter();
|
||||
|
||||
chartOptions: EChartsOption = {};
|
||||
chartInitOptions = {
|
||||
renderer: 'svg',
|
||||
};
|
||||
chartInstance: any = undefined;
|
||||
error: any;
|
||||
isLoading = true;
|
||||
subscription: Subscription;
|
||||
redraw$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
walletBalance: Record<string, number> = {};
|
||||
|
||||
constructor(
|
||||
@Inject(LOCALE_ID) public locale: string,
|
||||
public stateService: StateService,
|
||||
private router: Router,
|
||||
private zone: NgZone,
|
||||
private cd: ChangeDetectorRef,
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isLoading = true;
|
||||
this.setupSubscription();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.walletSummaries$ || changes.selectedWallets || changes.mode) {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
this.setupSubscription();
|
||||
} else {
|
||||
// re-trigger subscription
|
||||
this.redraw$.next(true);
|
||||
}
|
||||
}
|
||||
|
||||
setupSubscription(): void {
|
||||
this.subscription = combineLatest([
|
||||
this.redraw$,
|
||||
this.walletSummaries$
|
||||
]).subscribe(([_, walletSummaries]) => {
|
||||
if (walletSummaries) {
|
||||
this.error = null;
|
||||
this.processWalletData(walletSummaries);
|
||||
this.prepareChartOptions();
|
||||
}
|
||||
this.isLoading = false;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
processWalletData(walletSummaries: Record<string, AddressTxSummary[]>): void {
|
||||
this.walletBalance = {};
|
||||
|
||||
Object.entries(walletSummaries).forEach(([walletId, summary]) => {
|
||||
if (summary?.length) {
|
||||
const total = this.walletStats[walletId] ? this.walletStats[walletId].balance : summary.reduce((acc, tx) => acc + tx.value, 0);
|
||||
this.walletBalance[walletId] = total;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
generateChartSeriesData(): PieSeriesOption[] {
|
||||
let sliceThreshold = 1;
|
||||
if (isMobile()) {
|
||||
sliceThreshold = 2;
|
||||
}
|
||||
|
||||
const data: object[] = [];
|
||||
|
||||
let edgeDistance: any = '20%';
|
||||
if (isMobile()) {
|
||||
edgeDistance = 0;
|
||||
} else {
|
||||
edgeDistance = 10;
|
||||
}
|
||||
|
||||
const treasuriesTotal = Object.values(this.walletBalance).reduce((acc, v) => acc + v, 0);
|
||||
const total = this.mode === 'relative' ? treasuriesTotal : 2099999997690000;
|
||||
|
||||
const entries = this.wallets.map((id, index) => ({
|
||||
id,
|
||||
balance: this.walletBalance[id],
|
||||
share: (this.walletBalance[id] / total) * 100,
|
||||
color: chartColors[index % chartColors.length],
|
||||
}));
|
||||
if (this.mode === 'all') {
|
||||
entries.unshift({
|
||||
id: 'remaining',
|
||||
balance: (total - treasuriesTotal),
|
||||
share: ((total - treasuriesTotal) / total) * 100,
|
||||
color: 'orange'
|
||||
});
|
||||
|
||||
console.log('ALL! ', entries);
|
||||
}
|
||||
|
||||
const otherEntry = { id: 'other', balance: 0, share: 0 };
|
||||
|
||||
entries.forEach((entry) => {
|
||||
if (entry.share < sliceThreshold) {
|
||||
otherEntry.balance += entry.balance;
|
||||
otherEntry.share = (otherEntry.balance / total) * 100;
|
||||
return;
|
||||
}
|
||||
data.push({
|
||||
itemStyle: {
|
||||
color: entry.color,
|
||||
},
|
||||
value: entry.share,
|
||||
name: entry.id,
|
||||
label: {
|
||||
overflow: 'none',
|
||||
color: 'var(--tooltip-grey)',
|
||||
alignTo: 'edge',
|
||||
edgeDistance: edgeDistance,
|
||||
},
|
||||
tooltip: {
|
||||
show: !isMobile(),
|
||||
backgroundColor: 'rgba(17, 19, 31, 1)',
|
||||
borderRadius: 4,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
textStyle: {
|
||||
color: 'var(--tooltip-grey)',
|
||||
},
|
||||
borderColor: '#000',
|
||||
formatter: () => {
|
||||
return `<b style="color: white">${entry.id} (${entry.share.toFixed(2)}%)</b><br>
|
||||
${formatNumber(entry.balance / 100_000_000, this.locale, '1.3-3')} BTC<br>`;
|
||||
}
|
||||
},
|
||||
data: entry.id as any,
|
||||
} as PieSeriesOption);
|
||||
});
|
||||
|
||||
const percentage = otherEntry.share.toFixed(2) + '%';
|
||||
|
||||
if (otherEntry.share > 0) {
|
||||
data.push({
|
||||
itemStyle: {
|
||||
color: '#6b6b6b',
|
||||
},
|
||||
value: otherEntry.share,
|
||||
name: $localize`Other (${percentage})`,
|
||||
label: {
|
||||
overflow: 'none',
|
||||
color: 'var(--tooltip-grey)',
|
||||
alignTo: 'edge',
|
||||
edgeDistance: edgeDistance
|
||||
},
|
||||
tooltip: {
|
||||
backgroundColor: 'rgba(17, 19, 31, 1)',
|
||||
borderRadius: 4,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
textStyle: {
|
||||
color: 'var(--tooltip-grey)',
|
||||
},
|
||||
borderColor: '#000',
|
||||
formatter: () => {
|
||||
return `<b style="color: white">${otherEntry.id} (${otherEntry.share}%)</b><br>
|
||||
${formatNumber(otherEntry.balance, this.locale, '1.3-3')}<br>`;
|
||||
}
|
||||
},
|
||||
data: 9999 as any,
|
||||
} as PieSeriesOption);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
prepareChartOptions(): void {
|
||||
const pieSize = ['20%', '80%']; // Desktop
|
||||
|
||||
this.chartOptions = {
|
||||
animation: false,
|
||||
color: chartColors,
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
textStyle: {
|
||||
align: 'left',
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
zlevel: 0,
|
||||
minShowLabelAngle: 1.8,
|
||||
name: 'Treasuries',
|
||||
type: 'pie',
|
||||
radius: pieSize,
|
||||
data: this.generateChartSeriesData(),
|
||||
labelLine: {
|
||||
lineStyle: {
|
||||
width: 2,
|
||||
},
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
},
|
||||
itemStyle: {
|
||||
borderRadius: 1,
|
||||
borderWidth: 1,
|
||||
borderColor: '#000',
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 40,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.75)',
|
||||
},
|
||||
labelLine: {
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
onChartInit(ec): void {
|
||||
if (this.chartInstance !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.chartInstance = ec;
|
||||
this.chartInstance.on('click', (e) => {
|
||||
if (e.data.data === 9999) { // "Other"
|
||||
return;
|
||||
}
|
||||
this.navigateToWallet.emit(e.data.data);
|
||||
});
|
||||
}
|
||||
|
||||
onSaveChart(): void {
|
||||
const now = new Date();
|
||||
this.chartOptions.backgroundColor = 'var(--active-bg)';
|
||||
this.chartInstance.setOption(this.chartOptions);
|
||||
download(this.chartInstance.getDataURL({
|
||||
pixelRatio: 2,
|
||||
excludeComponents: ['dataZoom'],
|
||||
}), `treasuries-pie-${Math.round(now.getTime() / 1000)}.svg`);
|
||||
this.chartOptions.backgroundColor = 'none';
|
||||
this.chartInstance.setOption(this.chartOptions);
|
||||
}
|
||||
|
||||
isEllipsisActive(e: HTMLElement): boolean {
|
||||
return (e.offsetWidth < e.scrollWidth);
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
<div class="container-xl dashboard-container">
|
||||
<div class="row">
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
@@ -12,7 +13,8 @@
|
||||
<th class="table-cell-value" i18n="dashboard.treasury-leaderboard.value">USD Value</th>
|
||||
</thead>
|
||||
<tbody *ngIf="walletStats$ | async as walletStats; else leaderboardSkeleton">
|
||||
<tr *ngFor="let wallet of sortedWallets$ | async; let i = index"
|
||||
<ng-container *ngIf="(sortedWallets$ | async) as sortedWallets">
|
||||
<tr *ngFor="let wallet of sortedWallets.slice(0, 7); let i = index"
|
||||
(click)="navigateToWallet(wallet)"
|
||||
class="clickable-row">
|
||||
<td class="table-cell-position">
|
||||
@@ -29,16 +31,36 @@
|
||||
<app-fiat [value]="walletStats[wallet]?.balance || 0" digitsInfo="1.0-0"></app-fiat>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body pl-2 pr-2">
|
||||
<h5 class="card-title" i18n="dashboard.treasury-distribution">Treasury Distribution</h5>
|
||||
<div *ngIf="walletStats$ | async as walletStats">
|
||||
<app-treasuries-pie
|
||||
[walletStats]="walletStats"
|
||||
[walletSummaries$]="walletSummaries$"
|
||||
[selectedWallets]="selectedWallets"
|
||||
[wallets]="currentSortedWallets"
|
||||
[height]="375"
|
||||
mode="relative"
|
||||
(navigateToWallet)="onNavigateToWallet($event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title" i18n="dashboard.balance-history">Balance History</h5>
|
||||
<div *ngIf="walletStats$ | async as walletStats">
|
||||
<app-treasuries-graph
|
||||
[walletStats]="walletStats"
|
||||
|
@@ -107,11 +107,13 @@
|
||||
}
|
||||
.table-cell-position {
|
||||
width: 10%;
|
||||
min-width: 50px;
|
||||
text-align: center;
|
||||
.position-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 40px;
|
||||
.color-swatch {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@@ -124,7 +126,7 @@
|
||||
}
|
||||
}
|
||||
.table-cell-name {
|
||||
width: 40%;
|
||||
width: 25%;
|
||||
text-align: left;
|
||||
}
|
||||
.table-cell-balance {
|
||||
@@ -135,6 +137,12 @@
|
||||
width: 25%;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.table-cell-value {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.position-container {
|
||||
|
@@ -7,7 +7,7 @@ import { catchError, map, scan, shareReplay, startWith, switchMap, tap } from 'r
|
||||
import { WalletStats } from '@app/shared/wallet-stats';
|
||||
import { ElectrsApiService } from '@app/services/electrs-api.service';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { chartColors } from '@app/app.constants';
|
||||
@Component({
|
||||
selector: 'app-treasuries',
|
||||
templateUrl: './treasuries.component.html',
|
||||
@@ -270,12 +270,12 @@ export class TreasuriesComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
getWalletColor(wallet: string): string {
|
||||
// Use a consistent color for each wallet based on its position in the sorted list
|
||||
const colors = [
|
||||
'#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40',
|
||||
];
|
||||
const index = this.currentSortedWallets.indexOf(wallet);
|
||||
return colors[index % colors.length];
|
||||
return chartColors[index % chartColors.length];
|
||||
}
|
||||
|
||||
onNavigateToWallet(wallet: string): void {
|
||||
this.navigateToWallet(wallet);
|
||||
}
|
||||
|
||||
navigateToWallet(wallet: string): void {
|
||||
|
@@ -39,6 +39,7 @@ 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 { TreasuriesGraphComponent } from '@components/treasuries/treasuries-graph/treasuries-graph.component';
|
||||
import { TreasuriesPieComponent } from '@components/treasuries/treasuries-pie/treasuries-pie.component';
|
||||
import { UtxoGraphComponent } from '@components/utxo-graph/utxo-graph.component';
|
||||
import { ActiveAccelerationBox } from '@components/acceleration/active-acceleration-box/active-acceleration-box.component';
|
||||
import { AddressesTreemap } from '@components/addresses-treemap/addresses-treemap.component';
|
||||
@@ -85,6 +86,7 @@ import { AsmStylerPipe } from '@app/shared/pipes/asm-styler/asm-styler.pipe';
|
||||
BlockHealthGraphComponent,
|
||||
AddressGraphComponent,
|
||||
TreasuriesGraphComponent,
|
||||
TreasuriesPieComponent,
|
||||
UtxoGraphComponent,
|
||||
ActiveAccelerationBox,
|
||||
AddressesTreemap,
|
||||
|
Reference in New Issue
Block a user