diff --git a/backend/src/api/bisq.ts b/backend/src/api/bisq.ts index 0e51f3117..09f201f13 100644 --- a/backend/src/api/bisq.ts +++ b/backend/src/api/bisq.ts @@ -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 { diff --git a/backend/src/routes.ts b/backend/src/routes.ts index ddb625f04..dc304020f 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -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); } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 5b3680f3d..4abc1dd4f 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -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, ], diff --git a/frontend/src/app/bisq/bisq-api.service.ts b/frontend/src/app/bisq/bisq-api.service.ts index f5690d5ea..0f9eb0868 100644 --- a/frontend/src/app/bisq/bisq-api.service.ts +++ b/frontend/src/app/bisq/bisq-api.service.ts @@ -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(API_BASE_URL + '/tx/' + txId); } - listTransactions$(start: number, length: number): Observable> { - return this.httpClient.get(API_BASE_URL + `/txs/${start}/${length}`, { observe: 'response' }); + listTransactions$(start: number, length: number, types: string[]): Observable> { + let params = new HttpParams(); + types.forEach((t: string) => { + params = params.append('types[]', t); + }); + return this.httpClient.get(API_BASE_URL + `/txs/${start}/${length}`, { params, observe: 'response' }); } getBlock$(hash: string): Observable { diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html index 7cfa7a407..b383d7132 100644 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html +++ b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html @@ -1,38 +1,94 @@

Transactions

+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
- - - - - - - - - - - - - - - - - -
TransactionTypeAmountConfirmedHeight
{{ tx.id | slice : 0 : 8 }} - - {{ tx.txTypeDisplayString }} - - - - {{ tx.burntFee / 100 | number: '1.2-2' }} BSQ - - - {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }} BSQ - - ago{{ tx.blockHeight }}
+ + + + + + + + + + + + + + + + + +
TransactionTypeAmountConfirmedHeight
{{ tx.id | slice : 0 : 8 }} + + {{ tx.txTypeDisplayString }} + + + + {{ tx.burntFee / 100 | number: '1.2-2' }} BSQ + + + {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }} BSQ + + ago{{ tx.blockHeight }}

diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss index e69de29bb..6ed335893 100644 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss +++ b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss @@ -0,0 +1,4 @@ +label { + padding: 0.25rem 1rem; + white-space: nowrap; +} diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts index 96977ce51..17f55c60c 100644 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts +++ b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts @@ -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(); + 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; diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 9c27e80dd..0acb01438 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -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,