AURORA-1837: статичные стили ячеек в CSS, overscan #230

Open
aep wants to merge 2 commits from feat/226-aurora-1837-cell-styles-css into feat/211-aurora-1836-row-measure
Owner

Closes #226

Jira: AURORA-1837. Стек: база — feat/211-aurora-1836-row-measure (PR #222), не test.

Что сделано

  • tableConfig.js: getTableHeadCellStyles/getTableBodyCellProps заменены константой TABLE_CONTAINER_SX: tbody td (рамка, шрифт, высота из TABLE_ROW_HEIGHT в rem, как в 1836), td[data-pinned="true"] (zIndex 5), tr[data-selected="true"] > td::after (затемнение выбранной строки). Невалидное whiteSpace: 'auto' удалено.
  • RealtimeTable.jsx: muiTableBodyCellProps -> только data-col-id; muiTableBodyRowProps -> onClick, data-row-id (+ статичные hover:false и style.height, см. R-1); sx контейнера = TABLE_CONTAINER_SX + getActiveCellSx(activeSearchMatch).
  • utils/activeCellCss.js: чистая функция селектора подсветки текущего совпадения поиска (CSS.escape, в node — эквивалентный fallback).
  • Overscan: строки листа 5 -> 2 (через хелпер 1836), колонки columnLayoutUtils.js 10 -> 3.
  • Скрытый заголовок MRT (visibility:hidden, рендерит ячейки заголовка на каждый коммит) не тронут — отмечено, при заметной доле в профиле вынести отдельно.

Тесты

  • Новый activeCellCss.test.js (экранирование 0.3.2, ITEM:123, null/неполное -> {}, инжект escape); columnLayoutUtils.test.js — проверка overscan === 3.
  • node --test src/components/RealtimeTable/utils/*.test.js: 19 pass, 0 fail. npm run build проходит. Biome по новым файлам чист (в изменённых старых файлах остаются прежние замечания форматирования).

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

  • верх-лево и середина листа выглядят как до правки
  • закреплённая колонка поверх прокрученных (z-index)
  • выделенная строка (затемнение)
  • текущее совпадение поиска: рамка 3 px, Enter / Shift+Enter переходят по совпадениям
  • невалидная ячейка
  • ячейка, заблокированная соавтором
  • быстрый горизонтальный скролл: нет пустых колонок дольше кадра
  • масштаб 0.8 и 1.5

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

Будет добавлен после ночного прогона на стенде perf/: FORM_2/AHR, PERF_AXES=y,x (скролл по y и x), цель <= 50 мс.

Rulings I made

  • R-1: в muiTableBodyRowProps оставлены статичные hover:false и style:{height} (не sx), чтобы не менять вид hover и высоту строки из 1836. Цена ошибки: низкая (две статичные пропсы).
  • R-2: для CSS.escape в node-тестах написан fallback по алгоритму CSSOM; в браузере используется нативный. Цена: расхождение только в тестовой среде.

🤖 Generated with Claude Code

Closes #226 Jira: AURORA-1837. Стек: база — `feat/211-aurora-1836-row-measure` (PR #222), не `test`. ## Что сделано - `tableConfig.js`: `getTableHeadCellStyles`/`getTableBodyCellProps` заменены константой `TABLE_CONTAINER_SX`: `tbody td` (рамка, шрифт, высота из `TABLE_ROW_HEIGHT` в rem, как в 1836), `td[data-pinned="true"]` (zIndex 5), `tr[data-selected="true"] > td::after` (затемнение выбранной строки). Невалидное `whiteSpace: 'auto'` удалено. - `RealtimeTable.jsx`: `muiTableBodyCellProps` -> только `data-col-id`; `muiTableBodyRowProps` -> `onClick`, `data-row-id` (+ статичные `hover:false` и `style.height`, см. R-1); `sx` контейнера = `TABLE_CONTAINER_SX` + `getActiveCellSx(activeSearchMatch)`. - `utils/activeCellCss.js`: чистая функция селектора подсветки текущего совпадения поиска (CSS.escape, в node — эквивалентный fallback). - Overscan: строки листа 5 -> 2 (через хелпер 1836), колонки `columnLayoutUtils.js` 10 -> 3. - Скрытый заголовок MRT (`visibility:hidden`, рендерит ячейки заголовка на каждый коммит) не тронут — отмечено, при заметной доле в профиле вынести отдельно. ## Тесты - Новый `activeCellCss.test.js` (экранирование `0.3.2`, `ITEM:123`, null/неполное -> `{}`, инжект escape); `columnLayoutUtils.test.js` — проверка overscan === 3. - `node --test src/components/RealtimeTable/utils/*.test.js`: 19 pass, 0 fail. `npm run build` проходит. Biome по новым файлам чист (в изменённых старых файлах остаются прежние замечания форматирования). ## Проверить руками - [ ] верх-лево и середина листа выглядят как до правки - [ ] закреплённая колонка поверх прокрученных (z-index) - [ ] выделенная строка (затемнение) - [ ] текущее совпадение поиска: рамка 3 px, Enter / Shift+Enter переходят по совпадениям - [ ] невалидная ячейка - [ ] ячейка, заблокированная соавтором - [ ] быстрый горизонтальный скролл: нет пустых колонок дольше кадра - [ ] масштаб 0.8 и 1.5 ## Замер до/после Будет добавлен после ночного прогона на стенде perf/: FORM_2/AHR, `PERF_AXES=y,x` (скролл по y и x), цель <= 50 мс. ## Rulings I made - R-1: в `muiTableBodyRowProps` оставлены статичные `hover:false` и `style:{height}` (не sx), чтобы не менять вид hover и высоту строки из 1836. Цена ошибки: низкая (две статичные пропсы). - R-2: для `CSS.escape` в node-тестах написан fallback по алгоритму CSSOM; в браузере используется нативный. Цена: расхождение только в тестовой среде. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 2 commits 2026-10-28 17:15:24 +03:00
Author
Owner

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

Сборки: test 2a28748; «до» по стеку — 1836 12a315b; «после» — этот PR f7e553a (= 1836 + 1837). API и БД одни.
Команда: PERF_TARGETS='FORM_2/AHR/*' PERF_ROLES=rf PERF_AXES=y,x PERF_REPEATS=3 PERF_TRACE=0 npx playwright test scenarios/scroll.spec.ts.

FORM_2/AHR, main_thread_ms_per_step test 1836 1837 (этот PR)
ось y 89.1 78.7 46.4 [45.5–47.2]
ось x 79.5 — 41.9 [41.8–42.1]
frame_p95_ms y / heavy_frame_n y 66.7 / 222 50.0 / 42 33.3 / 0

Вердикт по критерию «FORM_2/AHR ≤ 50 мс» — выполнен (46.4; −48 % от test, −41 % от 1836). Ось x не хуже базы — выполнено (−47 %).
Дополнительно (сценарий из #240, первый реальный прогон): pinned-resize.spec.ts на этой сборке — 3 из 3 без skip_reason (закреплённые колонки примыкают), main_thread_ms_per_step 47.2.

Скриншоты листа 1600×900 (y0/y1/y2 и x0/x1/x2): до — night/base/shots/base-sheet-1600-*.png, после — night/1837/shots/p1837-sheet-1600-*.png; каталог /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/. Попиксельная сверка — в итоговом комментарии.

🤖 Generated with Claude Code

## Ночной замер на стенде perf/ (29.10, масштаб 1, D0 без grow, CPU 1x, arm-ka-* остановлены; Apple M4) **Сборки:** `test` 2a28748; «до» по стеку — 1836 12a315b; «после» — этот PR f7e553a (= 1836 + 1837). API и БД одни. **Команда:** `PERF_TARGETS='FORM_2/AHR/*' PERF_ROLES=rf PERF_AXES=y,x PERF_REPEATS=3 PERF_TRACE=0 npx playwright test scenarios/scroll.spec.ts`. | FORM_2/AHR, main_thread_ms_per_step | test | 1836 | 1837 (этот PR) | |---|---|---|---| | ось y | 89.1 | 78.7 | **46.4** [45.5–47.2] | | ось x | 79.5 | — | **41.9** [41.8–42.1] | | frame_p95_ms y / heavy_frame_n y | 66.7 / 222 | 50.0 / 42 | 33.3 / 0 | **Вердикт по критерию** «FORM_2/AHR ≤ 50 мс» — **выполнен** (46.4; −48 % от `test`, −41 % от 1836). Ось x не хуже базы — выполнено (−47 %). Дополнительно (сценарий из #240, первый реальный прогон): `pinned-resize.spec.ts` на этой сборке — 3 из 3 без `skip_reason` (закреплённые колонки примыкают), main_thread_ms_per_step 47.2. Скриншоты листа 1600×900 (y0/y1/y2 и x0/x1/x2): до — `night/base/shots/base-sheet-1600-*.png`, после — `night/1837/shots/p1837-sheet-1600-*.png`; каталог `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/`. Попиксельная сверка — в итоговом комментарии. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Ночной замер — часть 2 (итог)

Сборки как в части 1 (до — 1836 12a315b, после — f7e553a; справочно test). Добавлено: сверка скриншотов и combo.

combo: лист FORM_2/AHR y 46.0 (1837 отдельно 46.4), x 42.6 (41.9; +1,7 %, внутри разброса); соавтор rate 5 в combo 50.2 (1837 52.6).

Сверка скриншотов листа 1600×900 (base против p1837), 7 позиций:

позиция %
top, y0 3,1 подпиксельный сдвиг строк, как у 1836
y1, y2 12,2; 2,5 то же
x0 3,1 то же
x1 20,2 другая горизонтальная позиция
x2 4,5 то же
На x1 в base видны колонки 158–162, у 1837 — 161–164 (сдвиг на ~3 колонки, ширины колонок прежние — 420 px); стили ячеек (фон, шрифты) совпадают. Позиции x1/x2 в сценарии — доля scrollWidth − clientWidth, значит scrollWidth у 1837 отличается от base; причина (ширины колонок, overscan, оценка ширины) не выяснена. Для 1836 те же позиции дают 2,7 %, т.е. сдвиг пришёл с 1837. Проверить: меняется ли реальная длина горизонтального скролла листа. Сравнить: /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/base/shots/base-sheet-1600-x1.png и /private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1837/shots/p1837-sheet-1600-x1.png.

Вердикт без изменений: FORM_2/AHR ≤ 50 — выполнен (46.4).

## Ночной замер — часть 2 (итог) Сборки как в части 1 (до — 1836 12a315b, после — f7e553a; справочно `test`). Добавлено: сверка скриншотов и combo. **combo:** лист FORM_2/AHR y 46.0 (1837 отдельно 46.4), x 42.6 (41.9; +1,7 %, внутри разброса); соавтор rate 5 в combo 50.2 (1837 52.6). **Сверка скриншотов листа 1600×900 (base против p1837)**, 7 позиций: | позиция | % | | |---|---|---| | top, y0 | 3,1 | подпиксельный сдвиг строк, как у 1836 | | y1, y2 | 12,2; 2,5 | то же | | x0 | 3,1 | то же | | **x1** | **20,2** | **другая горизонтальная позиция** | | **x2** | **4,5** | то же | На x1 в base видны колонки 158–162, у 1837 — 161–164 (сдвиг на ~3 колонки, ширины колонок прежние — 420 px); стили ячеек (фон, шрифты) совпадают. Позиции x1/x2 в сценарии — доля `scrollWidth − clientWidth`, значит `scrollWidth` у 1837 отличается от base; причина (ширины колонок, overscan, оценка ширины) не выяснена. Для 1836 те же позиции дают 2,7 %, т.е. сдвиг пришёл с 1837. Проверить: меняется ли реальная длина горизонтального скролла листа. Сравнить: `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/base/shots/base-sheet-1600-x1.png` и `/private/tmp/claude-501/-Users-andrey-epifancev-projects-fomichev-claude/6fa9c75e-eb11-4e5d-98c1-05eb590ab14f/scratchpad/night/1837/shots/p1837-sheet-1600-x1.png`. **Вердикт без изменений:** FORM_2/AHR ≤ 50 — **выполнен** (46.4).
Author
Owner

Разбор ночной находки: «сдвиг» колонок на x1/x2 — не дефект

Ночной скрипт ставил scrollLeft = (scrollWidth − clientWidth) × доля, читая scrollWidth сразу после загрузки. Сразу после загрузки scrollWidth временно завышен (в test 68 050 при фактической ширине 35 590, до первой горизонтальной прокрутки) и зависит от overscan виртуализатора колонок; 1837 уменьшил overscan 10→3 → 69 100. Отсюда разные позиции кадров.
Проверка: на одинаковых абсолютных scrollLeft 6000/12000/20000 в 1836 и 1837 видны одни и те же колонки (42–45, 69–72, 103–106), после прокрутки scrollWidth = 35 590 в обеих сборках.
Временно завышенный scrollWidth до первой прокрутки есть и в test — к этому PR не относится.

## Разбор ночной находки: «сдвиг» колонок на x1/x2 — не дефект Ночной скрипт ставил `scrollLeft = (scrollWidth − clientWidth) × доля`, читая scrollWidth сразу после загрузки. Сразу после загрузки scrollWidth временно завышен (в test 68 050 при фактической ширине 35 590, до первой горизонтальной прокрутки) и зависит от overscan виртуализатора колонок; 1837 уменьшил overscan 10→3 → 69 100. Отсюда разные позиции кадров. Проверка: на одинаковых абсолютных scrollLeft 6000/12000/20000 в 1836 и 1837 видны одни и те же колонки (42–45, 69–72, 103–106), после прокрутки scrollWidth = 35 590 в обеих сборках. Временно завышенный scrollWidth до первой прокрутки есть и в test — к этому PR не относится.
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/226-aurora-1837-cell-styles-css:feat/226-aurora-1837-cell-styles-css
git checkout feat/226-aurora-1837-cell-styles-css
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#230
No description provided.