diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html
index 5b35fc7b1..dcd59a1f8 100644
--- a/frontend/src/app/components/transaction/transaction.component.html
+++ b/frontend/src/app/components/transaction/transaction.component.html
@@ -208,7 +208,10 @@
[lineLimit]="inOutLimit"
[maxStrands]="graphExpanded ? maxInOut : 24"
[network]="network"
- [tooltip]="true">
+ [tooltip]="true"
+ (selectInput)="selectInput($event)"
+ (selectOutput)="selectOutput($event)"
+ >
Details
diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts
index 1db6e8f09..8aa313c81 100644
--- a/frontend/src/app/components/transaction/transaction.component.ts
+++ b/frontend/src/app/components/transaction/transaction.component.ts
@@ -47,6 +47,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
now = new Date().getTime();
timeAvg$: Observable
;
liquidUnblinding = new LiquidUnblinding();
+ inputIndex: number;
outputIndex: number;
showFlow: boolean = true;
graphExpanded: boolean = false;
@@ -334,6 +335,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.graphExpanded = false;
}
+ selectInput(input) {
+ this.inputIndex = input;
+ this.outputIndex = null;
+ }
+
+ selectOutput(output) {
+ this.outputIndex = output;
+ this.inputIndex = null;
+ }
+
@HostListener('window:resize', ['$event'])
setGraphSize(): void {
if (this.graphContainer) {
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html
index 81c3dce5c..e26740aa5 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.html
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.html
@@ -20,9 +20,9 @@
- rowLimit) ? tx.vin.slice(0, rowLimit - 2) : tx.vin.slice(0, rowLimit)) : tx.vin" [ngForTrackBy]="trackByIndexFn">
+ inputRowLimit) ? tx.vin.slice(0, inputRowLimit - 2) : tx.vin.slice(0, inputRowLimit)) : tx.vin" [ngForTrackBy]="trackByIndexFn">
@@ -146,7 +146,7 @@
|
- rowLimit && tx['@vinLimit']">
+
inputRowLimit && tx['@vinLimit']">
|
@@ -158,7 +158,7 @@
- rowLimit) ? tx.vout.slice(0, rowLimit - 2) : tx.vout.slice(0, rowLimit)) : tx.vout" [ngForTrackBy]="trackByIndexFn">
+ outputRowLimit) ? tx.vout.slice(0, outputRowLimit - 2) : tx.vout.slice(0, outputRowLimit)) : tx.vout" [ngForTrackBy]="trackByIndexFn">
- rowLimit && tx['@voutLimit'] && !outputIndex">
+
outputRowLimit && tx['@voutLimit']">
|
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts
index 8fd81af51..03c2d59ee 100644
--- a/frontend/src/app/components/transactions-list/transactions-list.component.ts
+++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts
@@ -24,6 +24,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
@Input() transactionPage = false;
@Input() errorUnblinded = false;
@Input() paginated = false;
+ @Input() inputIndex: number;
@Input() outputIndex: number;
@Input() address: string = '';
@Input() rowLimit = 12;
@@ -37,6 +38,8 @@ export class TransactionsListComponent implements OnInit, OnChanges {
showDetails$ = new BehaviorSubject(false);
assetsMinimal: any;
transactionsLength: number = 0;
+ inputRowLimit: number = 12;
+ outputRowLimit: number = 12;
constructor(
public stateService: StateService,
@@ -97,50 +100,57 @@ export class TransactionsListComponent implements OnInit, OnChanges {
).subscribe(() => this.ref.markForCheck());
}
- ngOnChanges(): void {
- if (!this.transactions || !this.transactions.length) {
- return;
+ ngOnChanges(changes): void {
+ if (changes.inputIndex || changes.outputIndex || changes.rowLimit) {
+ this.inputRowLimit = Math.max(this.rowLimit, (this.inputIndex || 0) + 3);
+ this.outputRowLimit = Math.max(this.rowLimit, (this.outputIndex || 0) + 3);
+ if (this.inputIndex || this.outputIndex) {
+ setTimeout(() => {
+ const assetBoxElements = document.getElementsByClassName('assetBox');
+ if (assetBoxElements && assetBoxElements[0]) {
+ assetBoxElements[0].scrollIntoView({block: "center"});
+ }
+ }, 10);
+ }
}
-
- this.transactionsLength = this.transactions.length;
- if (this.outputIndex) {
- setTimeout(() => {
- const assetBoxElements = document.getElementsByClassName('assetBox');
- if (assetBoxElements && assetBoxElements[0]) {
- assetBoxElements[0].scrollIntoView();
- }
- }, 10);
- }
-
- this.transactions.forEach((tx) => {
- tx['@voutLimit'] = true;
- tx['@vinLimit'] = true;
- if (tx['addressValue'] !== undefined) {
+ if (changes.transactions || changes.address) {
+ if (!this.transactions || !this.transactions.length) {
return;
}
- if (this.address) {
- const addressIn = tx.vout
- .filter((v: Vout) => v.scriptpubkey_address === this.address)
- .map((v: Vout) => v.value || 0)
- .reduce((a: number, b: number) => a + b, 0);
+ this.transactionsLength = this.transactions.length;
- const addressOut = tx.vin
- .filter((v: Vin) => v.prevout && v.prevout.scriptpubkey_address === this.address)
- .map((v: Vin) => v.prevout.value || 0)
- .reduce((a: number, b: number) => a + b, 0);
- tx['addressValue'] = addressIn - addressOut;
- }
- });
- const txIds = this.transactions.filter((tx) => !tx._outspends).map((tx) => tx.txid);
- if (txIds.length) {
- this.refreshOutspends$.next(txIds);
- }
- if (this.stateService.env.LIGHTNING) {
- const txIds = this.transactions.filter((tx) => !tx._channels).map((tx) => tx.txid);
+ this.transactions.forEach((tx) => {
+ tx['@voutLimit'] = true;
+ tx['@vinLimit'] = true;
+ if (tx['addressValue'] !== undefined) {
+ return;
+ }
+
+ if (this.address) {
+ const addressIn = tx.vout
+ .filter((v: Vout) => v.scriptpubkey_address === this.address)
+ .map((v: Vout) => v.value || 0)
+ .reduce((a: number, b: number) => a + b, 0);
+
+ const addressOut = tx.vin
+ .filter((v: Vin) => v.prevout && v.prevout.scriptpubkey_address === this.address)
+ .map((v: Vin) => v.prevout.value || 0)
+ .reduce((a: number, b: number) => a + b, 0);
+
+ tx['addressValue'] = addressIn - addressOut;
+ }
+ });
+ const txIds = this.transactions.filter((tx) => !tx._outspends).map((tx) => tx.txid);
if (txIds.length) {
- this.refreshChannels$.next(txIds);
+ this.refreshOutspends$.next(txIds);
+ }
+ if (this.stateService.env.LIGHTNING) {
+ const txIds = this.transactions.filter((tx) => !tx._channels).map((tx) => tx.txid);
+ if (txIds.length) {
+ this.refreshChannels$.next(txIds);
+ }
}
}
}
diff --git a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html
index 563e6ed00..6872438a0 100644
--- a/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html
+++ b/frontend/src/app/components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component.html
@@ -44,7 +44,7 @@
Output
Fee
- #{{ line.index }}
+ #{{ line.index + 1 }}
Confidential
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html
index 03056cd53..3f0143a67 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.html
@@ -60,6 +60,7 @@
attr.marker-start="url(#{{input.class}}-arrow)"
(pointerover)="onHover($event, 'input', i);"
(pointerout)="onBlur($event, 'input', i);"
+ (click)="onClick($event, 'input', inputData[i].index);"
/>
@@ -70,6 +71,7 @@
attr.marker-start="url(#{{output.class}}-arrow)"
(pointerover)="onHover($event, 'output', i);"
(pointerout)="onBlur($event, 'output', i);"
+ (click)="onClick($event, 'output', outputData[i].index);"
/>
diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
index 16e2736f7..592232955 100644
--- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
+++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, Input, OnChanges, HostListener } from '@angular/core';
+import { Component, OnInit, Input, Output, EventEmitter, OnChanges, HostListener } from '@angular/core';
import { Transaction } from '../../interfaces/electrs.interface';
interface SvgLine {
@@ -35,6 +35,9 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
@Input() maxStrands = 24; // number of inputs/outputs to keep fully on-screen.
@Input() tooltip = false;
+ @Output() selectInput = new EventEmitter();
+ @Output() selectOutput = new EventEmitter();
+
inputData: Xput[];
outputData: Xput[];
inputs: SvgLine[];
@@ -76,11 +79,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
this.combinedWeight = Math.min(this.maxCombinedWeight, Math.floor((this.width - (2 * this.midWidth)) / 6));
const totalValue = this.calcTotalValue(this.tx);
- let voutWithFee = this.tx.vout.map(v => {
+ let voutWithFee = this.tx.vout.map((v, i) => {
return {
type: v.scriptpubkey_type === 'fee' ? 'fee' : 'output',
value: v?.value,
address: v?.scriptpubkey_address || v?.scriptpubkey_type?.toUpperCase(),
+ index: i,
pegout: v?.pegout?.scriptpubkey_address,
confidential: (this.isLiquid && v?.value === undefined),
} as Xput;
@@ -91,11 +95,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
}
const outputCount = voutWithFee.length;
- let truncatedInputs = this.tx.vin.map(v => {
+ let truncatedInputs = this.tx.vin.map((v, i) => {
return {
type: 'input',
value: v?.prevout?.value,
address: v?.prevout?.scriptpubkey_address || v?.prevout?.scriptpubkey_type?.toUpperCase(),
+ index: i,
coinbase: v?.is_coinbase,
pegin: v?.is_pegin,
confidential: (this.isLiquid && v?.prevout?.value === undefined),
@@ -306,8 +311,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
};
} else {
this.hoverLine = {
- ...this.outputData[index],
- index
+ ...this.outputData[index]
};
}
}
@@ -315,4 +319,12 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
onBlur(event, side, index): void {
this.hoverLine = null;
}
+
+ onClick(event, side, index): void {
+ if (side === 'input') {
+ this.selectInput.emit(index);
+ } else {
+ this.selectOutput.emit(index);
+ }
+ }
}