Add pool presets, operator bake-ins, and USB pack improvements
- Pool preset checkboxes with failover in Calibrate and Forge - Tier 1/2 UX: setup banner, forge next worker, LAN defaults, blueprint prompt - USB: auto-install forge tools, seed config.json, sync LAUNCH.bat
This commit is contained in:
@@ -2,7 +2,15 @@ import { useState, useEffect, useRef } from 'react';
|
||||
import { api } from '../api/client';
|
||||
import { setStoredAuth, getStoredAuth, clearStoredAuth } from '../api/auth';
|
||||
import type { ServerConfig } from '../types';
|
||||
import {
|
||||
DEFAULT_PRESET_IDS,
|
||||
orderedPoolsFromSelection,
|
||||
applyPoolsToForgeFields,
|
||||
} from '../help/poolPresets';
|
||||
import { looksLikeXMRWallet } from '../help/forgeValidation';
|
||||
import { HelpTip, FieldHint } from '../components/HelpTip';
|
||||
import PoolPresetPicker from '../components/PoolPresetPicker';
|
||||
import type { BackupPool } from '../types';
|
||||
import NeonCard from '../components/NeonCard/NeonCard';
|
||||
import './Pages.css';
|
||||
|
||||
@@ -89,6 +97,17 @@ export default function SettingsPage() {
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!config) return;
|
||||
const wallet = config.wallet.address?.trim() ?? '';
|
||||
if (wallet && !looksLikeXMRWallet(wallet)) {
|
||||
const strict = config.server?.strict_wallet_validation ?? false;
|
||||
if (strict) {
|
||||
setSaveMessage('Save blocked: wallet does not look like a valid Monero mainnet address.');
|
||||
return;
|
||||
}
|
||||
if (!window.confirm('Wallet does not look like a standard Monero address. Save anyway?')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
setSaving(true);
|
||||
setSaveMessage('');
|
||||
try {
|
||||
@@ -272,10 +291,26 @@ export default function SettingsPage() {
|
||||
updateField('server.open_firewall_on_start', true);
|
||||
updateField('server.obfuscate_default', false);
|
||||
updateField('server.sign_enabled', false);
|
||||
const pools = orderedPoolsFromSelection(
|
||||
[...DEFAULT_PRESET_IDS],
|
||||
config.pool.password || 'x'
|
||||
);
|
||||
const poolFields = applyPoolsToForgeFields(pools);
|
||||
updateField('pool.host', poolFields.pool_host);
|
||||
updateField('pool.port', poolFields.pool_port);
|
||||
updateField('pool.use_tls', poolFields.pool_tls);
|
||||
updateField(
|
||||
'pool.backup_pools',
|
||||
poolFields.backup_pools.map((bp) => ({
|
||||
host: bp.host,
|
||||
port: bp.port,
|
||||
use_tls: bp.tls,
|
||||
}))
|
||||
);
|
||||
if (!config.wallet.address?.trim()) {
|
||||
setSaveMessage('Set your Monero wallet below, then Save Calibration.');
|
||||
setSaveMessage('TLS pool presets + LAN URL applied — set your Monero wallet, then Save Calibration.');
|
||||
} else {
|
||||
setSaveMessage('Best defaults applied to the form — click Save Calibration to keep them.');
|
||||
setSaveMessage('Best defaults applied (LAN URL + TLS pool presets) — click Save Calibration to keep them.');
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -335,26 +370,29 @@ export default function SettingsPage() {
|
||||
|
||||
<NeonCard accent="cyan" className="settings-section">
|
||||
<h2 className="font-display">Upstream Pool</h2>
|
||||
<p className="section-desc">The control server connects here and relays work to your fleet (not per-miner in this tab).</p>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cfg-pool-host" className="label">Pool Host <HelpTip field="pool_host" /></label>
|
||||
<input id="cfg-pool-host" type="text" className="input" value={config.pool.host}
|
||||
onChange={(e) => updateField('pool.host', e.target.value)} />
|
||||
</div>
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label htmlFor="cfg-pool-port" className="label">Port</label>
|
||||
<input id="cfg-pool-port" type="number" className="input" value={config.pool.port}
|
||||
onChange={(e) => updateField('pool.port', parseInt(e.target.value) || 3333)} />
|
||||
</div>
|
||||
<div className="form-group checkbox-group" style={{ alignSelf: 'flex-end' }}>
|
||||
<label className="checkbox-label">
|
||||
<input type="checkbox" className="checkbox" checked={config.pool.use_tls}
|
||||
onChange={(e) => updateField('pool.use_tls', e.target.checked)} />
|
||||
<span>Use TLS</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p className="section-desc">The control server connects here and relays work to your fleet. Pick presets or add your own — unreachable pools are skipped automatically.</p>
|
||||
<PoolPresetPicker
|
||||
host={config.pool.host}
|
||||
port={config.pool.port}
|
||||
tls={config.pool.use_tls}
|
||||
pass={config.pool.password || 'x'}
|
||||
backups={(config.pool.backup_pools ?? []).map(
|
||||
(bp): BackupPool => ({ host: bp.host, port: bp.port, tls: bp.use_tls, pass: config.pool.password || 'x' })
|
||||
)}
|
||||
onChange={(next) => {
|
||||
updateField('pool.host', next.pool_host);
|
||||
updateField('pool.port', next.pool_port);
|
||||
updateField('pool.use_tls', next.pool_tls);
|
||||
updateField(
|
||||
'pool.backup_pools',
|
||||
(next.backup_pools ?? []).map((bp) => ({
|
||||
host: bp.host,
|
||||
port: bp.port,
|
||||
use_tls: bp.tls,
|
||||
}))
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cfg-pool-pass" className="label">Pool Password</label>
|
||||
<input id="cfg-pool-pass" type="text" className="input" value={config.pool.password}
|
||||
|
||||
Reference in New Issue
Block a user