Bisq: Feature to filter transaction types.
This commit is contained in:
		
							parent
							
								
									d72075a51f
								
							
						
					
					
						commit
						91594f0df6
					
				@ -39,8 +39,12 @@ class Bisq {
 | 
			
		||||
    return this.transactionIndex[txId];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTransactions(start: number, length: number): [BisqTransaction[], number] {
 | 
			
		||||
    return [this.transactions.slice(start, length + start), this.transactions.length];
 | 
			
		||||
  getTransactions(start: number, length: number, types: string[]): [BisqTransaction[], number] {
 | 
			
		||||
    let transactions = this.transactions;
 | 
			
		||||
    if (types.length) {
 | 
			
		||||
      transactions = transactions.filter((tx) => types.indexOf(tx.txType) > -1);
 | 
			
		||||
    }
 | 
			
		||||
    return [transactions.slice(start, length + start), transactions.length];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock(hash: string): BisqBlock | undefined {
 | 
			
		||||
 | 
			
		||||
@ -108,9 +108,21 @@ class Routes {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public getBisqTransactions(req: Request, res: Response) {
 | 
			
		||||
    const types: string[] = [];
 | 
			
		||||
    if (req.query.types && !Array.isArray(req.query.types)) {
 | 
			
		||||
      res.status(500).send('Types is not an array');
 | 
			
		||||
      return;
 | 
			
		||||
    } else {
 | 
			
		||||
      for (const _type in req.query.types) {
 | 
			
		||||
        if (typeof req.query.types[_type] === 'string') {
 | 
			
		||||
          types.push(req.query.types[_type].toString());
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const index = parseInt(req.params.index, 10) || 0;
 | 
			
		||||
    const length = parseInt(req.params.length, 10) > 100 ? 100 : parseInt(req.params.length, 10) || 25;
 | 
			
		||||
    const [transactions, count] = bisq.getTransactions(index, length);
 | 
			
		||||
    const [transactions, count] = bisq.getTransactions(index, length, types);
 | 
			
		||||
    res.header('X-Total-Count', count.toString());
 | 
			
		||||
    res.json(transactions);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,7 @@
 | 
			
		||||
import { BrowserModule } from '@angular/platform-browser';
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { HttpClientModule } from '@angular/common/http';
 | 
			
		||||
import { ReactiveFormsModule } from '@angular/forms';
 | 
			
		||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 | 
			
		||||
import { NgbButtonsModule, NgbPaginationModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
 | 
			
		||||
 | 
			
		||||
import { AppRoutingModule } from './app-routing.module';
 | 
			
		||||
@ -76,11 +74,7 @@ import { SharedModule } from './shared/shared.module';
 | 
			
		||||
    BrowserModule,
 | 
			
		||||
    AppRoutingModule,
 | 
			
		||||
    HttpClientModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
    BrowserAnimationsModule,
 | 
			
		||||
    NgbButtonsModule,
 | 
			
		||||
    NgbPaginationModule,
 | 
			
		||||
    NgbDropdownModule,
 | 
			
		||||
    InfiniteScrollModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient, HttpResponse } from '@angular/common/http';
 | 
			
		||||
import { HttpClient, HttpResponse, HttpParams } from '@angular/common/http';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { BisqTransaction, BisqBlock, BisqStats } from './bisq.interfaces';
 | 
			
		||||
 | 
			
		||||
@ -23,8 +23,12 @@ export class BisqApiService {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction>(API_BASE_URL + '/tx/' + txId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listTransactions$(start: number, length: number): Observable<HttpResponse<BisqTransaction[]>> {
 | 
			
		||||
    return this.httpClient.get<BisqTransaction[]>(API_BASE_URL + `/txs/${start}/${length}`, { observe: 'response' });
 | 
			
		||||
  listTransactions$(start: number, length: number, types: string[]): Observable<HttpResponse<BisqTransaction[]>> {
 | 
			
		||||
    let params = new HttpParams();
 | 
			
		||||
    types.forEach((t: string) => {
 | 
			
		||||
      params = params.append('types[]', t);
 | 
			
		||||
    });
 | 
			
		||||
    return this.httpClient.get<BisqTransaction[]>(API_BASE_URL + `/txs/${start}/${length}`, { params, observe: 'response' });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock$(hash: string): Observable<BisqBlock> {
 | 
			
		||||
 | 
			
		||||
@ -1,38 +1,94 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
  <h1 style="float: left;">Transactions</h1>
 | 
			
		||||
 | 
			
		||||
  <div ngbDropdown class="d-block float-right">
 | 
			
		||||
    <button class="btn btn-primary" id="dropdownForm1" ngbDropdownToggle>Filter</button>
 | 
			
		||||
    <div ngbDropdownMenu aria-labelledby="dropdownForm1">
 | 
			
		||||
      <form [formGroup]="radioGroupForm">
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="GENESIS"> Genesis
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="TRANSFER_BSQ"> Transfer BSQ
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="PAY_TRADE_FEE"> Pay trade fee
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="PROPOSAL"> Proposal
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="COMPENSATION_REQUEST"> Compensation request
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="REIMBURSEMENT_REQUEST"> Reimbursement request
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="BLIND_VOTE"> Blind vote
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="VOTE_REVEAL"> Vote reveal
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="LOCKUP"> Lockup
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="UNLOCK"> Unlock
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="ASSET_LISTING_FEE"> Asset listing fee
 | 
			
		||||
        </label>
 | 
			
		||||
        <br>
 | 
			
		||||
        <label>
 | 
			
		||||
          <input type="checkbox" formControlName="PROOF_OF_BURN"> Proof of burn
 | 
			
		||||
        </label>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <table class="table table-borderless table-striped">
 | 
			
		||||
      <thead>
 | 
			
		||||
        <th style="width: 20%;">Transaction</th>
 | 
			
		||||
        <th class="d-none d-md-block" style="width: 20%;">Type</th>
 | 
			
		||||
        <th style="width: 20%;">Amount</th>
 | 
			
		||||
        <th style="width: 20%;">Confirmed</th>
 | 
			
		||||
        <th class="d-none d-md-block" style="width: 20%;">Height</th>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody *ngIf="!isLoading; else loadingTmpl">
 | 
			
		||||
        <tr *ngFor="let tx of transactions; trackBy: trackByFn">
 | 
			
		||||
          <td><a [routerLink]="['/tx/' | relativeUrl, tx.id]" [state]="{ data: tx }">{{ tx.id | slice : 0 : 8 }}</a></td>
 | 
			
		||||
          <td class="d-none d-md-block">
 | 
			
		||||
            <app-bisq-icon class="mr-1" [txType]="tx.txType"></app-bisq-icon>
 | 
			
		||||
            <span class="d-none d-md-inline"> {{ tx.txTypeDisplayString }}</span>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <app-bisq-icon class="d-inline d-md-none mr-1" [txType]="tx.txType"></app-bisq-icon>
 | 
			
		||||
            <ng-template [ngIf]="tx.txType === 'PAY_TRADE_FEE'" [ngIfElse]="defaultTxType">
 | 
			
		||||
              {{ tx.burntFee / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
            <ng-template #defaultTxType>
 | 
			
		||||
              {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td><app-time-since [time]="tx.time / 1000" [fastRender]="true"></app-time-since> ago</td>
 | 
			
		||||
          <td class="d-none d-md-block"><a [routerLink]="['/block/' | relativeUrl, tx.blockHash]" [state]="{ data: { blockHeight: tx.blockHeight } }">{{ tx.blockHeight }}</a></td>
 | 
			
		||||
        </tr> 
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
  <table class="table table-borderless table-striped">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <th style="width: 20%;">Transaction</th>
 | 
			
		||||
      <th class="d-none d-md-block" style="width: 20%;">Type</th>
 | 
			
		||||
      <th style="width: 20%;">Amount</th>
 | 
			
		||||
      <th style="width: 20%;">Confirmed</th>
 | 
			
		||||
      <th class="d-none d-md-block" style="width: 20%;">Height</th>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody *ngIf="!isLoading; else loadingTmpl">
 | 
			
		||||
      <tr *ngFor="let tx of transactions; trackBy: trackByFn">
 | 
			
		||||
        <td><a [routerLink]="['/tx/' | relativeUrl, tx.id]" [state]="{ data: tx }">{{ tx.id | slice : 0 : 8 }}</a></td>
 | 
			
		||||
        <td class="d-none d-md-block">
 | 
			
		||||
          <app-bisq-icon class="mr-1" [txType]="tx.txType"></app-bisq-icon>
 | 
			
		||||
          <span class="d-none d-md-inline"> {{ tx.txTypeDisplayString }}</span>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <app-bisq-icon class="d-inline d-md-none mr-1" [txType]="tx.txType"></app-bisq-icon>
 | 
			
		||||
          <ng-template [ngIf]="tx.txType === 'PAY_TRADE_FEE'" [ngIfElse]="defaultTxType">
 | 
			
		||||
            {{ tx.burntFee / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
          <ng-template #defaultTxType>
 | 
			
		||||
            {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }}<span class="d-none d-md-inline"> BSQ</span>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td><app-time-since [time]="tx.time / 1000" [fastRender]="true"></app-time-since> ago</td>
 | 
			
		||||
        <td class="d-none d-md-block"><a [routerLink]="['/block/' | relativeUrl, tx.blockHash]" [state]="{ data: { blockHeight: tx.blockHeight } }">{{ tx.blockHeight }}</a></td>
 | 
			
		||||
      </tr> 
 | 
			
		||||
    </tbody>
 | 
			
		||||
  </table>
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,4 @@
 | 
			
		||||
label {
 | 
			
		||||
  padding: 0.25rem 1rem;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { BisqTransaction, BisqOutput } from '../bisq.interfaces';
 | 
			
		||||
import { Subject } from 'rxjs';
 | 
			
		||||
import { switchMap, tap } from 'rxjs/operators';
 | 
			
		||||
import { Subject, merge } from 'rxjs';
 | 
			
		||||
import { switchMap, tap, map } from 'rxjs/operators';
 | 
			
		||||
import { BisqApiService } from '../bisq-api.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { FormGroup, FormBuilder } from '@angular/forms';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-bisq-transactions',
 | 
			
		||||
@ -20,6 +21,8 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
  isLoading = true;
 | 
			
		||||
  loadingItems: number[];
 | 
			
		||||
  pageSubject$ = new Subject<number>();
 | 
			
		||||
  radioGroupForm: FormGroup;
 | 
			
		||||
  types: string[] = [];
 | 
			
		||||
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  paginationSize: 'sm' | 'lg' = 'md';
 | 
			
		||||
@ -28,11 +31,29 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private bisqApiService: BisqApiService,
 | 
			
		||||
    private seoService: SeoService,
 | 
			
		||||
    private formBuilder: FormBuilder,
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.seoService.setTitle('Transactions', true);
 | 
			
		||||
 | 
			
		||||
    this.radioGroupForm = this.formBuilder.group({
 | 
			
		||||
      UNVERIFIED: false,
 | 
			
		||||
      INVALID: false,
 | 
			
		||||
      GENESIS: false,
 | 
			
		||||
      TRANSFER_BSQ: false,
 | 
			
		||||
      PAY_TRADE_FEE: false,
 | 
			
		||||
      PROPOSAL: false,
 | 
			
		||||
      COMPENSATION_REQUEST: false,
 | 
			
		||||
      REIMBURSEMENT_REQUEST: false,
 | 
			
		||||
      BLIND_VOTE: false,
 | 
			
		||||
      VOTE_REVEAL: false,
 | 
			
		||||
      LOCKUP: false,
 | 
			
		||||
      UNLOCK: false,
 | 
			
		||||
      ASSET_LISTING_FEE: false,
 | 
			
		||||
      PROOF_OF_BURN: false,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10);
 | 
			
		||||
    this.loadingItems = Array(this.itemsPerPage);
 | 
			
		||||
 | 
			
		||||
@ -41,10 +62,25 @@ export class BisqTransactionsComponent implements OnInit {
 | 
			
		||||
      this.paginationMaxSize = 3;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.pageSubject$
 | 
			
		||||
    merge(
 | 
			
		||||
      this.pageSubject$,
 | 
			
		||||
      this.radioGroupForm.valueChanges
 | 
			
		||||
        .pipe(
 | 
			
		||||
          map((data) => {
 | 
			
		||||
            const types: string[] = [];
 | 
			
		||||
            for (const i in data) {
 | 
			
		||||
              if (data[i]) {
 | 
			
		||||
                types.push(i);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            this.types = types;
 | 
			
		||||
            return 1;
 | 
			
		||||
          })
 | 
			
		||||
        )
 | 
			
		||||
      )
 | 
			
		||||
      .pipe(
 | 
			
		||||
        tap(() => this.isLoading = true),
 | 
			
		||||
        switchMap((page) => this.bisqApiService.listTransactions$((page - 1) * this.itemsPerPage, this.itemsPerPage))
 | 
			
		||||
        switchMap((page) => this.bisqApiService.listTransactions$((page - 1) * this.itemsPerPage, this.itemsPerPage, this.types))
 | 
			
		||||
      )
 | 
			
		||||
      .subscribe((response) => {
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
 | 
			
		||||
@ -12,9 +12,11 @@ import { TimeSinceComponent } from '../components/time-since/time-since.componen
 | 
			
		||||
import { ClipboardComponent } from '../components/clipboard/clipboard.component';
 | 
			
		||||
import { QrcodeComponent } from '../components/qrcode/qrcode.component';
 | 
			
		||||
import { FiatComponent } from '../fiat/fiat.component';
 | 
			
		||||
import { NgbNavModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
import { NgbNavModule, NgbTooltipModule, NgbButtonsModule, NgbPaginationModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
 | 
			
		||||
import { TxFeaturesComponent } from '../components/tx-features/tx-features.component';
 | 
			
		||||
import { TxFeeRatingComponent } from '../components/tx-fee-rating/tx-fee-rating.component';
 | 
			
		||||
import { ReactiveFormsModule } from '@angular/forms';
 | 
			
		||||
import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -35,8 +37,12 @@ import { TxFeeRatingComponent } from '../components/tx-fee-rating/tx-fee-rating.
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
    NgbNavModule,
 | 
			
		||||
    NgbTooltipModule,
 | 
			
		||||
    NgbButtonsModule,
 | 
			
		||||
    NgbPaginationModule,
 | 
			
		||||
    NgbDropdownModule,
 | 
			
		||||
  ],
 | 
			
		||||
  providers: [
 | 
			
		||||
    VbytesPipe,
 | 
			
		||||
@ -44,7 +50,11 @@ import { TxFeeRatingComponent } from '../components/tx-fee-rating/tx-fee-rating.
 | 
			
		||||
  exports: [
 | 
			
		||||
    NgbNavModule,
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
    NgbTooltipModule,
 | 
			
		||||
    NgbButtonsModule,
 | 
			
		||||
    NgbPaginationModule,
 | 
			
		||||
    NgbDropdownModule,
 | 
			
		||||
    TimeSinceComponent,
 | 
			
		||||
    ClipboardComponent,
 | 
			
		||||
    QrcodeComponent,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user