- fix card-stale-after-download-finish: карточка списка не обновляется после выхода задачи из downloading - goal bulk-download-management + feature bulk-delete-page: удаление раздач с файлами пачкой на отдельной странице
6.5 KiB
🐞 Обновлять карточку списка после завершения загрузки
- Тип: fix
- Категория: Ядро продукта
- Зачем: завершённая загрузка висит в списке с бейджем «Загружается» до ручной перезагрузки: карточка самополлится только в catched, а прогресс перестаёт поллить, выйдя из downloading — обновлять карточку становится некому
Карточка списка показывает состояние, которого уже нет: качание кончилось, задача ушла в распознавание и дальше в ревью, а на экране прежний бейдж и прежний набор действий.
Причина видна в коде. Самополлинг карточки включает поле SelfPoll, а оно
истинно только в catched (internal/httpapi/httpapi.go:664,
web/templates/partials/card.html:2). Внутренний фрагмент прогресса поллится,
пока состояние downloading (internal/httpapi/live.go:88,
web/templates/partials/progress.html:1). Задача, покинувшая downloading, не
опрашивается уже ничем. На странице /download/{id} то же самое:
web/templates/partials/download_main.html:2 самополлится только в catched
(internal/httpapi/download.go:116).
Спека нынешнее поведение не запрещает: live-status → «Живой прогресс активных
загрузок» прямо требует прекращать поллинг прогресса на выходе из
downloading, а web-ui → «Отображение промежуточного состояния catched»
заказывает самообновление только для перехода catched → downloading.
Поэтому починка несёт дельту спеки, а не только правку кода.
Воспроизведение
- Открыть главную
/, добавить раздачу, дождаться состоянияdownloading. - Страницу не перезагружать. Дождаться, пока qBittorrent доведёт раздачу до
100% и воркер уведёт задачу из
downloading(вrecognizing, дальше вreviewилиdone). - Наблюдается: бейдж карточки остаётся «Загружается», прогресс-бар замирает на последнем значении, кнопка «Ревью →» не появляется. Фоновых запросов от этой карточки в панели сети больше нет.
- Ожидается: карточка сама показывает новое состояние — бейдж, набор действий, исчезнувший прогресс.
- Перезагрузить страницу руками: карточка сразу показывает верное состояние — расходится отображение, а не данные.
Затрагивает
- фрагменты
GET /fragments/downloads/{id}/cardиGET /fragments/downloads/{id}/progress(internal/httpapi/live.go); - поле
SelfPollвида карточки и вида страницы загрузки (internal/httpapi/httpapi.go,internal/httpapi/download.go); - шаблоны
web/templates/partials/card.html,progress.html,download_main.html; - спека
web-ui, требование «Отображение промежуточного состояния catched» — условие самообновления перестаёт быть привязанным к одной фазе; - спека
live-status, требование «Живой прогресс активных загрузок» и его сценарий «Завершение останавливает поллинг» — прекращение поллинга прогресса перестаёт означать прекращение обновления карточки.
Критерии приёмки
- Карточка нетерминальной загрузки самополлится, и первый ответ фрагмента после
смены состояния несёт новый бейдж (оракул: тест
internal/httpapi— рендер карточки вdownloadingсодержитhx-getна/fragments/downloads/{id}/card, а подставной читатель, сменивший состояние наreview, отдаёт карточку с бейджем ревью). - Терминальная карточка себя не опрашивает: фоновых запросов после
done,failed,cancelledиdeletedнет (оракул: тот же тест — в разметке такой карточки нет ниhx-get, ниhx-trigger). - Появившееся действие видно без перезагрузки: карточка задачи, перешедшей в
review, несёт кнопку «Ревью →» (оракул: тест фрагмента карточки). - Страница
/download/{id}обновляет бейдж и блок действий по тому же правилу, что и карточка (оракул: тестinternal/httpapi/download.go—SelfPollистинен для нетерминальных состояний и ложен для терминальных). - Правило записано в дельта-спеках обеих затронутых capability (оракул:
openspec validate --strictи шаг канона вtask gate).
Рамки
Чинится поллингом фрагментов: переход на SSE — отдельная задача
sse-live-updates, и эта починка её не делает и не отменяет. Расширение
самополлинга на все нетерминальные состояния добавляет фоновых запросов к БД —
частота и её потолок решаются в предложении, а не молча.