v0.154.0 — R-48: one restore entry per app, and the intent is a described choice
The offsite restore list rendered up to five inline forms per app row. Two of them —
„Helyreállítás az élő adatok közé (csak a hiányzó fájlok)" and „Teljes visszaállítás
(fájlok + adatbázis)" — were sibling buttons whose difference is whether the customer's
data comes back at all. That mis-selection CAUSED the round-2 incident: an operator who
had read the source pressed the missing-only button and /backup/offbox/reconstitute was
never hit (DIAG-immich-restore-round2-2026-07-19, finding 1).
The rule this establishes: two adjacent controls whose difference is "your data comes
back" vs "your data cannot come back" must never be distinguishable only by layout.
Each row now carries ONE „Visszaállítás…" entry linking to a per-app wizard at
GET /backups/restore/app?name=<app>: three intent CARDS with consequence sentences, a
visible phase strip, danger styling plus the R-43 double-confirm carried over verbatim on
the destructive one, and the pair-honesty panel bound to real OffsiteScratchPair facts.
deriveWizardStep is pure over (op running, size-gate flash, scratch ready); the step is
never accepted from the request, and a running op outranks a stale ?full_prep= so no
commit button survives into a restore. While ANY op runs every mutation form is suppressed
server-side instead of being offered and refused.
No new mutation endpoint: every card posts to the pre-existing /backup/offbox/* handler
with the same field names and gates, and the page works with JavaScript disabled.
internal/{backup,appbackup,selfupdate} untouched. R-45's job registry stays its own item.
Fixes a latent bug found on the way: offboxRedirectTo hardcoded "?" when appending its
flash, which against the wizard's ?name=<app> target would have buried the flash inside
the name value.
No new agent coupling — MinAgent stays 0.90.0.
This commit is contained in:
@@ -51,9 +51,16 @@ func TestAppRow_RestoreLists(t *testing.T) {
|
||||
if strings.Contains(html, "storage-path-item") {
|
||||
t.Error("old storage-path-item row structure survives on the restore page")
|
||||
}
|
||||
// Behavior unchanged: restore-to-verify form + .fab download button.
|
||||
if !strings.Contains(html, `action="/backup/offbox/restore"`) {
|
||||
t.Error("restore-to-verify form missing")
|
||||
// v0.154.0 (R-48): the restore row is now a single entry that LINKS to the per-app wizard —
|
||||
// the mutation forms moved there. The row itself must still be the one, and only, restore
|
||||
// control for the app.
|
||||
if !strings.Contains(html, `href="/backups/restore/app?name=calibre-web"`) {
|
||||
t.Error("per-app restore wizard entry missing")
|
||||
}
|
||||
if strings.Contains(html, `action="/backup/offbox/restore"`) ||
|
||||
strings.Contains(html, `action="/backup/offbox/place"`) ||
|
||||
strings.Contains(html, `action="/backup/offbox/reconstitute"`) {
|
||||
t.Error("offsite restore mutation forms must not render on the list page (R-48)")
|
||||
}
|
||||
if !strings.Contains(html, `fab-dl-btn`) || !strings.Contains(html, "Letöltés (.fab)") {
|
||||
t.Error(".fab download action missing")
|
||||
|
||||
Reference in New Issue
Block a user