Files
jellybit/openspec/changes/archive/2026-07-01-web-ui-list-detail/tasks.md
T
avandClaude Opus 4.8 c0b5ab7295 UI/UX списка и карточки загрузки: серверные фильтр/поиск/пагинация, матч-ссылка, имя раздачи (web-ui-list-detail)
- Список: серверные фильтр по группе состояний, поиск и пагинация (GET
  f/q/page/all, по 25), сортировка по времени добавления в qBittorrent
  (added_on) с фолбеком на created_at и tie-break по id.
- Заголовок загрузки = имя раздачи (display_name) → распознанное название →
  усечённый источник; сырой magnet вынесен в блок «Информация о торренте».
- Матч метабазы показан ссылкой на запись (страница загрузки и ревью);
  URL берётся у выбранного кандидата либо строится по provider+id и типу.
- Полировка вёрстки; клиентская JS-фильтрация убрана (всё серверное, без JS).
- Миграция 0005 (display_name, source_added_at); воркер однократно
  фиксирует source_added_at при поллинге/усыновлении; ER-схема обновлена.
- OpenSpec: дельты влиты в specs/{web-ui,ingest}, change заархивирован.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 09:50:24 +03:00

49 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 1. Персистентность имени раздачи и времени добавления (БД + ingest + worker)
- [x] 1.1 Миграция `0005` (goose): `download.display_name TEXT NOT NULL DEFAULT ''` и `download.source_added_at` (nullable timestamp), обратная миграция (down)
- [x] 1.2 Добавить поля `DisplayName` и `SourceAddedAt` в `store.Download`; писать `display_name` в `CreateDownload`; метод однократной записи `source_added_at` с SQL-гардом `WHERE source_added_at IS NULL`; экспортировать хелпер форматирования времени в формате `sqliteTimeLayout` (UTC)
- [x] 1.3 В `internal/ingest` заполнять `DisplayName` выведенным именем `rename` при создании загрузки; в `discover.adopt()``display_name = t.Name` для усыновлённых торрентов
- [x] 1.4 В `internal/worker` персистить `source_added_at` из `qbt.Torrent.AddedOn` в цикле `Poll` сразу после `byHash`-сопоставления (до `reconcile`, для любого класса состояния) и в `adopt()`; формат — `time.Unix(...).UTC().Format(sqliteTimeLayout)`; однократно (гард по `d.SourceAddedAt` + SQL IS NULL); под `w.mu`
- [x] 1.5 Обновить ER-схему `docs/specs/database.md` (колонки `display_name`, `source_added_at`)
- [x] 1.6 Тесты: ingest сохраняет `display_name`; adopt пишет `display_name` из имени торрента; worker пишет `source_added_at` однократно и в формате `created_at`; пустой контекст → пустое имя
## 2. Серверные фильтр, поиск, сортировка и пагинация списка (store)
- [x] 2.1 Вынести маппинг состояние↔группа фильтра в единый источник истины (используется и в UI, и в запросе); учесть `all` с исключением `deleted` и осознанно — группу `other` (cancelled/reverted/deleted) без своего чипа
- [x] 2.2 Метод `store.ListDownloadsPage(ctx, ListFilter)` → страница + общий count: `WHERE` по группе состояний, `deleted` только при «показать всё», поиск `LIKE`/`COLLATE NOCASE` по `source_ref`/`display_name`/`context`/`infohash`, сортировка `ORDER BY COALESCE(source_added_at, created_at) DESC, id DESC`, `LIMIT`/`OFFSET`
- [x] 2.3 Тесты `store`: фильтр по группе, поиск, скрытие `deleted` по умолчанию, порядок по времени добавления с фолбеком + тай-брейк по id при равных метках, границы пагинации и count
## 3. Список на главной (httpapi + шаблоны)
- [x] 3.1 Разбор GET-параметров `f`/`q`/`page`/`all` в `handleIndex` (клэмп `page`: `<1`/нечисловой → 1, за пределом → пустая страница), константа размера страницы (25), вызов `ListDownloadsPage`; расширить интерфейс `Reader` методом `ListDownloadsPage`
- [x] 3.2 View-модель списка: элементы страницы + данные пагинации + текущие фильтр/поиск; удалить ставшие мёртвыми `SearchText` и (если больше не нужен) `Group` из `downloadView`
- [x] 3.3 `index.html`: чипы-фильтр и «показать всё» как ссылки (сохраняют `q`), форма поиска (GET), навигация по страницам (сохраняет `f`/`q`); серверный рендер пустого состояния («ничего не найдено» при активных фильтре/поиске, иначе «пока пусто»)
- [x] 3.4 Убрать клиентскую JS-фильтрацию из `app.js` (`applyFilters`/`setFilter` + `DOMContentLoaded`-хук), оставить `copyHash` и `<details>`; сохранить живой прогресс активных карточек
- [x] 3.5 Заголовок карточки — фолбек-цепочка `display_name` → распознанное → усечённый источник (одна строка)
- [x] 3.6 Тесты `httpapi`: параметры списка → корректная выборка/пагинация; заголовок из `display_name` и фолбеки
## 4. Страница загрузки: имя, матч-ссылка, блок торрента (httpapi + шаблоны)
- [x] 4.1 Заголовок/шапка `/download/{id}` — та же фолбек-цепочка заголовка
- [x] 4.2 Хелпер `providerURL(provider, id, mediaType)` (tmdb: movie/tv; tvdb: медиазависимый путь; imdb: /title) + выбор URL матча: URL выбранного кандидата только если его provider+id == эффективным `rd.Provider`/`rd.ProviderID`, иначе построенный; нет надёжного URL → без ссылки
- [x] 4.3 «Распознано как»: показать матч ссылкой на запись (провайдер, id, год); при отсутствии URL — текст без ссылки
- [x] 4.4 Блок «Информация о торренте»: полный источник (magnet) + infohash с копированием
- [x] 4.5 Тесты `httpapi`: матч-ссылка при наличии/отсутствии URL; расхождение выбранного кандидата и эффективного provider_id (ссылка ведёт на эффективную запись); блок торрента
## 5. Ревью: матч-ссылка (httpapi + шаблон)
- [x] 5.1 В блоке «Источник совпадения» строку «Выбрано» показывать ссылкой на запись (та же логика выбора URL, что в 4.2)
## 6. Полировка вёрстки (CSS/шаблоны)
- [x] 6.1 «Распознано как»: снять `max-width` у списка полей — блок на всю ширину
- [x] 6.2 Layout-виджет: приклеить стрелку к строке файла-источника (источник и цель строго друг под другом)
- [x] 6.3 Проверить отсутствие инлайн-`<style>` с хардкодом цветов в изменённых шаблонах (правки — в `jellybit.css`)
## 7. Проверка и ревью
- [x] 7.1 `task test` и `task lint` зелёные
- [x] 7.2 `openspec validate web-ui-list-detail --strict`
- [ ] 7.3 Ручная проверка: список с фильтром/поиском/пагинацией, живой прогресс не сбрасывается; заголовки; матч-ссылки; блок торрента; полировка
- [x] 7.4 Ревью кода перед archive