controller: Felhom-offsite status card — three honest states from local data (opt-in pitch / Aktív-nincs-kijelölt / the regular status block); display-only by design (decision 2: never a state change), state-tested incl. the no-form/no-button invariant

Claude-Session: https://claude.ai/code/session_01GzammAMzsJTgpQHqxwM2bC
This commit is contained in:
2026-07-13 09:37:05 +02:00
parent 0ece2ba85c
commit aa967fbf69
2 changed files with 62 additions and 0 deletions
@@ -85,6 +85,59 @@ func TestBackupsSplit_CrossPageAnchors(t *testing.T) {
}
}
// Felhom-offsite status card (v0.124.0, decision 2): three honest states, display-only —
// the card itself must never carry a form or button (no state change from the card, ever).
func TestBackupsRemote_OffsiteStatusCardStates(t *testing.T) {
cardOf := func(html string) string {
i := strings.Index(html, `id="felhom-offsite-card"`)
if i < 0 {
return ""
}
j := strings.Index(html[i:], "</div>")
return html[i : i+j]
}
// State 1: no target configured → the opt-in pitch (and no "Aktív" headline).
data := splitTestData()
data["OffboxConfigured"] = false
data["Offbox"] = nil
data["OffboxToggledCount"] = 0
html := renderBackupPage(t, "backups_remote", data)
if !strings.Contains(html, "Felhom offsite tárhely — igényelhető szolgáltatás. Titkosított, házon kívüli másolat a mentéseidről. Érdeklődj az üzemeltetőnél.") {
t.Error("state 1: the opt-in pitch is missing")
}
if strings.Contains(html, "Aktív — nincs kijelölt alkalmazás") {
t.Error("state 1 must not render the state-2 headline")
}
if card := cardOf(html); strings.Contains(card, "<form") || strings.Contains(card, "<button") {
t.Error("the status card must be display-only (no form/button)")
}
// State 2: applied, zero apps toggled → the honest active-but-empty headline.
data = splitTestData()
data["OffboxToggledCount"] = 0
data["OffboxApps"] = []OffboxAppRow{{Name: "calibre-web", DisplayName: "Calibre-Web", Enabled: false}}
html = renderBackupPage(t, "backups_remote", data)
if !strings.Contains(html, "Aktív — nincs kijelölt alkalmazás") {
t.Error("state 2: 'Aktív — nincs kijelölt alkalmazás' missing")
}
if strings.Contains(html, "igényelhető szolgáltatás") {
t.Error("state 2 must not render the state-1 pitch")
}
if card := cardOf(html); strings.Contains(card, "<form") || strings.Contains(card, "<button") {
t.Error("the status card must be display-only (no form/button)")
}
// State 3: applied + toggled → NO card; the regular status block carries the state.
html = renderBackupPage(t, "backups_remote", splitTestData())
if strings.Contains(html, `id="felhom-offsite-card"`) {
t.Error("state 3 must not render the status card (the status block is the state)")
}
if !strings.Contains(html, "Utolsó távoli mentés") {
t.Error("state 3: the regular status block is missing")
}
}
// Route → handler wiring: each sub-route sets its own .Page id, so the sidebar child renders
// active on the right page (backupMgr nil → the empty state renders, the nav still does).
func TestBackupsSplit_RoutesSetPageIDs(t *testing.T) {
@@ -12,6 +12,15 @@
{{template "backups_empty" .}}
{{else}}
<!-- Felhom-offsite status card (v0.124.0, decision 2): three honest states from LOCAL data only —
display + opt-in pointers, NEVER a state change (no form, no button in this card). State 3
(applied + apps toggled) is the existing status block below; the card renders nothing then. -->
{{if not .OffboxConfigured}}
<div class="alert alert-info" style="margin-bottom:1rem" id="felhom-offsite-card">Felhom offsite tárhely — igényelhető szolgáltatás. Titkosított, házon kívüli másolat a mentéseidről. Érdeklődj az üzemeltetőnél.</div>
{{else if eq .OffboxToggledCount 0}}
<div class="alert alert-info" style="margin-bottom:1rem" id="felhom-offsite-card">Aktív — nincs kijelölt alkalmazás</div>
{{end}}
<!-- Off-box (NAS) backup — Part B: encrypted restic repo over SFTP (the off-site 3-2-1 leg). -->
<h3 id="offbox-section" class="backup-tier-divider">Távoli mentés (3. mentés) — titkosított, offsite</h3>
<p class="form-hint" style="margin:-0.25rem 0 1rem">Az alkalmazás-mentések titkosított másolata egy távoli tárolóra — saját NAS vagy Felhom offsite tárhely — restic + SFTP kapcsolaton. A tároló csak titkosított adatot lát. Ez a 3-2-1 szabály „1 off-site" lába — független a helyi másodpéldánytól és a teljes rendszermentéstől.</p>