Refactory and fix table behaviour

This commit is contained in:
everoddandeven 2024-10-19 15:10:03 +02:00
parent 99ecc5f136
commit f5e74b62d9
19 changed files with 284 additions and 321 deletions

View file

@ -0,0 +1 @@
<p>base-page works!</p>

View file

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BasePageComponent } from './base-page.component';
describe('BasePageComponent', () => {
let component: BasePageComponent;
let fixture: ComponentFixture<BasePageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BasePageComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BasePageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,116 @@
import { AfterContentInit, Component, OnDestroy } from '@angular/core';
import { NavbarLink, NavbarService } from '../../shared/components';
import { Subscription } from 'rxjs';
@Component({
template: '',
})
export abstract class BasePageComponent implements AfterContentInit, OnDestroy {
private readonly initializedTables: { [key: string]: boolean } = {};
private _links: NavbarLink[] = [];
public get links(): NavbarLink[] {
return this._links;
}
protected subscriptions: Subscription[] = [];
constructor(private navbarService: NavbarService) {
}
protected setLinks(links: NavbarLink[] = []): void {
this._links = links;
}
protected initTable(id: string, loading: boolean = false): void {
if (!document.getElementById(id)) {
console.warn(`Cannot find table ${id}`);
return;
}
if (this.isTableInitialized(id)) {
console.warn(`BootstrapTable ${id} already initiliazed`);
return;
}
const $table = $(`#${id}`);
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
if(loading) $table.bootstrapTable('showLoading');
this.setTableInitialized(id);
}
protected loadTable(id: string, rows: any[]): void {
if (!this.isTableInitialized(id)) {
this.initTable(id);
}
if (!this.isTableInitialized(id)) {
console.warn(`Cannot load table ${id}`);
}
const $table = $(`#${id}`);
$table.bootstrapTable('load', rows);
$table.bootstrapTable('hideLoading');
}
private destroyTable(id: string): void {
if (!document.getElementById(id)) {
console.warn(`Cannot find table ${id}`);
return;
}
if (!this.isTableInitialized(id)) {
console.warn(`Table ${id} is not initialized`);
return;
}
const $table = $(`#${id}`);
$table.bootstrapTable('destroy');
this.setTableInitialized(id, false);
}
private destroyTables(): void {
for(const key in this.initializedTables) {
const initialized: boolean = this.initializedTables[key];
if (!initialized) continue;
this.destroyTable(key);
}
}
private setTableInitialized(id: string, initialized: boolean = true): void {
this.initializedTables[id] = initialized;
}
protected isTableInitialized(id: string): boolean {
const initalized: boolean | undefined = this.initializedTables[id];
if (initalized == true) {
return true;
}
return false;
}
public ngAfterContentInit(): void {
this.navbarService.setLinks(this._links);
}
public ngOnDestroy(): void {
if (this.subscriptions.length == 0) return;
this.subscriptions.forEach((sub: Subscription) => sub.unsubscribe());
this.subscriptions = [];
this.destroyTables();
}
}

View file

@ -3,7 +3,7 @@
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>

View file

@ -1,17 +1,17 @@
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { Component, NgZone } from '@angular/core';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { Block, BlockHeader } from '../../../common';
import { DaemonDataService } from '../../core/services';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-blockchain',
templateUrl: './blockchain.component.html',
styleUrl: './blockchain.component.scss'
})
export class BlockchainComponent implements AfterViewInit {
public readonly navbarLinks: NavbarLink[];
export class BlockchainComponent extends BasePageComponent {
public get daemonRunning(): boolean {
return this.daemonData.running;
@ -67,19 +67,16 @@ export class BlockchainComponent implements AfterViewInit {
public pruneBlockchainError: string = '';
public blockchainPruned: boolean = false;
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService);
this.setLinks([
new NavbarLink('pills-last-block-header-tab', '#pills-last-block-header', 'pills-last-block-header', false, 'Last Block Header'),
new NavbarLink('pills-get-block-tab', '#pills-get-block', 'pills-get-block', false, 'Get Block'),
new NavbarLink('pills-get-block-header-tab', '#pills-get-block-header', 'pills-get-block-header', false, 'Get Block Header'),
new NavbarLink('pills-pop-blocks-tab', '#pills-pop-blocks', 'pills-pop-blocks', false, 'Pop Blocks'),
new NavbarLink('pills-prune-blockchain-tab', '#pills-prune-blockchain', 'pills-prune-blockchain', false, 'Prune'),
new NavbarLink('pills-save-bc-tab', '#pills-save-bc', 'pills-save-bc', false, 'Save')
];
}
public ngAfterViewInit(): void {
this.navbarService.setLinks(this.navbarLinks);
]);
}
public async getBlock(): Promise<void> {

View file

@ -2,7 +2,7 @@
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>
@ -26,6 +26,13 @@
</div>
</div>
<div *ngIf="daemonRunning && !stoppingDaemon && !syncDisabledByPeriodPolicy && !syncDisabledByWifiPolicy && syncDisabled" class="alert alert-warning d-flex align-items-center justify-content-center text-center" role="alert">
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>&nbsp;&nbsp;
<div>
Sync is disabled
</div>
</div>
<div *ngIf="daemonRunning && !stoppingDaemon" class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab" tabindex="0">
<div class="row d-flex justify-content-center">

View file

@ -1,18 +1,18 @@
import { Component, AfterViewInit, NgZone, OnDestroy } from '@angular/core';
import { Peer } from '../../../common/Peer';
import { Component, AfterViewInit, NgZone } from '@angular/core';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { DaemonService, DaemonDataService } from '../../core/services';
import { Subscription } from 'rxjs';
import { Connection, Span } from '../../../common';
import { Connection, Span, Peer } from '../../../common';
import { SimpleBootstrapCard } from '../../shared/utils';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
styleUrls: ['./detail.component.scss']
})
export class DetailComponent implements AfterViewInit, OnDestroy {
export class DetailComponent extends BasePageComponent implements AfterViewInit {
public get daemonRunning(): boolean {
return this.daemonData.running;
@ -26,8 +26,6 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
return this.daemonData.stopping;
}
public readonly navbarLinks: NavbarLink[];
public get syncDisabledByWifiPolicy(): boolean {
return this.daemonData.syncDisabledByWifiPolicy;
}
@ -36,6 +34,10 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
return this.daemonData.syncDisabledByPeriodPolicy;
}
public get syncDisabled(): boolean {
return this.daemonService.settings.noSync;
}
public get syncDisabledFrom(): string {
return this.daemonService.settings.syncPeriodFrom;
}
@ -123,22 +125,24 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
public cards: SimpleBootstrapCard[];
private subscriptions: Subscription[] = [];
constructor(
private daemonService: DaemonService,
private navbarService: NavbarService,
navbarService: NavbarService,
private daemonData: DaemonDataService,
private ngZone: NgZone) {
super(navbarService);
this.navbarLinks = [
this.setLinks([
new NavbarLink('pills-home-tab', '#pills-home', 'pills-home', false, 'Overview', true),
new NavbarLink('pills-peers-tab', '#pills-peers', 'pills-peers', false, 'Peers', true),
new NavbarLink('pills-spans-tab', '#pills-spans', 'pills-spans', false, 'Spans', true)
];
]);
this.cards = this.createCards();
}
private registerEventListeners(): void {
const syncStartSub: Subscription = this.daemonData.syncStart.subscribe((info) => {
if(!info.first) {
return;
@ -150,77 +154,32 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
});
const syncInfoRefreshEndSub: Subscription = this.daemonData.syncInfoRefreshEnd.subscribe(() => {
this.refreshTables();
this.loadTables();
this.cards = this.createCards();
});
this.subscriptions.push(syncStartSub, syncInfoRefreshEndSub);
}
}
public ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setLinks(this.navbarLinks);
this.ngZone.run(() => {
this.initTables();
});
}
public ngOnDestroy(): void {
this.subscriptions.forEach((sub) => sub.unsubscribe());
this.subscriptions = [];
}
private initTable(table: string): void {
const $table = $(`#${table}Table`);
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
this.registerEventListeners();
this.loadTables();
});
$table.bootstrapTable('showLoading');
}
private initPeerTable(): void {
this.initTable('peers');
private loadPeersTable(): void {
this.loadTable('peersTable', this.getPeers());
}
private initSpansTable(): void {
this.initTable('spans');
private loadSpansTable(): void {
this.loadTable('spansTable', this.getSpans());
}
private initTables() {
this.initPeerTable();
this.initSpansTable();
}
private refreshTable(table: string, data: any[]): void {
const $peersTable = $(`#${table}Table`);
//$table.bootstrapTable({});
$peersTable.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
if (this.getPeers().length == 0) $peersTable.bootstrapTable('showLoading');
else
{
$peersTable.bootstrapTable('load', data);
$peersTable.bootstrapTable('hideLoading');
}
}
private refreshPeersTable(): void {
this.refreshTable('peers', this.getPeers());
}
private refreshSpansTable(): void {
this.refreshTable('spans', this.getSpans());
}
private refreshTables(): void {
this.refreshPeersTable();
this.refreshSpansTable();
private loadTables(): void {
this.loadPeersTable();
this.loadSpansTable();
}
private createCards(): SimpleBootstrapCard[] {
@ -266,7 +225,7 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
return cards;
}
public getPeers(): Connection[] {
private getPeers(): Connection[] {
if (!this.daemonData.syncInfo) return [];
const infos: Connection[] = [];
@ -277,7 +236,7 @@ export class DetailComponent implements AfterViewInit, OnDestroy {
return infos;
}
public getSpans(): Span[] {
private getSpans(): Span[] {
if (!this.daemonData.syncInfo) return [];
return this.daemonData.syncInfo.spans;
}

View file

@ -2,7 +2,7 @@
<h1 class="h2">Hard Fork Info</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>

View file

@ -1,17 +1,17 @@
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { NavigationEnd, Router } from '@angular/router';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { SimpleBootstrapCard } from '../../shared/utils';
import { DaemonDataService } from '../../core/services';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-hard-fork-info',
templateUrl: './hard-fork-info.component.html',
styleUrl: './hard-fork-info.component.scss'
})
export class HardForkInfoComponent implements AfterViewInit {
export class HardForkInfoComponent extends BasePageComponent implements AfterViewInit {
public cards: SimpleBootstrapCard[];
private earliestHeight: number;
private enabled: boolean;
@ -31,11 +31,12 @@ export class HardForkInfoComponent implements AfterViewInit {
public loading: boolean = false;
public readonly navbarLinks: NavbarLink[] = [
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', false, 'Overview'),
];
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService);
constructor(private router: Router, private daemonData: DaemonDataService, private daemonService: DaemonService, private navbarService: NavbarService, private ngZone: NgZone) {
this.setLinks([
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', false, 'Overview'),
]);
this.cards = [];
this.enabled = false;
this.earliestHeight = 0;
@ -44,26 +45,14 @@ export class HardForkInfoComponent implements AfterViewInit {
this.votes = 0;
this.voting = 0;
this.window = 0;
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
if (event.url != '/hardforkinfo') return;
this.onNavigationEnd();
}
});
}
ngAfterViewInit(): void {
this.navbarService.setLinks(this.navbarLinks);
}
private onNavigationEnd(): void {
public ngAfterViewInit(): void {
this.load().then(() => {
this.cards = this.createCards();
}).catch((error: any) => {
console.error(error);
});
});
}
private async load(): Promise<void> {

View file

@ -2,7 +2,7 @@
<h1 class="h2">Mining</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>
@ -330,7 +330,6 @@
<div class="card-body">
<table
(load)="initAuxPowTable()"
id="auxPowTable"
data-toggle="auxPowTable"
data-toolbar="#toolbar"

View file

@ -1,21 +1,16 @@
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { MinerData } from '../../../common/MinerData';
import { NavigationEnd, Router } from '@angular/router';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { Chain } from '../../../common/Chain';
import { AddedAuxPow, AuxPoW, BlockTemplate, GeneratedBlocks, MiningStatus } from '../../../common';
import { DaemonDataService } from '../../core/services';
import { DaemonService, DaemonDataService } from '../../core/services';
import { NavbarLink, NavbarService } from '../../shared/components';
import { AddedAuxPow, AuxPoW, BlockTemplate, GeneratedBlocks, MiningStatus, MinerData, Chain } from '../../../common';
import { BasePageComponent } from '../base-page/base-page.component';
import { SimpleBootstrapCard } from '../../shared/utils';
@Component({
selector: 'app-mining',
templateUrl: './mining.component.html',
styleUrl: './mining.component.scss'
})
export class MiningComponent implements AfterViewInit {
public readonly navbarLinks: NavbarLink[];
export class MiningComponent extends BasePageComponent implements AfterViewInit {
public get coreBusy(): boolean {
return this.daemonData.info? !this.daemonData.info.synchronized : true;
@ -104,7 +99,7 @@ export class MiningComponent implements AfterViewInit {
}
//private txBacklog: MineableTxBacklog[]
public cards: Card[];
public cards: SimpleBootstrapCard[];
public get daemonRunning(): boolean {
return this.daemonData.running;
@ -136,10 +131,11 @@ export class MiningComponent implements AfterViewInit {
return this.startMiningMinerAddress != '';
}
constructor(private router: Router, private daemonService: DaemonService, private daemonData: DaemonDataService, private navbarService: NavbarService, private ngZone: NgZone) {
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService)
this.cards = [];
this.navbarLinks = [
this.setLinks([
new NavbarLink('pills-mining-status-tab', '#pills-mining-status', 'mining-status', false, 'Status'),
new NavbarLink('pills-miner-data-tab', '#pills-miner-data', 'miner-data', false, 'Miner Data'),
new NavbarLink('pills-hashrate-tab', '#pills-hashrate', 'hashrate', false, 'Hashrate'),
@ -149,14 +145,7 @@ export class MiningComponent implements AfterViewInit {
new NavbarLink('pills-submit-block-tab', '#pills-submit-block', 'submit-block', false, 'Submit Block'),
new NavbarLink('pills-calc-pow-tab', '#pills-calc-pow', 'calc-pow', false, 'Calculate PoW Hash'),
new NavbarLink('pills-add-aux-pow-tab', '#pills-add-aux-pow', 'add-aux-pow', false, 'Add Aux PoW')
];
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
if (event.url != '/mining') return;
this.onNavigationEnd();
}
});
]);
this.daemonData.syncEnd.subscribe(() => {
this.refresh();
@ -165,34 +154,21 @@ export class MiningComponent implements AfterViewInit {
public ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setLinks(this.navbarLinks);
setTimeout(() => {
const options = {
classes: 'table table-bordered table-hover table-dark table-striped'
};
const $chainsTable = $('#chainsTable');
$chainsTable.bootstrapTable({});
$chainsTable.bootstrapTable('refreshOptions', options);
this.refresh();
}, 500);
this.loadTables();
this.cards = this.createCards();
}
public initAuxPowTable(): void {
const options = {
classes: 'table table-bordered table-hover table-dark table-striped'
};
const $auxPowTable = $('#auxPowTable');
$auxPowTable.bootstrapTable({});
$auxPowTable.bootstrapTable('refreshOptions', options);
$auxPowTable.bootstrapTable('load', this.addAuxPowResult?.auxPoW);
private loadTables(): void {
this.loadChainsTable();
this.loadAuxPowTable();
}
private onNavigationEnd(): void {
this.refresh();
private loadChainsTable(): void {
this.loadTable('chainsTable', this.alternateChains);
}
private loadAuxPowTable(): void {
this.loadTable('auxPowTable', this.addAuxPowResult ? this.addAuxPowResult.auxPoW : []);
}
public async getBlockTemplate(): Promise<void> {
@ -250,48 +226,26 @@ export class MiningComponent implements AfterViewInit {
}
private refresh(): void {
try {
const $table = $('#chainsTable');
$table.bootstrapTable('load', this.getChains());
this.cards = this.createCards();
}
catch(error) {
this.navbarService.disableLinks();
}
this.loadChainsTable();
this.cards = this.createCards();
}
private createCards(): Card[] {
private createCards(): SimpleBootstrapCard[] {
if (this.coreBusy) {
return [
]
}
return [
new Card('Major Fork Version', `${this.majorVersion}`),
new Card('Current block height', `${this.height}`),
new Card('Previous Block Id', `${this.prevId}`),
new Card('Seed hash', `${this.seedHash}`),
new Card('Network difficulty', `${this.difficulty}`),
new Card('Median block weight', `${this.medianWeight}`),
new Card('Generated Coins', `${this.alreadyGeneratedCoins}`)
new SimpleBootstrapCard('Major Fork Version', `${this.majorVersion}`),
new SimpleBootstrapCard('Current block height', `${this.height}`),
new SimpleBootstrapCard('Previous Block Id', `${this.prevId}`),
new SimpleBootstrapCard('Seed hash', `${this.seedHash}`),
new SimpleBootstrapCard('Network difficulty', `${this.difficulty}`),
new SimpleBootstrapCard('Median block weight', `${this.medianWeight}`),
new SimpleBootstrapCard('Generated Coins', `${this.alreadyGeneratedCoins}`)
];
}
private getChains(): any[] {
const chains: any[] = [];
this.alternateChains.forEach((chain: Chain) => chains.push({
'blockHash': chain.blockHash,
'height': chain.height,
'length': chain.length,
'mainChainParentBlock': chain.mainChainParentBlock,
'wideDifficulty': chain.wideDifficulty
}))
return chains;
}
public async calcPowHash() {
this.gettingCalcPow = true;
@ -394,6 +348,7 @@ export class MiningComponent implements AfterViewInit {
this.addAuxPowResult = await this.daemonService.addAuxPoW(this.addAuxPowBlockTemplateBlob, this.auxPowArray);
this.addAuxPowError = ``;
this.addAuxPowSuccess = true;
this.loadAuxPowTable();
}
catch (error: any) {
this.addAuxPowSuccess = false;
@ -404,13 +359,3 @@ export class MiningComponent implements AfterViewInit {
}
}
class Card {
public header: string;
public content: string;
constructor(header: string, content: string) {
this.header = header;
this.content = content;
}
}

View file

@ -2,7 +2,7 @@
<h1 class="h2">Outputs</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>

View file

@ -1,17 +1,17 @@
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { Component, NgZone } from '@angular/core';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { HistogramEntry, Output, OutputDistribution } from '../../../common';
import { DaemonDataService } from '../../core/services';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-outputs',
templateUrl: './outputs.component.html',
styleUrl: './outputs.component.scss'
})
export class OutputsComponent implements AfterViewInit {
public readonly navbarLinks: NavbarLink[];
export class OutputsComponent extends BasePageComponent {
public get daemonRunning(): boolean {
return this.daemonData.running;
@ -97,41 +97,15 @@ export class OutputsComponent implements AfterViewInit {
return <number[]>JSON.parse(this.getOutDistributionAmountsJsonString);
}
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService);
this.setLinks([
new NavbarLink('pills-outputs-get-outs-tab', '#pills-outputs-get-outs', 'outputs-get-outs', false, 'Get Outs'),
new NavbarLink('pills-outputs-histogram-tab', '#pills-outputs-histogram', 'outputs-histogram', false, 'Histogram'),
new NavbarLink('pills-outputs-distribution-tab', '#pills-outputs-distribution', 'outputs-distribution', false, 'Distribution'),
new NavbarLink('pills-is-key-image-spent-tab', '#pills-is-key-image-spent', 'is-key-image-spent', false, 'Is Key Image Spent')
];
}
public ngAfterViewInit(): void {
this.navbarService.setLinks(this.navbarLinks);
this.ngZone.run(async () => {
//const $ = require('jquery');
//const bootstrapTable = require('bootstrap-table');
const options = {
classes: 'table table-bordered table-hover table-dark table-striped'
};
const $table = $('#outsTable');
$table.bootstrapTable({});
const $distributionsTable = $('#outDistributionsTable');
$distributionsTable.bootstrapTable({});
const $histogramTable = $('#outHistrogramsTable');
$histogramTable.bootstrapTable({});
$table.bootstrapTable('refreshOptions', options);
$distributionsTable.bootstrapTable('refreshOptions', options);
$histogramTable.bootstrapTable('refreshOptions', options);
await this.load();
}).then().catch((error: any) => {
console.error(error);
});
]);
}
public get getOutsOuts() {
@ -251,13 +225,11 @@ export class OutputsComponent implements AfterViewInit {
}
private loadOutDistributionTable(): void {
const $table = $('#outDistributionsTable');
$table.bootstrapTable('load', this.getOutDistributionResult);
this.loadTable('outDistributionsTable', this.getOutDistributionResult ? this.getOutDistributionResult : []);
}
private loadOutHistogramTable(): void {
const $table = $('#outHistogramsTable');
$table.bootstrapTable('load', this.getOutHistogramResult);
this.loadTable('outHistogramsTable', this.getOutHistogramResult ? this.getOutHistogramResult : []);
}
public async getOutHistogram(): Promise<void> {
@ -298,9 +270,7 @@ export class OutputsComponent implements AfterViewInit {
spentStatus: spentStatus == 0 ? 'unspent' : spentStatus == 1 ? 'spent in blockchain' : spentStatus == 2 ? 'spent in tx pool' : 'unknown'
})
const $table = $('#keyImagesTable');
$table.bootstrapTable({});
$table.bootstrapTable('load', this.isKeyImageSpentResult);
this.loadTable('keyImagesTable', this.isKeyImageSpentResult);
this.isKeyImageSpentError = '';
}
@ -312,6 +282,4 @@ export class OutputsComponent implements AfterViewInit {
this.gettingKeyImages = false;
}
public async load() {
}
}

View file

@ -2,7 +2,7 @@
<h1 class="h2">Peers</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>

View file

@ -1,17 +1,16 @@
import { AfterViewInit, Component, NgZone, OnDestroy } from '@angular/core';
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { DaemonDataService, DaemonService } from '../../core/services';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { Subscription } from 'rxjs';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-peers',
templateUrl: './peers.component.html',
styleUrl: './peers.component.scss'
})
export class PeersComponent implements AfterViewInit, OnDestroy {
public readonly navbarLinks: NavbarLink[];
export class PeersComponent extends BasePageComponent implements AfterViewInit {
public limitInPeers: number = 0;
public limitingInPeers: boolean = false;
@ -35,46 +34,41 @@ export class PeersComponent implements AfterViewInit, OnDestroy {
return this.daemonData.stopping;
}
private subscriptions: Subscription[] = [];
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
constructor(private daemonService: DaemonService, private daemonData: DaemonDataService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService);
this.setLinks([
new NavbarLink('pills-peer-list-tab', '#pills-peer-list', 'pills-peer-list', false, 'Peer List'),
new NavbarLink('pills-public-nodes-tab', '#pills-public-nodes', 'pills-public-nodes', false, 'Public Nodes'),
new NavbarLink('pills-in-peers-tab', '#pills-in-peers', 'pills-in-peers', false, 'In Peers'),
new NavbarLink('pills-out-peers-tab', '#pills-out-peers', 'pills-out-peers', false, 'Out Peers')
];
]);
}
public ngAfterViewInit(): void {
this.navbarService.setLinks(this.navbarLinks);
this.ngZone.run(() => {
const $publicNodesTable = $('#publicNodesTable');
const $peerListTable = $('#peerListTable');
$publicNodesTable.bootstrapTable({});
$publicNodesTable.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
$peerListTable.bootstrapTable({});
$peerListTable.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
$publicNodesTable.bootstrapTable('load', this.daemonData.publicNodes);
$peerListTable.bootstrapTable('load', this.daemonData.peerList);
this.loadTables();
const sub: Subscription = this.daemonData.syncEnd.subscribe(() => {
$publicNodesTable.bootstrapTable('load', this.daemonData.publicNodes);
//$peerListTable.bootstrapTable('load', this.daemonData.peerList);
this.loadPublicNodesTable();
});
this.subscriptions.push(sub);
});
}
private loadTables(): void {
this.loadPeerListTable();
this.loadPublicNodesTable();
}
private loadPeerListTable(): void {
this.loadTable('peerListTable', this.daemonData.peerList);
}
private loadPublicNodesTable(): void {
this.loadTable('publicNodesTable', this.daemonData.publicNodes);
}
public async refreshPeerListTable(): Promise<void> {
this.refreshingPeerList = true;
@ -83,8 +77,7 @@ export class PeersComponent implements AfterViewInit, OnDestroy {
setTimeout(() => {
this.ngZone.run(() => {
try {
const $peerListTable = $('#peerListTable');
$peerListTable.bootstrapTable('load', this.daemonData.peerList);
this.loadPeerListTable();
resolve();
}
catch(error) {
@ -101,14 +94,6 @@ export class PeersComponent implements AfterViewInit, OnDestroy {
this.refreshingPeerList = false;
}
public ngOnDestroy(): void {
this.subscriptions.forEach((sub) => {
sub.unsubscribe();
});
this.subscriptions = [];
}
public async inPeers(): Promise<void> {
this.limitingInPeers = true;

View file

@ -2,7 +2,7 @@
<h1 class="h2">Transactions</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<ul class="nav nav-pills m-3" id="pills-tab" role="tablist">
@for(navbarLink of navbarLinks; track navbarLink.name) {
@for(navbarLink of links; track navbarLink.name) {
<li class="nav-item mr-2" role="presentation">
<button [class]="navbarLink.selected ? 'nav-link active btn-sm' : 'nav-link btn-sm'" [id]="navbarLink.id" data-bs-toggle="pill" [attr.data-bs-target]="navbarLink.target" type="button" role="tab" [attr.aria-controls]="navbarLink.controls" [attr.aria-selected]="navbarLink.selected" [disabled]="navbarLink.disabled">{{navbarLink.name}}</button>
</li>
@ -24,6 +24,7 @@
data-toggle="transactionsTable"
data-toolbar="#toolbar"
data-height="460"
data-pagination="true"
>
<thead>
<tr>
@ -55,6 +56,7 @@
data-toggle="spentKeyImagesTable"
data-toolbar="#toolbar"
data-height="460"
data-pagination="true"
>
<thead>
<tr>
@ -211,6 +213,7 @@
data-toolbar="#toolbar"
data-pagination="true"
data-height="460"
data-pagination="true"
>
<thead>
<tr>

View file

@ -1,4 +1,4 @@
import { AfterViewInit, Component, NgZone, OnDestroy } from '@angular/core';
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { DaemonService } from '../../core/services/daemon/daemon.service';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
@ -7,14 +7,14 @@ import { SimpleBootstrapCard } from '../../shared/utils';
import { DaemonDataService } from '../../core/services';
import { FeeEstimate, SpentKeyImage, UnconfirmedTx } from '../../../common';
import { Subscription } from 'rxjs';
import { BasePageComponent } from '../base-page/base-page.component';
@Component({
selector: 'app-transactions',
templateUrl: './transactions.component.html',
styleUrl: './transactions.component.scss'
})
export class TransactionsComponent implements AfterViewInit, OnDestroy {
public readonly navbarLinks: NavbarLink[];
export class TransactionsComponent extends BasePageComponent implements AfterViewInit {
public canRelay: boolean;
@ -76,10 +76,10 @@ export class TransactionsComponent implements AfterViewInit, OnDestroy {
return this.daemonData.transactionPool.spentKeyImages;
}
private subscriptions: Subscription[] = [];
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, navbarService: NavbarService, private ngZone: NgZone) {
super(navbarService);
constructor(private daemonData: DaemonDataService, private daemonService: DaemonService, private navbarService: NavbarService, private ngZone: NgZone) {
this.navbarLinks = [
this.setLinks([
new NavbarLink('pills-tx-pool-tab', '#pills-tx-pool', 'pills-tx-pool', false, 'Pool'),
new NavbarLink('pills-relay-tx-tab', '#pills-relay-tx', 'pills-relay-tx', false, 'Relay Tx'),
new NavbarLink('pills-send-raw-tx-tab', '#pills-send-raw-tx', 'pills-send-raw-tx', false, 'Send Raw Tx'),
@ -88,7 +88,7 @@ export class TransactionsComponent implements AfterViewInit, OnDestroy {
new NavbarLink('pills-coinbase-tx-sum-tab', '#pills-coinbase-tx-sum', 'pills-coinbase-tx-sum', false, 'Coinbase Tx Sum'),
new NavbarLink('pills-flush-tx-pool-tab', '#pills-flush-tx-pool', 'pills-flush-tx-pool', false, 'Flush Tx Pool'),
new NavbarLink('pills-flush-cahe-tab', '#pills-flush-cache', 'pills-flush-cache', false, 'Flush Cache')
];
]);
this.height = 0;
this.count = 0;
@ -96,59 +96,28 @@ export class TransactionsComponent implements AfterViewInit, OnDestroy {
}
public ngAfterViewInit(): void {
this.ngZone.run(() => {
this.navbarService.setLinks(this.navbarLinks);
this.initTables();
this.ngZone.run(() => {
this.loadTables();
const onSyncEndSub: Subscription = this.daemonData.syncEnd.subscribe(() => this.refreshTables());
const onSyncEndSub: Subscription = this.daemonData.syncEnd.subscribe(() => this.loadTables());
this.subscriptions.push(onSyncEndSub);
});
}
public ngOnDestroy(): void {
this.subscriptions.forEach((sub) => {
sub.unsubscribe();
});
this.subscriptions = [];
}
private initTable(id: string): void {
const $table = $(`#${id}`);
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
}
private initTables(): void {
this.initTable('spentKeyImagesTable');
this.initTable('transactionsTable');
this.initTable('txPoolBacklogTable');
}
private loadTransactionsTable(): void {
const $table = $('#transactionsTable');
$table.bootstrapTable('load', this.unconfirmedTxs);
this.loadTable('transactionsTable', this.unconfirmedTxs);
}
private loadSpentKeyImagesTable(): void {
const $table = $('#spentKeyImagesTable');
$table.bootstrapTable('load', this.spentKeyImages);
this.loadTable('spentKeyImagesTable', this.spentKeyImages);
}
private loadTxPoolBacklogTable(): void {
const $table = $('#txPoolBacklogTable');
$table.bootstrapTable('load', this.txPoolBacklog)
this.loadTable('txPoolBacklogTable', this.txPoolBacklog);
}
private refreshTables(): void {
private loadTables(): void {
this.loadSpentKeyImagesTable();
this.loadTransactionsTable();
this.loadTxPoolBacklogTable();

View file

@ -1,3 +1,5 @@
export * from './page-not-found/page-not-found.component';
export * from './sidebar/sidebar.component';
export * from './daemon-not-running/daemon-not-running.component';
export * from './navbar/navbar.model';
export { NavbarService } from './navbar/navbar.service';