fix(text-node): persist text in label so it survives reload
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.
This commit is contained in:
@@ -248,14 +248,16 @@ export default function App() {
|
|||||||
const id = generateUUID()
|
const id = generateUUID()
|
||||||
const newNode: Node<NodeData> = {
|
const newNode: Node<NodeData> = {
|
||||||
id,
|
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',
|
type: 'text',
|
||||||
position: { x: 250, y: 250 },
|
position: { x: 250, y: 250 },
|
||||||
data: {
|
data: {
|
||||||
label: '',
|
label: data.text,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
status: 'unknown',
|
status: 'unknown',
|
||||||
services: [],
|
services: [],
|
||||||
text_content: data.text,
|
|
||||||
custom_colors: {
|
custom_colors: {
|
||||||
border: data.border_color,
|
border: data.border_color,
|
||||||
border_style: data.border_style,
|
border_style: data.border_style,
|
||||||
@@ -277,7 +279,10 @@ export default function App() {
|
|||||||
snapshotHistory()
|
snapshotHistory()
|
||||||
const existing = nodes.find((n) => n.id === editingTextId)
|
const existing = nodes.find((n) => n.id === editingTextId)
|
||||||
updateNode(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: {
|
custom_colors: {
|
||||||
...existing?.data.custom_colors,
|
...existing?.data.custom_colors,
|
||||||
border: data.border_color,
|
border: data.border_color,
|
||||||
|
|||||||
@@ -412,3 +412,24 @@ describe('round-trip: serialize → deserialize', () => {
|
|||||||
expect(restored.height).toBe(300)
|
expect(restored.height).toBe(300)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ── text nodes survive save+reload (regression for #lost text node) ──────────
|
||||||
|
describe('serializeNode — text node roundtrip', () => {
|
||||||
|
const emptyMap = new Map<string, boolean>()
|
||||||
|
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user