D62: restore copies kept 30 days, listed with their date, deletable by hand (typed name, never a needed copy, operator event); D63: a test-build-only fault switch for the R-1256 H4/H5 live proofs — tests red first
gates / gates (push) Successful in 33s

This commit is contained in:
admin committed 2026-10-29 08:50:59 +01:00
1 parent a815b37fbd
commit e3fce09d96
24 files changed
+1992 -11

No files matched your search

@@ -429,9 +429,9 @@ function submitRestore() {
{{/* D25 + D47: the kept copies (second-drive copies whose source is gone; set-aside units of an earlier install). Shown
inside the off-site card when the box has off-site, and after it when it has none — before 2026-10-25 it sat only inside
the off-site block, so a box without off-site never listed its kept copies. One body, two call sites. */}}
{{define "kept_copies_section"}}{{if .KeptCopies}}
{{define "kept_copies_section"}}{{if or .KeptCopies .RestoreCopies}}
<div class="backup-tier-divider" style="margin-top:1.5rem"></div>
<h3 style="margin-bottom:.5rem">{{T "backups_restore.megorzott_masolatok"}}</h3>
<h3 style="margin-bottom:.5rem">{{T "backups_restore.megorzott_masolatok"}}</h3>{{if .KeptCopies}}
<p class="form-hint" style="margin-bottom:.75rem">{{T "backups_restore.megorzott_masolatok_hint"}}</p>
<div class="app-row-list">
{{range .KeptCopies}}
@@ -467,4 +467,43 @@ the off-site block, so a box without off-site never listed its kept copies. One
});
}
</script>
{{end}}{{end}}
{{end}}{{if .RestoreCopies}}{{/* D62 (operator ruling 2026-10-29): restore copies — the app, the restore's date, the size, the day the box deletes
it; „Törlés most" after the warning and the app's name typed. A needed copy: the button is off, the reason in one line. */}}
<h4 style="margin:1rem 0 .5rem">{{T "restore_copy.title"}}</h4>
<p class="form-hint" style="margin-bottom:.75rem">{{T "restore_copy.hint"}}</p>
<div class="app-row-list" data-restore-copies="true">
{{range .RestoreCopies}}
{{template "app_list_row" dict "Slug" .App "Name" .Name "Secondary" .Line}}{{if .NeededText}}
<button type="button" class="btn btn-xs btn-danger-outline" disabled data-restore-copy-off="true">{{T "restore_copy.delete"}}</button>{{end}}
{{template "app_list_row_end"}}{{if .NeededText}}
<p class="form-hint" data-restore-copy-needed="true">{{.NeededText}}</p>{{else}}
<details class="kept-delete" data-restore-copy="{{.App}}/{{.Stamp}}">
<summary class="btn btn-xs btn-danger-outline">{{T "restore_copy.delete"}}</summary>
<form method="POST" action="/backup/restore-copy/delete" class="kept-delete-form" onsubmit="return deleteRestoreCopy(event, this)">
{{$.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<input type="hidden" name="stamp" value="{{.Stamp}}">
<p class="kept-delete-text">{{.Warning}}</p>
<label class="form-hint">{{.TypePrompt}}</label>
<input type="text" name="confirm" autocomplete="off" required>
<button type="submit" class="btn btn-sm btn-danger">{{T "restore_copy.delete"}}</button>
<p class="kept-delete-text" data-restore-copy-error="true" hidden></p>
</form>
</details>{{end}}
{{end}}
</div>
<script>
function deleteRestoreCopy(ev, f){
ev.preventDefault();
var err = f.querySelector('[data-restore-copy-error]');
fetch(f.action, {method: 'POST', headers: Object.assign({'Accept': 'application/json'}, csrfHeaders()), body: new URLSearchParams(new FormData(f))})
.then(function(r){ return r.json(); })
.then(function(d){
if (d.ok) { location.href = d.redirect; return; }
err.textContent = d.error || ''; err.hidden = false;
})
.catch(function(e){ err.textContent = '{{T "layout.halozati_hiba"}} ' + e; err.hidden = false; });
return false;
}
</script>
{{end}}{{end}}{{end}}