POST /api/system/reboot → systemctl reboot POST /api/system/shutdown → systemctl poweroff Both require confirm() before executing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
116 lines
5.0 KiB
Go
116 lines
5.0 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">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>
|
|
|
|
<div class="card">
|
|
<div class="card-head">Power</div>
|
|
<div class="card-body">
|
|
<div style="display:flex;gap:8px;align-items:center">
|
|
<button class="btn btn-secondary btn-sm" onclick="systemPower('reboot')">Reboot</button>
|
|
<button class="btn btn-secondary btn-sm" onclick="systemPower('shutdown')">Shutdown</button>
|
|
<span id="power-status" style="font-size:12px;color:var(--muted)"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function systemPower(action) {
|
|
var label = action === 'reboot' ? 'reboot' : 'shut down';
|
|
if (!confirm('Are you sure you want to ' + label + ' the server?')) return;
|
|
var el = document.getElementById('power-status');
|
|
if (el) el.textContent = action === 'reboot' ? 'Rebooting...' : 'Shutting down...';
|
|
fetch('/api/system/' + action, {method: 'POST'})
|
|
.then(function(r) { return r.json(); })
|
|
.catch(function(e) { if (el) el.textContent = 'Error: ' + e.message; });
|
|
}
|
|
</script>
|
|
|
|
`
|
|
}
|