diff --git a/web/src/components/RealtimeTable/Cell/EditCell/EditCell.jsx b/web/src/components/RealtimeTable/Cell/EditCell/EditCell.jsx index 2dd9d03..07788cf 100644 --- a/web/src/components/RealtimeTable/Cell/EditCell/EditCell.jsx +++ b/web/src/components/RealtimeTable/Cell/EditCell/EditCell.jsx @@ -2,7 +2,12 @@ import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat import { toast } from 'react-toastify'; import { nonNegativeColumnKeys } from '../../constants/validation'; import { getColumnRequestKey, useCellFormula, useRealtimeActions } from '../../contexts/RealtimeContext'; -import { FORMULA_NEEDS_EQUALS_MESSAGE, looksLikeExpressionWithoutEquals, resolveInitialEditorText } from '../../utils/cellFormulaUtils'; +import { + FORMULA_NEEDS_EQUALS_MESSAGE, + looksLikeExpressionWithoutEquals, + normalizeFormulaExpression, + resolveInitialEditorText, +} from '../../utils/cellFormulaUtils'; import { calculateFormula, extractFormula, @@ -197,7 +202,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, table, cell }) => { })); warnIfNegativeNotAllowed(formattedResult); // AURORA-1896: уходит значение и выражение без «=» — формулу сохраняет сервер. - onChange?.(formattedResult, { formula: extractFormula(currentValue) }); + onChange?.(formattedResult, { formula: normalizeFormulaExpression(extractFormula(currentValue)) }); return true; } diff --git a/web/src/components/RealtimeTable/utils/cellFormulaUtils.js b/web/src/components/RealtimeTable/utils/cellFormulaUtils.js index a7b7174..26c70f3 100644 --- a/web/src/components/RealtimeTable/utils/cellFormulaUtils.js +++ b/web/src/components/RealtimeTable/utils/cellFormulaUtils.js @@ -108,3 +108,7 @@ export const clearLegacyFormulaStorage = (storage) => { return 0; } }; + +// Сервер принимает в выражении только ASCII-пробел, а клиент при вычислении снимает любые \s +// (NBSP, узкий NBSP, табуляция, перевод строки): перед отправкой убираем все пробельные символы. +export const normalizeFormulaExpression = (expr) => String(expr ?? '').replace(/\s+/g, ''); diff --git a/web/src/components/RealtimeTable/utils/cellFormulaUtils.test.js b/web/src/components/RealtimeTable/utils/cellFormulaUtils.test.js index f871eb3..cec6c6a 100644 --- a/web/src/components/RealtimeTable/utils/cellFormulaUtils.test.js +++ b/web/src/components/RealtimeTable/utils/cellFormulaUtils.test.js @@ -10,6 +10,7 @@ import { formulaKey, isFormulaActual, looksLikeExpressionWithoutEquals, + normalizeFormulaExpression, resolveInitialEditorText, } from './cellFormulaUtils.js'; @@ -159,3 +160,12 @@ test('looksLikeExpressionWithoutEquals', () => { } assert.equal(FORMULA_NEEDS_EQUALS_MESSAGE, 'Формула начинается с ='); }); + +test('AURORA-1896: normalizeFormulaExpression снимает любые пробельные символы', () => { + assert.equal(normalizeFormulaExpression('1 000+500'), '1000+500'); + assert.equal(normalizeFormulaExpression('1\u00a0000+500'), '1000+500'); + assert.equal(normalizeFormulaExpression('1\u202f000+5\t0\n0'), '1000+500'); + assert.equal(normalizeFormulaExpression('100 + 50'), '100+50'); + assert.equal(normalizeFormulaExpression(''), ''); + assert.equal(normalizeFormulaExpression(null), ''); +}); diff --git a/web/src/components/RealtimeTable/utils/wsErrorUtils.js b/web/src/components/RealtimeTable/utils/wsErrorUtils.js index e8def58..aef7283 100644 --- a/web/src/components/RealtimeTable/utils/wsErrorUtils.js +++ b/web/src/components/RealtimeTable/utils/wsErrorUtils.js @@ -4,6 +4,10 @@ const KNOWN_PREFIX_MESSAGES = [ { prefix: 'computed_field:', message: 'Это расчётная ячейка, её нельзя изменить' }, { prefix: 'role_not_allowed:', message: 'Нет прав на изменение этой колонки' }, { prefix: 'window_closed:', message: 'Окно ввода для этой колонки закрыто' }, + { + prefix: 'invalid_formula:', + message: 'Формула содержит недопустимые символы, пуста или слишком длинная (до 500 символов)', + }, { prefix: 'org_not_assigned', message: 'Вы не назначены на эту форму' }, ]; diff --git a/web/src/components/RealtimeTable/utils/wsErrorUtils.test.js b/web/src/components/RealtimeTable/utils/wsErrorUtils.test.js index 1dbbda0..2cc4735 100644 --- a/web/src/components/RealtimeTable/utils/wsErrorUtils.test.js +++ b/web/src/components/RealtimeTable/utils/wsErrorUtils.test.js @@ -71,3 +71,12 @@ test('AURORA-1978: префикс класса исключения asyncpg ср ); assert.equal(getWsErrorMessage(": "), 'Неизвестная ошибка сервера'); }); + +test('AURORA-1896: invalid_formula: заменяется человеческим текстом', () => { + const expected = 'Формула содержит недопустимые символы, пуста или слишком длинная (до 500 символов)'; + assert.equal(getWsErrorMessage('invalid_formula: chars'), expected); + assert.equal( + getWsErrorMessage({ code: 422, field: '', message: ": invalid_formula: length" }), + expected, + ); +});