fix(formulas): нормализация пробелов выражения перед отправкой и текст ошибки invalid_formula (AURORA-1896, I-2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ecef6eb247
commit
e569d18624
@ -2,7 +2,12 @@ import { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { nonNegativeColumnKeys } from '../../constants/validation';
|
import { nonNegativeColumnKeys } from '../../constants/validation';
|
||||||
import { getColumnRequestKey, useCellFormula, useRealtimeActions } from '../../contexts/RealtimeContext';
|
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 {
|
import {
|
||||||
calculateFormula,
|
calculateFormula,
|
||||||
extractFormula,
|
extractFormula,
|
||||||
@ -197,7 +202,7 @@ const EditCell = memo(({ refCell, onChange, disabled, value, table, cell }) => {
|
|||||||
}));
|
}));
|
||||||
warnIfNegativeNotAllowed(formattedResult);
|
warnIfNegativeNotAllowed(formattedResult);
|
||||||
// AURORA-1896: уходит значение и выражение без «=» — формулу сохраняет сервер.
|
// AURORA-1896: уходит значение и выражение без «=» — формулу сохраняет сервер.
|
||||||
onChange?.(formattedResult, { formula: extractFormula(currentValue) });
|
onChange?.(formattedResult, { formula: normalizeFormulaExpression(extractFormula(currentValue)) });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -108,3 +108,7 @@ export const clearLegacyFormulaStorage = (storage) => {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Сервер принимает в выражении только ASCII-пробел, а клиент при вычислении снимает любые \s
|
||||||
|
// (NBSP, узкий NBSP, табуляция, перевод строки): перед отправкой убираем все пробельные символы.
|
||||||
|
export const normalizeFormulaExpression = (expr) => String(expr ?? '').replace(/\s+/g, '');
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
formulaKey,
|
formulaKey,
|
||||||
isFormulaActual,
|
isFormulaActual,
|
||||||
looksLikeExpressionWithoutEquals,
|
looksLikeExpressionWithoutEquals,
|
||||||
|
normalizeFormulaExpression,
|
||||||
resolveInitialEditorText,
|
resolveInitialEditorText,
|
||||||
} from './cellFormulaUtils.js';
|
} from './cellFormulaUtils.js';
|
||||||
|
|
||||||
@ -159,3 +160,12 @@ test('looksLikeExpressionWithoutEquals', () => {
|
|||||||
}
|
}
|
||||||
assert.equal(FORMULA_NEEDS_EQUALS_MESSAGE, 'Формула начинается с =');
|
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), '');
|
||||||
|
});
|
||||||
|
|||||||
@ -4,6 +4,10 @@ const KNOWN_PREFIX_MESSAGES = [
|
|||||||
{ prefix: 'computed_field:', message: 'Это расчётная ячейка, её нельзя изменить' },
|
{ prefix: 'computed_field:', message: 'Это расчётная ячейка, её нельзя изменить' },
|
||||||
{ prefix: 'role_not_allowed:', message: 'Нет прав на изменение этой колонки' },
|
{ prefix: 'role_not_allowed:', message: 'Нет прав на изменение этой колонки' },
|
||||||
{ prefix: 'window_closed:', message: 'Окно ввода для этой колонки закрыто' },
|
{ prefix: 'window_closed:', message: 'Окно ввода для этой колонки закрыто' },
|
||||||
|
{
|
||||||
|
prefix: 'invalid_formula:',
|
||||||
|
message: 'Формула содержит недопустимые символы, пуста или слишком длинная (до 500 символов)',
|
||||||
|
},
|
||||||
{ prefix: 'org_not_assigned', message: 'Вы не назначены на эту форму' },
|
{ prefix: 'org_not_assigned', message: 'Вы не назначены на эту форму' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -71,3 +71,12 @@ test('AURORA-1978: префикс класса исключения asyncpg ср
|
|||||||
);
|
);
|
||||||
assert.equal(getWsErrorMessage("<class 'asyncpg.exceptions.RaiseError'>: "), 'Неизвестная ошибка сервера');
|
assert.equal(getWsErrorMessage("<class 'asyncpg.exceptions.RaiseError'>: "), 'Неизвестная ошибка сервера');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('AURORA-1896: invalid_formula: заменяется человеческим текстом', () => {
|
||||||
|
const expected = 'Формула содержит недопустимые символы, пуста или слишком длинная (до 500 символов)';
|
||||||
|
assert.equal(getWsErrorMessage('invalid_formula: chars'), expected);
|
||||||
|
assert.equal(
|
||||||
|
getWsErrorMessage({ code: 422, field: '', message: "<class 'asyncpg.exceptions.RaiseError'>: invalid_formula: length" }),
|
||||||
|
expected,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user