29a9dcdd8c
Controller-only UI/orchestration over the agent's disk endpoints + StoragePath registry. New: storage overview (data_bearing badges), guided init (format -> resolve fs UUID -> assign -> register; data-bearing REFUSAL surfaces the felhom-opsign command, no force-format), guided attach, eject (+deregister, dependent-guest warning). agentapi: DiskInfo.DurableID/FSUUID + FormatResult. PendingOp (parsed from the 403). Honest buttons (migrate disabled, no 404s). Phase 3: removed dead CrossDrive blocks in deploy.html/backups.html. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
126 lines
6.9 KiB
HTML
126 lines
6.9 KiB
HTML
{{define "storage_init"}}
|
|
{{template "layout_start" .}}
|
|
|
|
<div class="page-header">
|
|
<div style="display:flex;align-items:center;gap:.5rem">
|
|
<a href="/settings" class="btn btn-sm btn-outline">← Vissza</a>
|
|
<h2>Új meghajtó inicializálása</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>1. Meghajtó kiválasztása</h3>
|
|
<p class="settings-card-desc">Válassza ki a formázandó meghajtót. A formázás biztonságát a host-ügynök
|
|
garantálja: <strong>adatot tartalmazó meghajtó nem formázható operátori aláírás nélkül</strong>.</p>
|
|
<div id="disk-error" class="alert alert-error" style="display:none;margin-bottom:1rem"></div>
|
|
<div id="disk-list">Betöltés…</div>
|
|
</div>
|
|
|
|
<div class="settings-card" id="cfg-card" style="display:none">
|
|
<h3>2. Konfiguráció</h3>
|
|
<form id="init-form" onsubmit="return submitInit(event)">
|
|
<div class="form-group">
|
|
<label>Kiválasztott eszköz</label>
|
|
<span class="settings-value mono" id="sel-device">—</span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="mount-name">Csatlakoztatási név <span class="required">*</span></label>
|
|
<div style="display:flex;align-items:center;gap:.25rem">
|
|
<span class="mono" style="opacity:.6">/mnt/</span>
|
|
<input type="text" id="mount-name" class="form-control" placeholder="hdd_1"
|
|
pattern="[a-zA-Z0-9_-]+" required style="max-width:180px">
|
|
</div>
|
|
<span class="form-hint">A meghajtó a /mnt/<név> útvonalra kerül.</span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="fstype">Fájlrendszer</label>
|
|
<select id="fstype" class="form-control" style="max-width:180px">
|
|
<option value="ext4" selected>ext4</option>
|
|
<option value="xfs">xfs</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="storage-label">Megnevezés</label>
|
|
<input type="text" id="storage-label" class="form-control" placeholder="Külső HDD 1TB" maxlength="50">
|
|
</div>
|
|
<label class="toggle" style="margin-bottom:1.25rem">
|
|
<input type="checkbox" id="set-default" checked>
|
|
<span class="toggle-label">Beállítás alapértelmezett adattárolóként új telepítéseknél</span>
|
|
</label>
|
|
<div class="alert alert-warning" id="warn-databearing" style="display:none;margin-bottom:1rem">
|
|
⚠️ A kiválasztott meghajtó <strong>adatot tartalmaz</strong>. A formázás védelmi okból csak
|
|
operátori aláírással hajtható végre — a rendszer megmutatja a szükséges parancsot.
|
|
</div>
|
|
<div class="form-actions" style="gap:.75rem">
|
|
<button type="submit" class="btn btn-danger-outline" id="init-btn">Inicializálás indítása</button>
|
|
<a href="/settings" class="btn btn-outline">Mégsem</a>
|
|
</div>
|
|
<div id="init-result" style="margin-top:1rem"></div>
|
|
</form>
|
|
</div>
|
|
|
|
<script>
|
|
var selDevice = "", selDataBearing = false;
|
|
|
|
function badge(d){
|
|
if(d.backing_device===""){ return '<span class="badge">—</span>'; }
|
|
return d.data_bearing
|
|
? '<span class="badge badge-error" title="'+(d.data_reason||'')+'">Adatot tartalmaz</span>'
|
|
: '<span class="badge badge-ok">Üres — formázható</span>';
|
|
}
|
|
|
|
async function loadDisks(){
|
|
try{
|
|
var r = await fetch('/api/disks'); var j = await r.json();
|
|
if(!j.ok){ throw new Error(j.error||'Hiba'); }
|
|
var disks = (j.data&&j.data.disks)||[];
|
|
var formattable = disks.filter(function(d){return d.backing_device!=="";});
|
|
if(formattable.length===0){ document.getElementById('disk-list').innerHTML='<p class="form-hint">Nincs formázható (blokkeszközzel rendelkező) meghajtó.</p>'; return; }
|
|
var html='<table class="data-table"><thead><tr><th></th><th>Tároló</th><th>Típus</th><th>Eszköz</th><th>Állapot</th><th>Osztály</th><th>Adat</th></tr></thead><tbody>';
|
|
formattable.forEach(function(d,i){
|
|
html+='<tr><td><input type="radio" name="disk" value="'+d.backing_device+'" data-db="'+(d.data_bearing?'1':'0')+'" onchange="pickDisk(this)"></td>'
|
|
+'<td>'+d.name+'</td><td>'+d.type+'</td><td class="mono">'+d.backing_device+'</td>'
|
|
+'<td>'+(d.state==='attached'?'csatlakoztatva':d.state)+'</td><td>'+(d.class||'—')+'</td><td>'+badge(d)+'</td></tr>';
|
|
});
|
|
html+='</tbody></table>';
|
|
document.getElementById('disk-list').innerHTML=html;
|
|
}catch(e){ var el=document.getElementById('disk-error'); el.style.display='block'; el.textContent='Meghajtók betöltése sikertelen: '+e.message; }
|
|
}
|
|
|
|
function pickDisk(radio){
|
|
selDevice=radio.value; selDataBearing=radio.getAttribute('data-db')==='1';
|
|
document.getElementById('sel-device').textContent=selDevice;
|
|
document.getElementById('warn-databearing').style.display=selDataBearing?'block':'none';
|
|
document.getElementById('cfg-card').style.display='block';
|
|
document.getElementById('cfg-card').scrollIntoView({behavior:'smooth'});
|
|
}
|
|
|
|
async function submitInit(ev){
|
|
ev.preventDefault();
|
|
var btn=document.getElementById('init-btn'); var out=document.getElementById('init-result');
|
|
btn.disabled=true; out.innerHTML='<p class="form-hint">Formázás és csatlakoztatás folyamatban…</p>';
|
|
try{
|
|
var body={device:selDevice, fstype:document.getElementById('fstype').value,
|
|
mount_name:document.getElementById('mount-name').value, label:document.getElementById('storage-label').value,
|
|
set_default:document.getElementById('set-default').checked};
|
|
var r=await fetch('/api/storage/init',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify(body)});
|
|
var j=await r.json();
|
|
if(r.status===409 && j.data && j.data.refused){
|
|
out.innerHTML='<div class="alert alert-warning"><strong>Operátori aláírás szükséges.</strong><br>'
|
|
+'A meghajtó adatot tartalmaz, ezért a formázás védelmi okból nem hajtható végre automatikusan'
|
|
+(j.data.reason?(' ('+j.data.reason+')'):'')+'.<br><br>Az engedélyezéshez futtassa offline az operátor gépén:'
|
|
+'<pre class="mono" style="white-space:pre-wrap;background:var(--bg-primary);padding:.75rem;border-radius:6px;margin-top:.5rem">'+(j.data.opsign||'(nem elérhető)')+'</pre>'
|
|
+'Az aláírás után a Hub végrehajtja a műveletet; ezután térjen vissza ide.</div>';
|
|
btn.disabled=false; return false;
|
|
}
|
|
if(!j.ok){ throw new Error(j.error||'Hiba'); }
|
|
out.innerHTML='<div class="alert alert-success">✅ A meghajtó sikeresen inicializálva és regisztrálva: <strong class="mono">'+(j.data.where||'')+'</strong>. <a href="/settings">Vissza a Beállításokhoz →</a></div>';
|
|
}catch(e){ out.innerHTML='<div class="alert alert-error">Hiba: '+e.message+'</div>'; btn.disabled=false; }
|
|
return false;
|
|
}
|
|
loadDisks();
|
|
</script>
|
|
|
|
{{template "layout_end" .}}
|
|
{{end}}
|