From 806c95e30539a057770e37990489b93e189e090c Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Fri, 2 Oct 2026 18:32:19 +0200 Subject: [PATCH] Make every clickable control look clickable, in two shared styles (closes #375) Many controls were plain coloured text with no sign they could be clicked: Edit, Activate, Deactivate, Delete, Replay, Resubmit, both Add controls and the copy control beside each entrypoint URL. Every clickable control is now a real button or link in one of two shared styles: the buttons in input.css, now with a pointer cursor, and btn-small, a small bordered secondary action in style.css, which the layout now loads. The site name, the footer links and each webhook list card show at rest that they open something, with focus states. The copy control shows "Copied" after a click. Rows on the webhook page and in the event log wrap at phone width. The browser test covers the copy control. Model: opus-5-5 --- README.md | 21 +++++----- internal/handlers/ui_copy_test.go | 11 ++--- internal/server/alpine_browser_test.go | 38 ++++++++++++++++- internal/server/routes_test.go | 4 +- static/css/style.css | 49 +++++++++++++++++++++- templates/base.html | 4 +- templates/htmlheader.html | 1 + templates/navbar.html | 20 ++++----- templates/source_detail.html | 32 +++++++-------- templates/source_edit.html | 2 +- templates/source_logs.html | 56 +++++++++++++------------- templates/sources_list.html | 7 +++- templates/sources_new.html | 2 +- templates/target_edit.html | 2 +- 14 files changed, 171 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index 55b45f9..1f845f4 100644 --- a/README.md +++ b/README.md @@ -1326,15 +1326,16 @@ A browser test in `internal/server` loads the webhook page and the event log under the real policy and checks that: both add forms stay hidden until Add is clicked; choosing Slack in the add target form leaves the HTTP fields out of what it submits, also after leaving the page and going back to it, when the -browser restores the choice; an event expands and collapses, and so do a -delivery's attempts inside it; and at phone width the menu button opens and -closes the mobile menu. It also fails if the browser reports a console warning -or error, an uncaught exception, or anything the policy refused. `make check` -and the image build lint it but do not run it, and `make test` leaves it out -(its file is built only with the `browser` build tag). Run it with -`make test-browser` after changing `templates/` or `static/js/`: that builds -`Dockerfile.browser`, which runs the test in a digest-pinned headless browser -image, so the host needs no browser. +browser restores the choice; the Copy button beside an entrypoint URL reads +"Copied" once clicked; an event expands and collapses, and so do a delivery's +attempts inside it; and at phone width the menu button opens and closes the +mobile menu. It also fails if the browser reports a console warning or error, +an uncaught exception, or anything the policy refused. `make check` and the +image build lint it but do not run it, and `make test` leaves it out (its file +is built only with the `browser` build tag). Run it with `make test-browser` +after changing `templates/` or `static/js/`: that builds `Dockerfile.browser`, +which runs the test in a digest-pinned headless browser image, so the host +needs no browser. The package's tarball is committed as `3p/alpinejs-csp-3.14.9.tgz`, byte for byte as the npm registry publishes it. It is a dependency, not this repo's build @@ -3026,7 +3027,7 @@ webhooker/ │ ├── static.go # //go:embed directive │ ├── css/input.css # Tailwind input, source for tailwind.css (make css) │ ├── css/tailwind.css # Generated stylesheet the pages load -│ ├── css/style.css # Older hand-written stylesheet, no longer loaded +│ ├── css/style.css # Hand-written, loaded after tailwind.css: btn-small, the pointer cursor for input.css's buttons, the webhook list cards' focus outline │ ├── js/app.js # Copy-to-clipboard, and the Alpine.js components │ └── js/alpine.min.js # Alpine.js CSP build, extracted from 3p/ by make assets, not committed ├── templates/ # Go HTML templates (base, login, sources, etc.) diff --git a/internal/handlers/ui_copy_test.go b/internal/handlers/ui_copy_test.go index ddf4186..206f07e 100644 --- a/internal/handlers/ui_copy_test.go +++ b/internal/handlers/ui_copy_test.go @@ -82,9 +82,9 @@ func TestNavbarUsesWebhookTerminology(t *testing.T) { }) assert.Contains(t, body, "Retention: 14 days") - assert.Contains(t, body, `class="btn-text">Webhooks`) + assert.Contains(t, body, `class="btn-secondary">Webhooks`) assert.Contains( - t, body, `class="btn-text w-full text-left">Webhooks`, + t, body, `class="btn-secondary w-full">Webhooks`, ) assert.Contains( t, body, @@ -163,7 +163,7 @@ func TestEventLogPageIsCalledFullEventLog(t *testing.T) { ) assert.Contains( t, detailBody, - `Full Event Log`, + `Full Event Log`, "the link under recent events", ) @@ -331,8 +331,9 @@ func TestEntrypointCopyButtonIsProgressiveEnhancement(t *testing.T) { assert.Contains(t, body, "https://hooks.example.com/h/abc123") assert.Contains( t, body, - `hidden data-copy-target="entrypoint-url-ep-1"`, - "the button must start hidden and be revealed by script", + ` + {{end}} {{end}} diff --git a/templates/source_detail.html b/templates/source_detail.html index cf75cc6..0cb0a66 100644 --- a/templates/source_detail.html +++ b/templates/source_detail.html @@ -9,7 +9,7 @@ no class this wide. -->
- ← Back to webhooks + ← Back to webhooks

{{.Webhook.Name}}

@@ -35,8 +35,8 @@

Entrypoints

-
- +
@@ -79,7 +79,7 @@ {{$.BaseURL}}/h/{{.Path}} - +
@@ -94,8 +94,8 @@

Targets

-
- +
@@ -188,7 +188,7 @@

50 Most Recent Events

- Full Event Log + Full Event Log
{{range .Events}} diff --git a/templates/source_edit.html b/templates/source_edit.html index 9b54780..43d2c4f 100644 --- a/templates/source_edit.html +++ b/templates/source_edit.html @@ -5,7 +5,7 @@ {{define "content"}}
diff --git a/templates/source_logs.html b/templates/source_logs.html index 019d729..d17c304 100644 --- a/templates/source_logs.html +++ b/templates/source_logs.html @@ -5,7 +5,7 @@ {{define "content"}}
- ← Back to {{.Webhook.Name}} + ← Back to {{.Webhook.Name}}

Full Event Log

{{.TotalEvents}} total event{{if ne .TotalEvents 1}}s{{end}} @@ -16,8 +16,8 @@
{{range .Events}}
-
-
+
-
+ + {{range .Deliveries}} {{.Target.DisplayName}}: {{.Status}} @@ -38,8 +38,8 @@ -
-
+ +
@@ -50,12 +50,12 @@
- +
{{.Body}}
{{if .BodyTruncated}} -

Body truncated for display: showing {{.BodyShownBytes}} of {{.BodyBytes}} bytes. The stored body is unchanged — download the full body.

+

Body truncated for display: showing {{.BodyShownBytes}} of {{.BodyBytes}} bytes. The stored body is unchanged — download the full body.

{{end}} {{if .Deliveries}} @@ -64,24 +64,26 @@
{{range .Deliveries}}
-
-
- {{.Target.DisplayName}} - {{.Status}} -
-
- {{if .Status.Terminal}} -
- - - -
- {{end}} - {{.AttemptCount}} attempt{{if ne .AttemptCount 1}}s{{end}} - - - -
+
+ + {{if .Status.Terminal}} +
+ + + +
+ {{end}}
diff --git a/templates/sources_list.html b/templates/sources_list.html index 18ce43d..927598a 100644 --- a/templates/sources_list.html +++ b/templates/sources_list.html @@ -25,7 +25,12 @@

{{.Description}}

{{end}}
- Retention: {{.RetentionLabel}} +
+ Retention: {{.RetentionLabel}} + + Open → +
{{.EntrypointCount}} entrypoint{{if ne .EntrypointCount 1}}s{{end}}{{if .InactiveEntrypointCount}}, {{.InactiveEntrypointCount}} inactive{{end}} diff --git a/templates/sources_new.html b/templates/sources_new.html index 41fe41c..a3181f9 100644 --- a/templates/sources_new.html +++ b/templates/sources_new.html @@ -5,7 +5,7 @@ {{define "content"}}
diff --git a/templates/target_edit.html b/templates/target_edit.html index 0f43d8b..59b2fec 100644 --- a/templates/target_edit.html +++ b/templates/target_edit.html @@ -5,7 +5,7 @@ {{define "content"}}
- ← Back to {{.Webhook.Name}} + ← Back to {{.Webhook.Name}}

Edit Target

Type: {{.Target.Type}}. A target's type cannot be changed; create a new target to deliver a different way.