Files
kpa39l c8fe5f7c85 fix(web): keep bulk checkbox selection across post navigation (openspec change keep-bulk-checkboxes)
- Save/restore checked candidate ids in sessionStorage (vesti_bulk_candidates / vesti_bulk_selected)
- Restore checks after page reload when opening a post via ?selected=N
- Fix selector: checkboxes live outside <form> (form=bulk-form attribute), query input[name=ids] globally
- Openspec: new capability candidates-bulk-selection, change archived
2026-09-17 00:52:51 +00:00

4.1 KiB

Context

Страницы /candidates и /selected (FastAPI + Jinja2 + Bootstrap, шаблоны web/templates/candidates.html и selected.html) имеют общий паттерн: слева список постов с чекбоксами массового выбора (form bulk-form, input name=ids), справа детали открытого поста. Открытие поста — обычная GET-навигация (?selected=N), которая перезагружает страницу: сервер отдаёт checked только для текущего поста, остальные отметки теряются. Серверный код (web/app.py) менять не требуется — фикс чистого frontend.

Goals / Non-Goals

Goals:

  • Сохранять отметки чекбоксов между перезагрузками страницы (навигация по постам) на /candidates и /selected.
  • Восстанавливать отметки при загрузке; считать sel-count по восстановленному состоянию.
  • Сбрасывать состояние после успешной отправки bulk-формы.

Non-Goals:

  • Не менять серверный рендеринг, API, БД.
  • Не делать мульти-выбор «как в трекере» со сложным состоянием на сервере — только сохранение существующих чекбоксов.

Decisions

  1. Хранилище — sessionStorage браузера (не localStorage, не сервер).

    • Отметки нужны только в рамках текущей вкладки/сессии просмотра, серверное состояние не требуется (список кандидатов меняется от краула, ids в sessionStorage «протухнут» — это ок, чекбокс просто не найдётся).
    • localStorage переживал бы вкладки и захламлялся бы; серверное состояние = лишний API + потеря при «назад».
    • Ключ: vesti_bulk_<page> где page ∈ {candidates, selected}. Изоляция страниц (требование спеки) — автоматически через разные ключи.
  2. JS-инициализация в конце body (block scripts), как существующий скрипт подсчёта.

    • После загрузки DOM: прочитать sessionStorage, проставить checked всем чекбоксам ids из сохранённого Set, затем вызвать upd() для счётчика.
    • Перехват change на чекбоксах: перезапись Set в sessionStorage (add/delete по value).
    • Перехват submit bulk-form: очистить sessionStorage (отметки отправлены — состояние больше не нужно).
  3. Чекбокс открытого поста продолжает получать checked от сервера (существующая логика {% if selected and selected.id == p.id %}checked{% endif %}) — сохраняется текущее поведение; поверх него восстанавливаются остальные.

Risks / Trade-offs

  • [Отметки «протухают» при повторном использовании страницы позже] → ок: sessionStorage живёт до закрытия вкладки; ids не найденных постов игнорируются.
  • [Дублирование кода в двух шаблонах] → приёмлемо: шаблоны уже дублируют bulk-логику; выносить общий JS в static-файл можно позже отдельным change-ом.
  • [Отключённый JS] → до фикса поведение было «отметки сбрасываются при навигации»; после фикса без JS — то же самое, регрессии нет.