Merge pull request #4799 from mempool/natsoni/blocks-table-url-pagination
Add page number to URL in blocks table
This commit is contained in:
		
						commit
						00a94f9e3c
					
				| @ -302,8 +302,9 @@ export class BlockComponent implements OnInit, OnDestroy { | ||||
|       throttleTime(300, asyncScheduler, { leading: true, trailing: true }), | ||||
|       shareReplay(1) | ||||
|     ); | ||||
|     this.transactionSubscription = block$.pipe( | ||||
|       switchMap((block) => this.electrsApiService.getBlockTransactions$(block.id) | ||||
|     this.transactionSubscription = combineLatest([block$, this.route.queryParams]).pipe( | ||||
|       tap(([_, queryParams]) => this.page = +queryParams['page'] || 1), | ||||
|       switchMap(([block, _]) => this.electrsApiService.getBlockTransactions$(block.id, (this.page - 1) * this.itemsPerPage) | ||||
|         .pipe( | ||||
|           catchError((err) => { | ||||
|             this.transactionsError = err; | ||||
| @ -592,19 +593,7 @@ export class BlockComponent implements OnInit, OnDestroy { | ||||
|     this.transactions = null; | ||||
|     this.transactionsError = null; | ||||
|     target.scrollIntoView(); // works for chrome
 | ||||
| 
 | ||||
|     this.electrsApiService.getBlockTransactions$(this.block.id, start) | ||||
|       .pipe( | ||||
|         catchError((err) => { | ||||
|           this.transactionsError = err; | ||||
|           return of([]); | ||||
|       }) | ||||
|       ) | ||||
|      .subscribe((transactions) => { | ||||
|         this.transactions = transactions; | ||||
|         this.isLoadingTransactions = false; | ||||
|         target.scrollIntoView(); // works for firefox
 | ||||
|       }); | ||||
|     this.router.navigate([], { queryParams: { page: page }, queryParamsHandling: 'merge' }); | ||||
|   } | ||||
| 
 | ||||
|   toggleShowDetails() { | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef } from '@angular/core'; | ||||
| import { BehaviorSubject, combineLatest, Observable, timer, of } from 'rxjs'; | ||||
| import { delayWhen, map, retryWhen, scan, switchMap, tap } from 'rxjs/operators'; | ||||
| import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, Inject, LOCALE_ID } from '@angular/core'; | ||||
| import { ActivatedRoute, Router } from '@angular/router'; | ||||
| import { BehaviorSubject, combineLatest, Observable, timer, of, Subscription } from 'rxjs'; | ||||
| import { debounceTime, delayWhen, filter, map, retryWhen, scan, skip, switchMap, tap, throttleTime } from 'rxjs/operators'; | ||||
| import { BlockExtended } from '../../interfaces/node-api.interface'; | ||||
| import { ApiService } from '../../services/api.service'; | ||||
| import { StateService } from '../../services/state.service'; | ||||
| @ -25,6 +26,7 @@ export class BlocksList implements OnInit { | ||||
|   auditAvailable = false; | ||||
|   isLoading = true; | ||||
|   fromBlockHeight = undefined; | ||||
|   lastBlockHeightFetched = -1; | ||||
|   paginationMaxSize: number; | ||||
|   page = 1; | ||||
|   lastPage = 1; | ||||
| @ -33,6 +35,10 @@ export class BlocksList implements OnInit { | ||||
|   fromHeightSubject: BehaviorSubject<number> = new BehaviorSubject(this.fromBlockHeight); | ||||
|   skeletonLines: number[] = []; | ||||
|   lastBlockHeight = -1; | ||||
|   blocksCountInitialized$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); | ||||
|   blocksCountInitializedSubscription: Subscription; | ||||
|   keyNavigationSubscription: Subscription; | ||||
|   dir: 'rtl' | 'ltr' = 'ltr'; | ||||
| 
 | ||||
|   constructor( | ||||
|     private apiService: ApiService, | ||||
| @ -41,8 +47,14 @@ export class BlocksList implements OnInit { | ||||
|     private cd: ChangeDetectorRef, | ||||
|     private seoService: SeoService, | ||||
|     private ogService: OpenGraphService, | ||||
|     private route: ActivatedRoute, | ||||
|     private router: Router, | ||||
|     @Inject(LOCALE_ID) private locale: string, | ||||
|   ) { | ||||
|     this.isMempoolModule = this.stateService.env.BASE_MODULE === 'mempool'; | ||||
|     if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { | ||||
|       this.dir = 'rtl'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
| @ -52,6 +64,34 @@ export class BlocksList implements OnInit { | ||||
| 
 | ||||
|     if (!this.widget) { | ||||
|       this.websocketService.want(['blocks']); | ||||
|       this.blocksCountInitializedSubscription = combineLatest([this.blocksCountInitialized$, this.route.queryParams]).pipe( | ||||
|         filter(([blocksCountInitialized, _]) => blocksCountInitialized), | ||||
|         tap(([_, params]) => { | ||||
|           this.page = +params['page'] || 1; | ||||
|           this.page === 1 ? this.fromHeightSubject.next(undefined) : this.fromHeightSubject.next((this.blocksCount - 1) - (this.page - 1) * 15); | ||||
|           this.cd.markForCheck(); | ||||
|         }) | ||||
|       ).subscribe(); | ||||
| 
 | ||||
|       this.keyNavigationSubscription = this.stateService.keyNavigation$ | ||||
|       .pipe( | ||||
|         tap((event) => { | ||||
|           this.isLoading = true; | ||||
|           const prevKey = this.dir === 'ltr' ? 'ArrowLeft' : 'ArrowRight'; | ||||
|           const nextKey = this.dir === 'ltr' ? 'ArrowRight' : 'ArrowLeft'; | ||||
|           if (event.key === prevKey && this.page > 1) { | ||||
|             this.page--; | ||||
|             this.cd.markForCheck(); | ||||
|           } | ||||
|           if (event.key === nextKey && this.page * 15 < this.blocksCount) { | ||||
|             this.page++; | ||||
|             this.cd.markForCheck(); | ||||
|           } | ||||
|         }), | ||||
|         throttleTime(1000, undefined, { leading: true, trailing: true }), | ||||
|       ).subscribe(() => { | ||||
|         this.pageChange(this.page); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; | ||||
| @ -70,13 +110,16 @@ export class BlocksList implements OnInit { | ||||
| 
 | ||||
|     this.blocks$ = combineLatest([ | ||||
|       this.fromHeightSubject.pipe( | ||||
|         filter(fromBlockHeight => fromBlockHeight !== this.lastBlockHeightFetched), | ||||
|         switchMap((fromBlockHeight) => { | ||||
|           this.isLoading = true; | ||||
|           this.lastBlockHeightFetched = fromBlockHeight; | ||||
|           return this.apiService.getBlocks$(this.page === 1 ? undefined : fromBlockHeight) | ||||
|             .pipe( | ||||
|               tap(blocks => { | ||||
|                 if (this.blocksCount === undefined) { | ||||
|                   this.blocksCount = blocks[0].height + 1; | ||||
|                   this.blocksCountInitialized$.next(true); | ||||
|                 } | ||||
|                 this.isLoading = false; | ||||
|                 this.lastBlockHeight = Math.max(...blocks.map(o => o.height)); | ||||
| @ -138,7 +181,7 @@ export class BlocksList implements OnInit { | ||||
|   } | ||||
| 
 | ||||
|   pageChange(page: number): void { | ||||
|     this.fromHeightSubject.next((this.blocksCount - 1) - (page - 1) * 15); | ||||
|     this.router.navigate([], { queryParams: { page: page } }); | ||||
|   } | ||||
| 
 | ||||
|   trackByBlock(index: number, block: BlockExtended): number { | ||||
| @ -148,4 +191,9 @@ export class BlocksList implements OnInit { | ||||
|   isEllipsisActive(e): boolean { | ||||
|     return (e.offsetWidth < e.scrollWidth); | ||||
|   } | ||||
| 
 | ||||
|   ngOnDestroy(): void { | ||||
|     this.blocksCountInitializedSubscription?.unsubscribe(); | ||||
|     this.keyNavigationSubscription?.unsubscribe(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; | ||||
| import { BehaviorSubject, Observable, Subject, combineLatest, of, timer } from 'rxjs'; | ||||
| import { delayWhen, filter, map, share, shareReplay, switchMap, takeUntil, tap, throttleTime } from 'rxjs/operators'; | ||||
| import { ActivatedRoute, Router } from '@angular/router'; | ||||
| import { Component, OnInit, ChangeDetectionStrategy, Input, Inject, LOCALE_ID, ChangeDetectorRef } from '@angular/core'; | ||||
| import { BehaviorSubject, Observable, Subject, Subscription, combineLatest, of, timer } from 'rxjs'; | ||||
| import { delayWhen, filter, map, share, shareReplay, switchMap, take, takeUntil, tap, throttleTime } from 'rxjs/operators'; | ||||
| import { ApiService } from '../../../services/api.service'; | ||||
| import { Env, StateService } from '../../../services/state.service'; | ||||
| import { AuditStatus, CurrentPegs, RecentPeg } from '../../../interfaces/node-api.interface'; | ||||
| @ -29,20 +30,31 @@ export class RecentPegsListComponent implements OnInit { | ||||
|   lastReservesBlockUpdate: number = 0; | ||||
|   currentPeg$: Observable<CurrentPegs>; | ||||
|   pegsCount$: Observable<number>; | ||||
|   pegsCount: number; | ||||
|   startingIndexSubject: BehaviorSubject<number> = new BehaviorSubject(0); | ||||
|   currentIndex: number = 0; | ||||
|   lastPegBlockUpdate: number = 0; | ||||
|   lastPegAmount: string = ''; | ||||
|   isLoad: boolean = true; | ||||
|   queryParamSubscription: Subscription; | ||||
|   keyNavigationSubscription: Subscription; | ||||
|   dir: 'rtl' | 'ltr' = 'ltr'; | ||||
| 
 | ||||
|   private destroy$ = new Subject(); | ||||
| 
 | ||||
|   constructor( | ||||
|     private apiService: ApiService, | ||||
|     private cd: ChangeDetectorRef, | ||||
|     public stateService: StateService, | ||||
|     private websocketService: WebsocketService, | ||||
|     private seoService: SeoService | ||||
|     private seoService: SeoService, | ||||
|     private route: ActivatedRoute, | ||||
|     private router: Router, | ||||
|     @Inject(LOCALE_ID) private locale: string, | ||||
|   ) { | ||||
|     if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { | ||||
|       this.dir = 'rtl'; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
| @ -53,6 +65,34 @@ export class RecentPegsListComponent implements OnInit { | ||||
|     if (!this.widget) { | ||||
|       this.seoService.setTitle($localize`:@@a8b0889ea1b41888f1e247f2731cc9322198ca04:Recent Peg-In / Out's`); | ||||
|       this.websocketService.want(['blocks']); | ||||
| 
 | ||||
|       this.queryParamSubscription = this.route.queryParams.pipe( | ||||
|         tap((params) => { | ||||
|           this.page = +params['page'] || 1; | ||||
|           this.startingIndexSubject.next((this.page - 1) * 15); | ||||
|         }), | ||||
|       ).subscribe(); | ||||
| 
 | ||||
|       this.keyNavigationSubscription = this.stateService.keyNavigation$ | ||||
|       .pipe( | ||||
|         tap((event) => { | ||||
|           this.isLoading = true; | ||||
|           const prevKey = this.dir === 'ltr' ? 'ArrowLeft' : 'ArrowRight'; | ||||
|           const nextKey = this.dir === 'ltr' ? 'ArrowRight' : 'ArrowLeft'; | ||||
|           if (event.key === prevKey && this.page > 1) { | ||||
|             this.page--; | ||||
|             this.cd.markForCheck(); | ||||
|           } | ||||
|           if (event.key === nextKey && this.page < this.pegsCount / this.pageSize) { | ||||
|             this.page++; | ||||
|             this.cd.markForCheck(); | ||||
|           } | ||||
|         }), | ||||
|         throttleTime(1000, undefined, { leading: true, trailing: true }), | ||||
|       ).subscribe(() => { | ||||
|         this.pageChange(this.page); | ||||
|       }); | ||||
| 
 | ||||
|       this.auditStatus$ = this.stateService.blocks$.pipe( | ||||
|         takeUntil(this.destroy$), | ||||
|         throttleTime(40000), | ||||
| @ -99,7 +139,10 @@ export class RecentPegsListComponent implements OnInit { | ||||
|         tap(() => this.isPegCountLoading = true), | ||||
|         switchMap(_ => this.apiService.pegsCount$()), | ||||
|         map((data) => data.pegs_count), | ||||
|         tap(() => this.isPegCountLoading = false), | ||||
|         tap((pegsCount) => { | ||||
|           this.isPegCountLoading = false; | ||||
|           this.pegsCount = pegsCount; | ||||
|         }), | ||||
|         share() | ||||
|       ); | ||||
| 
 | ||||
| @ -129,11 +172,12 @@ export class RecentPegsListComponent implements OnInit { | ||||
|   ngOnDestroy(): void { | ||||
|     this.destroy$.next(1); | ||||
|     this.destroy$.complete(); | ||||
|     this.queryParamSubscription?.unsubscribe(); | ||||
|     this.keyNavigationSubscription?.unsubscribe(); | ||||
|   } | ||||
| 
 | ||||
|   pageChange(page: number): void { | ||||
|     this.startingIndexSubject.next((page - 1) * 15); | ||||
|     this.page = page; | ||||
|     this.router.navigate([], { queryParams: { page: page } }); | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user