feat(ui): agent-outdated banner on the NAS settings page (capability gate, Part 3)

- networkStoragePageData threads NetAddSupport (yes/no/unknown) via the short-budget
  netAddSupport probe (2 s ctx + cache — a down agent cannot stall the page)
- storage_network.html: support=no replaces the add form with the Hungarian
  alert-warning banner; share list + remove render in every state; yes/unknown
  render the form unchanged; load-time JS guarded for the formless render
- T5 render test (banner/no-form on 'no', form on yes/unknown); red-proof RP5 run
  (conditional dropped → banner assertions fail) and reverted
- template_id_gate + emoji_gate green

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-11 13:49:29 +02:00
parent d347dc48d2
commit 50da7329ac
3 changed files with 62 additions and 2 deletions
+3
View File
@@ -1048,6 +1048,9 @@ func (s *Server) storagePageData() map[string]interface{} {
func (s *Server) networkStoragePageData() map[string]interface{} {
data := s.settingsBaseData("storage-network", "Hálózati tárhely")
data["NetworkStoragePaths"] = s.networkStorageItems(context.Background())
// Capability banner: "no" swaps the add form for the agent-outdated notice (yes/unknown render
// the form — flaky states belong to the add-time gate). Short-budget probe, cache-backed.
data["NetAddSupport"] = s.netAddSupport()
return data
}
@@ -15,6 +15,7 @@ func TestStorageNetworkTemplate_CanonicalClasses(t *testing.T) {
s.loadTemplates()
data := map[string]interface{}{
"Page": "storage-network", "Title": "Hálózati tárhely",
"NetAddSupport": "yes",
"NetworkStoragePaths": []networkStorageItem{
{Name: "media", Label: "NAS media", Protocol: "nfs", Server: "10.0.0.5", Export: "/srv/media", Path: "/mnt/felhom-drives/media", Health: "ok"},
{Name: "ghost", Label: "Árva megosztás: ghost", Protocol: "nfs", Server: "10.0.0.5", Export: "/srv/ghost", Path: "/mnt/felhom-drives/ghost", Health: "idle", Orphan: true},
@@ -54,3 +55,52 @@ func TestStorageNetworkTemplate_CanonicalClasses(t *testing.T) {
t.Error("remove action missing")
}
}
// --- T5 (Scenario D): capability banner replaces the add form on an old agent -------------------
// Companion red-proof: drop the {{if eq .NetAddSupport "no"}} wrapper (always render the form) →
// the banner-present + form-absent assertions on "no" fail.
func TestStorageNetworkTemplate_AgentOutdatedBanner(t *testing.T) {
s := testServer(t)
s.loadTemplates()
render := func(support string) string {
t.Helper()
var buf bytes.Buffer
err := s.tmpl.ExecuteTemplate(&buf, "storage_network", map[string]interface{}{
"Page": "storage-network", "Title": "Hálózati tárhely",
"NetAddSupport": support,
"NetworkStoragePaths": []networkStorageItem{
{Name: "media", Label: "NAS media", Protocol: "nfs", Server: "10.0.0.5", Export: "/srv/media", Path: "/mnt/felhom-drives/media", Health: "ok"},
},
})
if err != nil {
t.Fatalf("render (support=%s): %v", support, err)
}
return buf.String()
}
const banner = "A rendszer háttérszolgáltatása (ügynök) régebbi verziójú"
t.Run("no → banner instead of form; list + remove intact", func(t *testing.T) {
html := render("no")
if !strings.Contains(html, banner) {
t.Error("the §Part-3 banner is missing on an old agent")
}
if strings.Contains(html, `id="ns-add-form"`) {
t.Error("the add form must NOT render on an old agent")
}
// The share list + remove action stay fully usable in every state.
if !strings.Contains(html, "NAS media") || !strings.Contains(html, "Eltávolítás") {
t.Error("share list/remove must still render under the banner")
}
})
for _, support := range []string{"yes", "unknown"} {
t.Run(support+" → form as today", func(t *testing.T) {
html := render(support)
if !strings.Contains(html, `id="ns-add-form"`) {
t.Errorf("the add form must render on support=%s", support)
}
if strings.Contains(html, banner) {
t.Errorf("the banner must NOT render on support=%s", support)
}
})
}
}
@@ -48,6 +48,13 @@
<div class="settings-card">
<h3>Hálózati tárhely hozzáadása</h3>
{{if eq .NetAddSupport "no"}}
<!-- Capability gate (agent predates the verify-before-commit add semantics): the add form is
withheld; the share list + remove above stay fully usable. -->
<div class="alert alert-warning">A rendszer háttérszolgáltatása (ügynök) régebbi verziójú, ezért új
hálózati tárhely most nem csatlakoztatható. A frissítés megérkezése után a funkció automatikusan
elérhetővé válik — a meglévő megosztások addig is működnek.</div>
{{else}}
<p class="settings-card-desc">A csatlakoztatás előtt a rendszer ellenőrzi a megosztást: valóban
csatolható-e, és tudnak-e írni rá az alkalmazások. Hiba esetén semmi nem marad félkészen beállítva.</p>
<form id="ns-add-form" onsubmit="return netStorageAdd(event)">
@@ -93,6 +100,7 @@
</div>
<div id="ns-add-result" style="margin-top:1rem"></div>
</form>
{{end}}
</div>
<div class="settings-card">
@@ -206,8 +214,7 @@ function netStorageRemove(name,label){
}).catch(function(e){ alert('Hiba: '+e); });
}});
}
nsToggleSmb();
nsUpdateHostID();
if(document.getElementById('ns-add-form')){ nsToggleSmb(); nsUpdateHostID(); } // form absent on the capability banner
</script>
<div id="dialog-root"></div>
<script>