diff --git a/.changeset/persist-without-measured.md b/.changeset/persist-without-measured.md new file mode 100644 index 000000000..095c7bf66 --- /dev/null +++ b/.changeset/persist-without-measured.md @@ -0,0 +1,5 @@ +--- +'@workflowbuilder/sdk': patch +--- + +Saved and exported diagrams (`getStoreDataForIntegration`, the localStorage/API/props integrations) no longer include the runtime `measured` node sizes; nodes are measured again on load, so stored data cannot carry stale dimensions. diff --git a/apps/ai-studio/src/data/ai-debate-flow.ts b/apps/ai-studio/src/data/ai-debate-flow.ts index a98de28cd..5b94fd544 100644 --- a/apps/ai-studio/src/data/ai-debate-flow.ts +++ b/apps/ai-studio/src/data/ai-debate-flow.ts @@ -21,7 +21,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 63 }, dragging: false, }, { @@ -41,7 +40,6 @@ why now. Be persuasive but honest, no hype.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -61,7 +59,6 @@ hidden costs, what could go wrong. Surface the objections others gloss over.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -92,7 +89,6 @@ Be decisive.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -110,7 +106,6 @@ Be decisive.`, icon: 'Eye', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, ], diff --git a/apps/ai-studio/src/data/content-repurposer-flow.ts b/apps/ai-studio/src/data/content-repurposer-flow.ts index 8eefa272c..2d71af2b2 100644 --- a/apps/ai-studio/src/data/content-repurposer-flow.ts +++ b/apps/ai-studio/src/data/content-repurposer-flow.ts @@ -26,7 +26,6 @@ of the most tedious parts of their week.`, icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 63 }, dragging: false, }, { @@ -48,7 +47,6 @@ Number each post (1/, 2/, ...).`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -71,7 +69,6 @@ Keep it under 200 words. Professional but human.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -93,7 +90,6 @@ Keep it under 200 words. Professional but human.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -125,7 +121,6 @@ Keep each draft's wording as-is - do not rewrite it. Just organize and label.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -143,7 +138,6 @@ Keep each draft's wording as-is - do not rewrite it. Just organize and label.`, icon: 'Eye', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, ], diff --git a/apps/ai-studio/src/data/meeting-notes-flow.ts b/apps/ai-studio/src/data/meeting-notes-flow.ts index dcf46a382..d32aa6d14 100644 --- a/apps/ai-studio/src/data/meeting-notes-flow.ts +++ b/apps/ai-studio/src/data/meeting-notes-flow.ts @@ -25,7 +25,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 63 }, dragging: false, }, { @@ -44,7 +43,6 @@ was decided. Neutral, factual tone.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -64,7 +62,6 @@ mark it "unassigned". Do not invent items that were not discussed.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -94,7 +91,6 @@ line "_Meeting Bot_".`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -112,7 +108,6 @@ line "_Meeting Bot_".`, icon: 'Eye', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, ], diff --git a/apps/ai-studio/src/data/research-flow.ts b/apps/ai-studio/src/data/research-flow.ts index 065408ee6..4a48b7d4a 100644 --- a/apps/ai-studio/src/data/research-flow.ts +++ b/apps/ai-studio/src/data/research-flow.ts @@ -20,7 +20,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 63 }, dragging: false, }, { @@ -52,7 +51,6 @@ Only state things you found via search. If a claim isn't supported by a result, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -70,7 +68,6 @@ Only state things you found via search. If a claim isn't supported by a result, icon: 'Eye', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, ], diff --git a/apps/ai-studio/src/data/support-triage-flow.ts b/apps/ai-studio/src/data/support-triage-flow.ts index f611ceccf..ebd7257fe 100644 --- a/apps/ai-studio/src/data/support-triage-flow.ts +++ b/apps/ai-studio/src/data/support-triage-flow.ts @@ -34,7 +34,6 @@ Head of Ops, Brightwave`, icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 63 }, dragging: false, }, { @@ -65,7 +64,6 @@ Use the exact lowercase keyword on the Type line - it drives downstream routing. icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -116,7 +114,6 @@ Use the exact lowercase keyword on the Type line - it drives downstream routing. icon: 'ArrowsSplit', }, selected: false, - measured: { width: 258, height: 236 }, dragging: false, }, { @@ -141,7 +138,6 @@ You handle billing issues. Draft a reply to the customer: icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -166,7 +162,6 @@ You triage product bugs. Draft a reply to the customer: icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -190,7 +185,6 @@ You answer how-to and general questions. Draft a friendly reply: icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -217,7 +211,6 @@ If not, output "⚠️ NEEDS REVISION" followed by specific, actionable fixes.`, icon: 'AiAgent', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, { @@ -235,7 +228,6 @@ If not, output "⚠️ NEEDS REVISION" followed by specific, actionable fixes.`, icon: 'Eye', }, selected: false, - measured: { width: 258, height: 123 }, dragging: false, }, ], diff --git a/apps/demo/src/app/data/templates/black-friday.ts b/apps/demo/src/app/data/templates/black-friday.ts index 289414c3b..358e26d11 100644 --- a/apps/demo/src/app/data/templates/black-friday.ts +++ b/apps/demo/src/app/data/templates/black-friday.ts @@ -21,7 +21,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '8ca95405-7bb6-496d-90ae-850b3ee88dc1', @@ -39,7 +38,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '3817f8c6-eba8-485d-9476-cf944f64a373', @@ -57,7 +55,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'aebc5083-5773-492d-bb49-1e928f56e331', @@ -75,7 +72,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -98,7 +94,6 @@ const diagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '60ed7855-3c3a-42ca-a770-8240a3a8ee12', @@ -120,7 +115,6 @@ const diagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '77a46d81-8b23-43a0-8c37-1e29335b67a0', @@ -138,7 +132,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -157,7 +150,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '455a0738-c1cc-4856-992a-07654eb29182', @@ -175,7 +167,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'd27658ca-925d-450d-9ddd-737a5f0aeeb4', @@ -193,7 +184,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -216,7 +206,6 @@ const diagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, ], diff --git a/apps/demo/src/app/data/templates/call-flow.ts b/apps/demo/src/app/data/templates/call-flow.ts index 1d46283bd..898d6d705 100644 --- a/apps/demo/src/app/data/templates/call-flow.ts +++ b/apps/demo/src/app/data/templates/call-flow.ts @@ -17,7 +17,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '6e4c57e4-4136-4aa4-a183-43679b1f7170', @@ -35,7 +34,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'a845d12e-0852-4809-96ce-334159e100fe', @@ -53,7 +51,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '65706043-b1d2-4600-b918-3b82ff5dfc13', @@ -71,7 +68,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'c187ef68-0fb8-47da-9a62-310afe91bfaa', @@ -89,7 +85,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -108,7 +103,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '09c67367-8d0d-44ae-bf4e-66b36f5c389f', @@ -126,7 +120,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'b01ced25-ca06-47c7-a14f-21e5a0200a61', @@ -144,7 +137,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -163,7 +155,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '6c3fca17-a1d4-4008-8a72-605d91eb7fd6', @@ -181,7 +172,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '6c0ecb78-cd09-4728-8dc7-414ab1c42ea2', @@ -199,7 +189,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -218,7 +207,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'bc34e3ae-6dd2-4543-8efe-190863df49e6', @@ -236,7 +224,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -255,7 +242,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -274,7 +260,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -293,7 +278,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'cd9ae822-5ae4-4fe0-b876-760d460faf0e', @@ -311,7 +295,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -330,7 +313,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, ], diff --git a/apps/demo/src/app/data/templates/simple-flow.ts b/apps/demo/src/app/data/templates/simple-flow.ts index 4746a71cd..e49506c9e 100644 --- a/apps/demo/src/app/data/templates/simple-flow.ts +++ b/apps/demo/src/app/data/templates/simple-flow.ts @@ -23,7 +23,6 @@ const defaultDiagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -42,7 +41,6 @@ const defaultDiagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -61,7 +59,6 @@ const defaultDiagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -80,7 +77,6 @@ const defaultDiagram: DiagramModel = { icon: 'ArrowsSplit', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -99,7 +95,6 @@ const defaultDiagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '801b6f56-05d9-4639-b426-ef171741a408', @@ -121,7 +116,6 @@ const defaultDiagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -140,7 +134,6 @@ const defaultDiagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'c87efe62-6394-43c2-8714-96c0dc19a407', @@ -158,7 +151,6 @@ const defaultDiagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '3bfaad20-c0b8-4a90-bf8b-04c3eec2ce31', @@ -176,7 +168,6 @@ const defaultDiagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '8b356b4a-5959-48ff-9374-cd07dc9522f6', @@ -194,7 +185,6 @@ const defaultDiagram: DiagramModel = { icon: 'ArrowsSplit', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'abac90c2-af48-458e-8e0c-48a505d0826e', @@ -216,7 +206,6 @@ const defaultDiagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -235,7 +224,6 @@ const defaultDiagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '263e749c-dfaa-4aed-af11-c7ad161aee54', @@ -253,7 +241,6 @@ const defaultDiagram: DiagramModel = { icon: 'ArrowsSplit', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'caae31f8-9bf6-4488-addf-d1b80842e1f7', @@ -271,7 +258,6 @@ const defaultDiagram: DiagramModel = { icon: 'PaperPlaneRight', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: 'c125ce95-d5f4-4a93-a9de-407e45016d8d', @@ -289,7 +275,6 @@ const defaultDiagram: DiagramModel = { icon: 'PaperPlaneRight', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, ], diff --git a/apps/demo/src/app/data/templates/user-registration.ts b/apps/demo/src/app/data/templates/user-registration.ts index 5c310196d..d3e1b4c9c 100644 --- a/apps/demo/src/app/data/templates/user-registration.ts +++ b/apps/demo/src/app/data/templates/user-registration.ts @@ -17,7 +17,6 @@ const diagram: DiagramModel = { icon: 'Lightning', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '5e11be1b-8db6-4a73-9fef-4e0bdf3f4aad', @@ -35,7 +34,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '91c179cb-71f5-4c14-abdc-24d17480af18', @@ -53,7 +51,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, { id: '2b2942c5-56a2-41c6-bb3d-d653b4c314da', @@ -71,7 +68,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -94,7 +90,6 @@ const diagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -113,7 +108,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -132,7 +126,6 @@ const diagram: DiagramModel = { icon: 'ListChecks', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -151,7 +144,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -174,7 +166,6 @@ const diagram: DiagramModel = { icon: 'Timer', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -193,7 +184,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, dragging: false, }, { @@ -212,7 +202,6 @@ const diagram: DiagramModel = { icon: 'PlayCircle', }, selected: false, - measured: { width: 258, height: 64 }, }, ], edges: [ diff --git a/packages/sdk/src/store/slices/diagram-slice/actions.ts b/packages/sdk/src/store/slices/diagram-slice/actions.ts index 282e3b000..3fe7e61d4 100644 --- a/packages/sdk/src/store/slices/diagram-slice/actions.ts +++ b/packages/sdk/src/store/slices/diagram-slice/actions.ts @@ -88,9 +88,9 @@ type GetStoreDataParams = { * persistable payload to the host — e.g. inside a `props`-strategy * `onDataSave` callback or before posting to a custom backend. * - * Dynamic, runtime-only values (selection, computed avoid-edge points, - * …) are stripped by default; pass `shouldSkipDynamicValues: false` if - * you specifically need the live values. + * Dynamic, runtime-only values (selection, measured node sizes, computed + * avoid-edge points, …) are stripped by default; pass + * `shouldSkipDynamicValues: false` if you specifically need the live values. * * @category Store */ diff --git a/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.spec.ts b/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.spec.ts new file mode 100644 index 000000000..d1939bccb --- /dev/null +++ b/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.spec.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from 'vitest'; + +import type { WorkflowBuilderEdge, WorkflowBuilderNode } from '../../../../node/node-data'; +import { skipDynamicValuesInEdges, skipDynamicValuesInNodes } from './dynamic-values'; + +describe('skipDynamicValuesInNodes', () => { + it('drops measured sizes and selection while keeping the rest of the node', () => { + const node = { + id: 'node-1', + type: 'node', + position: { x: 10, y: 20 }, + selected: true, + measured: { width: 258, height: 64 }, + data: { label: 'Node' }, + } as unknown as WorkflowBuilderNode; + + const [result] = skipDynamicValuesInNodes([node]); + + expect(result).not.toHaveProperty('measured'); + expect(result.selected).toBe(false); + expect(result).toMatchObject({ id: 'node-1', type: 'node', position: { x: 10, y: 20 }, data: { label: 'Node' } }); + expect(node.measured).toEqual({ width: 258, height: 64 }); + }); +}); + +describe('skipDynamicValuesInEdges', () => { + it('resets routing points and selection', () => { + const edge = { + id: 'edge-1', + source: 'a', + target: 'b', + selected: true, + data: { label: 'Edge', routerPointsFromAvoidNodes: [{ x: 1, y: 2 }], layoutPoints: [{ x: 3, y: 4 }] }, + } as unknown as WorkflowBuilderEdge; + + const [result] = skipDynamicValuesInEdges([edge]); + + expect(result.selected).toBe(false); + expect(result.data).toMatchObject({ label: 'Edge', routerPointsFromAvoidNodes: [], layoutPoints: [] }); + }); +}); diff --git a/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.ts b/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.ts index 3de0a1634..40a7a9621 100644 --- a/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.ts +++ b/packages/sdk/src/store/slices/diagram-slice/utils/dynamic-values.ts @@ -1,7 +1,7 @@ import type { WorkflowBuilderEdge, WorkflowBuilderNode } from '../../../../node/node-data'; export const skipDynamicValuesInNodes = (nodes: WorkflowBuilderNode[]): WorkflowBuilderNode[] => { - return nodes.map((node) => ({ + return nodes.map(({ measured: _measured, ...node }) => ({ ...node, selected: false, }));