Add logs, version and other

This commit is contained in:
everoddandeven 2024-09-25 23:24:46 +02:00
parent 5deb58f135
commit 91bb85e119
35 changed files with 549 additions and 99 deletions

View file

@ -96,7 +96,7 @@ function execMoneroDaemon(configFilePath: string): ChildProcess {
return monerodProcess;
}
function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStreams {
function startMoneroDaemon(commandOptions: string[], logHandler?: (message: string) => void): ChildProcessWithoutNullStreams {
const monerodPath = path.resolve(__dirname, monerodFilePath);
console.log("Starting monerod daemon with options: " + commandOptions.join(" "));
@ -107,17 +107,20 @@ function startMoneroDaemon(commandOptions: string[]): ChildProcessWithoutNullStr
// Gestisci l'output di stdout in streaming
monerodProcess.stdout.on('data', (data) => {
console.log(`monerod stdout: ${data}`);
win?.webContents.send('monero-stdout', `${data}`);
// Puoi anche inviare i log all'interfaccia utente tramite IPC
});
// Gestisci gli errori in stderr
monerodProcess.stderr.on('data', (data) => {
console.error(`monerod stderr: ${data}`);
win?.webContents.send('monero-stderr', `${data}`);
});
// Gestisci la chiusura del processo
monerodProcess.on('close', (code) => {
console.log(`monerod chiuso con codice: ${code}`);
win?.webContents.send('monero-stdout', `monerod exited with code: ${code}`);
});
return monerodProcess;
@ -147,8 +150,8 @@ try {
}
});
ipcMain.on('start-monerod', (event, configFilePath) => {
startMoneroDaemon(configFilePath);
ipcMain.on('start-monerod', (event, configFilePath: string[], logHandler?: (message: string) => void) => {
startMoneroDaemon(configFilePath, logHandler);
})
} catch (e) {

View file

@ -23,6 +23,8 @@ import { TransactionsModule } from './pages/transactions/transactions.module';
import { OutputsModule } from './pages/outputs/outputs.module';
import { SidebarComponent } from './shared/components';
import { SettingsModule } from './pages/settings/settings.module';
import { LogsModule } from './pages/logs/logs.module';
import { VersionModule } from './pages/version/version.module';
// AoT requires an exported function for factories
const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './assets/i18n/', '.json');
@ -41,7 +43,9 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new Transl
MiningModule,
TransactionsModule,
OutputsModule,
LogsModule,
SettingsModule,
VersionModule,
TranslateModule,
AppRoutingModule,
TranslateModule.forRoot({

View file

@ -1,4 +1,4 @@
import { HttpClient } from '@angular/common/http';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { EventEmitter, Injectable } from '@angular/core';
import { BlockCount } from '../../../../common/BlockCount';
import { firstValueFrom } from 'rxjs';
@ -181,7 +181,12 @@ export class DaemonService {
}
private async delay(ms: number = 0): Promise<void> {
await new Promise<void>(f => setTimeout(f, ms));
}
private async callRpc(request: RPCRequest): Promise<{ [key: string]: any }> {
try {
let method: string = '';
if (request instanceof JsonRPCRequest) {
@ -199,6 +204,19 @@ export class DaemonService {
return response;
}
catch (error) {
if (error instanceof HttpErrorResponse && error.status == 0) {
const wasRunning = this.daemonRunning;
this.daemonRunning = false;
if (wasRunning) {
this.onDaemonStart.emit(false);
}
}
throw error;
}
}
public async startDaemon(): Promise<void> {
if (await this.isRunning()) {
@ -215,7 +233,7 @@ export class DaemonService {
const settings = await this.getSettings();
this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions());
await new Promise(f => setTimeout(f, 3000));
await this.delay(3000);
if (await this.isRunning(true)) {
console.log("Daemon started");
@ -485,8 +503,21 @@ export class DaemonService {
public async getTxPoolBacklog(): Promise<TxBacklogEntry[]> {
const response = await this.callRpc(new GetTxPoolBacklogRequest());
if (typeof response.status == 'string' && response.status != 'OK') {
throw new Error(`Error code: ${response.status}`)
}
if (!response.bakclog && !response.result) {
return [];
}
if (response.backlog) {
return TxBacklogEntry.fromBinary(response.backlog);
}
else if (response.result.backlog) return TxBacklogEntry.fromBinary(response.result.backlog);
return [];
}
public async pruneBlockchain(check: boolean = false): Promise<BlockchainPruneInfo> {
const response = await this.callRpc(new PruneBlockchainRequest(check));
@ -577,11 +608,20 @@ export class DaemonService {
}
public async stopDaemon(): Promise<void> {
if (!this.daemonRunning) {
console.warn("Daemon not running");
return;
}
const response = await this.callRpc(new StopDaemonRequest());
console.log(response);
if (typeof response.status == 'string' && response.status != 'OK') {
throw new Error(`Could not stop daemon: ${response.status}`);
}
this.daemonRunning = false;
this.onDaemonStart.emit(false);
}
public async setLimit(limitDown: number, limitUp: number): Promise<{ limitDown: number, limitUp: number }> {

View file

@ -20,7 +20,7 @@ export class BansComponent implements AfterViewInit {
}
ngAfterViewInit(): void {
this.navbarService.removeNavbarLinks();
this.navbarService.removeLinks();
console.log('BansComponent AFTER VIEW INIT');
@ -36,7 +36,7 @@ export class BansComponent implements AfterViewInit {
}
private onNavigationEnd(): void {
this.navbarService.removeNavbarLinks();
this.navbarService.removeLinks();
}
private async load(): Promise<void> {

View file

@ -10,12 +10,27 @@
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Starting daemon
</button>
&nbsp;
<button routerLink="/settings" class="btn btn-outline-light" type="button" [disabled]="startingDaemon"><i class="bi bi-gear"></i> Configure</button>
</div>
<div *ngIf="daemonRunning" class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
<div class="card-header"><strong>Daemon running</strong></div>
<div class="card-body">
<h5 class="card-title">
<button *ngIf="!stoppingDaemon" type="button" class="btn btn-danger btn-lg" (click)="stopDaemon()"><i class="bi bi-stop-circle"></i>&nbsp;Stop</button>
<button *ngIf="stoppingDaemon" class="btn btn-danger-light" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Stopping daemon
</button>
</h5>
</div>
</div>
@for(card of cards; track card.header) {
@if(card.loading) {
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;" aria-hidden="true">
<div class="card-header">{{card.header}}</div>
<div class="card-header"><strong>{{card.header}}</strong></div>
<div class="card-body">
<p class="card-text placeholder-glow">
@ -39,6 +54,8 @@
}
</div>
</div>
<div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0">

View file

@ -9,6 +9,7 @@ import { DaemonInfo } from '../../../common/DaemonInfo';
import * as $ from 'jquery';
import * as bootstrapTable from 'bootstrap-table';
import { LogsService } from '../logs/logs.service';
@Component({
selector: 'app-detail',
@ -19,6 +20,7 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
public daemonRunning: boolean;
public startingDaemon: boolean;
public stoppingDaemon: boolean;
private syncInfo?: SyncInfo;
private daemonInfo?: DaemonInfo;
private readonly navbarLinks: NavbarLink[];
@ -50,9 +52,10 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
public cards: Card[];
constructor(private router: Router,private daemonService: DaemonService, private navbarService: NavbarService, private ngZone: NgZone) {
constructor(private router: Router,private daemonService: DaemonService, private navbarService: NavbarService, private logsService: LogsService) {
this.daemonRunning = false;
this.startingDaemon = false;
this.stoppingDaemon = false;
this.syncStatus = 'Not synced';
this.height = 0;
this.targetHeight = 0;
@ -72,7 +75,9 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
this.navbarLinks = [
new NavbarLink('pills-home-tab', '#pills-home', 'pills-home', true, 'Overview', true),
new NavbarLink('pills-profile-tab', '#pills-profile', 'pills-profile', false, 'Peers', true)
new NavbarLink('pills-profile-tab', '#pills-profile', 'pills-profile', false, 'Peers', true),
new NavbarLink('pills-spans-tab', '#pills-spans', 'pills-spans', false, 'Spans', true),
new NavbarLink('pills-save-bc-tab', '#pills-save-bc', 'pills-save-bc', false, 'Save Blockchain', true)
];
this.cards = this.createLoadingCards();
@ -91,7 +96,9 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setNavbarLinks(this.navbarLinks);
this.navbarService.setLinks(this.navbarLinks);
if (this.loadInterval != null) return;
this.load().then(() => {
this.cards = this.createCards();
@ -106,6 +113,8 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
});
*/
if (this.stoppingDaemon) return;
this.load().then(() => {
this.cards = this.createCards();
});
@ -125,6 +134,11 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
console.warn("Daemon already running");
return;
}
if (this.startingDaemon || this.stoppingDaemon) {
return;
}
this.startingDaemon = true;
setTimeout(async () => {
@ -141,6 +155,27 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
}, 500);
}
public async stopDaemon(): Promise<void> {
if (this.stoppingDaemon || this.startingDaemon || !this.daemonRunning) {
return;
}
this.stoppingDaemon = true;
try {
if (this.loadInterval) clearInterval(this.loadInterval);
await this.daemonService.stopDaemon();
this.daemonRunning = false;
}
catch (error) {
console.error(error);
}
this.stoppingDaemon = false;
}
private onNavigationEnd(): void {
this.load().then(() => {
//this.cards = this.createCards();
@ -194,12 +229,12 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
this.daemonRunning = await this.daemonService.isRunning();
if (!this.daemonRunning) {
this.navbarService.disableNavbarLinks();
this.navbarService.disableLinks();
this.isLoading = false;
return;
}
this.navbarService.enableNavbarLinks();
this.navbarService.enableLinks();
const $table = $('#table');

View file

@ -37,7 +37,7 @@ export class HardForkInfoComponent implements AfterViewInit {
}
ngAfterViewInit(): void {
this.navbarService.removeNavbarLinks();
this.navbarService.removeLinks();
}
private onNavigationEnd(): void {

View file

@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LogsComponent } from './logs.component';
const routes: Routes = [{
path: 'logs',
component: LogsComponent
}];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class LogsRoutingModule { }

View file

@ -0,0 +1,8 @@
<div class="terminal bg-dark text-light p-3 m-4">
<div class="terminal-output" id="terminalOutput">
<ng-container *ngFor="let line of lines; trackBy: trackByFn">
<div>{{ line }}</div>
</ng-container>
</div>
</div>

View file

@ -0,0 +1,11 @@
.terminal {
max-height: 700px;
overflow-y: auto;
font-family: monospace;
border: 1px solid #333;
border-radius: 5px;
}
.terminal-output {
white-space: pre-wrap;
}

View file

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

View file

@ -0,0 +1,42 @@
import { AfterViewInit, Component, NgZone } from '@angular/core';
import { LogsService } from './logs.service';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
@Component({
selector: 'app-logs',
templateUrl: './logs.component.html',
styleUrl: './logs.component.scss'
})
export class LogsComponent implements AfterViewInit {
constructor(private navbarService: NavbarService, private logsService: LogsService, private ngZone: NgZone) {
this.logsService.onLog.subscribe((message: string) => this.onLog());
}
public get lines(): string[] {
return this.logsService.lines;
}
private onLog(): void {
// Scorri automaticamente in basso
setTimeout(() => {
this.ngZone.run(() => {
this.lines;
const terminalOutput = document.getElementById('terminalOutput');
if (terminalOutput) {
terminalOutput.style.width = `${window.innerWidth}`;
terminalOutput.scrollTop = terminalOutput.scrollHeight;
}
})
}, 100);
}
public trackByFn(index: number, item: string): number {
return index; // usa l'indice per tracciare gli elementi
}
ngAfterViewInit(): void {
this.navbarService.removeLinks();
}
}

View file

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LogsRoutingModule } from './logs-routing.module';
import { SharedModule } from '../../shared/shared.module';
import { LogsComponent } from './logs.component';
@NgModule({
declarations: [LogsComponent],
imports: [
CommonModule,
SharedModule,
LogsRoutingModule
]
})
export class LogsModule { }

View file

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { LogsService } from './logs.service';
describe('LogsService', () => {
let service: LogsService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(LogsService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View file

@ -0,0 +1,27 @@
import { EventEmitter, Injectable, NgZone } from '@angular/core';
import { ipcRenderer, webFrame } from 'electron';
import { ElectronService } from '../../core/services';
@Injectable({
providedIn: 'root'
})
export class LogsService {
public readonly onLog: EventEmitter<string> = new EventEmitter<string>();
public readonly lines: string[] = [];
constructor(private electronService: ElectronService, private ngZone: NgZone) {
if (this.electronService.isElectron) {
this.electronService.ipcRenderer.on('monero-stdout', (event, message: string) => this.log(message));
this.electronService.ipcRenderer.on('monero-stderr', (event, message: string) => this.log(message));
}
}
public log(message: string): void {
this.ngZone.run(() => {
this.lines.push(message);
this.onLog.emit(message);
});
}
}

View file

@ -52,7 +52,7 @@
<div class="tab-pane fade" id="pills-disabled" role="tabpanel" aria-labelledby="pills-disabled-tab" tabindex="0">...</div>
</div>
<div *ngIf="coreBusy" class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column text-center">
<div *ngIf="coreBusy" class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column text-bg-dark rounded-3 m-4 text-center">
<main class="px-3">
<h1><i class="bi bi-exclamation-diamond"></i> Core is busy.</h1>

View file

@ -7,7 +7,6 @@ import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { MineableTxBacklog } from '../../../common/MineableTxBacklog';
import { Chain } from '../../../common/Chain';
import { CoreIsBusyError } from '../../../common/error';
import { CommonModule, NgIf } from '@angular/common';
@Component({
selector: 'app-mining',
@ -64,7 +63,7 @@ export class MiningComponent implements AfterViewInit {
ngAfterViewInit(): void {
console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setNavbarLinks(this.navbarLinks);
this.navbarService.setLinks(this.navbarLinks);
setTimeout(() => {
const $table = $('#chainsTable');
@ -106,10 +105,10 @@ export class MiningComponent implements AfterViewInit {
const $table = $('#chainsTable');
$table.bootstrapTable('load', this.getChains());
this.coreBusy = false;
this.navbarService.enableNavbarLinks();
this.navbarService.enableLinks();
}
catch(error) {
this.navbarService.disableNavbarLinks();
this.navbarService.disableLinks();
if (error instanceof CoreIsBusyError) {
this.coreBusy = true;
}

View file

@ -15,12 +15,12 @@ export class OutputsComponent implements AfterViewInit {
this.navbarLinks = [
new NavbarLink('pills-outputs-overview-tab', '#pills-outputs-overview', 'outputs-overview', true, 'Overview'),
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-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')
];
}
ngAfterViewInit(): void {
this.navbarService.setNavbarLinks(this.navbarLinks);
this.navbarService.setLinks(this.navbarLinks);
}
}

View file

@ -75,7 +75,7 @@ export class SettingsComponent implements AfterViewInit {
}
ngAfterViewInit(): void {
this.navbarService.setNavbarLinks(this.navbarLinks);
this.navbarService.setLinks(this.navbarLinks);
}
public OnOfflineChange() {

View file

@ -1,4 +1,5 @@
<div class="tab-pane fade show active" id="pills-rpc" role="tabpanel" aria-labelledby="pills-rpc-tab" tabindex="0">
<div class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="pills-relay-tx" role="tabpanel" aria-labelledby="pills-relay-tx-tab" tabindex="0">
<div class="row g-5 m-2">
<div class="col-md-7 col-lg-10">
<h4 class="mb-3">Relay a list of transaction IDs</h4>
@ -7,7 +8,13 @@
<div class="col-12">
<label for="tx_ids" class="form-label">Tx Ids</label>
<textarea type="text" class="form-control" id="tx_ids" placeholder="" rows="15" cols="15"></textarea>
<textarea type="text" class="form-control" id="tx_ids" placeholder="[
'tx_hash_1',
'tx_hash_2',
... ,
'tx_hash_n'
]"
rows="15" cols="15"></textarea>
<small class="text-body-secondary">List of transaction IDs to relay</small>
</div>
@ -18,5 +25,93 @@
</div>
</div>
<button class="w-100 btn btn-primary btn-lg" type="button" [disabled]="!canRelay" (click)="onRelay()">Relay Tx</button>
</div>
<div class="tab-pane fade" id="pills-coinbase-tx-sum" role="tabpanel" aria-labelledby="pills-coinbase-tx-sum-tab" tabindex="0">
<div class="row g-5 m-2">
<div class="col-md-7 col-lg-10">
<h4 class="mb-3">Get coinbase tx sum</h4>
<form class="needs-validation" novalidate="">
<div class="row g-3">
<div class="col-md-4">
<label for="height" class="form-label">Height</label>
<input type="number" class="form-control" id="height" placeholder="" [(ngModel)]="height" [ngModelOptions]="{standalone: true}">
<small class="text-body-secondary">Block height from which getting the amounts</small>
</div>
<div class="col-md-4">
<label for="count" class="form-label">Count</label>
<input type="number" class="form-control" id="count" placeholder="" [(ngModel)]="count" [ngModelOptions]="{standalone: true}">
<small class="text-body-secondary">Number of blocks to include in the sum</small>
</div>
<hr class="my-4">
</div>
</form>
</div>
</div>
<button class="w-100 btn btn-primary btn-lg" type="button" (click)="onGetCoinbaseTxSum()">Get Coinbase Tx Sum</button>
</div>
<div class="tab-pane fade" id="pills-flush-tx-pool" role="tabpanel" aria-labelledby="pills-flush-tx-pool-tab" tabindex="0">
<div class="row g-5 m-2">
<div class="col-md-7 col-lg-10">
<h4 class="mb-3">Flush a list of transaction IDs</h4>
<form class="needs-validation" novalidate="">
<div class="row g-3">
<div class="col-12">
<label for="tx_ids" class="form-label">Tx Ids</label>
<textarea type="text" class="form-control" id="tx_ids" placeholder="[
'tx_hash_1',
'tx_hash_2',
... ,
'tx_hash_n'
]"
rows="15" cols="15"></textarea>
<small class="text-body-secondary">List of transaction IDs to flush in tx pool</small>
</div>
<hr class="my-4">
</div>
</form>
</div>
</div>
<button class="w-100 btn btn-primary btn-lg" type="button" [disabled]="!canRelay" (click)="onFlush()">Flush Tx Pool</button>
</div>
<div class="tab-pane fade" id="pills-flush-cache" role="tabpanel" aria-labelledby="pills-flush-cache-tab" tabindex="0">
<div class="row g-5 m-2">
<div class="col-md-7 col-lg-10">
<h4 class="mb-3">Flush a list of bad transaction IDs from cache</h4>
<form class="needs-validation" novalidate="">
<div class="row g-3">
<div class="col-12">
<label for="tx_ids" class="form-label">Tx Ids</label>
<textarea type="text" class="form-control" id="tx_ids" placeholder="[
'tx_hash_1',
'tx_hash_2',
... ,
'tx_hash_n'
]"
rows="15" cols="15"></textarea>
<small class="text-body-secondary">List of bad transaction IDs to flush from cache</small>
</div>
<hr class="my-4">
</div>
</form>
</div>
</div>
<button class="w-100 btn btn-primary btn-lg" type="button" [disabled]="!canRelay" (click)="onFlushFromCache()">Flush Bad Txs</button>
</div>
</div>

View file

@ -2,6 +2,7 @@ import { AfterViewInit, Component } 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';
import { TxBacklogEntry } from '../../../common/TxBacklogEntry';
@Component({
selector: 'app-transactions',
@ -12,27 +13,58 @@ export class TransactionsComponent implements AfterViewInit {
private readonly navbarLinks: NavbarLink[];
public canRelay: boolean;
public txPoolBacklog: TxBacklogEntry[];
public height: number;
public count: number;
constructor(private daemonService: DaemonService, private navbarService: NavbarService) {
this.navbarLinks = [
new NavbarLink('pills-relay-tx-tab', '#pills-relay-tx', 'pills-relay-tx', true, 'Relay Tx', true),
new NavbarLink('pills-tx-backlog', '#pills-tx-backlog', 'pills-tx-backlog', false, 'Tx Backlog', true),
new NavbarLink('pills-tx-backlog-tab', '#pills-tx-backlog', 'pills-tx-backlog', false, 'Tx Backlog', true),
new NavbarLink('pills-coinbase-tx-sum-tab', '#pills-coinbase-tx-sum', 'pills-coinbase-tx-sum', false, 'Coinbase Tx Sum', true),
new NavbarLink('pills-flush-tx-pool-tab', '#pills-flush-tx-pool', 'pills-flush-tx-pool', false, 'Flush Tx Pool', true),
new NavbarLink('pills-flush-cahe', '#pills-flush-cache', 'pills-flush-cache', false, 'Flush Cache', true)
new NavbarLink('pills-flush-cahe-tab', '#pills-flush-cache', 'pills-flush-cache', false, 'Flush Cache', true)
];
this.height = 0;
this.count = 0;
this.txPoolBacklog = [];
this.canRelay = false;
}
ngAfterViewInit(): void {
this.navbarService.setNavbarLinks(this.navbarLinks);
this.navbarService.setLinks(this.navbarLinks);
this.load().then(() => {
this.navbarService.enableLinks();
}).catch((error) => {
console.error(error);
this.navbarService.disableLinks();
})
}
private async load(): Promise<void> {
try {
this.txPoolBacklog = await this.daemonService.getTxPoolBacklog();
console.log(this.txPoolBacklog)
}
catch (error) {
throw error;
}
}
public async onRelay(): Promise<void> {
}
public async onFlush(): Promise<void> {
}
public async onFlushFromCache(): Promise<void> {
}
public async onGetCoinbaseTxSum(): Promise<void> {
}
}

View file

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { VersionComponent } from './version.component';
import { CommonModule } from '@angular/common';
const routes: Routes = [
{
path: 'version',
component: VersionComponent
}
];
@NgModule({
imports: [CommonModule, RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class VersionRoutingModule { }

View file

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

View file

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

View file

@ -0,0 +1,23 @@
import { AfterViewInit, Component } from '@angular/core';
import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { DaemonService } from '../../core/services/daemon/daemon.service';
@Component({
selector: 'app-version',
templateUrl: './version.component.html',
styleUrl: './version.component.scss'
})
export class VersionComponent implements AfterViewInit {
private readonly links: NavbarLink[];
constructor(private navbarService: NavbarService, private daemonService: DaemonService) {
this.links = [
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', true, 'Overview')
];
}
ngAfterViewInit(): void {
this.navbarService.setLinks(this.links);
}
}

View file

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { VersionRoutingModule } from './version-routing.module';
import { VersionComponent } from './version.component';
import { SharedModule } from '../../shared/shared.module';
@NgModule({
declarations: [VersionComponent],
imports: [
CommonModule,
SharedModule,
VersionRoutingModule
]
})
export class VersionModule { }

View file

@ -1,7 +1,8 @@
<nav class="navbar navbar-expand-lg d-flex justify-content-center py-3 text-bg-dark">
&nbsp;&nbsp;
<a href="/" class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none">
<img src="/assets/icons/monero-symbol-on-white-480.png" width="40" height="40">
<span class="fs-4">Monero Daemon</span>
<img class="m-1" src="/assets/icons/monero-symbol-on-white-480.png" width="40" height="40">
<span class="fs-4"><strong>Monero Daemon</strong></span>
</a>
<ul class="nav nav-pills" id="pills-tab" role="tablist">

View file

@ -12,7 +12,7 @@ import { NavbarLink } from './navbar.model';
export class NavbarComponent {
public get navbarLinks(): NavbarLink[] {
return this.navbarService.navbarLinks;
return this.navbarService.links;
}
constructor(private navbarService: NavbarService) {

View file

@ -7,29 +7,29 @@ import { NavbarLink } from './navbar.model';
export class NavbarService {
private _navbarLinks: NavbarLink[] = [];
public get navbarLinks(): NavbarLink[] {
public get links(): NavbarLink[] {
return this._navbarLinks;
}
constructor() { }
public addNavbarLink(... navbarLinks: NavbarLink[]): void {
public addLink(... navbarLinks: NavbarLink[]): void {
navbarLinks.forEach((navLink: NavbarLink) => this._navbarLinks.push(navLink));
}
public setNavbarLinks(navbarLinks: NavbarLink[]): void {
public setLinks(navbarLinks: NavbarLink[]): void {
this._navbarLinks = navbarLinks;
}
public removeNavbarLinks(): void {
this.setNavbarLinks([]);
public removeLinks(): void {
this.setLinks([]);
}
public disableNavbarLinks(): void {
public disableLinks(): void {
this._navbarLinks.forEach((link) => link.disabled = true);
}
public enableNavbarLinks(): void {
public enableLinks(): void {
this._navbarLinks.forEach((link) => link.disabled = false);
}

View file

@ -21,45 +21,42 @@ export class SidebarComponent implements OnChanges {
this.errorMessage = '';
this.daemonService.onDaemonStart.subscribe((started: boolean) => {
if (!started) {
this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
this.navLinks = this.createLightLinks();
}
else {
this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Blockchain', '/blockchain', 'bi bi-bounding-box'),
new NavLink('Transactions', '/transactions', 'bi bi-credit-card-2-front'),
new NavLink('Outputs', '/outputs', 'bi bi-circle-fill'),
new NavLink('Mining', '/mining', 'bi bi-minecart-loaded'),
new NavLink('Hard Fork Info', '/hardforkinfo', 'bi bi-signpost-split'),
new NavLink('Bans', '/bans', 'bi bi-ban'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
this.navLinks = this.createFullLinks();
}
});
}
private updateLinks(): void {
if (!this.isDaemonRunning) {
this.navLinks = [
private createLightLinks(): NavLink[] {
return [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
}
else {
this.navLinks = [
private createFullLinks(): NavLink[] {
return this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Blockchain', '/blockchain', 'bi bi-bounding-box'),
new NavLink('Transactions', '/transactions', 'bi bi-credit-card-2-front'),
new NavLink('Outputs', '/outputs', 'bi bi-circle-fill'),
new NavLink('Mining', '/mining', 'bi bi-minecart-loaded'),
new NavLink('Hard Fork Info', '/hardforkinfo', 'bi bi-signpost-split'),
new NavLink('Bans', '/bans', 'bi bi-ban'),
new NavLink('Logs', '/logs', 'bi bi-terminal'),
new NavLink('Version', '/version', 'bi bi-git'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
}
private updateLinks(): void {
if (!this.isDaemonRunning) {
this.navLinks = this.createLightLinks();
}
else {
this.navLinks = this.createFullLinks();
}
}
public isActive(navLink: NavLink): boolean {
@ -68,22 +65,10 @@ export class SidebarComponent implements OnChanges {
public ngOnChanges(changes: SimpleChanges): void {
if (!this.isDaemonRunning) {
this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
this.navLinks = this.createLightLinks();
}
else {
this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
new NavLink('Blockchain', '/blockchain', 'bi bi-bounding-box'),
new NavLink('Transactions', '/transactions', 'bi bi-credit-card-2-front'),
new NavLink('Outputs', '/outputs', 'bi bi-circle-fill'),
new NavLink('Mining', '/mining', 'bi bi-minecart-loaded'),
new NavLink('Hard Fork Info', '/hardforkinfo', 'bi bi-signpost-split'),
new NavLink('Bans', '/bans', 'bi bi-ban'),
new NavLink('Settings', '/settings', 'bi bi-gear')
];
this.navLinks = this.createFullLinks();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -10,6 +10,7 @@ export class TxBacklogEntry {
}
public static fromBinary(binary: string): TxBacklogEntry[] {
throw new Error("TxBacklogEntry.fromBinary(): not implemented");
}
}

View file

@ -2,7 +2,7 @@
<html data-bs-theme="dark">
<head>
<meta charset="utf-8">
<title>Angular Electron</title>
<title>Monero Daemon</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">