Schedule pickers, and target progress at one row

"Check feeds every" becomes a number plus a unit dropdown in both global
and per-feed settings; parse_interval gained weeks to back it. The
per-feed dropdown can select the global default, clearing the override.

Fixes progress painting every pending row: the event carried no enclosure
id, so the handler had nothing to target and set the width on all of them.
Adding a feed looked like it was downloading everything. Progress,
DownloadDone and DownloadError now carry the enclosure id.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
2026-09-10 02:38:14 +00:00
parent 9960befed5
commit e97f2b9c2f
8 changed files with 155 additions and 30 deletions

View File

@@ -56,6 +56,35 @@ and until now nothing set them.
---
## 2026-09-10 — Schedule pickers, and progress painting every row
**Pickers.** "Check feeds every" is a number input plus a unit dropdown (minutes/hours/days/weeks)
in both global and per-feed Settings, replacing free text. `parse_interval` gained weeks first — it
only knew m/h/d, so the backend would have rejected the new option. The per-feed dropdown's first
entry is "Use the default — every N", which disables the number and sends `null`; that rides on the
null-clearing path fixed earlier today, and would not have worked before it. `splitEvery` picks the
largest unit that divides evenly, so 120 reads "2 hours" rather than "120 min". The API now returns
`schedule_mins` so the page does not re-implement the parser.
**Bug: one download painted every pending row's progress bar.** Reported after adding the TWiT feed.
The `progress` event carried feed/url/file but no enclosure id, so the handler had nothing to target
and set the width on all of them — the code even carried a comment admitting it applied "to whatever
is downloading now". Adding a feed therefore looked like it was downloading the entire back
catalogue.
`Event::Progress`, `DownloadDone` and `DownloadError` now carry `enclosure`, threaded through both
the HTTP and torrent paths (`db::Pending` gained its row id to make that possible), and the handler
targets `.dlbar[data-bar="<id>"]` alone. A test asserts the id is on the wire. Idle bars are
transparent and only get a track while live, so a row that is not downloading shows nothing.
`tests/page-smoke.js` also drives each modal with live-shaped data now — load-time smoke never
reaches code that only runs when a dialog opens, which is exactly where these changes landed.
Verified live: weeks round-trips (`every 2w` -> 20160 min), both pickers render, clearing an
override returns to the global default. `cargo test` 37/37.
---
## 2026-09-10 — The whole UI was dead, and server-side tests could not see it
Reported as "my feeds seem to have disappeared", then "settings and dark/light mode don't do