feat(phase 4a): chronological timeline at /timeline + dashboard VTODO edit/delete
/timeline braids every dated thing in projax into a single chronological spine:
CalDAV VTODOs (DUE anchor), VEVENTs (DTSTART), dated item_links (event_date),
and item-creation markers. Default window past-30d to future-90d; ?order=
toggles asc/desc; ?kind= narrows by row type; tree filter (?tag/?mgmt/?has)
applies across kinds. Today / Tomorrow get sticky pills; rows > today+30d
fade. 90s in-memory TTL cache keyed by (filter, window, order, kinds);
busted on any VTODO writeback or dated-link change.
Scope expansion (per head message during 4a): the dashboard Tasks card now
has edit + delete affordances on every row, matching the detail page. New
/dashboard/task/{edit,delete} endpoints share a writeback path with /done.
Timeline VTODO rows reuse the same handlers; HX-Target=timeline-section
selects the re-render surface. Timeline item_link rows reuse the existing
/i/{path}/links/remove handler with the same surface-switch.
VEVENT rows on the timeline remain read-only at v1 (3l decision stands).
Item-creation events render as muted "added X to projax" markers.
Tests cover empty state, dated-doc surfacing, kind-filter narrowing, order
toggle, mixed CalDAV todos + all-day events (with the (2 days) duration
hint), and tag-filter cross-kind. New dashboard test asserts the edit/
delete affordances are wired up.
docs/design.md gains §12 with the full source list, layout rules, time
window, filter integration, cache TTL, and deferred items.
This commit is contained in:
@@ -482,6 +482,54 @@ This is deliberately the smallest correct service worker. Mutations (CalDAV/Gite
|
||||
|
||||
**Out of scope for 3j**: push notifications, background sync, full offline write mode, splash-screen tuning.
|
||||
|
||||
## 12. Timeline view (Phase 4a)
|
||||
|
||||
A chronological "what's happening in my life by date" surface at `/timeline`, nav-linked next to `/dashboard`, `/graph`, `/admin`. Different shape from the dashboard (which is "right now") — the timeline is a scrollable spine that braids every dated thing in projax under its anchor date.
|
||||
|
||||
**Sources** (each row carries a `(date, kind, item, label, link)` tuple):
|
||||
|
||||
1. **CalDAV VTODOs** with a `DUE` date — open ones plus completed/cancelled in the recent past (anchor: `LAST-MODIFIED` for done/cancelled, otherwise `DUE`).
|
||||
2. **CalDAV VEVENTs** with `DTSTART` in window — past 30 days and future 90 days by default. `DTEND` drives the duration hint (`(2 days)` / `(1h)`).
|
||||
3. **Dated `projax.item_links`** (`event_date IS NOT NULL`) — letters, notes, documents, URLs anchored to a date. Surfaced under the canonical PER (`{primary_path}.{YYMMDD}`).
|
||||
4. **Item creation events** — `projax.items.created_at::date` rendered as a muted "added X to projax" marker.
|
||||
|
||||
Items without a date never appear here — the tree/graph/dashboard cover the rest. Gitea-issue activity is explicitly out of scope for 4a (already on the dashboard).
|
||||
|
||||
**Layout**:
|
||||
|
||||
- Vertical spine. Each day is a `<li class="spine-day">` with a header and per-day row list. Days with zero rows collapse — no header emitted.
|
||||
- Default order is newest first; `?order=asc` reverses both the outer day list and (implicitly) the reader's mental model. Within a day rows sort: timed events → all-day events → VTODOs → docs → creation markers, ties broken by summary / PER / slug.
|
||||
- Today / Tomorrow get sticky pills next to the day header; the spine border-left highlights those days in the accent / ok colour.
|
||||
- Far-future rows (`Date > today+30d`) get `.far-future` opacity 0.5 so the foreseeable future stands out from the speculative future.
|
||||
|
||||
**Time window**:
|
||||
|
||||
- Default: past 30 days through next 90 days.
|
||||
- `?from=YYYY-MM-DD&to=YYYY-MM-DD` overrides both bounds (`to` is inclusive in URL terms; the handler shifts to exclusive internally).
|
||||
- `?before=YYYY-MM-DD` advances the window into the past for "older" pagination.
|
||||
- `?when=past` / `?when=future` clamps to the half-line containing today.
|
||||
|
||||
**Filters**:
|
||||
|
||||
- Reuses the tree filter strip — `?q=`, `?tag=`, `?mgmt=`, `?has=` — so the timeline can be scoped to "work things" or "anything mentioning paliad" with the same vocabulary as `/` and `/dashboard`.
|
||||
- Timeline-specific narrowing: `?kind=todo,event,doc,creation` (multi-select; default all four). `?when=` for past/future split.
|
||||
|
||||
**Affordances on rows** (per the 4a scope-expansion message):
|
||||
|
||||
- **VTODOs**: ✓ complete, ✎ edit (summary + due), × delete — using the existing `/dashboard/task/done|edit|delete` handlers. The dashboard's Tasks card grew the same edit + delete on the same day.
|
||||
- **Dated `item_links` (docs)**: × delete via `/i/{path}/links/remove`. The link-remove handler now re-renders the timeline section when the swap target is `#timeline-section` (it still re-renders the Documents fragment when called from the detail page).
|
||||
- **VEVENTs**: read-only at v1 (consistent with the 3l decision). Multi-day events render once on the first day with the duration hint.
|
||||
- **Item creation markers**: read-only display only.
|
||||
|
||||
**Cache**: 90 s in-memory map keyed by `(filter, from, to, order, kinds)`. Looser than the dashboard's 60 s because timeline is browse-y, not action-y. The cache is invalidated wholesale on VTODO writeback (`/dashboard/task/*`, `/i/{path}/caldav/todo/*`) and on dated-link add/remove — any of those could move rows on or off the spine and the cost of a re-aggregation is cheap.
|
||||
|
||||
**Out of scope for 4a**:
|
||||
|
||||
- Drag-to-create-on-date (would require write paths from a non-detail page).
|
||||
- iCal export of the timeline.
|
||||
- Per-row inline edit of VEVENT (use the source calendar app — the 3l read-only stance still holds for v1).
|
||||
- Gitea issue created/closed activity (deferred until m asks; dashboard already covers it).
|
||||
|
||||
## 9. Phase-1 deliverable checklist
|
||||
|
||||
- [ ] `projax.items` + `projax.item_links` migrations in `db/migrations/`
|
||||
|
||||
Reference in New Issue
Block a user