controller: drill F-11 — inline two-step confirm (felhomConfirm + data-confirm) replaces every native confirm(); native_confirm_gate.py enforces zero; stale-data delete keeps its double acknowledgement inline

Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
This commit is contained in:
2026-07-13 08:19:39 +02:00
parent 40b53047f1
commit 8987ce0f67
8 changed files with 141 additions and 62 deletions
+17 -16
View File
@@ -182,9 +182,9 @@
<button type="submit" class="btn btn-xs {{if .Enabled}}btn-outline{{else}}btn-primary{{end}}">{{if .Enabled}}NAS-mentés kikapcsolása{{else}}NAS-mentés bekapcsolása{{end}}</button>
</form>
{{if .Enabled}}
<form method="POST" action="/backup/offbox/restore" style="display:inline" onsubmit="return confirm('Visszaállítja a(z) {{.DisplayName}} adatait a NAS-ról egy ellenőrző mappába? A meglévő adatok NEM íródnak felül.')">{{$.CSRFField}}
<form method="POST" action="/backup/offbox/restore" style="display:inline">{{$.CSRFField}}
<input type="hidden" name="app" value="{{.Name}}">
<button type="submit" class="btn btn-xs btn-outline">Visszaállítás (ellenőrzéshez)</button>
<button type="submit" class="btn btn-xs btn-outline" data-confirm="Visszaállítja a(z) {{.DisplayName}} adatait a távoli tárolóról egy ellenőrző mappába? A meglévő adatok NEM íródnak felül.">Visszaállítás (ellenőrzéshez)</button>
</form>
{{end}}
</div>
@@ -469,9 +469,9 @@
<span class="tier-browsable" title="A mentés böngészhető fájlrendszerben"><svg class="ico ico-sm"><use href="#i-file-text"/></svg></span>
<div class="layer-actions">
{{if .Tier2LastRun}}
<form method="POST" action="/backup/tier2/restore" style="display:inline" onsubmit="return confirm('Visszaállítja a hiányzó fájlokat a másodlagos másolatból? A meglévő fájlok NEM módosulnak és NEM törlődnek. Az alkalmazás a művelet idejére leáll. Legutóbbi másolat: {{.Tier2LastRun}}')">{{$.CSRFField}}
<form method="POST" action="/backup/tier2/restore" style="display:inline">{{$.CSRFField}}
<input type="hidden" name="stack_name" value="{{.StackName}}">
<button type="submit" class="btn btn-xs btn-outline">Fájlok visszaállítása</button>
<button type="submit" class="btn btn-xs btn-outline" data-confirm="Visszaállítja a hiányzó fájlokat a másodlagos másolatból? A meglévő fájlok NEM módosulnak és NEM törlődnek. Az alkalmazás a művelet idejére leáll. Legutóbbi másolat: {{.Tier2LastRun}}">Fájlok visszaállítása</button>
</form>
{{end}}
<a href="/stacks/{{.StackName}}/backup" class="btn btn-xs btn-outline">Beállítás</a>
@@ -673,19 +673,20 @@ function startBackupPolling() {
// Whole-guest (appliance) backup — manual trigger via the quiesce loop (controller-owned quiesce:
// stop stacks → agent vzdump → resume). Returns immediately; we poll /api/guest-backup/status.
function triggerGuestBackup() {
if (!confirm('Elindítja a teljes rendszermentést most? A mentés ideje alatt az alkalmazások rövid időre leállhatnak.')) return;
var btn = document.getElementById('wg-backup-btn');
var out = document.getElementById('wg-backup-result');
btn.disabled = true;
out.innerHTML = '<span class="form-hint">Mentés indítása…</span>';
fetch('/api/guest-backup/trigger', { method: 'POST', headers: Object.assign({'Content-Type':'application/json'}, csrfHeaders()) })
.then(r => r.json())
.then(data => {
if (!data.ok) { out.innerHTML = '<div class="alert alert-error">' + (data.error || 'Hiba') + '</div>'; btn.disabled = false; return; }
out.innerHTML = '<span class="form-hint">Mentés folyamatban…</span>';
pollGuestBackup(out, btn);
})
.catch(e => { out.innerHTML = '<div class="alert alert-error">Hiba: ' + e + '</div>'; btn.disabled = false; });
felhomConfirm(btn, 'Elindítja a teljes rendszermentést most? A mentés ideje alatt az alkalmazások rövid időre leállhatnak.', function () {
var out = document.getElementById('wg-backup-result');
btn.disabled = true;
out.innerHTML = '<span class="form-hint">Mentés indítása…</span>';
fetch('/api/guest-backup/trigger', { method: 'POST', headers: Object.assign({'Content-Type':'application/json'}, csrfHeaders()) })
.then(r => r.json())
.then(data => {
if (!data.ok) { out.innerHTML = '<div class="alert alert-error">' + (data.error || 'Hiba') + '</div>'; btn.disabled = false; return; }
out.innerHTML = '<span class="form-hint">Mentés folyamatban…</span>';
pollGuestBackup(out, btn);
})
.catch(e => { out.innerHTML = '<div class="alert alert-error">Hiba: ' + e + '</div>'; btn.disabled = false; });
});
}
function pollGuestBackup(out, btn) {