Save settings to IndexDB and other fixes

This commit is contained in:
everoddandeven 2024-09-25 18:14:08 +02:00
parent bb694c5d7a
commit 5deb58f135
12 changed files with 278 additions and 86 deletions

6
package-lock.json generated
View file

@ -20,6 +20,7 @@
"bootstrap": "5.3.3",
"bootstrap-icons": "1.11.3",
"bootstrap-table": "1.23.2",
"idb": "8.0.0",
"jquery": "3.7.1",
"rxjs": "7.8.1",
"tslib": "2.6.2",
@ -13593,6 +13594,11 @@
"postcss": "^8.1.0"
}
},
"node_modules/idb": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/idb/-/idb-8.0.0.tgz",
"integrity": "sha512-l//qvlAKGmQO31Qn7xdzagVPPaHTxXx199MhrAFuVBTPqydcPYBWjkrbv4Y0ktB+GmWOiwHl237UUOrLmQxLvw=="
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",

View file

@ -57,6 +57,7 @@
"bootstrap": "5.3.3",
"bootstrap-icons": "1.11.3",
"bootstrap-table": "1.23.2",
"idb": "8.0.0",
"jquery": "3.7.1",
"rxjs": "7.8.1",
"tslib": "2.6.2",

View file

@ -38,6 +38,21 @@ export class AppComponent {
private async load(): Promise<void> {
this.loading = true;
if (!window.indexedDB) {
console.log("Il tuo browser non supporta indexedDB");
}
else {
console.log("Browser supports IndexedDB");
var request = window.indexedDB.open("dati", 1);
console.log(request);
request.onsuccess = function(event: Event) {
if(event.target instanceof IDBOpenDBRequest) {
console.log(event.target.result)
}
};
}
try {
this.daemonRunning = await this.daemonService.isRunning();
}

View file

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { EventEmitter, Injectable } from '@angular/core';
import { BlockCount } from '../../../../common/BlockCount';
import { firstValueFrom } from 'rxjs';
import {
@ -72,11 +72,17 @@ import { MiningStatus } from '../../../../common/MiningStatus';
import { TxInfo } from '../../../../common/TxInfo';
import { DaemonSettings } from '../../../../common/DaemonSettings';
import { MethodNotFoundError } from '../../../../common/error/MethodNotFoundError';
import { openDB, IDBPDatabase } from "idb"
import { resolve } from 'path';
@Injectable({
providedIn: 'root'
})
export class DaemonService {
private dbName = 'DaemonSettingsDB';
private storeName = 'settingsStore';
private openDbPromise: Promise<IDBPDatabase>;
private daemonRunning?: boolean;
private url: string = "http://127.0.0.1:28081";
public settings: DaemonSettings;
@ -85,15 +91,57 @@ export class DaemonService {
//private url: string = "https://xmr.yemekyedim.com:18081";
//private url: string = "https://moneronode.org:18081";
public readonly onDaemonStart: EventEmitter<boolean> = new EventEmitter<boolean>();
private readonly headers: { [key: string]: string } = {
"Access-Control-Allow-Headers": "*", // this will allow all CORS requests
"Access-Control-Allow-Methods": 'POST,GET' // this states the allowed methods
};
constructor(private httpClient: HttpClient, private electronService: ElectronService) {
this.openDbPromise = this.openDatabase();
this.settings = this.loadSettings();
}
private async openDatabase(): Promise<IDBPDatabase> {
return openDB(this.dbName, 1, {
upgrade(db) {
// Crea un archivio (store) per i settings se non esiste già
if (!db.objectStoreNames.contains('settingsStore')) {
db.createObjectStore('settingsStore', {
keyPath: 'id',
autoIncrement: true,
});
}
},
});
}
public async saveSettings(settings: DaemonSettings): Promise<void> {
const db = await this.openDbPromise;
await db.put(this.storeName, { id: 1, ...settings });
this.settings = settings;
}
public async getSettings(): Promise<DaemonSettings> {
const db = await this.openDbPromise;
const result = await db.get(this.storeName, 1);
if (result) {
this.settings = DaemonSettings.parse(result);
}
else
{
this.settings = new DaemonSettings();
}
return this.settings;
}
public async deleteSettings(): Promise<void> {
const db = await this.openDbPromise;
await db.delete(this.storeName, 1);
}
private loadSettings(): DaemonSettings {
/*
const args = [
@ -164,10 +212,20 @@ export class DaemonService {
}
console.log("Starting daemon");
const settings = await this.getSettings();
this.electronService.ipcRenderer.send('start-monerod', settings.toCommandOptions());
this.electronService.ipcRenderer.send('start-monerod', this.settings.toCommandOptions());
await new Promise(f => setTimeout(f, 3000));
if (await this.isRunning(true)) {
console.log("Daemon started");
this.onDaemonStart.emit(true);
}
else
{
console.log("Daemon not started");
this.onDaemonStart.emit(false);
}
setTimeout(() => {
}, 500)

View file

@ -1,10 +1,8 @@
<app-load [show]="loading"></app-load>
<div class="tab-content" id="pills-tabContent" [hidden]="loading">
<div 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">
<div *ngIf="!daemonRunning" class="h-100 p-5 text-bg-dark rounded-3 m-4 text-center">
<div *ngIf="!daemonRunning && !loading" class="h-100 p-5 text-bg-dark rounded-3 m-4 text-center">
<h2><i class="bi bi-exclamation-diamond"></i> Daemon not running</h2>
<p>Start monero daemon</p>
<button *ngIf="!startingDaemon" class="btn btn-outline-light" type="button" (click)="startDaemon()"><i class="bi bi-play-fill"></i> Start</button>
@ -15,6 +13,22 @@
</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-body">
<p class="card-text placeholder-glow">
<span class="placeholder col-7"></span>
<span class="placeholder col-4"></span>
<span class="placeholder col-4"></span>
<span class="placeholder col-6"></span>
<span class="placeholder col-8"></span>
</p>
</div>
</div>
}
@else {
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
<div class="card-header"><strong>{{card.header}}</strong></div>
<div class="card-body">
@ -23,6 +37,8 @@
</div>
}
}
</div>
</div>
<div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0">

View file

@ -7,6 +7,9 @@ import { NavbarService } from '../../shared/components/navbar/navbar.service';
import { NavigationEnd, Router } from '@angular/router';
import { DaemonInfo } from '../../../common/DaemonInfo';
import * as $ from 'jquery';
import * as bootstrapTable from 'bootstrap-table';
@Component({
selector: 'app-detail',
templateUrl: './detail.component.html',
@ -72,12 +75,12 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
new NavbarLink('pills-profile-tab', '#pills-profile', 'pills-profile', false, 'Peers', true)
];
this.cards = [];
this.cards = this.createLoadingCards();
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
if (event.url != '/detail') return;
this.onNavigationEnd();
//this.onNavigationEnd();
}
});
}
@ -90,20 +93,23 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
console.log('DetailComponent AFTER VIEW INIT');
this.navbarService.setNavbarLinks(this.navbarLinks);
setTimeout(() => {
this.ngZone.run(() => {
if (this.isLoading) {
return;
}
this.load().then(() => {
this.cards = this.createCards();
});
this.loadInterval = setInterval(() => {
/*
const $table = $('#table');
$table.bootstrapTable({});
$table.bootstrapTable('refreshOptions', {
classes: 'table table-bordered table-hover table-dark table-striped'
});
this.load();
*/
this.load().then(() => {
this.cards = this.createCards();
});
}, 500);
}, 5000);
}
ngOnDestroy(): void {
@ -121,27 +127,50 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.startingDaemon = true;
setTimeout(async () => {
try {
await this.daemonService.startDaemon();
this.daemonRunning = await this.daemonService.isRunning();
}
catch(error) {
console.error(error);
this.daemonRunning = false;
}
this.startingDaemon = false;
}, 500);
}
private onNavigationEnd(): void {
this.load().then(() => {
this.cards = this.createCards();
//this.cards = this.createCards();
});
}
private createLoadingCards(): Card[] {
return [
new Card('Connection Status', this.connectionStatus, true),
new Card('Network Type', this.networkType, true),
new Card('Node Type', this.nodeType, true),
new Card('Sync progress', this.syncProgress, true),
new Card('Scan Height', `${this.height} / ${this.targetHeight}`, true),
new Card('Next needed pruning seed', `${this.nextNeededPruningSeed}`, true),
new Card('Block count', `${this.blockCount}`, true),
new Card('Monero version', this.version, true),
new Card('Blockchain size', this.blockchainSize, true),
new Card('Disk usage', this.diskUsage, true),
new Card('Transaction count', `${this.txCount}`, true),
new Card('Pool size', `${this.poolSize}`, true)
];
}
private createCards(): Card[] {
if (!this.daemonRunning) {
return []
return [];
}
if (this.isLoading) {
return this.createLoadingCards();
}
return [
new Card('Connection Status', this.connectionStatus),
@ -193,9 +222,9 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
this.blockCount = blockCount.count;
const version = await this.daemonService.getVersion();
//const version = await this.daemonService.getVersion();
this.version = `${version.version}`;
//this.version = `${version.version}`;
this.daemonInfo = await this.daemonService.getInfo();
@ -211,8 +240,8 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
this.version = this.daemonInfo.version;
this.syncProgress = `${(this.height*100/this.targetHeight).toFixed(2)} %`;
//const blockchainPruned = await this.isBlockchainPruned();
const blockchainPruned = false;
const blockchainPruned = await this.isBlockchainPruned();
//const blockchainPruned = false;
this.nodeType = blockchainPruned ? 'pruned' : 'full';
$table.bootstrapTable('load', this.getPeers());
}
@ -251,9 +280,11 @@ export class DetailComponent implements OnInit, AfterViewInit, OnDestroy {
class Card {
public header: string;
public content: string;
public loading: boolean;
constructor(header: string, content: string) {
constructor(header: string, content: string, loading: boolean = false) {
this.header = header;
this.content = content;
this.loading = loading;
}
}

View file

@ -1,4 +1,4 @@
<div class="tab-content" id="pills-settings-tabContent">
<div *ngIf="!loading" class="tab-content" id="pills-settings-tabContent">
<div class="tab-pane fade show active" id="pills-rpc" role="tabpanel" aria-labelledby="pills-rpc-tab" tabindex="0">
<div class="row g-5 m-2">
<div class="col-md-7 col-lg-10">
@ -7,42 +7,42 @@
<div class="form-check form-switch col-md-6">
<label for="offline" class="form-check-label">Offline</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="offline" (change)="OnOfflineChange()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="offline" [checked]="currentSettings.offline" (change)="OnOfflineChange()">
<br>
<small class="text-body-secondary">Do not listen for peers, nor connect to any</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="public-node" class="form-check-label">Public node</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="public-node" (change)="OnPublicNodeChange()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="public-node" [checked]="currentSettings.publicNode" (change)="OnPublicNodeChange()">
<br>
<small class="text-body-secondary">Allow other users to use the node as a remote (restricted RPC mode, view-only commands) and advertise it over P2P</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="restricted-rpc" class="form-check-label">Restricted RPC</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="restricted-rpc" (change)="OnRestrictedRPCChange()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="restricted-rpc" [checked]="currentSettings.restrictedRpc" (change)="OnRestrictedRPCChange()">
<br>
<small class="text-body-secondary">Restrict RPC to view-only commands and do not return privacy sensitive data in RPC calls</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="confirm-external-bind" class="form-check-label">Confirm external bind</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="confirm-external-bind" (change)="OnConfirmExternalBindChange()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="confirm-external-bind" [checked]="currentSettings.confirmExternalBind" (change)="OnConfirmExternalBindChange()">
<br>
<small class="text-body-secondary">Confirm Bind IP is not a loopback (local) IP</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="rpc-ignore-ipv4" class="form-check-label">Ignore IPv4</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ignore-ipv4" (change)="OnIgnoreIPv4Change()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ignore-ipv4" [checked]="currentSettings.rpcIgnoreIpv4" (change)="OnIgnoreIPv4Change()">
<br>
<small class="text-body-secondary">Ignore unsuccessful IPv4 bind for RPC</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="disable-rpc-ban" class="form-check-label">Disable ban</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="disable-rpc-ban" (change)="OnDisableRpcBanChange()">
<input class="form-control form-check-input" type="checkbox" role="switch" id="disable-rpc-ban" [checked]="currentSettings.disableRpcBan" (change)="OnDisableRpcBanChange()">
<br>
<small class="text-body-secondary">Do not ban hosts on RPC errors</small>
</div>
@ -85,7 +85,7 @@
<div class="form-check form-switch col-md-12">
<label for="rpc-use-ipv6" class="form-check-label">Enabled</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-use-ipv6" [(ngModel)]="currentSettings.rpcUseIpv6" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-use-ipv6" [checked]="currentSettings.rpcUseIpv6" [(ngModel)]="currentSettings.rpcUseIpv6" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow IPv6 for RPC</small>
</div>
@ -161,7 +161,7 @@
<div class="form-check form-switch col-md-6">
<label for="rpc-payment-allow-free-loopback" class="form-check-label">Allow free loopback</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-payment-allow-free-loopback" [(ngModel)]="currentSettings.rpcPaymentAllowFreeLoopback" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-payment-allow-free-loopback" [checked]="currentSettings.allowLocalIp" [(ngModel)]="currentSettings.rpcPaymentAllowFreeLoopback" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow free access from the loopback address (ie, the local host)</small>
</div>
@ -176,23 +176,23 @@
<div class="col-md-4">
<label for="rpc-ssl" class="form-label">SSL Mode</label>
<select class="form-select" id="rpc-ssl" [(ngModel)]="currentSettings.rpcSsl" [ngModelOptions]="{standalone: true}">
<option [ngValue]="'autodetect'">Autodetect</option>
<option [ngValue]="'enabled'">Enabled</option>
<option [ngValue]="'disabled'">Disabled</option>
<option [ngValue]="'autodetect'" [selected]="currentSettings.rpcSsl == 'autodetect'">Autodetect</option>
<option [ngValue]="'enabled'" [selected]="currentSettings.rpcSsl == 'enabled'">Enabled</option>
<option [ngValue]="'disabled'" [selected]="currentSettings.rpcSsl == 'disabled'">Disabled</option>
</select>
</div>
<div class="form-check form-switch col-md-4">
<label for="rpc-ssl-allow-chained" class="form-check-label">Allow chained</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ssl-allow-chained" [(ngModel)]="currentSettings.rpcSslAllowChained" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ssl-allow-chained" [checked]="currentSettings.rpcSslAllowChained" [(ngModel)]="currentSettings.rpcSslAllowChained" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow user chain certificates</small>
</div>
<div class="form-check form-switch col-md-4">
<label for="rpc-ssl-allow-any-cert" class="form-check-label">Allow any cert</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ssl-allow-any-cert" [(ngModel)]="currentSettings.rpcSslAllowAnyCert" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="rpc-ssl-allow-any-cert" [checked]="currentSettings.rpcSslAllowAnyCert" [(ngModel)]="currentSettings.rpcSslAllowAnyCert" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow any peer certificate</small>
</div>
@ -229,14 +229,14 @@
<div class="form-check form-switch col-md-6">
<label for="allow-local-ip" class="form-check-label">Allow local IP</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="allow-local-ip" [(ngModel)]="currentSettings.allowLocalIp" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="allow-local-ip" [checked]="currentSettings.allowLocalIp" [(ngModel)]="currentSettings.allowLocalIp" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow local ip add to peer list, mostly in debug process</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="p2p-ignore-ipv4" class="form-check-label">Ignore IPv4</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="p2p-ignore-ipv4" [(ngModel)]="currentSettings.p2pIgnoreIpv4">
<input class="form-control form-check-input" type="checkbox" role="switch" id="p2p-ignore-ipv4" [checked]="currentSettings.p2pIgnoreIpv4" [(ngModel)]="currentSettings.p2pIgnoreIpv4">
<br>
<small class="text-body-secondary">Ignore unsuccessful IPv4 bind for P2P</small>
</div>
@ -332,21 +332,21 @@
<div class="form-check form-switch col-md-6">
<label for="prune-blockchain" class="form-check-label">Prune Blockchain</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="prune-blockchain" [(ngModel)]="currentSettings.pruneBlockchain" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="prune-blockchain" [checked]="currentSettings.pruneBlockchain" [(ngModel)]="currentSettings.pruneBlockchain" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Reduce blockchain disk usage</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="sync-pruned-blocks" class="form-check-label">Sync pruned blocks</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="sync-pruned-blocks" [(ngModel)]="currentSettings.syncPrunedBlocks" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="sync-pruned-blocks" [checked]="currentSettings.syncPrunedBlocks" [(ngModel)]="currentSettings.syncPrunedBlocks" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Allow syncing from nodes with only pruned blocks</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="fast-block-sync" class="form-check-label">Fast block sync</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="fast-block-sync" [(ngModel)]="currentSettings.fastBlockSync" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="fast-block-sync" [checked]="currentSettings.fastBlockSync" [(ngModel)]="currentSettings.fastBlockSync" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Sync up most of the way by using embedded, known block hashes</small>
</div>
@ -360,7 +360,7 @@
<div class="form-check form-switch col-md-6">
<label for="keep-alt-blocks" class="form-check-label">Keep alternative blocks</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="keep-alt-blocks" [(ngModel)]="currentSettings.keepAltBlocks" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="keep-alt-blocks" [checked]="currentSettings.keepAltBlocks" [(ngModel)]="currentSettings.keepAltBlocks" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Keep alternative blocks on restart</small>
</div>
@ -380,21 +380,23 @@
<input type="text" class="form-control" id="db-sync-mode" placeholder="fast:async:250000000bytes" [(ngModel)]="currentSettings.dbSyncMode" [ngModelOptions]="{standalone: true}">
</div>
<hr class="my-4">
<h4 class="mb-3">Network type</h4>
<div class="my-3">
<div class="form-check">
<input id="credit" name="paymentMethod" type="radio" class="form-check-input">
<input id="credit" name="paymentMethod" type="radio" class="form-check-input" [value]="'mainnet'" [(ngModel)]="networkType" [ngModelOptions]="{standalone: true}" (change)="OnNetworkTypeChange()">
<label class="form-check-label" for="credit">mainnet</label>
</div>
<div class="form-check">
<input id="debit" name="paymentMethod" type="radio" class="form-check-input" [(ngModel)]="currentSettings.testnet" [ngModelOptions]="{standalone: true}">
<input id="debit" name="paymentMethod" type="radio" class="form-check-input" [value]="'testnet'" [(ngModel)]="networkType" [ngModelOptions]="{standalone: true}" (change)="OnNetworkTypeChange()">
<label class="form-check-label" for="debit">testnet</label>
</div>
<div class="form-check">
<input id="paypal" name="paymentMethod" type="radio" class="form-check-input" [(ngModel)]="currentSettings.stagenet" [ngModelOptions]="{standalone: true}">
<input id="paypal" name="paymentMethod" type="radio" class="form-check-input" [value]="'stagenet'" [(ngModel)]="networkType" [ngModelOptions]="{standalone: true}" (change)="OnNetworkTypeChange()">
<label class="form-check-label" for="paypal">stagenet</label>
</div>
</div>
@ -415,14 +417,14 @@
<div class="form-check form-switch col-md-6">
<label for="bg-mining-enable" class="form-check-label">Enabled</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="bg-mining-enable" [(ngModel)]="currentSettings.bgMiningEnable" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="bg-mining-enable" [checked]="currentSettings.bgMiningEnable" [(ngModel)]="currentSettings.bgMiningEnable" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Enable background mining</small>
</div>
<div class="form-check form-switch col-md-6">
<label for="bg-mining-ignore-battery" class="form-check-label">Ignore battery</label>
<input class="form-control form-check-input" type="checkbox" role="switch" id="bg-mining-ignore-battery" [(ngModel)]="currentSettings.bgMiningIgnoreBattery" [ngModelOptions]="{standalone: true}">
<input class="form-control form-check-input" type="checkbox" role="switch" id="bg-mining-ignore-battery" [checked]="currentSettings.bgMiningIgnoreBattery" [(ngModel)]="currentSettings.bgMiningIgnoreBattery" [ngModelOptions]="{standalone: true}">
<br>
<small class="text-body-secondary">Reduce blockchain disk usage</small>
</div>
@ -491,6 +493,6 @@
<hr class="my-4">
<button class="w-50 btn btn-primary btn-lg" type="submit" [disabled]="!modified" (click)="OnSave()">Save</button>
<button class="w-100 btn btn-primary btn-lg" type="submit" [disabled]="!modified" (click)="OnSave()">Save</button>
</div>

View file

@ -4,13 +4,12 @@ import { NavigationEnd, NavigationStart, Router } from '@angular/router';
import { NavbarLink } from '../../shared/components/navbar/navbar.model';
import { DaemonSettings } from '../../../common/DaemonSettings';
import { FormsModule, NgModel } from '@angular/forms';
import { DaemonService } from '../../core/services/daemon/daemon.service';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrl: './settings.component.scss',
imports: [FormsModule],
standalone: true
styleUrl: './settings.component.scss'
})
export class SettingsComponent implements AfterViewInit {
@ -20,9 +19,12 @@ export class SettingsComponent implements AfterViewInit {
public rpcLoginUser: string;
public rpcLoginPassword: string;
public loading: boolean;
constructor(private router: Router, private navbarService: NavbarService) {
public networkType: 'mainnet' | 'testnet' | 'stagenet' = 'mainnet';
constructor(private router: Router, private navbarService: NavbarService, private daemonService: DaemonService) {
this.loading = true;
this.navbarLinks = [
new NavbarLink('pills-rpc-tab', '#pills-rpc', 'pills-rpc', true, 'RPC'),
@ -50,6 +52,17 @@ export class SettingsComponent implements AfterViewInit {
this.onNavigationEnd();
}
});
this.load();
}
private async load(): Promise<void> {
console.log("getting settings");
this.originalSettings = await this.daemonService.getSettings();
this.currentSettings = this.originalSettings.clone();
this.loading = false;
this.networkType = this.currentSettings.mainnet ? 'mainnet' : this.currentSettings.testnet ? 'testnet' : this.currentSettings.stagenet ? 'stagenet' : 'mainnet';
}
public get modified(): boolean {
@ -105,12 +118,36 @@ export class SettingsComponent implements AfterViewInit {
this.currentSettings.noFluffyBlocks = !this.currentSettings.noFluffyBlocks;
}
public OnNetworkTypeChange(): void {
if (this.networkType == 'mainnet') {
this.currentSettings.mainnet = true;
this.currentSettings.testnet = false;
this.currentSettings.stagenet = false;
}
else if (this.networkType == 'testnet') {
this.currentSettings.mainnet = false;
this.currentSettings.testnet = true;
this.currentSettings.stagenet = false;
}
else if (this.networkType == 'stagenet') {
this.currentSettings.mainnet = false;
this.currentSettings.testnet = false;
this.currentSettings.stagenet = true;
}
}
private onNavigationEnd(): void {
}
public OnSave(): void {
public async OnSave(): Promise<void> {
if (!this.modified) {
return;
}
await this.daemonService.saveSettings(this.currentSettings);
this.originalSettings = this.currentSettings.clone();
}
}
/**

View file

@ -4,10 +4,11 @@ import { CommonModule } from '@angular/common';
import { SettingsRoutingModule } from './settings-routing.module';
import { SharedModule } from '../../shared/shared.module';
import { FormsModule } from '@angular/forms';
import { SettingsComponent } from './settings.component';
@NgModule({
declarations: [],
declarations: [SettingsComponent],
imports: [
CommonModule,
FormsModule,

View file

@ -1,10 +1,10 @@
<div class="d-flex flex-column flex-shrink-0 p-3 text-bg-dark" style="width: 200px;">
<div class="d-flex flex-column flex-shrink-0 p-3 text-bg-dark" style="width: 280px;">
<ul class="nav nav-pills flex-column mb-auto">
@for (navLink of navLinks; track navLink.title) {
<a routerLink="{{navLink.path}}" [ngClass]="isActive(navLink) ? 'nav-link active' : 'nav-link text-white'">
<i [class]="navLink.icon"></i>
{{navLink.title}}
<i [class]="navLink.icon"></i>&nbsp;
<strong>{{navLink.title}}</strong>
</a>
}
</ul>

View file

@ -1,6 +1,7 @@
import { CommonModule, NgClass, NgFor } from '@angular/common';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { ChildActivationEnd, ChildActivationStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouterEvent, RouterModule, RoutesRecognized } from '@angular/router';
import { DaemonService } from '../../../core/services/daemon/daemon.service';
@Component({
selector: 'app-sidebar',
@ -10,11 +11,37 @@ import { ChildActivationEnd, ChildActivationStart, NavigationCancel, NavigationE
export class SidebarComponent implements OnChanges {
@Input() public isDaemonRunning: boolean = false;
public navLinks: NavLink[];
public navLinks: NavLink[] = [];
public isLoading: boolean;
public errorMessage: string;
constructor(private router: Router) {
constructor(private router: Router, private daemonService: DaemonService) {
this.updateLinks();
this.isLoading = false;
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')
];
}
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')
];
}
});
}
private updateLinks(): void {
if (!this.isDaemonRunning) {
this.navLinks = [
new NavLink('Dashboard', '/detail', 'bi bi-speedometer2'),
@ -33,8 +60,6 @@ export class SidebarComponent implements OnChanges {
new NavLink('Settings', '/settings', 'bi bi-gear')
];
}
this.isLoading = false;
this.errorMessage = '';
}
public isActive(navLink: NavLink): boolean {

View file

@ -20,7 +20,7 @@ export class DaemonSettings {
public testDbgLockSleep: number = 0;
public testnet: boolean = false;
public mainnet: boolean = false;
public mainnet: boolean = true;
public stagenet: boolean = false;
public regtest: boolean = false;