Веб-UI: обзор жизненного цикла в карточке загрузки
Карточка списка на главной теперь даёт краткий обзор «от загрузки до
решения об удалении»: метка «ID:» перед идентификатором, дата добавления
(абсолютная + относительная, всегда), размер раздачи и рейтинг отдачи.
Спойлер контекста убран — контекст смотрят на /download/{id}.
Данные:
- рейтинг и общий размер — из живого снимка воркера (qbt total_size →
worker.Live.TotalSize); размер доступен для любой раздачи в снимке;
- размер-фолбэк, когда торрента нет в qBittorrent (orphaned) — сумма
размеров разложенных файлов: новая колонка file_link.size, layouter
пишет размер при линковке, ридер LayoutSizeByDownload суммирует по
странице одним запросом (дедуп по dst_path);
- дата — source_added_at → фолбэк created_at, показ в TZ сервера.
handleIndex читает снимок для всех карточек (map-lookup), рейтинг/размер
статичны на рендере (без поллинга). Миграция 0007, ER-схема обновлена.
Change download-card-lifecycle-overview влит в спеки и заархивирован.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
# file-layout Specification (delta)
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Запись размера разложенного файла
|
||||
|
||||
При линковке файла раскладка SHALL сохранять его размер в байтах вместе с
|
||||
записью о созданной ссылке (`file_link`). Сохранённый размер SHALL позволять
|
||||
вычислить суммарный размер разложенных файлов загрузки — он служит фолбэком
|
||||
размера раздачи, когда торрента нет в qBittorrent (например, состояние
|
||||
`orphaned`, где файлы библиотеки — последняя копия данных). Запись размера MUST
|
||||
NOT влиять на инвариант неприкосновенности источника (по-прежнему только
|
||||
`mkdir`/`link`/копия в цель).
|
||||
|
||||
#### Scenario: Размер сохраняется при линковке
|
||||
|
||||
- **WHEN** раскладка создаёт хардлинк (или копию при copy-fallback) файла
|
||||
- **THEN** размер этого файла в байтах сохраняется в записи ссылки `file_link`
|
||||
|
||||
#### Scenario: Суммарный размер доступен без торрента
|
||||
|
||||
- **WHEN** у загрузки есть разложенные файлы, а её торрента нет в qBittorrent
|
||||
- **THEN** суммарный размер разложенных файлов доступен как размер раздачи для
|
||||
показа в карточке
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# live-status Specification (delta)
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Состав телеметрии
|
||||
|
||||
Телеметрия одной раздачи SHALL включать прогресс (доля 0..1), скорость загрузки,
|
||||
ETA и общий размер раздачи (total size); а для сидирующих раздач дополнительно —
|
||||
рейтинг, число сидов и пиров, объём отданного и скорость отдачи. Общий размер
|
||||
SHALL быть доступен для любой раздачи, присутствующей в снимке (не только
|
||||
сидирующей). Значения SHALL извлекаться из ответа qBittorrent `/torrents/info`
|
||||
без дополнительного сетевого вызова.
|
||||
|
||||
#### Scenario: Телеметрия качающейся задачи
|
||||
|
||||
- **WHEN** торрент задачи находится в состоянии загрузки
|
||||
- **THEN** в снимке для неё доступны прогресс, скорость загрузки и ETA
|
||||
|
||||
#### Scenario: Общий размер доступен для любой раздачи в снимке
|
||||
|
||||
- **WHEN** торрент задачи присутствует в снимке в любом состоянии
|
||||
- **THEN** в телеметрии для неё доступен общий размер раздачи
|
||||
|
||||
#### Scenario: Телеметрия сидирующей задачи
|
||||
|
||||
- **WHEN** торрент задачи завершён и раздаётся
|
||||
- **THEN** в снимке для неё доступны рейтинг, число сидов/пиров, объём
|
||||
отданного и скорость отдачи
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
# web-ui Specification (delta)
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Обзор жизненного цикла в карточке списка
|
||||
|
||||
Карточка загрузки в списке SHALL показывать обзорную мета-строку для решения о
|
||||
судьбе раздачи: метку `ID:` перед копируемым идентификатором загрузки, дату
|
||||
добавления раздачи (всегда), размер раздачи и рейтинг отдачи. Контекст загрузки
|
||||
MUST NOT показываться в карточке списка — он доступен на странице `/download/{id}`.
|
||||
|
||||
Дата добавления SHALL показываться всегда как абсолютная дата и относительная
|
||||
давность (например «`2026-06-30 · 5 дней назад`»); источником SHALL быть время
|
||||
добавления раздачи в источник (`source_added_at`, qBittorrent `added_on`) с
|
||||
фолбэком на время создания загрузки (`created_at`), согласованным с порядком
|
||||
списка.
|
||||
|
||||
Рейтинг отдачи SHALL браться из живого снимка телеметрии; если торрента нет в
|
||||
снимке (источник ушёл из qBittorrent), рейтинг SHALL отображаться прочерком «—».
|
||||
|
||||
Размер раздачи SHALL браться из живого снимка (общий размер торрента), а при
|
||||
отсутствии торрента в снимке — из суммарного размера разложенных файлов загрузки;
|
||||
если неизвестно ни то, ни другое — прочерк «—».
|
||||
|
||||
#### Scenario: Метка идентификатора
|
||||
|
||||
- **WHEN** рендерится карточка загрузки в списке
|
||||
- **THEN** перед значением `download.id` показана метка «ID:», а кнопка
|
||||
копирования копирует именно `download.id`
|
||||
|
||||
#### Scenario: Дата добавления показана всегда
|
||||
|
||||
- **WHEN** рендерится любая карточка списка
|
||||
- **THEN** в ней показана дата добавления раздачи абсолютной датой и
|
||||
относительной давностью
|
||||
- **AND** если `source_added_at` неизвестно, используется `created_at`
|
||||
|
||||
#### Scenario: Рейтинг из живого снимка
|
||||
|
||||
- **WHEN** торрент загрузки присутствует в живом снимке
|
||||
- **THEN** в карточке показан его рейтинг отдачи
|
||||
- **AND** если торрента в снимке нет, рейтинг показан прочерком «—»
|
||||
|
||||
#### Scenario: Размер с фолбэком на разложенные файлы
|
||||
|
||||
- **WHEN** торрент загрузки присутствует в живом снимке
|
||||
- **THEN** размер раздачи в карточке берётся из общего размера торрента
|
||||
- **AND** если торрента в снимке нет, но у загрузки есть разложенные файлы —
|
||||
размер берётся из суммарного размера этих файлов
|
||||
|
||||
#### Scenario: Контекст не в карточке
|
||||
|
||||
- **WHEN** у загрузки есть переданный контекст
|
||||
- **THEN** он не показывается в карточке списка, но доступен на странице
|
||||
`/download/{id}`
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Клиентские взаимодействия без сборки
|
||||
|
||||
Веб-UI SHALL реализовывать клиентскую логику без шага сборки и без реактивных
|
||||
фреймворков: копирование идентификатора загрузки (vanilla JS). Основной
|
||||
копируемый идентификатор в карточке списка и в шапке страницы просмотра SHALL
|
||||
быть `download.id` (ULID) — тот же ключ, что пишется в логи (`download_id`). Все
|
||||
действия над загрузкой SHALL выполняться через формы/htmx (раундтрип на сервер),
|
||||
без клиентского пересчёта доменного состояния.
|
||||
|
||||
#### Scenario: Копирование идентификатора загрузки
|
||||
|
||||
- **WHEN** пользователь нажимает кнопку копирования рядом с идентификатором
|
||||
загрузки (`download.id`) в карточке списка или шапке страницы просмотра
|
||||
- **THEN** значение `download.id` копируется в буфер обмена без перезагрузки
|
||||
страницы
|
||||
|
||||
#### Scenario: Действия только через раундтрип
|
||||
|
||||
- **WHEN** пользователь выполняет действие над загрузкой
|
||||
- **THEN** оно исполняется формой/htmx-запросом на сервер, без клиентского
|
||||
пересчёта доменного состояния
|
||||
Reference in New Issue
Block a user