Sync новых требований в openspec/specs/: web-ui («Действия обновляют интерфейс на месте») и review («Петлевые действия ревью обновляют экран на месте»). Change перемещён в changes/archive/2026-07-04-htmx-action-swap. Конвенция web-ui.md актуализирована: сняты маркеры «будем» по реализованному. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72 lines
6.1 KiB
Markdown
72 lines
6.1 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Действия обновляют интерфейс на месте
|
|
|
|
Мутирующие действия над загрузкой в списке (`/`) и на странице `/download/{id}` SHALL выполняться htmx-запросом и обновлять затронутую область HTML на месте (partial swap), без навигации на другую страницу и без сброса контекста списка (фильтр, поиск, страница пагинации, позиция прокрутки).
|
|
Сервер SHALL отвечать на такой запрос HTML-фрагментом обновлённой области, а не
|
|
редиректом.
|
|
|
|
Область свопа SHALL соответствовать поверхности действия: в списке — карточка
|
|
загрузки (`<article class="card">`) целиком, отражающая новое состояние, бейдж
|
|
и допустимый набор действий; на странице `/download/{id}` — содержимое
|
|
страницы, отражающее новое состояние загрузки. После свопа набор показанных
|
|
действий MUST соответствовать новому состоянию (см. «Действия соответствуют
|
|
состоянию»).
|
|
|
|
Поведение MUST деградировать без htmx: если запрос действия пришёл без признака
|
|
htmx (нет заголовка `HX-Request`), обработчик SHALL отвечать прежним
|
|
PRG-редиректом, и действие исполняется тем же доменным вызовом. Формы действий
|
|
остаются обычными POST-формами.
|
|
|
|
Ошибка действия (доменная или валидации) SHALL показываться на месте — в
|
|
подменённом фрагменте той же области, — а не только через параметр `?err=`
|
|
после редиректа; при ошибке активное состояние загрузки не меняется молча.
|
|
Ответ на htmx-запрос действия SHALL иметь статус `200` даже при ошибке действия
|
|
(иначе htmx не подменит фрагмент): сообщение об ошибке несёт сам фрагмент.
|
|
|
|
После свопа карточка SHALL оставаться на своём месте в списке, даже если её
|
|
новое состояние уже не подходит под активный фильтр; согласованность списка с
|
|
фильтром восстанавливается при следующей полной загрузке. Клиентского
|
|
переупорядочивания или пересчёта доменного состояния не выполняется.
|
|
|
|
#### Scenario: Откат из карточки списка обновляет карточку на месте
|
|
|
|
- **GIVEN** в списке есть загрузка в состоянии `done` с действием отката
|
|
- **WHEN** пользователь нажимает «Откатить» (htmx активен)
|
|
- **THEN** карточка этой загрузки подменяется на месте на её новое состояние
|
|
(`reverted`) с соответствующим бейджем и набором действий
|
|
- **AND** список не перезагружается: фильтр, поиск, страница и позиция прокрутки
|
|
сохраняются
|
|
|
|
#### Scenario: Действие со страницы загрузки оставляет на странице
|
|
|
|
- **GIVEN** открыта страница `GET /download/{id}` загрузки в состоянии `done`
|
|
- **WHEN** пользователь нажимает «Откатить» или «Привязать заново» (htmx активен)
|
|
- **THEN** содержимое страницы обновляется на месте под новое состояние
|
|
загрузки, без перехода на список и без прыжка прокрутки наверх
|
|
|
|
#### Scenario: Деградация без htmx — прежний редирект
|
|
|
|
- **WHEN** действие над загрузкой приходит POST-запросом без заголовка
|
|
`HX-Request` (htmx недоступен)
|
|
- **THEN** обработчик исполняет то же доменное действие и отвечает
|
|
PRG-редиректом, как раньше; поведение без JavaScript не ломается
|
|
|
|
#### Scenario: Ошибка действия показана на месте
|
|
|
|
- **GIVEN** пользователь запускает действие через htmx
|
|
- **WHEN** доменный вызов возвращает ошибку (например, состояние уже изменилось)
|
|
- **THEN** ответ имеет статус `200`, а сообщение об ошибке показывается в
|
|
подменённом фрагменте той же области, а не только на отдельной странице после
|
|
редиректа
|
|
- **AND** активное состояние загрузки не меняется
|
|
|
|
#### Scenario: Свопнутая карточка остаётся вне фильтра
|
|
|
|
- **GIVEN** список отфильтрован по группе состояний (например, `review`) и в нём
|
|
есть карточка загрузки
|
|
- **WHEN** действие через htmx переводит загрузку в состояние вне этого фильтра
|
|
(например, `cancelled`)
|
|
- **THEN** карточка подменяется на месте новым состоянием и остаётся видимой до
|
|
следующей полной загрузки списка, без клиентского переупорядочивания
|