v0.43.0: rebuilt storage management (guided init/attach/eject on agent disk model)
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>
This commit is contained in:
@@ -289,7 +289,7 @@ function pollUntilBack() {
|
||||
<div class="storage-app-row">
|
||||
<a href="/apps/{{.Stack}}" class="storage-app-link">{{.Name}}</a>
|
||||
{{if .SizeHuman}}<span class="mono form-hint">{{.SizeHuman}}</span>{{end}}
|
||||
<a href="/stacks/{{.Stack}}/migrate" class="btn btn-xs btn-outline" title="Adatok áthelyezése másik tárolóra">📦 Mozgatás</a>
|
||||
<span class="btn btn-xs btn-outline" style="opacity:.45;cursor:not-allowed" title="Hamarosan">📦 Mozgatás</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
@@ -334,7 +334,7 @@ function pollUntilBack() {
|
||||
</form>
|
||||
{{end}}
|
||||
{{if and (gt .AppCount 0) .HasOtherPaths}}
|
||||
<a href="/settings/storage/migrate-drive?source={{.Path}}" class="btn btn-xs btn-outline">📦 Összes adat átköltöztetése</a>
|
||||
<span class="btn btn-xs btn-outline" style="opacity:.45;cursor:not-allowed" title="Hamarosan">📦 Összes adat átköltöztetése</span>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -352,6 +352,53 @@ function pollUntilBack() {
|
||||
<a href="/settings/storage/attach" class="btn btn-sm btn-outline">🔗 Meglévő meghajtó csatolása</a>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:1.5rem">
|
||||
<h4 style="margin-bottom:.25rem">Meghajtók (ügynök nézet)</h4>
|
||||
<p class="form-hint" style="margin-bottom:.75rem">A host-ügynök által észlelt meghajtók élő nézete (a tárolás végrehajtása az ügynöké).</p>
|
||||
<div id="agent-disks">Betöltés…</div>
|
||||
</div>
|
||||
<script>
|
||||
window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}{{end}}];
|
||||
(function(){
|
||||
function badge(d){
|
||||
if(d.backing_device===""){ return ''; }
|
||||
return d.data_bearing
|
||||
? '<span class="badge badge-error" title="'+(d.data_reason||'')+'">Adatot tartalmaz</span>'
|
||||
: '<span class="badge badge-ok">Üres</span>';
|
||||
}
|
||||
function reg(d, registered){ return registered[d.mount_path] ? '<span class="badge badge-ok">Regisztrálva</span>' : (d.mount_path?'<span class="badge">Nem regisztrált</span>':''); }
|
||||
async function load(){
|
||||
var box=document.getElementById('agent-disks'); if(!box) return;
|
||||
try{
|
||||
var r=await fetch('/api/disks'); var j=await r.json();
|
||||
if(!j.ok){ box.innerHTML='<p class="form-hint">'+(j.error||'Nem elérhető')+'</p>'; return; }
|
||||
var disks=(j.data&&j.data.disks)||[];
|
||||
if(disks.length===0){ box.innerHTML='<p class="form-hint">Nincs észlelt meghajtó.</p>'; return; }
|
||||
var registered={}; (window.__registeredPaths||[]).forEach(function(p){registered[p]=true;});
|
||||
var html='<table class="data-table"><thead><tr><th>Tároló</th><th>Típus</th><th>Eszköz</th><th>Csatolás</th><th>Osztály</th><th>Adat</th><th>Reg.</th><th></th></tr></thead><tbody>';
|
||||
disks.forEach(function(d){
|
||||
var ej = (d.mount_path && d.mount_path.indexOf('/mnt/')===0) ? '<button class="btn btn-xs btn-danger-outline" onclick="ejectDisk(\''+d.mount_path+'\')">Leválasztás</button>' : '';
|
||||
html+='<tr><td>'+d.name+'</td><td>'+d.type+'</td><td class="mono">'+(d.backing_device||'—')+'</td><td class="mono">'+(d.mount_path||'—')+'</td><td>'+(d.class||'—')+'</td><td>'+badge(d)+'</td><td>'+reg(d,registered)+'</td><td>'+ej+'</td></tr>';
|
||||
});
|
||||
html+='</tbody></table>';
|
||||
box.innerHTML=html;
|
||||
}catch(e){ box.innerHTML='<p class="form-hint">Hiba: '+e.message+'</p>'; }
|
||||
}
|
||||
window.ejectDisk=async function(where){
|
||||
if(!confirm('Leválasztja a(z) '+where+' meghajtót? Az adatok megmaradnak, de az ott lévő alkalmazások elveszítik a tárhelyet.')) return;
|
||||
try{
|
||||
var r=await fetch('/api/storage/eject',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({where:where})});
|
||||
var j=await r.json();
|
||||
if(!j.ok){ alert('Hiba: '+(j.error||'')); return; }
|
||||
var dep=(j.data&&j.data.dependent_guests)||[];
|
||||
if(dep.length>0){ alert('Leválasztva. Figyelem: '+dep.length+' vendég (VMID: '+dep.join(', ')+') függött ettől a tárhelytől.'); }
|
||||
location.reload();
|
||||
}catch(e){ alert('Hiba: '+e.message); }
|
||||
};
|
||||
load();
|
||||
})();
|
||||
</script>
|
||||
|
||||
<details class="storage-add-details">
|
||||
<summary class="btn btn-sm btn-outline" style="margin-top:.75rem;cursor:pointer">Már csatlakoztatott tárhely hozzáadása kézzel</summary>
|
||||
<form method="POST" action="/settings/storage/add" class="storage-add-form">
|
||||
|
||||
Reference in New Issue
Block a user