Andrey Epifancev 8558670b46 feat(table): редактирование одним кликом и с клавиатуры, без лишних записей в аудит (AURORA-1891)
- processColumns (tableColumns.jsx): enableEditing для каждой листовой колонки
  через isCellEditable (PR #281), а не только для vsp_dropdown — MRT больше не
  открывает редактор (даже disabled) на нередактируемой ячейке, сервер не берёт
  блокировку, коллеги не видят 🔒.
- Одиночный клик по редактируемой, не заблокированной ячейке открывает
  редактор (muiTableBodyCellProps.onClick, RealtimeTable.jsx); клик по
  нередактируемой/занятой ячейке, как раньше, выделяет строку. Удалён мёртвый
  onClick/handleClick из Cell.jsx.
- Клавиатура на выделенной ячейке: Enter/F2 — открыть редактор; Delete/Backspace
  — открыть с пустым значением; печатный символ — открыть и подставить его
  вместо текущего значения (хранится в state RealtimeTable, читается через
  table.options.meta.getEditorInitialInput).
- EditCell.jsx/VspDropdownEditCell.jsx: Esc — отмена без cell_updated; Tab/
  Shift+Tab и Enter — сохранить и перейти к следующей/предыдущей редактируемой
  ячейке через table.options.meta.openNextEditableCell → utils/cellNavigation.js
  (чистые findNextEditableColumnId/findNextEditableRowId по
  getOrderedVisibleColumns и table.getRowModel().flatRows).
- utils/formulaUtils.js: isSameCellValue — handleSave не шлёт cell_updated,
  если значение не изменилось (число/строка, «1 500,0», пусто/null); формула
  всегда считается изменённой.
- Фокус: setTimeout(50) → requestAnimationFrame; после закрытия редактора
  фокус возвращается в <td> ячейки.

Тесты: utils/cellNavigation.test.js, utils/formulaUtils.test.js (новые,
15 тестов). node --test src/components/RealtimeTable/utils/*.test.js:
85 тестов, 84 passed, 1 известный pre-existing fail (columnLayoutUtils.test.js,
нет node_modules в этом worktree, см. PR #281/#283).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-11-01 16:14:02 +04:00

47 lines
2.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* AURORA-1891: Tab/Shift+Tab и Enter в EditCell.jsx/VspDropdownEditCell.jsx
* вызывают table.options.meta.openNextEditableCell(row, column, direction)
* (RealtimeTable.jsx), который резолвит реальные MRT-строки/колонки
* (getOrderedVisibleColumns, table.getRowModel().flatRows — не .rows, см.
* рулинг AURORA-1893 про expandRows()/paginateExpandedRows: .rows уже
* отфильтрован состоянием свёрнутости групп, и строка в свёрнутой группе
* там попросту не нашлась бы) и предикат isCellEditable, а эти две функции
* делают только сам обход уже готового списка — без знания про MRT.
*/
/**
* Следующая (step: 1, Tab) или предыдущая (step: -1, Shift+Tab) редактируемая
* колонка в той же строке. columns — видимые листовые колонки в порядке
* getOrderedVisibleColumns (скрытые туда не попадают — для этой функции они
* просто не существуют). isEditable(column) — редактируема ли эта колонка
* ИМЕННО в текущей строке (вызывающая сторона уже знает строку).
* Возвращает id следующей редактируемой колонки или null, если дошли до края.
*/
export const findNextEditableColumnId = ({ columns, currentColumnId, step, isEditable }) => {
const startIndex = columns.findIndex((column) => column.id === currentColumnId);
if (startIndex < 0) return null;
for (let index = startIndex + step; index >= 0 && index < columns.length; index += step) {
if (isEditable(columns[index])) return columns[index].id;
}
return null;
};
/**
* Следующая (step: 1, Enter) или предыдущая (step: -1) строка, где заданная
* колонка редактируема. rows — table.getRowModel().flatRows (весь порядок
* строк независимо от текущего состояния свёрнутости групп). isEditable(row)
* — редактируема ли заданная колонка в этой строке (пропускает итоговые
* строки ROOT/GROUP/ITEM, у которых row_type !== 'INPUT').
* Возвращает id следующей строки или null, если дошли до края таблицы.
*/
export const findNextEditableRowId = ({ rows, currentRowId, step, isEditable }) => {
const startIndex = rows.findIndex((row) => row.id === currentRowId);
if (startIndex < 0) return null;
for (let index = startIndex + step; index >= 0 && index < rows.length; index += step) {
if (isEditable(rows[index])) return rows[index].id;
}
return null;
};