From 5ab0bdeb7f7408a9b1f4b0beba22d78ddd810cb2 Mon Sep 17 00:00:00 2001 From: Pouzor Date: Mon, 11 May 2026 00:34:38 +0200 Subject: [PATCH] fix(text-node): persist text in label so it survives reload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit text_content is not in the API serializer schema, so text node content was dropped on save and the node came back empty after reload. Store text in label instead — already persisted, and TextNode + the edit modal already fall back to label, so existing data stays compatible. Clear stale text_content on update. Regression test added for the text-node save/load roundtrip. --- frontend/src/App.tsx | 11 +++++++--- .../utils/__tests__/canvasSerializer.test.ts | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62df72c..4c82fe8 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -248,14 +248,16 @@ export default function App() { const id = generateUUID() const newNode: Node = { id, + // Text lives in `label` because the API serializer only persists top-level + // node fields; text_content is not in the schema and was lost on reload. + // TextNode and the edit modal both already fall back to label. type: 'text', position: { x: 250, y: 250 }, data: { - label: '', + label: data.text, type: 'text', status: 'unknown', services: [], - text_content: data.text, custom_colors: { border: data.border_color, border_style: data.border_style, @@ -277,7 +279,10 @@ export default function App() { snapshotHistory() const existing = nodes.find((n) => n.id === editingTextId) updateNode(editingTextId, { - text_content: data.text, + label: data.text, + // Clear stale text_content if present from older builds — label is the + // source of truth now. + text_content: undefined, custom_colors: { ...existing?.data.custom_colors, border: data.border_color, diff --git a/frontend/src/utils/__tests__/canvasSerializer.test.ts b/frontend/src/utils/__tests__/canvasSerializer.test.ts index 2d26a52..a38f729 100644 --- a/frontend/src/utils/__tests__/canvasSerializer.test.ts +++ b/frontend/src/utils/__tests__/canvasSerializer.test.ts @@ -412,3 +412,24 @@ describe('round-trip: serialize → deserialize', () => { expect(restored.height).toBe(300) }) }) + +// ── text nodes survive save+reload (regression for #lost text node) ────────── +describe('serializeNode — text node roundtrip', () => { + const emptyMap = new Map() + + it('persists text content through label so it survives reload', () => { + const node = makeRfNode({ + type: 'text', + data: { + label: 'Hello world', + type: 'text', + status: 'unknown', + services: [], + }, + }) + const serialized = serializeNode(node) as ApiNode + expect(serialized.label).toBe('Hello world') + const restored = deserializeApiNode(serialized, emptyMap) + expect(restored.data.label).toBe('Hello world') + }) +})