Files
jellybit/tasks/items/bulk-delete-page.md
T
av 969926fae3 tasks: заведены баг устаревшей карточки и цель группового удаления
- fix card-stale-after-download-finish: карточка списка не обновляется после выхода задачи из downloading
- goal bulk-download-management + feature bulk-delete-page: удаление раздач с файлами пачкой на отдельной странице
2026-08-10 12:32:17 +03:00

5.3 KiB
Raw Blame History

Удалять выбранные загрузки с файлами на отдельной странице

  • Тип: feature
  • Категория: Ядро продукта
  • Зачем: удаление с файлами живёт только в danger-секции страницы одной загрузки: чтобы снести десять раздач, надо десять раз пройти путь список → карточка → подтверждение
  • Теги: goal:bulk-download-management

Отдельная страница веб-UI, доступная из шапки: список загрузок, у которых удаление разрешено (done, orphaned, target_missinginternal/worker/review.go:631), чекбокс у каждой строки и одна кнопка «Удалить выбранные». Кнопка ведёт на подтверждение, где выбранные раздачи названы поимённо, и только оттуда уходит удаление.

Страница отдельная, чтобы не вешать режим выбора на основной список: там карточки живые, самополлятся и перерисовываются, а выбор пользователя такое перерисовывание переживать не обязан.

Речь только о полном удалении (снять хардлинки + снести раздачу с файлами из qBittorrent). Групповой Dismiss (смена статуса без файлов) в эту задачу не входит.

Затрагивает

  • новая страница веб-UI и ссылка на неё в web/templates/partials/header.html; новый шаблон страницы и её партиалы;
  • новый POST-эндпоинт группового удаления в internal/httpapi (рядом с POST /ui/downloads/{id}/delete, internal/httpapi/httpapi.go:143);
  • Reviewer.Delete воркера (internal/worker/review.go:619) — зовётся по каждой выбранной загрузке;
  • qBittorrent torrents/delete с deleteFiles=true — внешний сервис, необратимая операция;
  • спека web-ui, требования «Страницы веб-UI» и «Действия соответствуют состоянию»;
  • спека state-reconciliation в части Delete — групповой вызов не меняет условий поштучного, но подтверждение человека теперь одно на пачку.

Критерии приёмки

  • Страница открывается из шапки и показывает только те загрузки, для которых удаление разрешено поштучно (оракул: тест internal/httpapi — подставной читатель отдаёт задачи во всех состояниях, в разметке строки есть у done/orphaned/target_missing и нет у остальных).
  • Удаление уходит только после явного подтверждения, и подтверждение называет каждую выбранную раздачу поимённо (оракул: тест — POST без признака подтверждения отвечает отказом и не делает ни одного вызова Delete у подставного воркера; ответ подтверждения содержит заголовки всех выбранных).
  • Отказ на одной загрузке не отменяет остальных, а результат называет удалённые и отказавшие поимённо с причиной (оракул: тест, где второй Delete возвращает ошибку — первая и третья удалены, страница результата называет вторую и её причину).
  • Групповой путь не расширяет прав поштучного: попытка удалить задачу в состоянии, где кнопка недоступна, отклоняется с тем же отказом (оракул: тест — Delete для downloading возвращает ErrConflict, страница показывает отказ, остальные выбранные не затронуты).
  • Поведение страницы записано дельта-спекой и проходит валидацию (оракул: openspec validate --strict и task gate).

Рамки

Необратимое действие: deleteFiles=true сносит файлы раздачи, гард последней копии в Delete выключен сознательно. Ослаблять подтверждение ради удобства пачки нельзя — оно остаётся обязательным и поимённым. Групповой Dismiss и автоматическая чистка по сроку хранения (db-retention-cleanup) — не эта задача.