From 57e0cdb43cb4d28ba6f4df1144b914ef620a2057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesko=20Ansch=C3=BCtz?= Date: Sun, 22 Mar 2026 20:16:22 +0100 Subject: [PATCH] Ergaenze Auto-Refresh auf Detailseite und bereinige Fehlermeldungs-Duplikat Auto-Refresh auf GET /status/{screenId}: screenDetailPageData bekommt RefreshSeconds (wie statusPageData). Das Detail-Template rendert das Meta-Tag analog zur Uebersichtsseite mit denselben 15 Sekunden, damit ein Screen seinen Zustand (z.B. fresh -> stale, connectivity-Wechsel) auch ohne manuellen Reload sichtbar macht. Test: meta-refresh-Tag jetzt in TestRouterScreenDetailPageRoute geprueft. DRY-Refactor: Fehlermeldungen vereinheitlicht: overviewQueryErrorMessage und overviewQueryErrorCode sind jetzt in playerstatus.go definiert -- dort wo auch die Validierungslogik lebt. writeOverviewQueryError delegiert vollstaendig an beide Helper statt die Meldungen selbst zu duplizieren. Die vorherige Kopie in statuspage.go mit abweichenden Satzendezeichen und Grossschreibung wurde entfernt. Beide Fehlerpfade (JSON und HTML) nutzen jetzt exakt dieselben Meldungstexte. Co-Authored-By: Claude Sonnet 4.6 --- .../backend/internal/httpapi/playerstatus.go | 36 +++++++++++++++---- .../backend/internal/httpapi/router_test.go | 1 + server/backend/internal/httpapi/statuspage.go | 21 ++--------- 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/server/backend/internal/httpapi/playerstatus.go b/server/backend/internal/httpapi/playerstatus.go index 365190f..e865a47 100644 --- a/server/backend/internal/httpapi/playerstatus.go +++ b/server/backend/internal/httpapi/playerstatus.go @@ -243,21 +243,45 @@ var ( errInvalidStale = errors.New("invalid stale") ) -func writeOverviewQueryError(w http.ResponseWriter, err error) { +// overviewQueryErrorCode returns the machine-readable error code for query +// validation errors. It is used by both the JSON and HTML error paths. +func overviewQueryErrorCode(err error) string { switch err { case errInvalidUpdatedSince: - writeError(w, http.StatusBadRequest, "invalid_updated_since", "updated_since ist kein gueltiger RFC3339-Zeitstempel", nil) + return "invalid_updated_since" case errInvalidLimit: - writeError(w, http.StatusBadRequest, "invalid_limit", "limit muss eine positive Ganzzahl sein", nil) + return "invalid_limit" case errInvalidServerConnectivity: - writeError(w, http.StatusBadRequest, "invalid_server_connectivity", "server_connectivity muss online, offline, degraded oder unknown sein", nil) + return "invalid_server_connectivity" case errInvalidStale: - writeError(w, http.StatusBadRequest, "invalid_stale", "stale muss true oder false sein", nil) + return "invalid_stale" default: - writeError(w, http.StatusBadRequest, "invalid_query", "ungueltige Query-Parameter", nil) + return "invalid_query" } } +// overviewQueryErrorMessage returns the human-readable message for query +// validation errors. It is used by both the JSON and HTML error paths so +// that the wording stays consistent regardless of response format. +func overviewQueryErrorMessage(err error) string { + switch err { + case errInvalidUpdatedSince: + return "updated_since ist kein gueltiger RFC3339-Zeitstempel" + case errInvalidLimit: + return "limit muss eine positive Ganzzahl sein" + case errInvalidServerConnectivity: + return "server_connectivity muss online, offline, degraded oder unknown sein" + case errInvalidStale: + return "stale muss true oder false sein" + default: + return "ungueltige Query-Parameter" + } +} + +func writeOverviewQueryError(w http.ResponseWriter, err error) { + writeError(w, http.StatusBadRequest, overviewQueryErrorCode(err), overviewQueryErrorMessage(err), nil) +} + func validateOptionalRFC3339(value string) error { if strings.TrimSpace(value) == "" { return nil diff --git a/server/backend/internal/httpapi/router_test.go b/server/backend/internal/httpapi/router_test.go index adaa783..7e70106 100644 --- a/server/backend/internal/httpapi/router_test.go +++ b/server/backend/internal/httpapi/router_test.go @@ -218,6 +218,7 @@ func TestRouterScreenDetailPageRoute(t *testing.T) { "← All screens", "Timing", "Endpoints", + "", } { if !strings.Contains(body, want) { t.Fatalf("body missing %q", want) diff --git a/server/backend/internal/httpapi/statuspage.go b/server/backend/internal/httpapi/statuspage.go index 39719d0..00d1757 100644 --- a/server/backend/internal/httpapi/statuspage.go +++ b/server/backend/internal/httpapi/statuspage.go @@ -34,6 +34,7 @@ type statusFilterLink struct { type screenDetailPageData struct { GeneratedAt string + RefreshSeconds int Record playerStatusRecord StatusPagePath string } @@ -606,6 +607,7 @@ var screenDetailTemplate = template.Must(template.New("screen-detail").Funcs(sta + {{.Record.ScreenID}} – Screen Status ` + statusPageCSSBlock + ` @@ -768,6 +770,7 @@ func handleScreenDetailPage(store playerStatusStore) http.HandlerFunc { data := screenDetailPageData{ GeneratedAt: store.Now().Format(time.RFC3339), + RefreshSeconds: 15, Record: record, StatusPagePath: "/status", } @@ -875,24 +878,6 @@ func writeStatusPageQueryError(w http.ResponseWriter, queryErr error) { } } -// overviewQueryErrorMessage returns a human-readable message for the given -// overview query validation error. It is shared between the HTML and JSON -// error paths to keep messages consistent. -func overviewQueryErrorMessage(err error) string { - switch err { - case errInvalidUpdatedSince: - return "updated_since ist kein gueltiger RFC3339-Zeitstempel." - case errInvalidLimit: - return "limit muss eine positive Ganzzahl sein." - case errInvalidServerConnectivity: - return "server_connectivity muss online, offline, degraded oder unknown sein." - case errInvalidStale: - return "stale muss true oder false sein." - default: - return "Ungueltige Query-Parameter." - } -} - func statusClass(value string) string { trimmed := strings.TrimSpace(value) if trimmed == "" {