From a5282f1c86acb766b0cd82f55da08aaed23412cf Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 28 Oct 2026 21:51:09 +0400 Subject: [PATCH] =?UTF-8?q?fix(realtime):=20=D0=BF=D1=83=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20=D1=83=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D1=82=20=D0=BA=D0=B0=D0=BA=20value:=20null,?= =?UTF-8?q?=20=D0=B0=20=D0=BD=D0=B5=20=D0=B1=D0=B5=D0=B7=20=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B0=20(AURORA-1848)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../RealtimeTable/contexts/RealtimeContext.js | 11 ++--------- .../RealtimeTable/utils/messageUtils.js | 10 ++++++++++ .../RealtimeTable/utils/messageUtils.test.js | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 web/src/components/RealtimeTable/utils/messageUtils.js create mode 100644 web/src/components/RealtimeTable/utils/messageUtils.test.js diff --git a/web/src/components/RealtimeTable/contexts/RealtimeContext.js b/web/src/components/RealtimeTable/contexts/RealtimeContext.js index c56e894..cce0cb6 100644 --- a/web/src/components/RealtimeTable/contexts/RealtimeContext.js +++ b/web/src/components/RealtimeTable/contexts/RealtimeContext.js @@ -1,6 +1,7 @@ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'; import { toast } from 'react-toastify'; import { useWebSocket } from '../hooks/useWebSocket'; +import { buildCellUpdatedMessage } from '../utils/messageUtils'; import { getRowId } from '../utils/rowUtils'; const RealtimeActionsContext = createContext(null); @@ -310,15 +311,7 @@ export const RealtimeProvider = ({ children, formId, sheetName, direction, year, const lineId = getRowId(row); const columnKey = getColumnRequestKey(column); - const message = { - event: 'cell_updated', - data: { - line_id: lineId, - line_id_code: row.id, - column: columnKey, - value: value, - }, - }; + const message = buildCellUpdatedMessage({ lineId, lineIdCode: row.id, column: columnKey, value }); const sent = sendMessage(message); if (!sent) { diff --git a/web/src/components/RealtimeTable/utils/messageUtils.js b/web/src/components/RealtimeTable/utils/messageUtils.js new file mode 100644 index 0000000..5e305ed --- /dev/null +++ b/web/src/components/RealtimeTable/utils/messageUtils.js @@ -0,0 +1,10 @@ +// value всегда присутствует: сервер читает event_data["value"], AURORA-1848 D5.2 +export const buildCellUpdatedMessage = ({ lineId, lineIdCode, column, value }) => ({ + event: 'cell_updated', + data: { + line_id: lineId, + line_id_code: lineIdCode, + column, + value: value === undefined ? null : value, + }, +}); diff --git a/web/src/components/RealtimeTable/utils/messageUtils.test.js b/web/src/components/RealtimeTable/utils/messageUtils.test.js new file mode 100644 index 0000000..2e7bb6c --- /dev/null +++ b/web/src/components/RealtimeTable/utils/messageUtils.test.js @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { buildCellUpdatedMessage } from './messageUtils.js'; + +const msg = (value) => buildCellUpdatedMessage({ lineId: 1, lineIdCode: '0.1', column: 'q1.m1', value }); + +test('buildCellUpdatedMessage: undefined → null, ключ value есть после JSON.stringify', () => { + const m = msg(undefined); + assert.deepEqual(m, { event: 'cell_updated', data: { line_id: 1, line_id_code: '0.1', column: 'q1.m1', value: null } }); + assert.match(JSON.stringify(m), /"value":null/); +}); + +test('buildCellUpdatedMessage: прочие значения не меняются', () => { + for (const v of [null, 0, '', '1.5', 42, 'текст']) { + assert.equal(msg(v).data.value, v); + } +});