From e4e02a475367c615138b71fe6fcba264a82d68a3 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 23 Oct 2026 13:56:29 +0200 Subject: [PATCH] :bug: Clear source grid cells when relocating children Recalculate cell positions in the previous grids after moving children. The destination update alone left cell references to shapes that moved. Validation: reset and move suites, 21 tests / 92 assertions. The grid move regression failed before the fix and checks exact undo. Benchmark ratios against Phase 1e: main 10/100/1000 copies 0.54/0.56/0.60; three levels 0.52; chain 0.52; library 0.55; many shapes 0.58; variant switch 0.61. No regression flag. AI-assisted-by: GPT-6 --- common/src/app/common/logic/shapes.cljc | 8 ++++++++ .../common_tests/logic/move_shapes_test.cljc | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/common/src/app/common/logic/shapes.cljc b/common/src/app/common/logic/shapes.cljc index afb94ee564..c861d74797 100644 --- a/common/src/app/common/logic/shapes.cljc +++ b/common/src/app/common/logic/shapes.cljc @@ -555,6 +555,14 @@ shapes to-index) + ;; A move also removes children from their previous layout. + (pcb/update-shapes (disj all-parents parent-id) + (fn [shape objects] + (if (ctl/grid-layout? shape) + (ctl/assign-cell-positions shape objects) + shape)) + {:ignore-touched true :with-objects? true}) + ;; Remove empty groups (pcb/remove-objects groups-to-delete) diff --git a/common/test/common_tests/logic/move_shapes_test.cljc b/common/test/common_tests/logic/move_shapes_test.cljc index 8fdb32cb51..7619e8abbf 100644 --- a/common/test/common_tests/logic/move_shapes_test.cljc +++ b/common/test/common_tests/logic/move_shapes_test.cljc @@ -21,6 +21,25 @@ (t/use-fixtures :each thi/test-fixture) +(t/deftest moving-a-child-out-of-a-grid-clears-its-old-cell + (let [file (-> (thf/sample-file :file1) + (tho/add-grid-frame :grid :width 200 :height 100) + (tho/add-rect :first :parent-label :grid) + (tho/add-rect :second :parent-label :grid) + (tho/place-in-grid-columns :grid 2 {1 :first 2 :second}) + (tho/add-frame :destination)) + page (thf/current-page file) + changes (cls/generate-relocate (-> (pcb/empty-changes nil (:id page)) + (pcb/with-objects (:objects page)) + (pcb/with-library-data (:data file))) + (thi/id :destination) 0 #{(thi/id :first)}) + moved (thf/apply-changes file changes) + grid (ths/get-shape moved :grid) + members (mapcat :shapes (vals (:layout-grid-cells grid))) + undone (thf/apply-changes moved {:redo-changes (:undo-changes changes)})] + (t/is (= #{(thi/id :second)} (set members))) + (t/is (= (thn/normalize-file file) (thn/normalize-file undone))))) + (t/deftest deleting-a-grid-child-clears-its-cell-and-keeps-undo (let [file (-> (thf/sample-file :file1) (tho/add-grid-frame :grid :width 200 :height 100)