v0.319.0: the app page in panels, the login in one place, a password the box never had is said in words
gates / gates (push) Successful in 52s

- style A (operator 2026-10-16): hero, tab bar and every section are panels on --bg-1, one width, 16px apart;
  the install page's form groups use the same rule; the settings tab's 700px inner wrapper is gone
- „Belépés az alkalmazásba": name + password side by side, fetched on demand (R-254, R-709); pairing in app_login.go
- the empty-value rule: no stored value -> a sentence, never an eye; page and reveal endpoint share storedValuePresent
- „Cím és kulcsok" is rows (no Domain input, no disabled storage select, no install form); hint under the title
- tests red-proved: app_page_tuning_test.go (4); 36 app-page parity fixtures re-captured, 4 new; install fixtures unchanged

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-16 12:12:06 +02:00
parent 8d44416610
commit d170a2aecf
58 changed files with 6046 additions and 1776 deletions
+9 -2
View File
@@ -489,9 +489,15 @@ func (s *Server) deployPageData(w http.ResponseWriter, r *http.Request, name str
if appCfg != nil {
for _, n := range appCfg.RestoredLogins {
restored[n] = true
delete(decryptedEnv, n)
}
}
// v0.319.0: the settings tab's login panel and „Cim es kulcsok" rows, read BEFORE any value
// is dropped below — they learn only whether a value is stored, never the secret itself.
data["LoginFields"] = appLoginFields(meta, decryptedEnv, restored)
data["SettingsRows"] = appSettingRows(meta, decryptedEnv, s.msgLang(lang, "deploy.igen"), s.msgLang(lang, "app_page.value_no"))
for n := range restored {
delete(decryptedEnv, n)
}
// R-709 (v0.280.0): a `type: password` value is never written into this page's HTML either — like a
// `type: secret` (R-254) it is fetched on demand (/stacks/<n>/auto-field/reveal).
for _, f := range meta.DeployFields {
@@ -578,6 +584,7 @@ func (s *Server) deployPageData(w http.ResponseWriter, r *http.Request, name str
for _, dp := range deployPaths {
if dp.Path == hdd {
inList = true
data["CurrentHDDLabel"] = dp.Label // v0.319.0: the settings tab's „Tarhely" row
break
}
}
@@ -2626,7 +2633,7 @@ func (s *Server) appAutoFieldRevealHandler(w http.ResponseWriter, r *http.Reques
return
}
val := crypto.DecryptMap(s.encKey, appCfg.Env)[envVar]
if strings.TrimSpace(val) == "" {
if !storedValuePresent(val) { // the settings tab reads the same function, so it never offers this 404
w.Header().Set("Cache-Control", "no-store")
escrowJSON(w, http.StatusNotFound, nil, s.msg(r, "escrow.no_stored_value"))
return