Tools page now contains only NVMe Block Format and Supermicro - DMI. Moved to Settings (7): - System Install (Install to RAM + Install to Disk) - Support Bundle + USB Black-Box - Tool Check - NVIDIA Self Heal (replaces simple NVIDIA Recovery card) - Network - Services Update TestToolsPageRendersNvidiaSelfHealSection to assert the moved cards on /settings instead of /tools. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
123 lines
5.4 KiB
Go
123 lines
5.4 KiB
Go
package webui
|
|
|
|
import "html"
|
|
|
|
func renderSettings(opts HandlerOptions) string {
|
|
version := opts.BuildLabel
|
|
if version == "" {
|
|
version = "dev"
|
|
}
|
|
return `<div class="card" style="margin-bottom:16px">
|
|
<div class="card-head">System Install</div>
|
|
<div class="card-body">
|
|
<div style="margin-bottom:20px">
|
|
<div style="font-weight:600;margin-bottom:8px">Install to RAM</div>
|
|
<p id="boot-source-text" style="color:var(--muted);font-size:13px;margin-bottom:8px">Detecting boot source...</p>
|
|
<p id="ram-status-text" style="color:var(--muted);font-size:13px;margin-bottom:8px">Checking...</p>
|
|
<button id="ram-install-btn" class="btn btn-primary" onclick="installToRAM()" style="display:none">▶ Copy to RAM</button>
|
|
</div>
|
|
<div style="border-top:1px solid var(--line);padding-top:20px">
|
|
<div style="font-weight:600;margin-bottom:8px">Install to Disk</div>` +
|
|
renderInstallInline() + `
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
fetch('/api/system/ram-status').then(r=>r.json()).then(d=>{
|
|
const boot = document.getElementById('boot-source-text');
|
|
const txt = document.getElementById('ram-status-text');
|
|
const btn = document.getElementById('ram-install-btn');
|
|
let kind = d.kind || 'unknown';
|
|
let source = d.device || d.source || 'unknown source';
|
|
let label = kind==='ram'?'RAM':kind==='usb'?'USB ('+source+')':kind==='cdrom'?'CD-ROM ('+source+')':kind==='disk'?'disk ('+source+')':source;
|
|
boot.textContent = 'Current boot source: ' + label + '.';
|
|
txt.textContent = d.blocked_reason || d.message || 'Checking...';
|
|
txt.style.color = (d.status==='ok'||d.in_ram)?'var(--ok,green)':d.status==='failed'?'var(--err,#b91c1c)':'var(--muted)';
|
|
if (d.can_start_task) { btn.style.display=''; btn.disabled=false; } else { btn.style.display='none'; }
|
|
});
|
|
function installToRAM() {
|
|
document.getElementById('ram-install-btn').disabled = true;
|
|
fetch('/api/system/install-to-ram', {method:'POST'}).then(r=>r.json()).then(d=>{
|
|
window.location.href = '/tasks#' + d.task_id;
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<div class="card"><div class="card-head">Support Bundle</div><div class="card-body">
|
|
<p style="font-size:13px;color:var(--muted);margin-bottom:12px">Downloads a tar.gz archive of all audit files, SAT results, and logs.</p>
|
|
` + renderSupportBundleInline() + `
|
|
<div style="border-top:1px solid var(--border);margin-top:16px;padding-top:16px">
|
|
<div style="font-weight:600;margin-bottom:8px">USB Black-Box</div>
|
|
` + renderUSBExportInline() + `
|
|
</div>
|
|
</div></div>
|
|
|
|
<div class="card"><div class="card-head">Tool Check <button class="btn btn-sm btn-secondary" onclick="checkTools()" style="margin-left:auto">↻ Check</button></div>
|
|
<div class="card-body"><div id="tools-table"><p style="color:var(--muted);font-size:13px">Checking...</p></div></div></div>
|
|
<script>
|
|
function checkTools() {
|
|
document.getElementById('tools-table').innerHTML = '<p style="color:var(--muted);font-size:13px">Checking...</p>';
|
|
fetch('/api/tools/check').then(r=>r.json()).then(tools => {
|
|
const rows = tools.map(t =>
|
|
'<tr><td>'+t.Name+'</td><td><span class="badge '+(t.OK?'badge-ok':'badge-err')+'">'+(t.OK?'✓ '+t.Path:'✗ missing')+'</span></td></tr>'
|
|
).join('');
|
|
document.getElementById('tools-table').innerHTML = '<table><tr><th>Tool</th><th>Status</th></tr>'+rows+'</table>';
|
|
});
|
|
}
|
|
checkTools();
|
|
</script>
|
|
|
|
<div class="card"><div class="card-head">NVIDIA Self Heal</div><div class="card-body">` +
|
|
renderNvidiaSelfHealInline() + `</div></div>
|
|
|
|
<div class="card"><div class="card-head">Network</div><div class="card-body">` +
|
|
renderNetworkInline() + `</div></div>
|
|
|
|
<div class="card"><div class="card-head">Services</div><div class="card-body">` +
|
|
renderServicesInline() + `</div></div>
|
|
|
|
<div class="card">
|
|
<div class="card-head">Blackbox Logging</div>
|
|
<div class="card-body">
|
|
<p style="font-size:13px;color:var(--muted);margin-bottom:14px">Continuous hardware monitoring that writes a rolling log of sensor readings to the export directory.</p>
|
|
<div style="display:flex;gap:8px;align-items:center">
|
|
<button class="btn btn-primary btn-sm" onclick="blackboxToggle('enable')">Enable</button>
|
|
<button class="btn btn-secondary btn-sm" onclick="blackboxToggle('disable')">Disable</button>
|
|
<span id="blackbox-status" style="font-size:12px;color:var(--muted)">Loading...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-head">Build Info</div>
|
|
<div class="card-body">
|
|
<table style="width:auto">
|
|
<tbody>
|
|
<tr><td style="color:var(--muted);padding-right:24px">Version</td><td>` + html.EscapeString(version) + `</td></tr>
|
|
<tr><td style="color:var(--muted);padding-right:24px">Title</td><td>` + html.EscapeString(opts.Title) + `</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function() {
|
|
fetch('/api/blackbox/status', {cache:'no-store'}).then(r => r.json()).then(d => {
|
|
var el = document.getElementById('blackbox-status');
|
|
if (el) el.textContent = d.enabled ? 'Enabled' : 'Disabled';
|
|
}).catch(() => {
|
|
var el = document.getElementById('blackbox-status');
|
|
if (el) el.textContent = 'Status unavailable';
|
|
});
|
|
})();
|
|
function blackboxToggle(action) {
|
|
var el = document.getElementById('blackbox-status');
|
|
if (el) el.textContent = 'Updating...';
|
|
fetch('/api/blackbox/' + action, {method:'POST', cache:'no-store'})
|
|
.then(r => r.json())
|
|
.then(d => { if (el) el.textContent = d.enabled ? 'Enabled' : 'Disabled'; })
|
|
.catch(err => { if (el) el.textContent = 'Error: ' + err.message; });
|
|
}
|
|
</script>`
|
|
}
|