feat: alive UI wave, galaxy presence, spread and fleet enhancements
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Dashboard ambient layer, comrade presence, Mission Deck and War Room, Emberwake supply chain, spread/docs publishing, fleet policy and modules API, CI docker mining, and refreshed USB pack.
This commit is contained in:
@@ -17,11 +17,19 @@ import RVNPoolPresetPicker from '../components/RVNPoolPresetPicker';
|
||||
import type { BackupPool } from '../types';
|
||||
import NeonCard from '../components/NeonCard/NeonCard';
|
||||
import FleetTasksPanel from '../components/Fleet/FleetTasksPanel';
|
||||
import FleetRuntimePanel from '../components/Fleet/FleetRuntimePanel';
|
||||
import { AuditLogStrip } from '../components/Fleet/FleetOpsWidgets';
|
||||
import { useSound } from '../context/SoundContext';
|
||||
import { useAmbientMusic } from '../context/AmbientMusicContext';
|
||||
import { AMBIENT_MUSIC_SRC } from '../audio/ambientMusic';
|
||||
import { useVisualEffects } from '../context/VisualEffectsContext';
|
||||
import {
|
||||
FORGE_SKIN_IDS,
|
||||
loadStoredForgeTheme,
|
||||
storeForgeTheme,
|
||||
type ForgeSkinId,
|
||||
type ForgeThemeOverride,
|
||||
} from '../help/forgeOperationModes';
|
||||
import './Pages.css';
|
||||
|
||||
/** Recursively merge `override` into `base`, preserving keys not in `override`. */
|
||||
@@ -62,6 +70,7 @@ export default function SettingsPage() {
|
||||
} = useSound();
|
||||
const { enabled: bgmEnabled, volume: bgmVolume, setEnabled: setBgmEnabled, setVolume: setBgmVolume } = useAmbientMusic();
|
||||
const { glowParticles, setGlowParticles } = useVisualEffects();
|
||||
const [forgeTheme, setForgeTheme] = useState<ForgeThemeOverride>(loadStoredForgeTheme);
|
||||
const [config, setConfig] = useState<ServerConfig | null>(null);
|
||||
const [serverInfo, setServerInfo] = useState<{ suggested_url: string; local_ips: string[] } | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -121,6 +130,8 @@ export default function SettingsPage() {
|
||||
strict_wallet_validation: cfg.server?.strict_wallet_validation ?? false,
|
||||
dashboard_subtitle: cfg.server?.dashboard_subtitle ?? 'security is just an emotion',
|
||||
open_firewall_on_start: cfg.server?.open_firewall_on_start ?? true,
|
||||
public_builds_enabled: cfg.server?.public_builds_enabled ?? false,
|
||||
public_builds_latest_n: cfg.server?.public_builds_latest_n ?? 3,
|
||||
},
|
||||
});
|
||||
setServerInfo(info);
|
||||
@@ -301,7 +312,7 @@ export default function SettingsPage() {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="page fade-in command-deck">
|
||||
<div className="page fade-in command-deck operator-deck-page">
|
||||
<header className="deck-hero">
|
||||
<div className="deck-hero-text">
|
||||
<p className="deck-eyebrow font-tech">SERVER ONLY</p>
|
||||
@@ -315,7 +326,7 @@ export default function SettingsPage() {
|
||||
|
||||
if (!config) {
|
||||
return (
|
||||
<div className="page fade-in command-deck">
|
||||
<div className="page fade-in command-deck operator-deck-page">
|
||||
<NeonCard accent="brass"><p>Failed to load server configuration.</p></NeonCard>
|
||||
</div>
|
||||
);
|
||||
@@ -340,10 +351,12 @@ export default function SettingsPage() {
|
||||
sign_cert_thumbprint: '',
|
||||
sign_tool_path: '',
|
||||
sign_timestamp_url: 'http://timestamp.digicert.com',
|
||||
public_builds_enabled: false,
|
||||
public_builds_latest_n: 3,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="page fade-in command-deck">
|
||||
<div className="page fade-in command-deck operator-deck-page">
|
||||
<input type="file" ref={fileInputRef} style={{ display: 'none' }} accept=".json" onChange={handleFileSelected} />
|
||||
|
||||
<header className="deck-hero">
|
||||
@@ -379,7 +392,7 @@ export default function SettingsPage() {
|
||||
)}
|
||||
|
||||
{serverInfo && (
|
||||
<NeonCard accent="cyan" className="calibrate-banner" hud>
|
||||
<NeonCard accent="cyan" className="calibrate-banner operator-deck-card operator-interactive" hud>
|
||||
<p className="font-tech">DETECTED LAN ENDPOINTS</p>
|
||||
<p><strong>Suggested:</strong> <code className="mono-sm">{serverInfo.suggested_url}</code></p>
|
||||
{serverInfo.local_ips?.length > 0 && (
|
||||
@@ -426,7 +439,7 @@ export default function SettingsPage() {
|
||||
)}
|
||||
|
||||
<div className="settings-grid">
|
||||
<NeonCard accent="cyan" className="settings-section">
|
||||
<NeonCard accent="cyan" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Deck Atmosphere</h2>
|
||||
<p className="section-desc">
|
||||
Background glow particles and sparkles sit behind the UI (pointer-events off). Turn off on
|
||||
@@ -443,9 +456,43 @@ export default function SettingsPage() {
|
||||
<span>Glow particles & sparkles</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-group" style={{ marginTop: '1.25rem' }}>
|
||||
<label htmlFor="cfg-forge-theme" className="label">
|
||||
Forge theme
|
||||
</label>
|
||||
<p className="section-desc" style={{ marginBottom: '0.5rem' }}>
|
||||
Seasonal forge chrome on The Forge page. Auto follows the selected operation mode preset;
|
||||
pick a skin to override.
|
||||
</p>
|
||||
<select
|
||||
id="cfg-forge-theme"
|
||||
className="select"
|
||||
value={forgeTheme}
|
||||
onChange={(e) => {
|
||||
const next = e.target.value as ForgeThemeOverride;
|
||||
setForgeTheme(next);
|
||||
storeForgeTheme(next);
|
||||
}}
|
||||
>
|
||||
<option value="auto">Auto (follow operation mode)</option>
|
||||
{FORGE_SKIN_IDS.map((id: ForgeSkinId) => (
|
||||
<option key={id} value={id}>
|
||||
{id === 'aether'
|
||||
? 'Default Aether'
|
||||
: id === 'halloween'
|
||||
? 'Halloween'
|
||||
: id === 'ghost'
|
||||
? 'Ghost Walk'
|
||||
: id === 'wildfire'
|
||||
? 'Wildfire'
|
||||
: 'Crucible Storm'}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="green" className="settings-section">
|
||||
<NeonCard accent="green" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Sound & Haptics</h2>
|
||||
<p className="section-desc">
|
||||
Short UI bleeps and vibration on supported phones/tablets. Browsers require a click anywhere
|
||||
@@ -582,7 +629,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="brass" className="settings-section">
|
||||
<NeonCard accent="brass" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Control Server</h2>
|
||||
<p className="section-desc">How this dashboard and API are hosted on your network.</p>
|
||||
<div className="form-row">
|
||||
@@ -647,7 +694,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="cyan" className="settings-section">
|
||||
<NeonCard accent="cyan" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Upstream Pool</h2>
|
||||
<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
|
||||
@@ -684,7 +731,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="purple" className="settings-section">
|
||||
<NeonCard accent="purple" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Fleet Payout Wallet</h2>
|
||||
<p className="section-desc">Default wallet the server uses when connecting to the pool. The Forge pre-fills this when building miners.</p>
|
||||
<div className="form-group">
|
||||
@@ -708,7 +755,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="amber" className="settings-section">
|
||||
<NeonCard accent="amber" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Ravencoin (GPU) Pool</h2>
|
||||
<p className="section-desc">
|
||||
Default RVN pool and wallet used when forging GPU-enabled agents. These pre-populate the Forge GPU mining fields.
|
||||
@@ -770,7 +817,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="amber" className="settings-section">
|
||||
<NeonCard accent="amber" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Fleet Alerts</h2>
|
||||
<p className="section-desc">Dashboard thresholds for agent health.</p>
|
||||
<div className="form-group">
|
||||
@@ -792,7 +839,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="amber" className="settings-section">
|
||||
<NeonCard accent="amber" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Alert Notifications</h2>
|
||||
<p className="section-desc">
|
||||
Telegram, optional webhook, and email for fleet events (operator pub/sub — MITRE T1071.005 lite).
|
||||
@@ -931,7 +978,42 @@ export default function SettingsPage() {
|
||||
)}
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="brass" className="settings-section">
|
||||
<NeonCard accent="cyan" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Emberwake / Public Builds</h2>
|
||||
<p className="section-desc">
|
||||
Control which forged installers appear on the login-page public builds drawer and unauthenticated{' '}
|
||||
<code className="mono-sm">/api/v1/public/builds</code> API. Mark individual builds public in Builds, or
|
||||
enable all-builds mode below.
|
||||
</p>
|
||||
<div className="form-group checkbox-group">
|
||||
<label className="checkbox-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="checkbox"
|
||||
checked={s.public_builds_enabled ?? false}
|
||||
onChange={(e) => updateField('server.public_builds_enabled', e.target.checked)}
|
||||
/>
|
||||
<span>Expose all builds on public API (no login)</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="cfg-public-latest-n" className="label">Latest N on login drawer</label>
|
||||
<input
|
||||
id="cfg-public-latest-n"
|
||||
type="number"
|
||||
className="input"
|
||||
min={1}
|
||||
max={50}
|
||||
value={s.public_builds_latest_n ?? 3}
|
||||
onChange={(e) => updateField('server.public_builds_latest_n', parseInt(e.target.value, 10) || 3)}
|
||||
/>
|
||||
<span className="form-hint">
|
||||
When all-builds mode is off, login drawer lists pinned + explicitly public builds + this many recent forges.
|
||||
</span>
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="brass" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Forge Pipeline</h2>
|
||||
<p className="section-desc">Defaults for obfuscation and code signing applied when forging on this control PC.</p>
|
||||
<div className="form-group checkbox-group">
|
||||
@@ -972,7 +1054,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="green" className="settings-section">
|
||||
<NeonCard accent="green" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Data & Limits</h2>
|
||||
<p className="section-desc">Retention and capacity for this host.</p>
|
||||
<div className="form-row">
|
||||
@@ -1006,7 +1088,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="brass" className="settings-section">
|
||||
<NeonCard accent="brass" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Server Logging</h2>
|
||||
<p className="section-desc">What this control server writes to its log.</p>
|
||||
<div className="form-group checkbox-group">
|
||||
@@ -1032,7 +1114,7 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="magenta" className="settings-section">
|
||||
<NeonCard accent="magenta" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Access Control</h2>
|
||||
<p className="section-desc">
|
||||
API routes require login. On first server start, credentials are printed once in the server console (<code>admin</code> + random password). Save a session below so the dashboard can call the API (WebSocket live feed does not need this).
|
||||
@@ -1078,7 +1160,9 @@ export default function SettingsPage() {
|
||||
)}
|
||||
</NeonCard>
|
||||
|
||||
<NeonCard accent="amber" className="settings-section">
|
||||
<FleetRuntimePanel />
|
||||
|
||||
<NeonCard accent="amber" className="settings-section operator-deck-card operator-interactive">
|
||||
<h2 className="font-display">Fleet Security</h2>
|
||||
<p className="section-desc">
|
||||
A <strong>Fleet Secret</strong> is auto-generated on first server start and baked into every forged agent.
|
||||
|
||||
Reference in New Issue
Block a user