From c8fe5f7c8512f16a16e231607cf5f502bfbb3a6e Mon Sep 17 00:00:00 2001 From: kpa39l Date: Thu, 17 Sep 2026 00:52:51 +0000 Subject: [PATCH] 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=bulk-form attribute), query input[name=ids] globally - Openspec: new capability candidates-bulk-selection, change archived --- .../.openspec.yaml | 2 + .../2026-09-17-keep-bulk-checkboxes/design.md | 34 ++++++++++++++++ .../proposal.md | 29 ++++++++++++++ .../specs/candidates-bulk-selection/spec.md | 33 ++++++++++++++++ .../2026-09-17-keep-bulk-checkboxes/tasks.md | 14 +++++++ .../specs/candidates-bulk-selection/spec.md | 34 ++++++++++++++++ web/templates/candidates.html | 29 +++++++++++++- web/templates/selected.html | 39 +++++++++++++++++-- 8 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/.openspec.yaml create mode 100644 openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/design.md create mode 100644 openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/proposal.md create mode 100644 openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/specs/candidates-bulk-selection/spec.md create mode 100644 openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/tasks.md create mode 100644 openspec/specs/candidates-bulk-selection/spec.md diff --git a/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/.openspec.yaml b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/.openspec.yaml new file mode 100644 index 0000000..d28e909 --- /dev/null +++ b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-09-17 diff --git a/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/design.md b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/design.md new file mode 100644 index 0000000..3b854ea --- /dev/null +++ b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/design.md @@ -0,0 +1,34 @@ +## 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 ∈ {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 — то же самое, регрессии нет. \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/proposal.md b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/proposal.md new file mode 100644 index 0000000..caa5686 --- /dev/null +++ b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/proposal.md @@ -0,0 +1,29 @@ +## Why + +При массовом отборе кандидатов пользователь отмечает несколько постов чекбоксами, затем открывает один из них для просмотра (ссылка ?selected=N). Перезагрузка страницы сбрасывает все отмеченные чекбоксы, кроме чекбокса текущего поста, — приходится отмечать их заново, что замедляет работу с потоком кандидатов. + +## What Changes + +- Сохранять отмеченные чекбоксы постов при переходе по ссылке ?selected=N (открытие поста в правой панели) в списках кандидатов (/candidates) и отобранных (/selected). +- Механизм: состояние чекбоксов хранится в sessionStorage браузера по ключу с namespace страницы (candidates/selected) и доп. параметрами фильтров; при перезагрузке страницы отмеченные чекбоксы восстанавливаются. +- Чекбокс открытого поста остаётся отмеченным (текущее поведение сохраняется). +- При отправке bulk-формы (Отобрать/Отклонить/Обработать и т.д.) состояние очищается, чтобы не «протухали» старые отметки. +- Счётчик выбранных (badge sel-count) считается по фактически отмеченным чекбоксам после восстановления. + +## Capabilities + +### New Capabilities + +- `candidates-bulk-selection`: сохранение отметок массового выбора кандидатов между перезагрузками страницы при навигации по постам. + +## Status: implemented (2026-09-17) + +- Реализовано: скрипты сохранения/восстановления чекбоксов из sessionStorage в candidates.html и selected.html (ключи `vesti_bulk_candidates` / `vesti_bulk_selected`). +- Проверено в браузере (Camofox): отметки 24/52 на /candidates сохранены при открытии поста 52; отметки 109/110 на /selected сохранены при открытии поста 110; изоляция страниц подтверждена; badge sel-count обновляется. +- Выявлен и исправлен баг: чекбоксы лежат вне `` (атрибут form="bulk-form"), поэтому исходный селектор `#bulk-form input[name="ids"]` не находил их; заменён на `input[name="ids"]`. + +## Impact + +- Файлы: web/templates/candidates.html, web/templates/selected.html (JS-скрипт восстановления чекбоксов из sessionStorage). +- Серверный код не меняется (чистый frontend-fix, без изменения API/БД). +- Сервис: веб VESTI на bigbox, порт 8400; рестарт не требуется (шаблоны перечитываются при перезагрузке страницы). \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/specs/candidates-bulk-selection/spec.md b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/specs/candidates-bulk-selection/spec.md new file mode 100644 index 0000000..3770de2 --- /dev/null +++ b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/specs/candidates-bulk-selection/spec.md @@ -0,0 +1,33 @@ +## Purpose + +Сохранение отметок массового выбора кандидатов между перезагрузками страницы при просмотре отдельных постов. + +## ADDED Requirements + +### Requirement: сохранение отметок чекбоксов при навигации по постам + +Когда пользователь отмечает несколько постов чекбоксами в списке кандидатов и затем открывает один из постов (переход по ссылке ?selected=N, перезагрузка страницы), отмеченные ранее чекбоксы MUST оставаться отмеченными. + +#### Scenario: открытие поста сохраняет отметки +- **WHEN** пользователь отметил несколько постов чекбоксами в списке кандидатов и открыл один из постов по ссылке ?selected=N +- **THEN** все ранее отмеченные чекбоксы остаются отмеченными после перезагрузки страницы + +#### Scenario: сброс отметок после массовой операции +- **WHEN** пользователь выполнил массовую операцию (Отобрать/Отклонить) над отмеченными постами +- **THEN** отметки сбрасываются и счётчик выбранных показывает 0 + +### Requirement: изоляция состояния по страницам и фильтрам + +Состояние чекбоксов MUST храниться отдельно для страницы кандидатов и страницы отобранных, чтобы отметки одной страницы не влияли на другую. + +#### Scenario: независимость кандидаты/отобранные +- **WHEN** пользователь отметил посты на странице кандидатов и перешёл на страницу отобранных +- **THEN** на странице отобранных не восстанавливаются отметки со страницы кандидатов + +### Requirement: счётчик выбранных соответствует восстановленным отметкам + +Счётчик выбранных (badge sel-count) MUST отображать количество фактически отмеченных чекбоксов после восстановления состояния при загрузке страницы. + +#### Scenario: счётчик после восстановления +- **WHEN** страница загружена и восстановлены сохранённые отметки чекбоксов +- **THEN** счётчик показывает количество восстановленных отметок \ No newline at end of file diff --git a/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/tasks.md b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/tasks.md new file mode 100644 index 0000000..3f5b8a8 --- /dev/null +++ b/openspec/changes/archive/2026-09-17-keep-bulk-checkboxes/tasks.md @@ -0,0 +1,14 @@ +## 1. candidates.html — сохранение чекбоксов + +- [x] 1.1 В script-блок candidates.html добавить: чтение сохранённого Set ids из sessionStorage (`vesti_bulk_candidates`), простановку checked восстановленным чекбоксам; verify: после открытия поста ?selected=N ранее отмеченные чекбоксы остаются отмеченными +- [x] 1.2 В script-блок candidates.html перехватить change чекбоксов (запись/удаление id в sessionStorage) и submit bulk-form (очистка sessionStorage); verify: отметка/снятие чекбокса обновляет sessionStorage, после отправки bulk-формы sessionStorage пуст + +## 2. selected.html — сохранение чекбоксов + +- [x] 2.1 В script-блок selected.html добавить восстановление чекбоксов из sessionStorage (`vesti_bulk_selected`) по аналогии с candidates.html; verify: отметки сохраняются при навигации по /selected +- [x] 2.2 В script-блок selected.html перехватить change чекбоксов и submit bulk-form (очистка); verify: после «Обработать моделью»/«Опубликовать» отметки сбрасываются + +## 3. Проверка счётчика и интеграции + +- [x] 3.1 Проверить, что badge sel-count показывает количество восстановленных отметок после перезагрузки; verify: открыть /candidates, отметить 2-3 поста, открыть пост, счётчик показывает прежнее число +- [x] 3.2 Проверить изоляцию /candidates и /selected (отметки одной страницы не восстанавливаются на другой); verify: отметить на /candidates, перейти на /selected — там пусто \ No newline at end of file diff --git a/openspec/specs/candidates-bulk-selection/spec.md b/openspec/specs/candidates-bulk-selection/spec.md new file mode 100644 index 0000000..438be9a --- /dev/null +++ b/openspec/specs/candidates-bulk-selection/spec.md @@ -0,0 +1,34 @@ +# candidates-bulk-selection Specification + +## Purpose +Сохранение отметок массового выбора кандидатов между перезагрузками страницы при просмотре отдельных постов. + +## Requirements + +### Requirement: сохранение отметок чекбоксов при навигации по постам + +Когда пользователь отмечает несколько постов чекбоксами в списке кандидатов и затем открывает один из постов (переход по ссылке ?selected=N, перезагрузка страницы), отмеченные ранее чекбоксы MUST оставаться отмеченными. + +#### Scenario: открытие поста сохраняет отметки +- **WHEN** пользователь отметил несколько постов чекбоксами в списке кандидатов и открыл один из постов по ссылке ?selected=N +- **THEN** все ранее отмеченные чекбоксы остаются отмеченными после перезагрузки страницы + +#### Scenario: сброс отметок после массовой операции +- **WHEN** пользователь выполнил массовую операцию (Отобрать/Отклонить) над отмеченными постами +- **THEN** отметки сбрасываются и счётчик выбранных показывает 0 + +### Requirement: изоляция состояния по страницам и фильтрам + +Состояние чекбоксов MUST храниться отдельно для страницы кандидатов и страницы отобранных, чтобы отметки одной страницы не влияли на другую. + +#### Scenario: независимость кандидаты/отобранные +- **WHEN** пользователь отметил посты на странице кандидатов и перешёл на страницу отобранных +- **THEN** на странице отобранных не восстанавливаются отметки со страницы кандидатов + +### Requirement: счётчик выбранных соответствует восстановленным отметкам + +Счётчик выбранных (badge sel-count) MUST отображать количество фактически отмеченных чекбоксов после восстановления состояния при загрузке страницы. + +#### Scenario: счётчик после восстановления +- **WHEN** страница загружена и восстановлены сохранённые отметки чекбоксов +- **THEN** счётчик показывает количество восстановленных отметок diff --git a/web/templates/candidates.html b/web/templates/candidates.html index b7f8f70..11e0be3 100644 --- a/web/templates/candidates.html +++ b/web/templates/candidates.html @@ -196,14 +196,39 @@ {% block scripts %} diff --git a/web/templates/selected.html b/web/templates/selected.html index 2b190dd..3756bbf 100644 --- a/web/templates/selected.html +++ b/web/templates/selected.html @@ -131,9 +131,15 @@
{% if selected.status != 'published' %} - + {{ hid }} - + + {% endif %} {% if selected.status != 'published' %} @@ -221,14 +227,39 @@ {% block scripts %}