AURORA-1840: состояние модалок листа вынесено из RealtimeTable #218

Open
aep wants to merge 2 commits from feat/213-aurora-1840-sheet-modals into test
Owner

Closes #213

Jira: AURORA-1840

Что сделано

  • Новый компонент Modals/SheetModals.jsx (React.memo + forwardRef + useImperativeHandle): внутри состояние и три модалки (ВСП, статья расходов, программа/проект), наружу open('vsp' | 'expense' | 'program' | 'project'). Пропсы только стабильные: formId, sheetName, onAddVsp, onAddExpenseItem, onAddProgram, onAddProject (handleAdd*Row уже в useCallback, table стабильный).
  • RealtimeTable: убраны три useState модалок, три close-колбэка и JSX модалок; проверки выделенной строки остаются в таблице, затем modalsRef.current?.open(...).
  • Чистый редьюсер utils/sheetModalsState.js (open/close, заголовок и обработчик для программы/проекта).
  • Отдельным коммитом: onSearchNext/onSearchPrevious для SettingsPanel обёрнуты в useCallback (были стрелками и ломали memo).

Тесты

  • sheetModalsState.test.js (4 теста), node --test по utils: зелёные. npm run build проходит. Biome: новые файлы чистые; в RealtimeTable.jsx остались исходные замечания (2 ошибки, предупреждения), не связанные с правкой.
  • Бэк не менялся.

Проверить руками

  • FORM_2 AHR_RENT / AHR_UTILITY / AHR_SECURITY: кнопка добавления открывает выбор ВСП, выбор добавляет строку
  • FORM_4 AHR/CAP/OPER: выбор статьи расходов добавляет строку под проектом
  • FORM_4: создание программы и создание проекта (при выделенной программе) добавляют строки; заголовки модалок верные
  • Без выделенной строки / не на той строке: тосты «Выделите строку…», «Выделите строку проекта/программы», модалка не открывается
  • Esc и клик по фону закрывают модалку, повторное открытие работает

Замер до/после

Будет добавлен после ночного прогона на стенде perf/. Сценарий: modals.spec.ts с PERF_MODALS='sheet_select_vsp,sheet_select_expense,sheet_create_program,sheet_create_project' PERF_REPEATS=5 (было 74-93 мс, критерий ≤ 40 мс); затем профилирующая сборка PERF_WEB=http://localhost:8081 PERF_PROFILING=1 PERF_MODALS='sheet_*': в renders_top не должно быть Styled(td) и MRT_TableBodyCell.

Rulings I made

  • R-1: стрелочные пропсы SettingsPanel поправлены только для поиска (onSearchNext/Previous), отдельным коммитом. Обоснование: тривиально и разрешено. Цена ошибки: нулевая, откат одного коммита.
  • R-2: невалидный kind в open() игнорируется редьюсером. Цена ошибки: модалка не откроется при опечатке.

🤖 Generated with Claude Code

Closes #213 Jira: AURORA-1840 ## Что сделано - Новый компонент `Modals/SheetModals.jsx` (`React.memo` + `forwardRef` + `useImperativeHandle`): внутри состояние и три модалки (ВСП, статья расходов, программа/проект), наружу `open('vsp' | 'expense' | 'program' | 'project')`. Пропсы только стабильные: `formId`, `sheetName`, `onAddVsp`, `onAddExpenseItem`, `onAddProgram`, `onAddProject` (`handleAdd*Row` уже в `useCallback`, `table` стабильный). - `RealtimeTable`: убраны три useState модалок, три close-колбэка и JSX модалок; проверки выделенной строки остаются в таблице, затем `modalsRef.current?.open(...)`. - Чистый редьюсер `utils/sheetModalsState.js` (open/close, заголовок и обработчик для программы/проекта). - Отдельным коммитом: `onSearchNext`/`onSearchPrevious` для SettingsPanel обёрнуты в `useCallback` (были стрелками и ломали memo). ## Тесты - `sheetModalsState.test.js` (4 теста), `node --test` по utils: зелёные. `npm run build` проходит. Biome: новые файлы чистые; в RealtimeTable.jsx остались исходные замечания (2 ошибки, предупреждения), не связанные с правкой. - Бэк не менялся. ## Проверить руками - [ ] FORM_2 AHR_RENT / AHR_UTILITY / AHR_SECURITY: кнопка добавления открывает выбор ВСП, выбор добавляет строку - [ ] FORM_4 AHR/CAP/OPER: выбор статьи расходов добавляет строку под проектом - [ ] FORM_4: создание программы и создание проекта (при выделенной программе) добавляют строки; заголовки модалок верные - [ ] Без выделенной строки / не на той строке: тосты «Выделите строку…», «Выделите строку проекта/программы», модалка не открывается - [ ] Esc и клик по фону закрывают модалку, повторное открытие работает ## Замер до/после Будет добавлен после ночного прогона на стенде perf/. Сценарий: `modals.spec.ts` с `PERF_MODALS='sheet_select_vsp,sheet_select_expense,sheet_create_program,sheet_create_project' PERF_REPEATS=5` (было 74-93 мс, критерий ≤ 40 мс); затем профилирующая сборка `PERF_WEB=http://localhost:8081 PERF_PROFILING=1 PERF_MODALS='sheet_*'`: в `renders_top` не должно быть `Styled(td)` и `MRT_TableBodyCell`. ## Rulings I made - R-1: стрелочные пропсы SettingsPanel поправлены только для поиска (`onSearchNext/Previous`), отдельным коммитом. Обоснование: тривиально и разрешено. Цена ошибки: нулевая, откат одного коммита. - R-2: невалидный `kind` в `open()` игнорируется редьюсером. Цена ошибки: модалка не откроется при опечатке. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 2 commits 2026-10-28 17:09:45 +03:00
Открытие модалки больше не перерисовывает RealtimeTable: состояние живёт
в memo-компоненте SheetModals, наружу открывается через ref.open(kind).
Проверки выделенной строки остаются в таблице. Редьюсер вынесен в
utils/sheetModalsState.js с node-тестом.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
onSearchNext/onSearchPrevious были стрелками в JSX и ломали memo панели.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

Ночной замер на стенде perf/ (29.10, масштаб 1, D0 без grow, CPU 1x, arm-ka-* остановлены; Apple M4)

Сборки: «до» — test 2a28748; «после» — этот PR 365becc (от test, без 1839). Данные и API одни.
Команда: PERF_MODALS='sheet_select_vsp,sheet_select_expense,sheet_create_program,sheet_create_project,sheet_columns_tree' PERF_PRIORITY=1 PERF_REPEATS=5 npx playwright test scenarios/modals.spec.ts; рендеры — профилирующая сборка :8081, PERF_PROFILING=1 PERF_REPEATS=1 (modal_renders, hotspots_summary.py --renders-only).

модалка (rf, лист FORM_2/FORM_4), медиана 5 click_to_visible до → после, мс main_thread до → после, мс рендеров за открытие до → после Styled(td)/MRT_TableBodyCell в renders_top
sheet_select_vsp 73.6 → 41.1 78.1 → 44.6 6 684 → 239 473 → нет
sheet_select_expense 80.6 → 44.6 88.6 → 48.5 6 841 → 301 539 → нет
sheet_create_program 76.2 → 42.1 82.1 → 46.6 6 670 → 130 539 → нет
sheet_create_project 77.1 → 46.0 82.3 → 52.9 6 670 → 130 539 → нет
sheet_columns_tree (справочно, не трогалась) 65.3 → 65.2 67.6 → 68.0 940 → 940 —

Вердикт по критерию «≤ 40 мс от клика до кадра; ячейки не перерисовываются»:

  • ячейки не перерисовываются — выполнен (в renders_top открытия нет Styled(td) и MRT_TableBodyCell; рендеров за открытие в 22–51 раз меньше);
  • ≤ 40 мс — не выполнен по абсолютному порогу: 41.1–46.0 мс (−44…−45 % от базы; относительный ориентир design −50 %). Остаток — сама модалка MUI (Dialog/Autocomplete/Transition: у sheet_select_expense 14,6 мс из 18,5 мс self React — Autocomplete).

Файлы: /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/{base,1840}/mprof/ (modal-renders.md), прогоны perf/report-data/n-base-modals, n-p1840-modals в worktree perf-bench.

🤖 Generated with Claude Code

## Ночной замер на стенде perf/ (29.10, масштаб 1, D0 без grow, CPU 1x, arm-ka-* остановлены; Apple M4) **Сборки:** «до» — `test` 2a28748; «после» — этот PR 365becc (от `test`, без 1839). Данные и API одни. **Команда:** `PERF_MODALS='sheet_select_vsp,sheet_select_expense,sheet_create_program,sheet_create_project,sheet_columns_tree' PERF_PRIORITY=1 PERF_REPEATS=5 npx playwright test scenarios/modals.spec.ts`; рендеры — профилирующая сборка :8081, `PERF_PROFILING=1 PERF_REPEATS=1` (`modal_renders`, `hotspots_summary.py --renders-only`). | модалка (rf, лист FORM_2/FORM_4), медиана 5 | click_to_visible до → после, мс | main_thread до → после, мс | рендеров за открытие до → после | Styled(td)/MRT_TableBodyCell в renders_top | |---|---|---|---|---| | sheet_select_vsp | 73.6 → **41.1** | 78.1 → 44.6 | 6 684 → 239 | 473 → нет | | sheet_select_expense | 80.6 → **44.6** | 88.6 → 48.5 | 6 841 → 301 | 539 → нет | | sheet_create_program | 76.2 → **42.1** | 82.1 → 46.6 | 6 670 → 130 | 539 → нет | | sheet_create_project | 77.1 → **46.0** | 82.3 → 52.9 | 6 670 → 130 | 539 → нет | | sheet_columns_tree (справочно, не трогалась) | 65.3 → 65.2 | 67.6 → 68.0 | 940 → 940 | — | **Вердикт по критерию** «≤ 40 мс от клика до кадра; ячейки не перерисовываются»: - ячейки не перерисовываются — **выполнен** (в `renders_top` открытия нет `Styled(td)` и `MRT_TableBodyCell`; рендеров за открытие в 22–51 раз меньше); - ≤ 40 мс — **не выполнен по абсолютному порогу**: 41.1–46.0 мс (−44…−45 % от базы; относительный ориентир design −50 %). Остаток — сама модалка MUI (Dialog/Autocomplete/Transition: у `sheet_select_expense` 14,6 мс из 18,5 мс self React — `Autocomplete`). Файлы: `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/{base,1840}/mprof/` (modal-renders.md), прогоны `perf/report-data/n-base-modals`, `n-p1840-modals` в worktree perf-bench. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/213-aurora-1840-sheet-modals:feat/213-aurora-1840-sheet-modals
git checkout feat/213-aurora-1840-sheet-modals
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#218
No description provided.