mirror of
https://github.com/everoddandeven/monerod-gui.git
synced 2025-01-03 09:29:36 +00:00
Minor fixes, hash rate chart, refactory about page
Some checks are pending
Lint Test / build (20) (push) Waiting to run
MacOS Build / build (20) (push) Waiting to run
MacOS 12 - x64 DMG Build / build (20) (push) Waiting to run
Ubuntu 22.04 - AppImage Build / build (20) (push) Waiting to run
Ubuntu 22.04 - x64 DEB Build / build (20) (push) Waiting to run
Ubuntu 24.04 - x64 DEB Build / build (20) (push) Waiting to run
Windows Build / build (20) (push) Waiting to run
Some checks are pending
Lint Test / build (20) (push) Waiting to run
MacOS Build / build (20) (push) Waiting to run
MacOS 12 - x64 DMG Build / build (20) (push) Waiting to run
Ubuntu 22.04 - AppImage Build / build (20) (push) Waiting to run
Ubuntu 22.04 - x64 DEB Build / build (20) (push) Waiting to run
Ubuntu 24.04 - x64 DEB Build / build (20) (push) Waiting to run
Windows Build / build (20) (push) Waiting to run
This commit is contained in:
parent
49ab64cf07
commit
920a9cfa34
13 changed files with 298 additions and 86 deletions
|
@ -43,9 +43,9 @@
|
|||
"node_modules/bootstrap-table/dist/bootstrap-table.min.js"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss",
|
||||
"node_modules/bootstrap-icons/font/bootstrap-icons.css",
|
||||
"node_modules/bootstrap-table/dist/bootstrap-table.min.css"
|
||||
"node_modules/bootstrap-table/dist/bootstrap-table.min.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"customWebpackConfig": {
|
||||
"path": "./angular.webpack.js",
|
||||
|
|
19
app/main.ts
19
app/main.ts
|
@ -1,5 +1,5 @@
|
|||
import { app, BrowserWindow, ipcMain, screen, dialog, Tray, Menu, MenuItemConstructorOptions,
|
||||
IpcMainInvokeEvent, Notification, NotificationConstructorOptions
|
||||
IpcMainInvokeEvent, Notification, NotificationConstructorOptions, clipboard,
|
||||
} from 'electron';
|
||||
import { ChildProcessWithoutNullStreams, exec, ExecException, spawn } from 'child_process';
|
||||
import * as path from 'path';
|
||||
|
@ -254,7 +254,11 @@ function createWindow(): BrowserWindow {
|
|||
return win;
|
||||
}
|
||||
|
||||
const createSplashWindow = async (): Promise<BrowserWindow> => {
|
||||
const createSplashWindow = async (): Promise<BrowserWindow | undefined> => {
|
||||
|
||||
if (os.platform() == 'win32') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
width: 480,
|
||||
|
@ -713,8 +717,11 @@ try {
|
|||
await new Promise<void>((resolve, reject) => {
|
||||
try {
|
||||
setTimeout(() => {
|
||||
splash.close();
|
||||
if (!minimized) win?.show();
|
||||
if (splash) splash.close();
|
||||
if (!minimized) {
|
||||
win?.show();
|
||||
win?.maximize();
|
||||
}
|
||||
resolve();
|
||||
}, 2600);
|
||||
}
|
||||
|
@ -1030,6 +1037,10 @@ try {
|
|||
win?.webContents.send('on-is-app-image', isAppImage ? true : false);
|
||||
});
|
||||
|
||||
ipcMain.handle('copy-to-clipboard', (event: IpcMainInvokeEvent, content: string) => {
|
||||
clipboard.writeText(content, "selection");
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
// Catch Error
|
||||
console.error(e);
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
copyToClipboard: (content) => {
|
||||
ipcRenderer.invoke('copy-to-clipboard', content);
|
||||
},
|
||||
onTrayStartDaemon: (callback) => {
|
||||
ipcRenderer.on('on-tray-start-daemon', callback);
|
||||
},
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "monerod-gui",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "monerod-gui",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "17.3.12",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EventEmitter, Injectable, NgZone } from '@angular/core';
|
||||
import { DaemonService } from './daemon.service';
|
||||
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetStats, NetStatsHistory, PeerInfo, ProcessStats, PublicNode, SyncInfo, TimeUtils, TxBacklogEntry, TxPool, TxPoolStats } from '../../../../common';
|
||||
import { BlockCount, BlockHeader, Chain, Connection, CoreIsBusyError, DaemonInfo, MinerData, MiningStatus, NetHashRateHistory, NetStats, NetStatsHistory, PeerInfo, ProcessStats, PublicNode, SyncInfo, TimeUtils, TxBacklogEntry, TxPool, TxPoolStats } from '../../../../common';
|
||||
import { ElectronService } from '../electron/electron.service';
|
||||
|
||||
@Injectable({
|
||||
|
@ -42,6 +42,8 @@ export class DaemonDataService {
|
|||
private _netStatsHistory: NetStatsHistory = new NetStatsHistory();
|
||||
private _gettingNetStats: boolean = false;
|
||||
|
||||
private _hashRateHistory: NetHashRateHistory = new NetHashRateHistory();
|
||||
|
||||
private _miningStatus?: MiningStatus;
|
||||
private _gettingMiningStatus: boolean = false;
|
||||
|
||||
|
@ -81,6 +83,7 @@ export class DaemonDataService {
|
|||
|
||||
this.daemonService.onDaemonStatusChanged.subscribe((running: boolean) => {
|
||||
this.ngZone.run(() => {
|
||||
this._hashRateHistory = new NetHashRateHistory();
|
||||
if (running) {
|
||||
this._daemonRunning = true;
|
||||
this.startLoop();
|
||||
|
@ -253,6 +256,10 @@ export class DaemonDataService {
|
|||
return this._gettingTxPoolStats;
|
||||
}
|
||||
|
||||
public get netHashRateHistory(): NetHashRateHistory {
|
||||
return this._hashRateHistory;
|
||||
}
|
||||
|
||||
public setRefreshTimeout(ms: number = 5000): void {
|
||||
this.refreshTimeoutMs = ms;
|
||||
}
|
||||
|
@ -357,13 +364,6 @@ export class DaemonDataService {
|
|||
try {
|
||||
const settings = await this.daemonService.getSettings();
|
||||
|
||||
const updateInfo = await this.daemonService.checkUpdate()
|
||||
|
||||
if (updateInfo.update && settings.upgradeAutomatically) {
|
||||
await this.daemonService.upgrade();
|
||||
return;
|
||||
}
|
||||
|
||||
const syncAlreadyDisabled = this.daemonService.settings.noSync;
|
||||
|
||||
if (!settings.noSync && !syncAlreadyDisabled && !settings.syncOnWifi) {
|
||||
|
@ -440,9 +440,17 @@ export class DaemonDataService {
|
|||
this._daemonInfo = await this.daemonService.getInfo();
|
||||
this._gettingDaemonInfo = false;
|
||||
|
||||
if (this._daemonInfo.synchronized) {
|
||||
this._hashRateHistory.add(this._daemonInfo.gigaHashRate);
|
||||
}
|
||||
|
||||
if (this.daemonService.settings.upgradeAutomatically && this._daemonInfo.updateAvailable) {
|
||||
await this.daemonService.upgrade();
|
||||
return;
|
||||
const updateInfo = await this.daemonService.checkUpdate()
|
||||
|
||||
if (updateInfo.update) {
|
||||
await this.daemonService.upgrade();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._gettingSyncInfo = true;
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
<div class="tab-pane fade show active" id="pills-overview" role="tabpanel" aria-labelledby="pills-overview-tab" tabindex="0">
|
||||
<div class="container mt-5">
|
||||
<div class="card shadow-lg border-0">
|
||||
|
||||
<div class="card-header bg-primary text-white text-center">
|
||||
<h3 class="card-title mb-0">Monerod GUI</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<h5 class="card-subtitle mb-2 text-muted">Version: {{ guiVersion }}</h5>
|
||||
<p class="card-text">
|
||||
|
@ -32,37 +34,24 @@
|
|||
<br>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. </p>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-12">
|
||||
<h6>Donations</h6>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item text-center">
|
||||
<h4>XMR</h4>
|
||||
<br>
|
||||
<p class="text-center">
|
||||
<img src="assets/donations/xmr.png" width="200" height="200"/><br>
|
||||
<br>
|
||||
<code>84Q1SdQgFWaEWRn5KcvSPCQUa3NF39EJ3HPCTaiM86RHLLftqgTZpkP24jXrK5YpeedWbQAjHcFcDLpFJfr9TypfAU7pPjA</code>
|
||||
</p>
|
||||
</li>
|
||||
<li class="list-group-item text-center">
|
||||
<h4>BTC</h4>
|
||||
<br>
|
||||
<p class="text-center">
|
||||
<img src="assets/donations/btc.png" width="200" height="200"/><br>
|
||||
<br>
|
||||
<code>bc1qndc2lesy0sse9vj33a35pnfrqz4znlhhs58vfp</code>
|
||||
</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer text-muted d-flex justify-content-between align-items-center">
|
||||
<span>© 2024 Monerod GUI</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-contact" role="tabpanel" aria-labelledby="pills-contact-tab" tabindex="0">
|
||||
<div class="container mt-5">
|
||||
<div class="card shadow-lg border-0">
|
||||
|
||||
<div class="card-header bg-primary text-white text-center">
|
||||
<h3 class="card-title mb-0">Contact</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item"><i class="bi bi-github fs-4 m-4"></i> <strong>GitHub:</strong> https://github.com/everoddandeven/monerod-gui</li>
|
||||
<li class="list-group-item"><i class="bi bi-chat-square-quote fs-4 m-4"></i> <strong>Matrix:</strong> @everoddandeven:monero.social</li>
|
||||
|
@ -70,13 +59,51 @@
|
|||
<li class="list-group-item"><i class="bi bi-signal fs-4 m-4"></i><strong>Signal:</strong> @everoddandeven.01</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-footer text-muted d-flex justify-content-between align-items-center">
|
||||
<span>© 2024 Monerod GUI</span>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-donate" role="tabpanel" aria-labelledby="pills-donate-tab" tabindex="0">
|
||||
<div class="container mt-5">
|
||||
<div class="card shadow-lg border-0">
|
||||
|
||||
<div class="card-header bg-primary text-white text-center">
|
||||
<h3 class="card-title mb-0">Donate</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item text-center">
|
||||
|
||||
<div class="col-md-2 mx-auto">
|
||||
<select class="form-select" id="log-level" [(ngModel)]="donateCrypto" [ngModelOptions]="{standalone: true}">
|
||||
<option [ngValue]="'XMR'">XMR</option>
|
||||
<option [ngValue]="'BTC'">BTC</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<p *ngIf="donateCrypto === 'XMR'" class="text-center">
|
||||
<img src="assets/donations/xmr.png" width="200" height="200"/><br>
|
||||
<br>
|
||||
<code>{{XMRAddress}}</code>
|
||||
</p>
|
||||
<p *ngIf="donateCrypto === 'BTC'" class="text-center">
|
||||
<img src="assets/donations/btc.png" width="200" height="200"/><br>
|
||||
<br>
|
||||
<code>{{BTCAddress}}</code>
|
||||
</p>
|
||||
<button *ngIf="!addressCopied" type="button" class="btn btn-secondary btn-sm" (click)="copyAddressToClipboard()"><i class="bi bi-clipboard"></i> Copy to clipboard</button>
|
||||
<button *ngIf="addressCopied" type="button" class="btn btn-success btn-sm" ><i class="bi bi-clipboard-check"></i> Copied to clipboard</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -9,9 +9,16 @@ import { DaemonService } from '../../core/services';
|
|||
})
|
||||
export class AboutComponent {
|
||||
public readonly links: NavbarLink[] = [
|
||||
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', true, 'Overview')
|
||||
new NavbarLink('pills-overview-tab', '#pills-overview', 'pills-overview', true, 'License', false),
|
||||
new NavbarLink('pills-contact-tab', '#pills-contact', 'pills-contact', false, 'Contact', false),
|
||||
new NavbarLink('pills-donate-tab', '#pills-donate', 'pills-donate', false, 'Donate', false)
|
||||
];
|
||||
|
||||
public donateCrypto: 'XMR' | 'BTC' = 'XMR';
|
||||
public readonly XMRAddress: string = '84Q1SdQgFWaEWRn5KcvSPCQUa3NF39EJ3HPCTaiM86RHLLftqgTZpkP24jXrK5YpeedWbQAjHcFcDLpFJfr9TypfAU7pPjA';
|
||||
public readonly BTCAddress: string = 'bc1qndc2lesy0sse9vj33a35pnfrqz4znlhhs58vfp';
|
||||
public addressCopied: boolean = false;
|
||||
|
||||
public get guiVersion(): string {
|
||||
return this.daemonService.getGuiVersion();
|
||||
}
|
||||
|
@ -20,5 +27,14 @@ export class AboutComponent {
|
|||
|
||||
}
|
||||
|
||||
public copyAddressToClipboard(): void {
|
||||
window.electronAPI.copyToClipboard(this.donateCrypto == 'XMR' ? this.XMRAddress : this.BTCAddress);
|
||||
this.addressCopied = true;
|
||||
|
||||
setTimeout(() => {
|
||||
this.addressCopied = false;
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
.terminal {
|
||||
max-height: 700px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
border: 1px solid #333;
|
||||
border-radius: 5px;
|
||||
}
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
border: 1px solid #333;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.terminal-output {
|
||||
white-space: pre-wrap;
|
||||
white-space: pre-wrap;
|
||||
font-size: small;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div *ngIf="coreBusy" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||
<div>
|
||||
Mining status not available, node is not synchronized
|
||||
Mining is not available, node is not synchronized
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -119,18 +119,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
<hr *ngIf="!coreBusy" class="my-4">
|
||||
|
||||
<button *ngIf="!startingMining && (!miningStatus || !miningStatus.active)" class="w-100 btn btn-primary btn-lg" type="button" (click)="startMining()" [disabled]="!validStartMiningMinerAddress">Start Mining</button>
|
||||
<button *ngIf="startingMining && (!miningStatus || !miningStatus.active)" class="w-100 btn btn-primary btn-lg" type="button" disabled>Starting Mining ...</button>
|
||||
<button *ngIf="!coreBusy && !startingMining && (!miningStatus || !miningStatus.active)" class="w-100 btn btn-primary btn-lg" type="button" (click)="startMining()" [disabled]="!validStartMiningMinerAddress">Start Mining</button>
|
||||
<button *ngIf="!coreBusy && startingMining && (!miningStatus || !miningStatus.active)" class="w-100 btn btn-primary btn-lg" type="button" disabled>Starting Mining ...</button>
|
||||
|
||||
<button *ngIf="!stoppingMining && miningStatus && miningStatus.active" class="w-100 btn btn-primary btn-lg" type="button" (click)="stopMining()">Stop Mining</button>
|
||||
<button *ngIf="stoppingMining && miningStatus && miningStatus.active" class="w-100 btn btn-primary btn-lg" type="button" disabled>Stopping Mining ...</button>
|
||||
<button *ngIf="!coreBusy && !stoppingMining && miningStatus && miningStatus.active" class="w-100 btn btn-primary btn-lg" type="button" (click)="stopMining()">Stop Mining</button>
|
||||
<button *ngIf="!coreBusy && stoppingMining && miningStatus && miningStatus.active" class="w-100 btn btn-primary btn-lg" type="button" disabled>Stopping Mining ...</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-miner-data" role="tabpanel" aria-labelledby="pills-miner-data-tab" tabindex="0">
|
||||
<h4 class="mb-3">Necessary data to create a custom block template, used by p2pool</h4>
|
||||
<h4 *ngIf="!coreBusy" class="mb-3">Necessary data to create a custom block template, used by p2pool</h4>
|
||||
|
||||
<div *ngIf="coreBusy" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||
|
@ -155,18 +155,21 @@
|
|||
|
||||
<div class="tab-pane fade" id="pills-hashrate" role="tabpanel" aria-labelledby="pills-hashrate-tab" tabindex="0">
|
||||
|
||||
<h4 class="mb-3">Monero network hash rate</h4>
|
||||
<h4 *ngIf="synchronized" class="mb-3">Monero Network Hashrate</h4>
|
||||
|
||||
<div class="row d-flex justify-content-center">
|
||||
|
||||
<div class="card text-bg-dark m-3 text-center" style="max-width: 18rem;">
|
||||
<div class="card-header">Current Hashrate</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{networkHashRate}} GH/s</h5>
|
||||
</div>
|
||||
<div *ngIf="!synchronized" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||
<div>
|
||||
Network hash rate is not available, node is not synchronized
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="synchronized" class="row d-flex justify-content-center">
|
||||
|
||||
<h2><i class="bi bi-speedometer m-4"></i> Current Hashrate: {{networkHashRate}} GH/s</h2>
|
||||
<canvas class="my-4 w-100" id="netHashRateChart" width="900" height="380"></canvas>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-alternate-chains" role="tabpanel" aria-labelledby="pills-alternate-chains-tab" tabindex="0">
|
||||
|
@ -331,6 +334,14 @@
|
|||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-add-aux-pow" role="tabpanel" aria-labelledby="pills-add-aux-pow-tab" tabindex="0">
|
||||
|
||||
<div *ngIf="coreBusy" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||
<div>
|
||||
Add Aux Pow is not available, node is not synchronized
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="addAuxPowError !== ''" class="alert alert-danger d-flex align-items-center justify-content-center text-center" role="alert">
|
||||
<h4><i class="bi bi-exclamation-triangle m-2"></i></h4>
|
||||
<div>
|
||||
|
@ -409,8 +420,7 @@
|
|||
|
||||
<hr *ngIf="addAuxPowResult !== undefined" class="my-4">
|
||||
|
||||
|
||||
<div class="row g-5 p-2">
|
||||
<div *ngIf="!coreBusy" class="row g-5 p-2">
|
||||
<div class="cold-md-7 col-lg-12">
|
||||
<div class="row gy-3">
|
||||
<h4 class="mb-3">Easily enable merge mining with Monero without requiring software that manually alters the extra field in the coinbase tx to include the merkle root of the aux blocks</h4>
|
||||
|
@ -450,10 +460,10 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-4">
|
||||
<hr *ngIf="!coreBusy" class="my-4">
|
||||
|
||||
<button *ngIf="!addingAuxPow" class="w-100 btn btn-primary btn-lg" type="button" (click)="addAuxPow()">Add Aux PoW</button>
|
||||
<button *ngIf="addingAuxPow" class="w-100 btn btn-primary btn-lg" type="button" disabled>Adding Aux PoW ...</button>
|
||||
<button *ngIf="!coreBusy && !addingAuxPow" class="w-100 btn btn-primary btn-lg" type="button" (click)="addAuxPow()">Add Aux PoW</button>
|
||||
<button *ngIf="!coreBusy && addingAuxPow" class="w-100 btn btn-primary btn-lg" type="button" disabled>Adding Aux PoW ...</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-submit-block" role="tabpanel" aria-labelledby="pills-submit-block-tab" tabindex="0">
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
import { AfterContentInit, AfterViewInit, Component, NgZone } from '@angular/core';
|
||||
import { AfterContentInit, AfterViewInit, Component, NgZone, OnDestroy } from '@angular/core';
|
||||
import { DaemonService, DaemonDataService } from '../../core/services';
|
||||
import { NavbarLink, NavbarService } from '../../shared/components';
|
||||
import { AddedAuxPow, AuxPoW, BlockTemplate, GeneratedBlocks, MiningStatus, MinerData, Chain } from '../../../common';
|
||||
import { AddedAuxPow, AuxPoW, BlockTemplate, GeneratedBlocks, MiningStatus, MinerData, Chain, NetHashRateHistoryEntry } from '../../../common';
|
||||
import { BasePageComponent } from '../base-page/base-page.component';
|
||||
import { SimpleBootstrapCard } from '../../shared/utils';
|
||||
import { Chart, ChartData } from 'chart.js';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-mining',
|
||||
templateUrl: './mining.component.html',
|
||||
styleUrl: './mining.component.scss'
|
||||
})
|
||||
export class MiningComponent extends BasePageComponent implements AfterViewInit, AfterContentInit {
|
||||
export class MiningComponent extends BasePageComponent implements AfterViewInit, AfterContentInit, OnDestroy {
|
||||
|
||||
public get coreBusy(): boolean {
|
||||
return this.daemonData.info? !this.daemonData.info.coreSynchronized : true;
|
||||
}
|
||||
|
||||
public get synchronized(): boolean {
|
||||
return this.daemonData.info ? this.daemonData.info.synchronized : false;
|
||||
}
|
||||
|
||||
public get miningStatus(): MiningStatus | undefined {
|
||||
return this.daemonData.miningStatus;
|
||||
}
|
||||
|
@ -98,6 +104,8 @@ export class MiningComponent extends BasePageComponent implements AfterViewInit,
|
|||
return parseFloat(origValue.toFixed(2));
|
||||
}
|
||||
|
||||
private netHashRateChart?: Chart;
|
||||
|
||||
//private txBacklog: MineableTxBacklog[]
|
||||
public cards: SimpleBootstrapCard[];
|
||||
|
||||
|
@ -147,13 +155,100 @@ export class MiningComponent extends BasePageComponent implements AfterViewInit,
|
|||
new NavbarLink('pills-add-aux-pow-tab', '#pills-add-aux-pow', 'add-aux-pow', false, 'Add Aux PoW')
|
||||
]);
|
||||
|
||||
this.daemonData.syncEnd.subscribe(() => {
|
||||
const syncEndSub: Subscription = this.daemonData.syncEnd.subscribe(() => {
|
||||
this.refresh();
|
||||
})
|
||||
});
|
||||
|
||||
this.subscriptions.push(syncEndSub);
|
||||
}
|
||||
|
||||
private initNetHashRateChart(): void {
|
||||
setTimeout(() => {
|
||||
this.ngZone.run(() => {
|
||||
const ctx = <HTMLCanvasElement>document.getElementById('netHashRateChart');
|
||||
|
||||
if (!ctx) {
|
||||
console.warn("Could not find net hash rate chart");
|
||||
return;
|
||||
}
|
||||
|
||||
this.netHashRateChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: this.buildNetHashRateData(),
|
||||
options: {
|
||||
animation: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
tooltip: {
|
||||
boxPadding: 3
|
||||
},
|
||||
decimation: {
|
||||
enabled: true,
|
||||
algorithm: 'min-max'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private refreshNetHashRateHistory(): void {
|
||||
if (!this.synchronized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.netHashRateChart) {
|
||||
this.initNetHashRateChart();
|
||||
}
|
||||
|
||||
if (!this.netHashRateChart) {
|
||||
console.warn("Net hash rate chart is not initiliazed");
|
||||
return;
|
||||
}
|
||||
|
||||
const last = this.daemonData.netHashRateHistory.last;
|
||||
|
||||
if (!last) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label = `${last.date.toLocaleDateString()} ${last.date.toLocaleTimeString()}`;
|
||||
|
||||
this.netHashRateChart.data.labels?.push(label);
|
||||
this.netHashRateChart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(last.gigaHashRate);
|
||||
});
|
||||
|
||||
this.netHashRateChart.update();
|
||||
}
|
||||
|
||||
private buildNetHashRateData(): ChartData {
|
||||
const labels: string [] = [];
|
||||
const data: number[] = [];
|
||||
this.daemonData.netHashRateHistory.history.forEach((entry: NetHashRateHistoryEntry) => {
|
||||
labels.push(`${entry.date.toLocaleTimeString()} ${entry.date.toLocaleDateString()}`);
|
||||
data.push(entry.gigaHashRate);
|
||||
});
|
||||
|
||||
return {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: '#ff5733',
|
||||
borderWidth: 4,
|
||||
pointBackgroundColor: '#ff5733',
|
||||
radius: 0
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
this.loadTables();
|
||||
this.initNetHashRateChart();
|
||||
}
|
||||
|
||||
public override ngAfterContentInit(): void {
|
||||
|
@ -162,6 +257,15 @@ export class MiningComponent extends BasePageComponent implements AfterViewInit,
|
|||
this.cards = this.createCards();
|
||||
}
|
||||
|
||||
public override ngOnDestroy(): void {
|
||||
if (this.netHashRateChart) {
|
||||
this.netHashRateChart.destroy();
|
||||
this.netHashRateChart = undefined;
|
||||
}
|
||||
|
||||
super.ngOnDestroy();
|
||||
}
|
||||
|
||||
private loadTables(): void {
|
||||
this.loadChainsTable();
|
||||
}
|
||||
|
@ -230,6 +334,7 @@ export class MiningComponent extends BasePageComponent implements AfterViewInit,
|
|||
|
||||
private refresh(): void {
|
||||
this.loadChainsTable();
|
||||
this.refreshNetHashRateHistory();
|
||||
this.cards = this.createCards();
|
||||
}
|
||||
|
||||
|
|
28
src/common/NetHashRateHistory.ts
Normal file
28
src/common/NetHashRateHistory.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
export class NetHashRateHistory {
|
||||
private readonly _history: NetHashRateHistoryEntry[] = [];
|
||||
private _last?: NetHashRateHistoryEntry;
|
||||
|
||||
public get history(): NetHashRateHistoryEntry[] {
|
||||
return this._history;
|
||||
}
|
||||
|
||||
public get last(): NetHashRateHistoryEntry | undefined {
|
||||
return this._last;
|
||||
}
|
||||
|
||||
public add(gigaHashRate: number): void {
|
||||
const last = new NetHashRateHistoryEntry(gigaHashRate);
|
||||
this._history.push(last);
|
||||
this._last = last;
|
||||
}
|
||||
}
|
||||
|
||||
export class NetHashRateHistoryEntry {
|
||||
public readonly gigaHashRate: number;
|
||||
public readonly date: Date;
|
||||
|
||||
public constructor(gigaHashRate: number, date: Date = new Date()) {
|
||||
this.gigaHashRate = gigaHashRate;
|
||||
this.date = date;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ export { SpentKeyImage } from './SpentKeyImage';
|
|||
export { TxPool } from './TxPool';
|
||||
export { TxPoolStats, TxPoolHisto } from './TxPoolStats';
|
||||
export { ProcessStats } from './ProcessStats';
|
||||
export { NetHashRateHistory, NetHashRateHistoryEntry } from './NetHashRateHistory';
|
||||
|
||||
export * from './error';
|
||||
export * from './request';
|
||||
|
|
|
@ -53,12 +53,14 @@ import 'zone.js'; // Included with Angular CLI.
|
|||
*/
|
||||
|
||||
import 'jquery';
|
||||
import '@popperjs/core';
|
||||
import 'bootstrap-table';
|
||||
import { NotificationConstructorOptions } from 'electron';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
electronAPI: {
|
||||
copyToClipboard: (content: string) => void;
|
||||
startMonerod: (options: string[]) => void;
|
||||
|
||||
monitorMonerod: () => void;
|
||||
|
|
Loading…
Reference in a new issue