Files
projax/web/templates/tasks_section.tmpl
mAi 83c965f111 feat(phase 2.b caldav): full read/write VTODO writeback from projax
caldav package:
- Todo carries URL, ETag, Raw so ListTodos rows can be PUT/DELETEd in place
- BuildVTodoICS for new VTODOs, ApplyVTodoEdit for in-place edits that
  preserve unknown properties (DESCRIPTION, CATEGORIES, X-*)
- PutTodo/DeleteTodo with If-Match optimistic concurrency
- ErrPreconditionFailed/ErrNotFound for 412/404
- RFC 5545 fold-at-75 + CRLF + text escape, hand-rolled UUID v4
- httptest round-trip (create -> list -> complete -> delete) plus 412 path

web:
- POST /i/{path}/caldav/todo/{complete,reopen,edit,delete,todo-create}
- Re-fetches the live ETag before each PUT/DELETE so ordinary use never
  trips 412; on actual 412 the section reloads with a banner
- Calendar URL must already be linked to the item (anti-forgery guard)
- tasks_section partial drives both the initial page render and HTMX
  swaps; detail.tmpl reduces to a one-liner template call

docs/design.md §5: rewrite for full read/write semantics + ETag concurrency.
2026-05-15 17:16:38 +02:00

103 lines
4.6 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{define "tasks-section"}}
<section class="tasks" id="tasks-section">
<h2>Tasks</h2>
{{if .Banner}}<p class="banner warn" role="alert">{{.Banner}}</p>{{end}}
{{if .Tasks}}
{{$root := .}}
{{range .Tasks}}
{{$calURL := .CalendarURL}}
<div class="cal-block" data-cal="{{$calURL}}">
<h3>{{.DisplayName}}</h3>
{{if .Error}}<p class="banner warn">{{.Error}}</p>{{end}}
<form class="todo-create"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/todo-create"
hx-target="#tasks-section"
hx-swap="outerHTML">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="text" name="summary" placeholder="Add a task…" required>
<input type="date" name="due" title="due date (optional)">
<button type="submit">Add</button>
</form>
{{if .Open}}
<ul class="todo open">
{{range .Open}}
<li class="todo-row" data-uid="{{.UID}}">
<form class="todo-complete inline"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/complete"
hx-target="#tasks-section"
hx-swap="outerHTML">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="hidden" name="uid" value="{{.UID}}">
<button type="submit" class="check" title="Mark complete" aria-label="Mark complete">☐</button>
</form>
<form class="todo-edit inline"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/edit"
hx-target="#tasks-section"
hx-swap="outerHTML">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="hidden" name="uid" value="{{.UID}}">
<input type="text" name="summary" value="{{.Summary}}" required>
<input type="date" name="due" value="{{if .Due}}{{.Due.Format "2006-01-02"}}{{end}}">
<button type="submit" title="Save edits">Save</button>
</form>
<form class="todo-delete inline"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/delete"
hx-target="#tasks-section"
hx-swap="outerHTML"
hx-confirm="Delete this task? This cannot be undone.">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="hidden" name="uid" value="{{.UID}}">
<button type="submit" class="x" title="Delete" aria-label="Delete">×</button>
</form>
</li>
{{end}}
</ul>
{{else}}
<p class="muted">No open tasks.</p>
{{end}}
{{if .DoneRecent}}
<details>
<summary class="muted">{{len .DoneRecent}} completed in last 30 days</summary>
<ul class="todo done">
{{range .DoneRecent}}
<li class="todo-row" data-uid="{{.UID}}">
<form class="todo-reopen inline"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/reopen"
hx-target="#tasks-section"
hx-swap="outerHTML"
title="Reopen">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="hidden" name="uid" value="{{.UID}}">
<button type="submit" class="check" aria-label="Reopen">☑</button>
</form>
<span class="summary">{{.Summary}}</span>
<form class="todo-delete inline"
hx-post="/i/{{$root.Item.PrimaryPath}}/caldav/todo/delete"
hx-target="#tasks-section"
hx-swap="outerHTML"
hx-confirm="Delete this task? This cannot be undone.">
<input type="hidden" name="calendar_url" value="{{$calURL}}">
<input type="hidden" name="uid" value="{{.UID}}">
<button type="submit" class="x" title="Delete" aria-label="Delete">×</button>
</form>
</li>
{{end}}
</ul>
</details>
{{end}}
</div>
{{end}}
{{else}}
<p class="muted">No CalDAV list linked.</p>
<form method="post" action="/i/{{.Item.PrimaryPath}}/caldav/create" class="inline">
<button type="submit">Create CalDAV list</button>
</form>
{{end}}
</section>
{{end}}