Handle network interruptions in scrollable blockchain
This commit is contained in:
parent
da3446f522
commit
8eca1e5f7e
@ -1,6 +1,6 @@
|
|||||||
<div class="blocks-container blockchain-blocks-container" [class.time-ltr]="timeLtr"
|
<div class="blocks-container blockchain-blocks-container" [class.time-ltr]="timeLtr"
|
||||||
[style.left]="static ? (offset || 0) + 'px' : null"
|
[style.left]="static ? (offset || 0) + 'px' : null"
|
||||||
*ngIf="(loadingBlocks$ | async) === false; else loadingBlocksTemplate">
|
*ngIf="static || (loadingBlocks$ | async) === false; else loadingBlocksTemplate">
|
||||||
<div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn">
|
<div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn">
|
||||||
<ng-container *ngIf="block && !block.loading && !block.placeholder; else placeholderBlock">
|
<ng-container *ngIf="block && !block.loading && !block.placeholder; else placeholderBlock">
|
||||||
<div [attr.data-cy]="'bitcoin-block-offset-' + offset + '-index-' + i"
|
<div [attr.data-cy]="'bitcoin-block-offset-' + offset + '-index-' + i"
|
||||||
@ -59,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #placeholderBlock>
|
<ng-template #placeholderBlock>
|
||||||
<ng-container *ngIf="block && block.placeholder; else loadingBlock">
|
<ng-container *ngIf="block && block.placeholder && !loadingTip; else loadingBlock">
|
||||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i"
|
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i"
|
||||||
class="text-center bitcoin-block mined-block placeholder-block blockchain-blocks-{{ i }}"
|
class="text-center bitcoin-block mined-block placeholder-block blockchain-blocks-{{ i }}"
|
||||||
id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]">
|
id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]">
|
||||||
@ -68,8 +68,8 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #loadingBlock>
|
<ng-template #loadingBlock>
|
||||||
<ng-container *ngIf="block && block.loading">
|
<ng-container *ngIf="loadingTip || (block && block.loading)">
|
||||||
<div class="flashing">
|
<div class="flashing loading">
|
||||||
<div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}"
|
<div class="text-center bitcoin-block mined-block" id="bitcoin-block-{{ block.height }}"
|
||||||
[ngStyle]="blockStyles[i]"></div>
|
[ngStyle]="blockStyles[i]"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -137,6 +137,10 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loading .bitcoin-block.mined-block {
|
||||||
|
background: #2d3348;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes opacityPulse {
|
@keyframes opacityPulse {
|
||||||
0% {opacity: 0.7;}
|
0% {opacity: 0.7;}
|
||||||
50% {opacity: 1.0;}
|
50% {opacity: 1.0;}
|
||||||
|
@ -22,6 +22,8 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
@Input() offset: number = 0;
|
@Input() offset: number = 0;
|
||||||
@Input() height: number = 0;
|
@Input() height: number = 0;
|
||||||
@Input() count: number = 8;
|
@Input() count: number = 8;
|
||||||
|
@Input() loadingTip: boolean = false;
|
||||||
|
@Input() connected: boolean = true;
|
||||||
|
|
||||||
specialBlocks = specialBlocks;
|
specialBlocks = specialBlocks;
|
||||||
network = '';
|
network = '';
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<app-mempool-blocks [hidden]="pageIndex > 0"></app-mempool-blocks>
|
<app-mempool-blocks [hidden]="pageIndex > 0"></app-mempool-blocks>
|
||||||
<app-blockchain-blocks [hidden]="pageIndex > 0"></app-blockchain-blocks>
|
<app-blockchain-blocks [hidden]="pageIndex > 0"></app-blockchain-blocks>
|
||||||
<ng-container *ngFor="let page of pages; trackBy: trackByPageFn">
|
<ng-container *ngFor="let page of pages; trackBy: trackByPageFn">
|
||||||
<app-blockchain-blocks [static]="true" [offset]="page.offset" [height]="page.height" [count]="blocksPerPage"></app-blockchain-blocks>
|
<app-blockchain-blocks [static]="true" [offset]="page.offset" [height]="page.height" [count]="blocksPerPage" [loadingTip]="loadingTip" [connected]="connected"></app-blockchain-blocks>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div id="divider" [hidden]="pageIndex > 0">
|
<div id="divider" [hidden]="pageIndex > 0">
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { firstValueFrom, Subscription } from 'rxjs';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -18,6 +18,9 @@ export class BlockchainComponent implements OnInit, OnDestroy {
|
|||||||
timeLtrSubscription: Subscription;
|
timeLtrSubscription: Subscription;
|
||||||
timeLtr: boolean = this.stateService.timeLtr.value;
|
timeLtr: boolean = this.stateService.timeLtr.value;
|
||||||
ltrTransitionEnabled = false;
|
ltrTransitionEnabled = false;
|
||||||
|
connectionStateSubscription: Subscription;
|
||||||
|
loadingTip: boolean = true;
|
||||||
|
connected: boolean = true;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
@ -28,10 +31,17 @@ export class BlockchainComponent implements OnInit, OnDestroy {
|
|||||||
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||||
this.timeLtr = !!ltr;
|
this.timeLtr = !!ltr;
|
||||||
});
|
});
|
||||||
|
this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => {
|
||||||
|
this.connected = (state === 2);
|
||||||
|
})
|
||||||
|
firstValueFrom(this.stateService.chainTip$).then(tip => {
|
||||||
|
this.loadingTip = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.timeLtrSubscription.unsubscribe();
|
this.timeLtrSubscription.unsubscribe();
|
||||||
|
this.connectionStateSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
trackByPageFn(index: number, item: { index: number }) {
|
trackByPageFn(index: number, item: { index: number }) {
|
||||||
|
@ -21,6 +21,7 @@ export class StartComponent implements OnInit, OnDestroy {
|
|||||||
timeLtr: boolean = this.stateService.timeLtr.value;
|
timeLtr: boolean = this.stateService.timeLtr.value;
|
||||||
chainTipSubscription: Subscription;
|
chainTipSubscription: Subscription;
|
||||||
chainTip: number = -1;
|
chainTip: number = -1;
|
||||||
|
tipIsSet: boolean = false;
|
||||||
markBlockSubscription: Subscription;
|
markBlockSubscription: Subscription;
|
||||||
blockCounterSubscription: Subscription;
|
blockCounterSubscription: Subscription;
|
||||||
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
||||||
@ -58,6 +59,7 @@ export class StartComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
this.chainTipSubscription = this.stateService.chainTip$.subscribe((height) => {
|
this.chainTipSubscription = this.stateService.chainTip$.subscribe((height) => {
|
||||||
this.chainTip = height;
|
this.chainTip = height;
|
||||||
|
this.tipIsSet = true;
|
||||||
this.updatePages();
|
this.updatePages();
|
||||||
if (this.pendingMark != null) {
|
if (this.pendingMark != null) {
|
||||||
this.scrollToBlock(this.pendingMark);
|
this.scrollToBlock(this.pendingMark);
|
||||||
@ -66,7 +68,7 @@ export class StartComponent implements OnInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
this.markBlockSubscription = this.stateService.markBlock$.subscribe((mark) => {
|
this.markBlockSubscription = this.stateService.markBlock$.subscribe((mark) => {
|
||||||
if (mark?.blockHeight != null) {
|
if (mark?.blockHeight != null) {
|
||||||
if (this.chainTip >=0) {
|
if (this.tipIsSet) {
|
||||||
if (!this.blockInViewport(mark.blockHeight)) {
|
if (!this.blockInViewport(mark.blockHeight)) {
|
||||||
this.scrollToBlock(mark.blockHeight);
|
this.scrollToBlock(mark.blockHeight);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,12 @@ export class CacheService {
|
|||||||
for (let i = 0; i < chunkSize; i++) {
|
for (let i = 0; i < chunkSize; i++) {
|
||||||
this.blockLoading[maxHeight - i] = true;
|
this.blockLoading[maxHeight - i] = true;
|
||||||
}
|
}
|
||||||
const result = await firstValueFrom(this.apiService.getBlocks$(maxHeight));
|
let result;
|
||||||
|
try {
|
||||||
|
result = await firstValueFrom(this.apiService.getBlocks$(maxHeight));
|
||||||
|
} catch (e) {
|
||||||
|
console.log("failed to load blocks: ", e.message);
|
||||||
|
}
|
||||||
for (let i = 0; i < chunkSize; i++) {
|
for (let i = 0; i < chunkSize; i++) {
|
||||||
delete this.blockLoading[maxHeight - i];
|
delete this.blockLoading[maxHeight - i];
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user