mirror of
https://github.com/mempool/mempool.git
synced 2025-02-24 14:50:52 +01:00
Merge pull request #4526 from mempool/mononaut/mined-goggles
Mined Goggles
This commit is contained in:
commit
2faca121d3
12 changed files with 92 additions and 31 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import { IBitcoinApi } from './bitcoin-api.interface';
|
||||||
import { IEsploraApi } from './esplora-api.interface';
|
import { IEsploraApi } from './esplora-api.interface';
|
||||||
|
|
||||||
export interface AbstractBitcoinApi {
|
export interface AbstractBitcoinApi {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import config from '../config';
|
||||||
import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
|
import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import memPool from './mempool';
|
import memPool from './mempool';
|
||||||
import { BlockExtended, BlockExtension, BlockSummary, PoolTag, TransactionExtended, TransactionStripped, TransactionMinerInfo, CpfpSummary, MempoolTransactionExtended } from '../mempool.interfaces';
|
import { BlockExtended, BlockExtension, BlockSummary, PoolTag, TransactionExtended, TransactionMinerInfo, CpfpSummary, MempoolTransactionExtended, TransactionClassified } from '../mempool.interfaces';
|
||||||
import { Common } from './common';
|
import { Common } from './common';
|
||||||
import diskCache from './disk-cache';
|
import diskCache from './disk-cache';
|
||||||
import transactionUtils from './transaction-utils';
|
import transactionUtils from './transaction-utils';
|
||||||
|
@ -201,7 +201,8 @@ class Blocks {
|
||||||
txid: tx.txid,
|
txid: tx.txid,
|
||||||
vsize: tx.weight / 4,
|
vsize: tx.weight / 4,
|
||||||
fee: tx.fee ? Math.round(tx.fee * 100000000) : 0,
|
fee: tx.fee ? Math.round(tx.fee * 100000000) : 0,
|
||||||
value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0) * 100000000)
|
value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0) * 100000000),
|
||||||
|
flags: 0,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -214,7 +215,7 @@ class Blocks {
|
||||||
public summarizeBlockTransactions(hash: string, transactions: TransactionExtended[]): BlockSummary {
|
public summarizeBlockTransactions(hash: string, transactions: TransactionExtended[]): BlockSummary {
|
||||||
return {
|
return {
|
||||||
id: hash,
|
id: hash,
|
||||||
transactions: Common.stripTransactions(transactions),
|
transactions: Common.classifyTransactions(transactions),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,7 +946,7 @@ class Blocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false,
|
public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false,
|
||||||
skipDBLookup = false, cpfpSummary?: CpfpSummary, blockHeight?: number): Promise<TransactionStripped[]>
|
skipDBLookup = false, cpfpSummary?: CpfpSummary, blockHeight?: number): Promise<TransactionClassified[]>
|
||||||
{
|
{
|
||||||
if (skipMemoryCache === false) {
|
if (skipMemoryCache === false) {
|
||||||
// Check the memory cache
|
// Check the memory cache
|
||||||
|
@ -974,7 +975,8 @@ class Blocks {
|
||||||
fee: tx.fee || 0,
|
fee: tx.fee || 0,
|
||||||
vsize: tx.vsize,
|
vsize: tx.vsize,
|
||||||
value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0)),
|
value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0)),
|
||||||
rate: tx.effectiveFeePerVsize
|
rate: tx.effectiveFeePerVsize,
|
||||||
|
flags: tx.flags || Common.getTransactionFlags(tx),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import * as bitcoinjs from 'bitcoinjs-lib';
|
import * as bitcoinjs from 'bitcoinjs-lib';
|
||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
import { Ancestor, CpfpInfo, CpfpSummary, CpfpCluster, EffectiveFeeStats, MempoolBlockWithTransactions, TransactionExtended, MempoolTransactionExtended, TransactionStripped, WorkingEffectiveFeeStats, TransactionClassified, TransactionFlags } from '../mempool.interfaces';
|
import { CpfpInfo, CpfpSummary, CpfpCluster, EffectiveFeeStats, MempoolBlockWithTransactions, TransactionExtended, MempoolTransactionExtended, TransactionStripped, WorkingEffectiveFeeStats, TransactionClassified, TransactionFlags } from '../mempool.interfaces';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { NodeSocket } from '../repositories/NodesSocketsRepository';
|
import { NodeSocket } from '../repositories/NodesSocketsRepository';
|
||||||
import { isIP } from 'net';
|
import { isIP } from 'net';
|
||||||
import rbfCache from './rbf-cache';
|
|
||||||
import transactionUtils from './transaction-utils';
|
import transactionUtils from './transaction-utils';
|
||||||
import { isPoint } from '../utils/secp256k1';
|
import { isPoint } from '../utils/secp256k1';
|
||||||
export class Common {
|
export class Common {
|
||||||
|
@ -349,14 +348,18 @@ export class Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
static classifyTransaction(tx: TransactionExtended): TransactionClassified {
|
static classifyTransaction(tx: TransactionExtended): TransactionClassified {
|
||||||
const flags = this.getTransactionFlags(tx);
|
const flags = Common.getTransactionFlags(tx);
|
||||||
tx.flags = flags;
|
tx.flags = flags;
|
||||||
return {
|
return {
|
||||||
...this.stripTransaction(tx),
|
...Common.stripTransaction(tx),
|
||||||
flags,
|
flags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static classifyTransactions(txs: TransactionExtended[]): TransactionClassified[] {
|
||||||
|
return txs.map(Common.classifyTransaction);
|
||||||
|
}
|
||||||
|
|
||||||
static stripTransaction(tx: TransactionExtended): TransactionStripped {
|
static stripTransaction(tx: TransactionExtended): TransactionStripped {
|
||||||
return {
|
return {
|
||||||
txid: tx.txid,
|
txid: tx.txid,
|
||||||
|
@ -369,7 +372,7 @@ export class Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
static stripTransactions(txs: TransactionExtended[]): TransactionStripped[] {
|
static stripTransactions(txs: TransactionExtended[]): TransactionStripped[] {
|
||||||
return txs.map(this.stripTransaction);
|
return txs.map(Common.stripTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static sleep$(ms: number): Promise<void> {
|
static sleep$(ms: number): Promise<void> {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { GbtGenerator, GbtResult, ThreadTransaction as RustThreadTransaction, ThreadAcceleration as RustThreadAcceleration } from 'rust-gbt';
|
import { GbtGenerator, GbtResult, ThreadTransaction as RustThreadTransaction, ThreadAcceleration as RustThreadAcceleration } from 'rust-gbt';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { MempoolBlock, MempoolTransactionExtended, TransactionStripped, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction, EffectiveFeeStats, PoolTag, TransactionClassified } from '../mempool.interfaces';
|
import { MempoolBlock, MempoolTransactionExtended, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction, EffectiveFeeStats, PoolTag, TransactionClassified } from '../mempool.interfaces';
|
||||||
import { Common, OnlineFeeStatsCalculator } from './common';
|
import { Common, OnlineFeeStatsCalculator } from './common';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { Worker } from 'worker_threads';
|
import { Worker } from 'worker_threads';
|
||||||
|
|
|
@ -280,7 +280,7 @@ export interface BlockExtended extends IEsploraApi.Block {
|
||||||
|
|
||||||
export interface BlockSummary {
|
export interface BlockSummary {
|
||||||
id: string;
|
id: string;
|
||||||
transactions: TransactionStripped[];
|
transactions: TransactionClassified[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuditSummary extends BlockAudit {
|
export interface AuditSummary extends BlockAudit {
|
||||||
|
@ -288,8 +288,8 @@ export interface AuditSummary extends BlockAudit {
|
||||||
size?: number,
|
size?: number,
|
||||||
weight?: number,
|
weight?: number,
|
||||||
tx_count?: number,
|
tx_count?: number,
|
||||||
transactions: TransactionStripped[];
|
transactions: TransactionClassified[];
|
||||||
template?: TransactionStripped[];
|
template?: TransactionClassified[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockPrice {
|
export interface BlockPrice {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import DB from '../database';
|
import DB from '../database';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { BlockSummary, TransactionStripped } from '../mempool.interfaces';
|
import { BlockSummary, TransactionClassified } from '../mempool.interfaces';
|
||||||
|
|
||||||
class BlocksSummariesRepository {
|
class BlocksSummariesRepository {
|
||||||
public async $getByBlockId(id: string): Promise<BlockSummary | undefined> {
|
public async $getByBlockId(id: string): Promise<BlockSummary | undefined> {
|
||||||
|
@ -17,7 +17,7 @@ class BlocksSummariesRepository {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $saveTransactions(blockHeight: number, blockId: string, transactions: TransactionStripped[]): Promise<void> {
|
public async $saveTransactions(blockHeight: number, blockId: string, transactions: TransactionClassified[]): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const transactionsStr = JSON.stringify(transactions);
|
const transactionsStr = JSON.stringify(transactions);
|
||||||
await DB.query(`
|
await DB.query(`
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<h5>{{ group.label }}</h5>
|
<h5>{{ group.label }}</h5>
|
||||||
<div class="filter-group">
|
<div class="filter-group">
|
||||||
<ng-container *ngFor="let filter of group.filters;">
|
<ng-container *ngFor="let filter of group.filters;">
|
||||||
<button class="btn filter-tag" [class.selected]="filterFlags[filter.key]" (click)="toggleFilter(filter.key)">{{ filter.label }}</button>
|
<button *ngIf="!disabledFilters[filter.key]" class="btn filter-tag" [class.selected]="filterFlags[filter.key]" (click)="toggleFilter(filter.key)">{{ filter.label }}</button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { Component, EventEmitter, Output, HostListener, Input, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core';
|
import { Component, EventEmitter, Output, HostListener, Input, ChangeDetectorRef, OnChanges, SimpleChanges, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { FilterGroups, TransactionFilters } from '../../shared/filters.utils';
|
import { FilterGroups, TransactionFilters } from '../../shared/filters.utils';
|
||||||
|
import { StateService } from '../../services/state.service';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -7,24 +9,48 @@ import { FilterGroups, TransactionFilters } from '../../shared/filters.utils';
|
||||||
templateUrl: './block-filters.component.html',
|
templateUrl: './block-filters.component.html',
|
||||||
styleUrls: ['./block-filters.component.scss'],
|
styleUrls: ['./block-filters.component.scss'],
|
||||||
})
|
})
|
||||||
export class BlockFiltersComponent implements OnChanges {
|
export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
@Input() cssWidth: number = 800;
|
@Input() cssWidth: number = 800;
|
||||||
|
@Input() excludeFilters: string[] = [];
|
||||||
@Output() onFilterChanged: EventEmitter<bigint | null> = new EventEmitter();
|
@Output() onFilterChanged: EventEmitter<bigint | null> = new EventEmitter();
|
||||||
|
|
||||||
|
filterSubscription: Subscription;
|
||||||
|
|
||||||
filters = TransactionFilters;
|
filters = TransactionFilters;
|
||||||
filterGroups = FilterGroups;
|
filterGroups = FilterGroups;
|
||||||
|
disabledFilters: { [key: string]: boolean } = {};
|
||||||
activeFilters: string[] = [];
|
activeFilters: string[] = [];
|
||||||
filterFlags: { [key: string]: boolean } = {};
|
filterFlags: { [key: string]: boolean } = {};
|
||||||
menuOpen: boolean = false;
|
menuOpen: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private stateService: StateService,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.filterSubscription = this.stateService.activeGoggles$.subscribe((activeFilters: string[]) => {
|
||||||
|
for (const key of Object.keys(this.filterFlags)) {
|
||||||
|
this.filterFlags[key] = false;
|
||||||
|
}
|
||||||
|
for (const key of activeFilters) {
|
||||||
|
this.filterFlags[key] = !this.disabledFilters[key];
|
||||||
|
}
|
||||||
|
this.activeFilters = [...activeFilters.filter(key => !this.disabledFilters[key])];
|
||||||
|
this.onFilterChanged.emit(this.getBooleanFlags());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes.cssWidth) {
|
if (changes.cssWidth) {
|
||||||
this.cd.markForCheck();
|
this.cd.markForCheck();
|
||||||
}
|
}
|
||||||
|
if (changes.excludeFilters) {
|
||||||
|
this.disabledFilters = {};
|
||||||
|
this.excludeFilters.forEach(filter => {
|
||||||
|
this.disabledFilters[filter] = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFilter(key): void {
|
toggleFilter(key): void {
|
||||||
|
@ -46,7 +72,9 @@ export class BlockFiltersComponent implements OnChanges {
|
||||||
// remove active filter
|
// remove active filter
|
||||||
this.activeFilters = this.activeFilters.filter(f => f != key);
|
this.activeFilters = this.activeFilters.filter(f => f != key);
|
||||||
}
|
}
|
||||||
this.onFilterChanged.emit(this.getBooleanFlags());
|
const booleanFlags = this.getBooleanFlags();
|
||||||
|
this.onFilterChanged.emit(booleanFlags);
|
||||||
|
this.stateService.activeGoggles$.next([...this.activeFilters]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getBooleanFlags(): bigint | null {
|
getBooleanFlags(): bigint | null {
|
||||||
|
@ -67,4 +95,8 @@ export class BlockFiltersComponent implements OnChanges {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.filterSubscription.unsubscribe();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,6 @@
|
||||||
[auditEnabled]="auditHighlighting"
|
[auditEnabled]="auditHighlighting"
|
||||||
[blockConversion]="blockConversion"
|
[blockConversion]="blockConversion"
|
||||||
></app-block-overview-tooltip>
|
></app-block-overview-tooltip>
|
||||||
<app-block-filters *ngIf="showFilters" [cssWidth]="cssWidth" (onFilterChanged)="setFilterFlags($event)"></app-block-filters>
|
<app-block-filters *ngIf="showFilters && filtersAvailable" [excludeFilters]="excludeFilters" [cssWidth]="cssWidth" (onFilterChanged)="setFilterFlags($event)"></app-block-filters>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,6 +40,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
@Input() unavailable: boolean = false;
|
@Input() unavailable: boolean = false;
|
||||||
@Input() auditHighlighting: boolean = false;
|
@Input() auditHighlighting: boolean = false;
|
||||||
@Input() showFilters: boolean = false;
|
@Input() showFilters: boolean = false;
|
||||||
|
@Input() excludeFilters: string[] = [];
|
||||||
@Input() filterFlags: bigint | null = null;
|
@Input() filterFlags: bigint | null = null;
|
||||||
@Input() blockConversion: Price;
|
@Input() blockConversion: Price;
|
||||||
@Input() overrideColors: ((tx: TxView) => Color) | null = null;
|
@Input() overrideColors: ((tx: TxView) => Color) | null = null;
|
||||||
|
@ -71,6 +72,8 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
|
|
||||||
searchText: string;
|
searchText: string;
|
||||||
searchSubscription: Subscription;
|
searchSubscription: Subscription;
|
||||||
|
filtersAvailable: boolean = true;
|
||||||
|
activeFilterFlags: bigint | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly ngZone: NgZone,
|
readonly ngZone: NgZone,
|
||||||
|
@ -110,16 +113,19 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
if (changes.overrideColor && this.scene) {
|
if (changes.overrideColor && this.scene) {
|
||||||
this.scene.setColorFunction(this.overrideColors);
|
this.scene.setColorFunction(this.overrideColors);
|
||||||
}
|
}
|
||||||
if ((changes.filterFlags || changes.showFilters) && this.scene) {
|
if ((changes.filterFlags || changes.showFilters)) {
|
||||||
this.setFilterFlags(this.filterFlags);
|
this.setFilterFlags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFilterFlags(flags: bigint | null): void {
|
setFilterFlags(flags?: bigint | null): void {
|
||||||
if (flags != null) {
|
this.activeFilterFlags = this.filterFlags || flags || null;
|
||||||
this.scene.setColorFunction(this.getFilterColorFunction(flags));
|
if (this.scene) {
|
||||||
} else {
|
if (flags != null) {
|
||||||
this.scene.setColorFunction(this.overrideColors);
|
this.scene.setColorFunction(this.getFilterColorFunction(flags));
|
||||||
|
} else {
|
||||||
|
this.scene.setColorFunction(this.overrideColors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
|
@ -150,6 +156,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
|
|
||||||
// initialize the scene without any entry transition
|
// initialize the scene without any entry transition
|
||||||
setup(transactions: TransactionStripped[]): void {
|
setup(transactions: TransactionStripped[]): void {
|
||||||
|
this.filtersAvailable = transactions.reduce((flagSet, tx) => flagSet || tx.flags > 0, false);
|
||||||
if (this.scene) {
|
if (this.scene) {
|
||||||
this.scene.setup(transactions);
|
this.scene.setup(transactions);
|
||||||
this.readyNextFrame = true;
|
this.readyNextFrame = true;
|
||||||
|
@ -260,7 +267,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,
|
this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution,
|
||||||
blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray,
|
blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray,
|
||||||
highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset,
|
highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset,
|
||||||
colorFunction: this.overrideColors });
|
colorFunction: this.getColorFunction() });
|
||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -504,6 +511,16 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||||
this.txHoverEvent.emit(hoverId);
|
this.txHoverEvent.emit(hoverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getColorFunction(): ((tx: TxView) => Color) {
|
||||||
|
if (this.filterFlags) {
|
||||||
|
return this.getFilterColorFunction(this.filterFlags);
|
||||||
|
} else if (this.activeFilterFlags) {
|
||||||
|
return this.getFilterColorFunction(this.activeFilterFlags);
|
||||||
|
} else {
|
||||||
|
return this.overrideColors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getFilterColorFunction(flags: bigint): ((tx: TxView) => Color) {
|
getFilterColorFunction(flags: bigint): ((tx: TxView) => Color) {
|
||||||
return (tx: TxView) => {
|
return (tx: TxView) => {
|
||||||
if ((tx.bigintFlags & flags) === flags) {
|
if ((tx.bigintFlags & flags) === flags) {
|
||||||
|
|
|
@ -115,6 +115,8 @@
|
||||||
[orientation]="'top'"
|
[orientation]="'top'"
|
||||||
[flip]="false"
|
[flip]="false"
|
||||||
[blockConversion]="blockConversion"
|
[blockConversion]="blockConversion"
|
||||||
|
[showFilters]="true"
|
||||||
|
[excludeFilters]="['replacement']"
|
||||||
(txClickEvent)="onTxClick($event)"
|
(txClickEvent)="onTxClick($event)"
|
||||||
></app-block-overview-graph>
|
></app-block-overview-graph>
|
||||||
<ng-container *ngTemplateOutlet="emptyBlockInfo"></ng-container>
|
<ng-container *ngTemplateOutlet="emptyBlockInfo"></ng-container>
|
||||||
|
@ -229,7 +231,8 @@
|
||||||
<div class="block-graph-wrapper">
|
<div class="block-graph-wrapper">
|
||||||
<app-block-overview-graph #blockGraphProjected [isLoading]="isLoadingOverview" [resolution]="86"
|
<app-block-overview-graph #blockGraphProjected [isLoading]="isLoadingOverview" [resolution]="86"
|
||||||
[blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" [auditHighlighting]="showAudit"
|
[blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" [auditHighlighting]="showAudit"
|
||||||
(txClickEvent)="onTxClick($event)" (txHoverEvent)="onTxHover($event)" [unavailable]="!isMobile && !showAudit"></app-block-overview-graph>
|
(txClickEvent)="onTxClick($event)" (txHoverEvent)="onTxHover($event)" [unavailable]="!isMobile && !showAudit"
|
||||||
|
[showFilters]="true" [excludeFilters]="['replacement']"></app-block-overview-graph>
|
||||||
<ng-container *ngIf="!isMobile || mode !== 'actual'; else emptyBlockInfo"></ng-container>
|
<ng-container *ngIf="!isMobile || mode !== 'actual'; else emptyBlockInfo"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="network !== 'liquid'">
|
<ng-container *ngIf="network !== 'liquid'">
|
||||||
|
@ -243,7 +246,8 @@
|
||||||
<div class="block-graph-wrapper">
|
<div class="block-graph-wrapper">
|
||||||
<app-block-overview-graph #blockGraphActual [isLoading]="isLoadingOverview" [resolution]="86"
|
<app-block-overview-graph #blockGraphActual [isLoading]="isLoadingOverview" [resolution]="86"
|
||||||
[blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" mode="mined" [auditHighlighting]="showAudit"
|
[blockLimit]="stateService.blockVSize" [orientation]="'top'" [flip]="false" [mirrorTxid]="hoverTx" mode="mined" [auditHighlighting]="showAudit"
|
||||||
(txClickEvent)="onTxClick($event)" (txHoverEvent)="onTxHover($event)" [unavailable]="isMobile && !showAudit"></app-block-overview-graph>
|
(txClickEvent)="onTxClick($event)" (txHoverEvent)="onTxHover($event)" [unavailable]="isMobile && !showAudit"
|
||||||
|
[showFilters]="true" [excludeFilters]="['replacement']"></app-block-overview-graph>
|
||||||
<ng-container *ngTemplateOutlet="emptyBlockInfo"></ng-container>
|
<ng-container *ngTemplateOutlet="emptyBlockInfo"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
<ng-container *ngIf="network !== 'liquid'">
|
<ng-container *ngIf="network !== 'liquid'">
|
||||||
|
|
|
@ -150,6 +150,8 @@ export class StateService {
|
||||||
searchFocus$: Subject<boolean> = new Subject<boolean>();
|
searchFocus$: Subject<boolean> = new Subject<boolean>();
|
||||||
menuOpen$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
menuOpen$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||||
|
|
||||||
|
activeGoggles$: BehaviorSubject<string[]> = new BehaviorSubject([]);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(PLATFORM_ID) private platformId: any,
|
@Inject(PLATFORM_ID) private platformId: any,
|
||||||
@Inject(LOCALE_ID) private locale: string,
|
@Inject(LOCALE_ID) private locale: string,
|
||||||
|
|
Loading…
Add table
Reference in a new issue