fix(web): перечитывание файлов гасит индикатор догрузки, OpenSpec files-pagination (AURORA-1816)
Ревью PR #242: перечитывание (опрос, удаление, загрузка, подтверждение) во время догрузки отбрасывало её ответ, а loadingMore оставался true — спиннер под списком и в переключателе документа не гас. Теперь перечитывание сразу сбрасывает флаг догрузки. useScrollSentinel: biome-ignore для trigger с причиной (переподписка после новой порции файлов). OpenSpec files-pagination: «Догрузка списка файлов» (primary-files-ui), опрос перечитывает все показанные страницы, переключатель документа догружает список при прокрутке (document-review-ui). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ca19d654da
commit
3cc7b82969
36
openspec/changes/files-pagination/proposal.md
Normal file
36
openspec/changes/files-pagination/proposal.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Proposal
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
AURORA-1816 (PR arm-core #242). Панель «Первичные документы» запрашивала файлы ЮЛ с `limit=100` и не догружала
|
||||||
|
остальные: в режиме «Все документы организации» у ЮЛ с сотней файлов и больше лишние не видны ни в панели, ни в
|
||||||
|
переключателе документа на экране проверки, и пользователь не знает, что список неполный. Сервер пагинацию уже
|
||||||
|
поддерживает (`total`, `offset`, `limit` до 200).
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- Панель «Первичные документы»: над списком «Всего N файлов» (`total` ответа); файлы страницами по 200, следующая —
|
||||||
|
при прокрутке до конца списка.
|
||||||
|
- Опрос раз в 5 секунд и перечитывание после удаления, загрузки и подтверждения перечитывают все показанные страницы,
|
||||||
|
список не сворачивается к первой.
|
||||||
|
- Переключатель «Документ» на экране проверки берёт тот же список: догрузка при прокрутке выпадающего списка, открытый
|
||||||
|
документ есть в списке, даже если он дальше загруженных страниц.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
- `primary-files-ui` — новое требование «Догрузка списка файлов»; «Опрос до окончания распознавания» перечитывает все
|
||||||
|
показанные страницы.
|
||||||
|
- `document-review-ui` — «Переключатель документа»: догрузка и открытый документ в списке.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
Только фронт arm-core: `web/src/hooks/useLegalEntityFiles.ts` (перенесён из `widgets/FilesDrawer/`),
|
||||||
|
`web/src/hooks/useScrollSentinel.ts`, `web/src/services/api/files.ts`, `web/src/widgets/FilesDrawer/*`,
|
||||||
|
`web/src/layouts/DocumentPage.tsx`. API, DBML, правила `05-domain-rules.md` не меняются.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Кнопка «Показать ещё» — выбрана подгрузка при прокрутке (задача допускала оба варианта).
|
||||||
|
- Серверный поиск и фильтры по файлам.
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Переключатель документа
|
||||||
|
В шапке экрана документа SHALL быть выпадающий список «Документ» с документами файлов того же ЮЛ в той же консолидации,
|
||||||
|
что и файл открытого документа (файл вне консолидации — все файлы ЮЛ): у пункта имя файла, вторая строка (тип · формат ·
|
||||||
|
дата) и статус; пункты, которые нельзя открыть, неактивны. Список читается теми же страницами, что панель «Первичные документы»
|
||||||
|
(требование «Догрузка списка файлов» `primary-files-ui`): следующая — при прокрутке выпадающего списка до конца;
|
||||||
|
открытый документ SHALL быть в списке и показываться по имени, даже если его файл дальше загруженных страниц. Выбор пункта SHALL открывать `/documents/:document_id`
|
||||||
|
выбранного документа заменой текущей записи истории браузера, без новой записи: кнопка «Назад» экрана и браузера
|
||||||
|
возвращает на экран, с которого открыт первый документ, а не к предыдущему выбранному. Если первый документ открыт из
|
||||||
|
панели «Первичные документы» консолидации, «Назад» SHALL открывать экран консолидации с этой панелью той же организации.
|
||||||
|
|
||||||
|
#### Scenario: Назад после перебора документов
|
||||||
|
- **WHEN** аналитик открыл документ из панели «Первичные документы» организации в карточке консолидации, выбрал в списке
|
||||||
|
«Документ» подряд ещё два документа и нажал «Назад»
|
||||||
|
- **THEN** открыт экран консолидации с той же выбранной версией и открытой панелью «Первичные документы» той же
|
||||||
|
организации
|
||||||
|
|
||||||
|
#### Scenario: Документ открыт прямой ссылкой
|
||||||
|
- **WHEN** документ открыт прямой ссылкой в новой вкладке, аналитик выбрал в списке «Документ» другой документ и нажал
|
||||||
|
«Назад» экрана
|
||||||
|
- **THEN** открыт список групп компаний `/groups`
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Догрузка списка файлов
|
||||||
|
Панель SHALL читать список файлов активного режима (стол или все документы) страницами по 200 (`limit=200&offset=…`,
|
||||||
|
`MAX_PAGE_LIMIT` бэка): первую — при открытии, следующую — когда аналитик прокрутил список до конца, пока показано
|
||||||
|
меньше `total`. Над списком SHALL стоять «Всего N файлов» с `total` ответа. Опрос, удаление, загрузка и подтверждение
|
||||||
|
документа SHALL перечитывать все показанные файлы (столько страниц, сколько было показано), а не только первую.
|
||||||
|
Перечитывание отменяет идущую догрузку: её ответ не применяется, индикатор догрузки гаснет.
|
||||||
|
|
||||||
|
#### Scenario: 450 файлов в режиме «все»
|
||||||
|
- **WHEN** у ЮЛ 450 файлов, панель открыта в режиме «Все документы организации»
|
||||||
|
- **THEN** над списком «Всего 450 файлов», показаны первые 200; прокрутка до конца догружает 201–400, ещё одна —
|
||||||
|
401–450, дальше запросов нет
|
||||||
|
|
||||||
|
#### Scenario: Опрос не сворачивает список
|
||||||
|
- **WHEN** показаны 400 файлов и среди них есть файл в `PROCESSING`
|
||||||
|
- **THEN** раз в 5 секунд перечитываются обе показанные страницы, после ответа в списке по-прежнему 400 файлов
|
||||||
|
|
||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Опрос до окончания распознавания
|
||||||
|
Пока панель открыта и среди файлов активного списка (стол или все документы) есть `UPLOADED` или `PROCESSING`, панель
|
||||||
|
SHALL перечитывать этот список раз в 5 секунд — все показанные страницы, не сворачивая список к первой (требование «Догрузка списка файлов»), и SHALL прекратить опрос, когда таких файлов нет или панель закрыта.
|
||||||
|
Переключение режима или смена ЮЛ SHALL сбрасывать список и перечитывать его. При закрытии панели карточка версии SHALL
|
||||||
|
перечитываться (обновить ячейки чек-листа).
|
||||||
|
|
||||||
|
#### Scenario: Опрос останавливается
|
||||||
|
- **WHEN** все файлы активного списка перешли в `PROCESSED` или `ERROR`
|
||||||
|
- **THEN** запросы списка файлов прекращаются
|
||||||
10
openspec/changes/files-pagination/tasks.md
Normal file
10
openspec/changes/files-pagination/tasks.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Tasks
|
||||||
|
|
||||||
|
- [x] 1.1 arm-core `web/src/services/api/files.test.ts` — несколько страниц: перечитывание показанного, догрузка с
|
||||||
|
позиции, конец по `total`, пустая страница раньше `total`
|
||||||
|
- [x] 1.2 arm-core `web/src/services/api/files.ts` — `listLegalEntityFiles(offset, limit)`, `listLegalEntityFilesFrom`,
|
||||||
|
`FILES_PAGE_LIMIT = 200`
|
||||||
|
- [x] 1.3 arm-core `web/` — хук `useLegalEntityFiles` со страницами, `useScrollSentinel`, «Всего N файлов» в панели,
|
||||||
|
переключатель документа на экране проверки (PR #242, автор)
|
||||||
|
- [x] 1.4 Ревью: перечитывание во время догрузки сбрасывает `loadingMore` (иначе спиннер под списком не гаснет);
|
||||||
|
`biome-ignore` для `trigger` в `useScrollSentinel` с причиной
|
||||||
@ -30,6 +30,8 @@ export function useLegalEntityFiles(legalEntityId: string | null, consolidationI
|
|||||||
const setBusy = append ? setLoadingMore : setLoading;
|
const setBusy = append ? setLoadingMore : setLoading;
|
||||||
const requestId = ++requestRef.current;
|
const requestId = ++requestRef.current;
|
||||||
inFlightRef.current = true;
|
inFlightRef.current = true;
|
||||||
|
// перечитывание отменяет идущую догрузку: её ответ отбросится, а finally не сбросит флаг чужого запроса
|
||||||
|
if (!append) setLoadingMore(false);
|
||||||
setBusy(true);
|
setBusy(true);
|
||||||
try {
|
try {
|
||||||
const { items, total } = await listLegalEntityFilesFrom(legalEntityId, consolidationId, from, count);
|
const { items, total } = await listLegalEntityFilesFrom(legalEntityId, consolidationId, from, count);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export function useScrollSentinel(enabled: boolean, trigger: unknown, onReach: (
|
|||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
const onReachRef = useRef(onReach);
|
const onReachRef = useRef(onReach);
|
||||||
onReachRef.current = onReach;
|
onReachRef.current = onReach;
|
||||||
|
// biome-ignore lint/correctness/useExhaustiveDependencies: trigger — переподписка после новой порции: если метка всё ещё на экране, наблюдатель сразу вызовет onReach
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const node = ref.current;
|
const node = ref.current;
|
||||||
if (!enabled || !node) return;
|
if (!enabled || !node) return;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user