diff --git a/TODO.md b/TODO.md index caf163c..7900d62 100644 --- a/TODO.md +++ b/TODO.md @@ -26,6 +26,10 @@ capability in the README rationale). # Completed Steps +- 2026-08-11 Web UI cleanup: nav terminology unified on Webhooks, the + Profile settings placeholder removed, a progressive-enhancement copy + button for the entrypoint URL, and retention form copy that states the + actual policy (deletion by the reaper, 0 retains forever) (#57) - 2026-08-09 Inactivity-based session timeout: sliding idle expiry (`SESSION_IDLE_TIMEOUT`, default `24h`) refreshed on authenticated requests, with the 7-day absolute cap kept as an independent diff --git a/internal/handlers/ui_copy_test.go b/internal/handlers/ui_copy_test.go new file mode 100644 index 0000000..23652f6 --- /dev/null +++ b/internal/handlers/ui_copy_test.go @@ -0,0 +1,299 @@ +package handlers_test + +import ( + "context" + "net/http" + "net/http/httptest" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "sneak.berlin/go/webhooker/internal/database" + "sneak.berlin/go/webhooker/internal/delivery" + "sneak.berlin/go/webhooker/internal/handlers" + "sneak.berlin/go/webhooker/internal/session" +) + +// Template data keys the page templates read. The handlers package has +// its own unexported constants for these; this is the external test +// package, so it needs its own. +const ( + dataKeyWebhook = "Webhook" + dataKeyError = "Error" +) + +// testWebhookID is the identifier given to the webhook under test on +// pages that render one. +const testWebhookID = "wh-1" + +// renderPage renders a page template through the real template set as +// an authenticated user and returns the resulting HTML. +func renderPage( + t *testing.T, + h *handlers.Handlers, + sess *session.Session, + page string, + data map[string]any, +) string { + t.Helper() + + cookies := authenticatedCookies(t, sess, "test-user-id", "testuser") + + req := httptest.NewRequestWithContext( + context.Background(), http.MethodGet, "/", nil, + ) + for _, c := range cookies { + req.AddCookie(c) + } + + w := httptest.NewRecorder() + h.RenderTemplateForTest(w, req, page, data) + + return w.Body.String() +} + +// TestNavbarUsesWebhookTerminology pins the user-visible navigation +// label to "Webhooks". The /sources route is deliberately unchanged, so +// the assertion targets the link text rather than the href. +func TestNavbarUsesWebhookTerminology(t *testing.T) { + t.Parallel() + + var h *handlers.Handlers + + var sess *session.Session + + app := newTestApp(t, &h, &sess) + app.RequireStart() + + t.Cleanup(app.RequireStop) + + // One item, so the list body renders too: it calls + // WebhookListItem.RetentionLabel, promoted from the embedded + // Webhook and therefore a pointer method. An empty list would + // skip that call and hide a template error behind the + // navigation assertions below. + item := handlers.WebhookListItem{} + item.Name = "wh" + item.ID = testWebhookID + item.RetentionDays = 14 + + body := renderPage(t, h, sess, "sources_list.html", map[string]any{ + "Webhooks": []handlers.WebhookListItem{item}, + }) + + assert.Contains(t, body, "Retention: 14 days") + assert.Contains(t, body, `class="btn-text">Webhooks`) + assert.Contains( + t, body, `class="btn-text w-full text-left">Webhooks`, + ) + assert.Contains( + t, body, + `
{{else}}
No entrypoints configured.
diff --git a/templates/source_edit.html b/templates/source_edit.html
index 5480b05..2263338 100644
--- a/templates/source_edit.html
+++ b/templates/source_edit.html
@@ -29,7 +29,7 @@
- Currently {{.Webhook.RetentionLabel}}. Enter 0 to retain events forever.
+ Currently {{.Webhook.RetentionLabel}}.{{if .Webhook.RetainsForever}} No events are deleted while retention is set to forever.{{else}} A periodic cleanup permanently deletes events older than this, along with their delivery records.{{end}} Enter 0 to retain events forever; leave blank to keep the current setting.
diff --git a/templates/sources_list.html b/templates/sources_list.html
index 6fc4cb6..22f4deb 100644
--- a/templates/sources_list.html
+++ b/templates/sources_list.html
@@ -1,6 +1,6 @@
{{template "base" .}}
-{{define "title"}}Sources - Webhooker{{end}}
+{{define "title"}}Webhooks - Webhooker{{end}}
{{define "content"}}
diff --git a/templates/sources_new.html b/templates/sources_new.html
index b7e20de..47c04be 100644
--- a/templates/sources_new.html
+++ b/templates/sources_new.html
@@ -29,7 +29,7 @@
- How long to keep event data. Enter 0 to retain events forever.
+ A periodic cleanup permanently deletes events older than this, along with their delivery records. Enter 0 to retain events forever; leave blank to use the default of {{.DefaultRetentionDays}} days.