diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-02-07 13:47:13 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-02-07 13:47:13 -1000 |
| commit | 0620afc98fdc0f764e82807bb0090b78618ddb1d (patch) | |
| tree | f0a868246adaa1a3e47ffa227787ce2eb3158e4a /web/templates | |
| parent | 27ee1a271248e9f1de8ecb981a6cabfa8e498b1b (diff) | |
Fix timeline task completion replacing view, fix passkey registration CSRF
- Fix checkboxes in timeline calendar grid targeting #tab-content (replaced
entire view). Now target closest .untimed-item/.calendar-event with outerHTML
- Fix passkey registration 403 by passing CSRFToken from settings handler
and exposing it via meta tag for JS to read
- Add TDD workflow requirement to CLAUDE.md
- Tests written first (red-green): template content assertions for checkbox
targets and CSRF token presence, handler data struct verification
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/templates')
| -rw-r--r-- | web/templates/partials/timeline-tab.html | 16 | ||||
| -rw-r--r-- | web/templates/settings.html | 15 |
2 files changed, 10 insertions, 21 deletions
diff --git a/web/templates/partials/timeline-tab.html b/web/templates/partials/timeline-tab.html index c73c1b5..4979744 100644 --- a/web/templates/partials/timeline-tab.html +++ b/web/templates/partials/timeline-tab.html @@ -134,8 +134,8 @@ {{if .IsCompleted}}checked{{end}} hx-post="{{if .IsCompleted}}/uncomplete-atom{{else}}/complete-atom{{end}}" hx-vals='{"id": "{{.ID}}", "source": "{{.Source}}"{{if .ListID}}, "listId": "{{.ListID}}"{{end}}}' - hx-target="#tab-content" - hx-swap="innerHTML" + hx-target="closest .untimed-item" + hx-swap="outerHTML" class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0"> {{end}} <span class="{{if .IsCompleted}}line-through text-white/50{{end}}">{{.Title}}</span> @@ -186,8 +186,8 @@ {{if .IsCompleted}}checked{{end}} hx-post="{{if .IsCompleted}}/uncomplete-atom{{else}}/complete-atom{{end}}" hx-vals='{"id": "{{.ID}}", "source": "{{.Source}}"{{if .ListID}}, "listId": "{{.ListID}}"{{end}}}' - hx-target="#tab-content" - hx-swap="innerHTML" + hx-target="closest .calendar-event" + hx-swap="outerHTML" onclick="event.stopPropagation();" class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0"> {{end}} @@ -223,8 +223,8 @@ {{if .IsCompleted}}checked{{end}} hx-post="{{if .IsCompleted}}/uncomplete-atom{{else}}/complete-atom{{end}}" hx-vals='{"id": "{{.ID}}", "source": "{{.Source}}"{{if .ListID}}, "listId": "{{.ListID}}"{{end}}}' - hx-target="#tab-content" - hx-swap="innerHTML" + hx-target="closest .untimed-item" + hx-swap="outerHTML" class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0"> {{end}} <span class="{{if .IsCompleted}}line-through text-white/50{{end}}">{{.Title}}</span> @@ -271,8 +271,8 @@ {{if .IsCompleted}}checked{{end}} hx-post="{{if .IsCompleted}}/uncomplete-atom{{else}}/complete-atom{{end}}" hx-vals='{"id": "{{.ID}}", "source": "{{.Source}}"{{if .ListID}}, "listId": "{{.ListID}}"{{end}}}' - hx-target="#tab-content" - hx-swap="innerHTML" + hx-target="closest .calendar-event" + hx-swap="outerHTML" onclick="event.stopPropagation();" class="h-4 w-4 rounded bg-black/40 border-white/30 text-white/80 focus:ring-white/30 cursor-pointer flex-shrink-0"> {{end}} diff --git a/web/templates/settings.html b/web/templates/settings.html index 50569e4..0803ae3 100644 --- a/web/templates/settings.html +++ b/web/templates/settings.html @@ -3,6 +3,7 @@ <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="csrf-token" content="{{.CSRFToken}}"> <title>Settings - Task Dashboard</title> <script src="https://unpkg.com/htmx.org@1.9.10"></script> <style> @@ -237,19 +238,7 @@ statusEl.textContent = 'Starting registration...'; try { - const csrfMeta = document.querySelector('input[name="csrf_token"]') || document.querySelector('[name="csrf_token"]'); - let csrfToken = ''; - // Get CSRF token from the feature toggle form's hidden fields or cookie - const forms = document.querySelectorAll('form'); - for (const f of forms) { - const input = f.querySelector('input[name="csrf_token"]'); - if (input) { csrfToken = input.value; break; } - } - // Fallback: fetch from HTMX headers - if (!csrfToken) { - const resp = await fetch('/settings/passkeys'); - // Try to extract from response - } + const csrfToken = document.querySelector('meta[name="csrf-token"]').content; const beginResp = await fetch('/passkeys/register/begin', { method: 'POST', |
