diff --git a/src/webui/internal/handlers/configure_keystore.go b/src/webui/internal/handlers/configure_keystore.go index eb4e23e6..ec1bb5c1 100644 --- a/src/webui/internal/handlers/configure_keystore.go +++ b/src/webui/internal/handlers/configure_keystore.go @@ -157,8 +157,7 @@ func (h *ConfigureKeystoreHandler) AddSymKey(w http.ResponseWriter, r *http.Requ renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Symmetric key added", "/configure/keystore") } // DeleteSymKey removes a symmetric key from the candidate. @@ -171,8 +170,7 @@ func (h *ConfigureKeystoreHandler) DeleteSymKey(w http.ResponseWriter, r *http.R renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Symmetric key deleted", "/configure/keystore") } // AddAsymKey adds an asymmetric key from a PEM-encoded private key. @@ -225,8 +223,7 @@ func (h *ConfigureKeystoreHandler) AddAsymKey(w http.ResponseWriter, r *http.Req renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Asymmetric key added", "/configure/keystore") } // derivePublicKeyFromDER extracts the public key from DER-encoded private key bytes @@ -289,8 +286,7 @@ func (h *ConfigureKeystoreHandler) DeleteAsymKey(w http.ResponseWriter, r *http. renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Asymmetric key deleted", "/configure/keystore") } // AddCert adds a certificate to an asymmetric key entry. @@ -327,8 +323,7 @@ func (h *ConfigureKeystoreHandler) AddCert(w http.ResponseWriter, r *http.Reques renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Certificate added", "/configure/keystore") } // UpdateCert replaces the PEM data of an existing certificate. @@ -380,8 +375,7 @@ func (h *ConfigureKeystoreHandler) DeleteCert(w http.ResponseWriter, r *http.Req renderSaveError(w, err) return } - w.Header().Set("HX-Location", `{"path":"/configure/keystore","target":"#content"}`) - w.WriteHeader(http.StatusNoContent) + renderSavedRedirect(w, "Certificate deleted", "/configure/keystore") } // derBase64ToPEM converts a base64-encoded DER blob (as returned by RESTCONF diff --git a/src/webui/internal/handlers/configure_system.go b/src/webui/internal/handlers/configure_system.go index 912a944d..b3582d54 100644 --- a/src/webui/internal/handlers/configure_system.go +++ b/src/webui/internal/handlers/configure_system.go @@ -365,6 +365,16 @@ func renderSaved(w http.ResponseWriter, msg string) { w.WriteHeader(http.StatusOK) } +// renderSavedRedirect logs a cfgSaved activity entry and then navigates HTMX to +// the given page path (targeting #content). Use this instead of a bare HX-Location +// for Add/Delete operations that redirect back to the listing page after success. +func renderSavedRedirect(w http.ResponseWriter, msg, path string) { + b, _ := json.Marshal(msg) + w.Header().Set("HX-Trigger", `{"cfgSaved":`+string(b)+`}`) + w.Header().Set("HX-Location", `{"path":"`+path+`","target":"#content"}`) + w.WriteHeader(http.StatusNoContent) +} + // renderSaveError writes an inline error for HTMX. HX-Trigger ensures forms with // hx-swap="none" still receive the cfgError event (body swap alone would be silenced). // RESTCONF errors surface their server-side Message; all other errors fall back to diff --git a/src/webui/internal/handlers/configure_users.go b/src/webui/internal/handlers/configure_users.go index fd511a35..489bd26d 100644 --- a/src/webui/internal/handlers/configure_users.go +++ b/src/webui/internal/handlers/configure_users.go @@ -339,7 +339,6 @@ func (h *ConfigureUsersHandler) DeleteKey(w http.ResponseWriter, r *http.Request renderSaveError(w, err) return } - var userEntry map[string]any for _, u := range raw.System.Auth.Users { if u.Name != name { @@ -391,7 +390,7 @@ func (h *ConfigureUsersHandler) DeleteKey(w http.ResponseWriter, r *http.Request renderSaveError(w, err) return } - w.WriteHeader(http.StatusOK) + renderSavedRedirect(w, "SSH key deleted", "/configure/users") } // fetchAllGroups reads NACM groups from candidate, falling back to running on 404.