Files
admin 11b790e314
gates / gates (push) Successful in 20s
v0.249.0: i18n slice 1 release B — backup pages in English, Hungarian byte-identical (R-556)
Seven backup pages + the restore-progress JS converted against fixtures captured unconverted
(f8ebc47); recovery renders through executeTemplateLang; English retrieval claims registered;
the Fut comparison left unconverted (R-563).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-09-17 18:01:09 +02:00

180 lines
10 KiB
HTML

{{define "backups_restore_wizard"}}
{{template "layout_start" .}}
<!-- R-48: the offsite restore wizard. One entry per app on /backups/restore leads here, and the
three intents are separately-described CARDS with a consequence sentence each — never sibling
buttons whose difference is whether the data comes back. Server-rendered throughout: every step
is a real form POST to the EXISTING endpoint, so the page works with JavaScript disabled. -->
<div class="page-header">
<div style="display:flex;align-items:center;gap:.5rem">
<a href="/backups/restore" class="btn btn-sm btn-outline">{{T "backups_restore_wizard.vissza"}}</a>
<h2>{{T "backups_restore_wizard.visszaallitas"}}</h2>
</div>
<span class="domain-badge">{{.Domain}}</span>
</div>
{{template "backups_flash" .}}
{{template "restore_banner" .}}
<!-- Phase strip: the customer can see there IS a sequence, and where they are in it. The round-2
incident's second half was that the decisive step appeared only after the first was pressed,
with nothing signposting that a second step existed at all. -->
{{$phase := printf "%s" .Wizard.Phase}}
<div class="restore-wizard-phases">
<span class="restore-wizard-phase{{if eq $phase "elokeszites"}} is-current{{end}}">{{T "backups_restore_wizard.elokeszites"}}</span>
<span class="restore-wizard-phase{{if eq $phase "megerosites"}} is-current{{end}}">{{T "backups_restore_wizard.megerosites"}}</span>
<span class="restore-wizard-phase{{if eq $phase "vegrehajtas"}} is-current{{end}}">{{T "backups_restore_wizard.vegrehajtas"}}</span>
<span class="restore-wizard-phase{{if eq $phase "eredmeny"}} is-current{{end}}">{{T "backups_restore_wizard.eredmeny"}}</span>
</div>
{{with .LastResult}}
<!-- „Eredmény": the outcome of the restore that just finished, for THIS app. The redirect flash says
the same thing but does not survive a reload; this does, for restoreResultWindow. -->
<div class="settings-card">
<h3>{{T "backups_restore_wizard.eredmeny"}}</h3>
<div class="alert {{if .OK}}alert-info{{else}}alert-error{{end}}">{{.Message}}</div>
<p class="form-hint">{{if .Interrupted}}{{T "backups_restore_wizard.eszlelve"}}{{else}}{{T "backups_restore_wizard.befejezve"}}{{end}}{{T "backups_restore_wizard.ha_szeretned_alabb_ujra_indithatsz"}}</p>
</div>
{{end}}
{{if eq (printf "%s" .Wizard.Step) "execution"}}
<!-- EXECUTION — every mutation form is suppressed server-side. The manager's single-flight would
refuse them anyway; offering a control guaranteed to fail is the same dishonesty class R-48
addresses. The live progress comes from the existing restore-status poll (the banner above). -->
<div class="settings-card">
<h3>{{T "backups_restore_wizard.vegrehajtas"}}</h3>
<p>{{T "backups_restore_wizard.jelenleg_egy_mentesi_vagy_visszaallitasi"}}{{with .RunningStack}} ({{.}}){{end}}{{T "backups_restore_wizard.amig_ez_tart_uj_visszaallitas"}}</p>
<!-- R-351: this used to say the state refreshes automatically AND that you must refresh the page
when it finishes. Both cannot be true, and the second half was the one people believed. The
banner now carries the terminal result too (RestoreOpStatus.LastRecent), so the sentence can
describe what the page actually does. -->
<p class="form-hint">{{T "backups_restore_wizard.az_allapot_fent_automatikusan_frissul"}}</p>
<div class="form-actions">
<a href="/backups/restore/app?name={{.App}}" class="btn btn-sm btn-outline">{{T "backups_restore_wizard.allapot_frissitese"}}</a>
</div>
</div>
{{else if eq (printf "%s" .Wizard.Step) "prepare-confirm"}}
<!-- MEGERŐSÍTÉS — the size gate. The preparation has measured what needs downloading; the customer
confirms with the size in front of them, before any transfer starts. -->
<div class="settings-card">
<h3>{{T "backups_restore_wizard.megerosites_teljes_visszaallitas_elokesz"}}</h3>
<p>{{T "backups_restore_wizard.a_teljes_visszaallitashoz_a_mentes"}}{{with .FullPrepSize}} {{T "backups_restore_wizard.a_becsult_meret"}}{{end}}{{T "backups_restore_wizard.a_letoltes_a_meghajton_egy"}}</p>
<p class="form-hint">{{T "backups_restore_wizard.a_letoltes_a_merettol_es"}}</p>
<div class="form-actions">
<form method="POST" action="/backup/offbox/restore">{{.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<input type="hidden" name="mode" value="full">
<input type="hidden" name="confirm" value="1">
<button type="submit" class="btn btn-primary">{{T "backups_restore_wizard.elokeszites_inditasa"}}{{with .FullPrepSize}} (~{{.}}){{end}}</button>
</form>
<a href="/backups/restore/app?name={{.App}}" class="btn btn-outline">{{T "backups_restore_wizard.megsem"}}</a>
</div>
</div>
{{else}}
<!-- INTENT — three cards, each with its own consequence sentence. Card order is deliberate:
harmless first, irreversible-looking last. -->
<div class="settings-card">
<h3>{{T "backups_restore_wizard.1_ellenorzes_kulon_mappaba_beallitasok"}}</h3>
<!-- R-204 item 3: this card's scope is stated BEFORE the choice, not only in the outcome. It
restores the recovery unit only; the customer's own files stay in the backup. Saying „a
mentés tartalma" here was how a disaster-recovery customer chose the one intent that does
not return their documents. -->
<p>{{T "backups_restore_wizard.az_alkalmazas_beallitasait_es_adatbazisa"}}</p>
<div class="form-actions">
<form method="POST" action="/backup/offbox/restore">{{.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<input type="hidden" name="mode" value="unit">
<button type="submit" class="btn btn-outline"{{if not .Wizard.VerifyEnabled}} disabled{{end}}>{{T "backups_restore_wizard.ellenorzes_inditasa"}}</button>
</form>
</div>
</div>
<div class="settings-card">
<h3>{{T "backups_restore_wizard.2_hianyzo_fajlok_visszahozasa"}}</h3>
<p>{{T "backups_restore_wizard.csak_a_hianyzo_fajlokat_masolja"}}</p>
{{if .Wizard.PlaceEnabled}}
<div class="form-actions">
<form method="POST" action="/backup/offbox/place">{{.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<button type="submit" class="btn btn-outline">{{T "backups_restore_wizard.hianyzo_fajlok_visszahozasa"}}</button>
</form>
</div>
{{else}}
<p class="form-hint">{{T "backups_restore_wizard.ehhez_elobb_elo_kell_kesziteni"}}</p>
{{end}}
</div>
<div class="settings-card restore-danger-card">
<h3>{{T "backups_restore_wizard.3_teljes_visszaallitas_fajlok_adatbazis"}}</h3>
<p>{{T "backups_restore_wizard.a_fajlokat_a_mentes_szerinti"}}</p>
{{if .Wizard.RestoreEnabled}}
<!-- Pair honesty (R-43): what the two halves of this restore actually ARE. A restore is the one
operation whose result cannot be inspected before committing to it. -->
<div class="alert alert-info" style="margin-bottom:.75rem">
<strong>{{T "backups_restore_wizard.az_elokeszitett_mentes"}}</strong>
{{if not .Pair.DumpsAt.IsZero}}{{T "backups_restore_wizard.adatbazis_mentes_ideje"}}{{else}}{{T "backups_restore_wizard.az_adatbazis_mentes_ideje_nem"}}{{end}}
</div>
{{if .Pair.Skewed}}
<div class="alert alert-warning" style="margin-bottom:.75rem">{{T "backups_restore_wizard.az_adatbazis_mentes_regebbi"}}{{if not .Pair.DumpsAt.IsZero}} ({{fmtTime .Pair.DumpsAt}}){{end}} {{T "backups_restore_wizard.a_fajlok_es_az_adatbazis"}}</div>
{{end}}
{{if .Pair.LooksEmpty}}
<div class="alert alert-warning" style="margin-bottom:.75rem">{{T "backups_restore_wizard.a_mentett_adatbazis_uresnek_tunik"}}</div>
{{end}}
<div class="form-actions">
<form method="POST" action="/backup/offbox/reconstitute">{{.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<input type="hidden" name="confirm" value="1">
<button type="button" class="btn btn-danger"
data-restore-app="{{.App}}"
data-restore-when="{{if not .Pair.DumpsAt.IsZero}}{{fmtTime .Pair.DumpsAt}}{{end}}"
data-restore-skewed="{{if .Pair.Skewed}}1{{end}}"
data-restore-empty="{{if .Pair.LooksEmpty}}1{{end}}"
onclick="confirmFullRestore(this)">{{T "backups_restore_wizard.teljes_visszaallitas_inditasa"}}</button>
</form>
</div>
{{else}}
<p class="form-hint">{{T "backups_restore_wizard.a_teljes_visszaallitashoz_eloszor_le"}}</p>
<div class="form-actions">
<form method="POST" action="/backup/offbox/restore">{{.CSRFField}}
<input type="hidden" name="app" value="{{.App}}">
<input type="hidden" name="mode" value="full">
<button type="submit" class="btn btn-outline"{{if not .Wizard.PrepareEnabled}} disabled{{end}}>{{T "backups_restore_wizard.teljes_visszaallitas_elokeszitese"}}</button>
</form>
</div>
{{end}}
</div>
{{end}}
<script>
{{template "restore_banner_js"}}
/* Carried VERBATIM from backups_restore.html (R-43). The double-confirm is the good part of the old
surface — it states the DB half's age and any warning before the customer commits — so it moves
with the action rather than being rewritten. felhomConfirm is the house inline idiom, never the
OS-modal confirm() (F-11). */
function confirmFullRestore(btn){
var app = btn.getAttribute('data-restore-app') || '';
var when = btn.getAttribute('data-restore-when') || '';
var skewed = btn.getAttribute('data-restore-skewed') === '1';
var empty = btn.getAttribute('data-restore-empty') === '1';
var q = '{{T "backups_restore_wizard.teljes_visszaallitas"}} ' + app + (when ? ' {{T "backups_restore_wizard.a_mentes_ideje"}} ' + when : '') + '.';
if (skewed) { q += ' {{T "backups_restore_wizard.figyelem_a_fajlok_es_az"}}'; }
if (empty) { q += ' {{T "backups_restore_wizard.figyelem_a_mentett_adatbazis_uresnek"}}'; }
q += ' {{T "backups_restore_wizard.a_fajlok_a_mentes_szerinti"}}';
felhomConfirm(btn, q, function(){
felhomConfirm(btn, '{{T "backups_restore_wizard.utolso_megerosites_az_alkalmazas_leall"}}', function(){
var f = btn.closest('form');
if (f) { if (f.requestSubmit) f.requestSubmit(); else f.submit(); }
});
});
}
</script>
{{template "layout_end" .}}
{{end}}