From 7280dfd3f7353fe136c8c1ba39fbe02b2a1a2675 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Mon, 6 May 2024 15:37:21 +0200 Subject: [PATCH] :sparkles: Tests for remove swap slot on move shapes to frame --- .../app/common/files/libraries_helpers.cljc | 128 +++++++++++++++ .../logic/comp_remove_swap_slots_test.cljc | 146 +++++++++++++++++- .../app/main/data/workspace/transforms.cljs | 133 +--------------- 3 files changed, 278 insertions(+), 129 deletions(-) diff --git a/common/src/app/common/files/libraries_helpers.cljc b/common/src/app/common/files/libraries_helpers.cljc index 9ac32219f..6df368eb6 100644 --- a/common/src/app/common/files/libraries_helpers.cljc +++ b/common/src/app/common/files/libraries_helpers.cljc @@ -2301,3 +2301,131 @@ ;; Resize parent containers that need to (pcb/resize-parents parents)))) + + +(defn generate-move-shapes-to-frame + [changes ids frame-id page-id objects drop-index [row column :as cell]] + (let [lookup (d/getf objects) + frame (get objects frame-id) + layout? (:layout frame) + + component-main-frame (ctn/find-component-main objects frame false) + + shapes (->> ids + (cfh/clean-loops objects) + (keep lookup) + ;;remove shapes inside copies, because we can't change the structure of copies + (remove #(ctk/in-component-copy? (get objects (:parent-id %))))) + + moving-shapes + (cond->> shapes + (not layout?) + (remove #(= (:frame-id %) frame-id)) + + layout? + (remove #(and (= (:frame-id %) frame-id) + (not= (:parent-id %) frame-id)))) + + ordered-indexes (cfh/order-by-indexed-shapes objects (map :id moving-shapes)) + moving-shapes (map (d/getf objects) ordered-indexes) + + all-parents + (reduce (fn [res id] + (into res (cfh/get-parent-ids objects id))) + (d/ordered-set) + ids) + + find-all-empty-parents + (fn recursive-find-empty-parents [empty-parents] + (let [all-ids (into empty-parents ids) + contains? (partial contains? all-ids) + xform (comp (map lookup) + (filter cfh/group-shape?) + (remove #(->> (:shapes %) (remove contains?) seq)) + (map :id)) + parents (into #{} xform all-parents)] + (if (= empty-parents parents) + empty-parents + (recursive-find-empty-parents parents)))) + + empty-parents + ;; Any empty parent whose children are moved to another frame should be deleted + (if (empty? moving-shapes) + #{} + (into (d/ordered-set) (find-all-empty-parents #{}))) + + ;; Not move absolute shapes that won't change parent + moving-shapes + (->> moving-shapes + (remove (fn [shape] + (and (ctl/position-absolute? shape) + (= frame-id (:parent-id shape)))))) + + frame-component + (ctn/get-component-shape objects frame) + + shape-ids-to-detach + (reduce (fn [result shape] + (if (and (some? shape) (ctk/in-component-copy-not-head? shape)) + (let [shape-component (ctn/get-component-shape objects shape)] + (if (= (:id frame-component) (:id shape-component)) + result + (into result (cfh/get-children-ids-with-self objects (:id shape))))) + result)) + #{} + moving-shapes) + + moving-shapes-ids + (map :id moving-shapes) + + moving-shapes-children-ids + (->> moving-shapes-ids + (mapcat #(cfh/get-children-ids-with-self objects %))) + + child-heads + (->> moving-shapes-ids + (mapcat #(ctn/get-child-heads objects %)) + (map :id))] + (-> changes + (pcb/with-page-id page-id) + (pcb/with-objects objects) + + ;; Remove layout-item properties when moving a shape outside a layout + (cond-> (not (ctl/any-layout? objects frame-id)) + (pcb/update-shapes moving-shapes-ids ctl/remove-layout-item-data)) + + ;; Remove the swap slots if it is moving to a different component + (pcb/update-shapes + child-heads + (fn [shape] + (cond-> shape + (not= component-main-frame (ctn/find-component-main objects shape false)) + (ctk/remove-swap-slot)))) + + ;; Remove component-root property when moving a shape inside a component + (cond-> (ctn/get-instance-root objects frame) + (pcb/update-shapes moving-shapes-children-ids #(dissoc % :component-root))) + + ;; Add component-root property when moving a component outside a component + (cond-> (not (ctn/get-instance-root objects frame)) + (pcb/update-shapes child-heads #(assoc % :component-root true))) + + (pcb/update-shapes moving-shapes-ids #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) + (pcb/update-shapes shape-ids-to-detach ctk/detach-shape) + (pcb/change-parent frame-id moving-shapes drop-index) + + ;; Change the grid cell in a grid layout + (cond-> (ctl/grid-layout? objects frame-id) + (-> (pcb/update-shapes + [frame-id] + (fn [frame objects] + (-> frame + ;; Assign the cell when pushing into a specific grid cell + (cond-> (some? cell) + (-> (ctl/free-cell-shapes moving-shapes-ids) + (ctl/push-into-cell moving-shapes-ids row column) + (ctl/assign-cells objects))) + (ctl/assign-cell-positions objects))) + {:with-objects? true}) + (pcb/reorder-grid-children [frame-id]))) + (pcb/remove-objects empty-parents)))) diff --git a/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc b/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc index 5773b1df0..ede14008d 100644 --- a/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc +++ b/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc @@ -60,7 +60,7 @@ changes (cflh/generate-relocate-shapes (pcb/empty-changes nil) (:objects page) #{(:parent-id blue1)} ;; parents - uuid/zero ;; paremt-id + uuid/zero ;; parent-id (:id page) ;; page-id 0 ;; to-index #{(:id blue1)}) ;; ids @@ -77,6 +77,34 @@ (t/is (some? blue1')) (t/is (nil? (ctk/get-swap-slot blue1'))))) +(t/deftest test-keep-swap-slot-move-blue1-to-root + (let [;; ============================== Setup =============================== + file (setup-file) + page (thf/current-page file) + blue1 (thf/get-shape file :blue1) + + ;; ============================== Action ============================== + changes (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id blue1)} ;; ids + uuid/zero ;; frame-id + (:id page) ;; page-id + (:objects page) ;; objects + 0 ;; drop-index + nil) ;; cell + + file' (thf/apply-changes file changes) + + ;; ============================== Get ================================= + blue1' (thf/get-shape file' :blue1)] + + ;; ================================== Check =============================== + ;; blue1 had swap-id before move + (t/is (some? (ctk/get-swap-slot blue1))) + + ;; blue1 has not swap-id after move + (t/is (some? blue1')) + (t/is (nil? (ctk/get-swap-slot blue1'))))) + (t/deftest test-keep-swap-slot-relocating-blue1-to-b2 (let [;; ============================== Setup =============================== @@ -107,6 +135,36 @@ (t/is (some? blue1')) (t/is (nil? (ctk/get-swap-slot blue1'))))) +(t/deftest test-keep-swap-slot-move-blue1-to-b2 + (let [;; ============================== Setup =============================== + file (setup-file) + page (thf/current-page file) + blue1 (thf/get-shape file :blue1) + b2 (thf/get-shape file :frame-b2) + + + ;; ============================== Action ============================== + changes (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id blue1)} ;; ids + (:id b2) ;; frame-id + (:id page) ;; page-id + (:objects page) ;; objects + 0 ;; drop-index + nil) ;; cell + + file' (thf/apply-changes file changes) + + ;; ============================== Get ================================= + blue1' (thf/get-shape file' :blue1)] + + ;; ================================== Check =============================== + ;; blue1 had swap-id before move + (t/is (some? (ctk/get-swap-slot blue1))) + + ;; blue1 has not swap-id after move + (t/is (some? blue1')) + (t/is (nil? (ctk/get-swap-slot blue1'))))) + (t/deftest test-keep-swap-slot-relocating-yellow-to-root (let [;; ============================== Setup =============================== file (setup-file) @@ -149,6 +207,48 @@ (t/is (some? blue1'')) (t/is (nil? (ctk/get-swap-slot blue1''))))) +(t/deftest test-keep-swap-slot-move-yellow-to-root + (let [;; ============================== Setup =============================== + file (setup-file) + page (thf/current-page file) + blue1 (thf/get-shape file :blue1) + yellow (thf/get-shape file :frame-yellow) + + ;; ============================== Action ============================== + ;; Move blue1 into yellow + changes (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id blue1)} ;; ids + (:id yellow) ;; frame-id + (:id page) ;; page-id + (:objects page) ;; objects + 0 ;; drop-index + nil) ;; cell + + file' (thf/apply-changes file changes) + page' (thf/current-page file') + yellow' (thf/get-shape file' :frame-yellow) + + ;; Move yellow into root + changes' (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id yellow')} ;; ids + uuid/zero ;; frame-id + (:id page') ;; page-id + (:objects page') ;; objects + 0 ;; drop-index + nil) ;; cell + file'' (thf/apply-changes file' changes') + + ;; ============================== Get ================================= + blue1'' (thf/get-shape file'' :blue1)] + + ;; ================================== Check =============================== + ;; blue1 had swap-id before move + (t/is (some? (ctk/get-swap-slot blue1))) + + ;; blue1 has not swap-id after move + (t/is (some? blue1'')) + (t/is (nil? (ctk/get-swap-slot blue1''))))) + (t/deftest test-keep-swap-slot-relocating-yellow-to-b2 (let [;; ============================== Setup =============================== @@ -192,3 +292,47 @@ ;; blue1 has not swap-id after move (t/is (some? blue1'')) (t/is (nil? (ctk/get-swap-slot blue1''))))) + +(t/deftest test-keep-swap-slot-move-yellow-to-b2 + (let [;; ============================== Setup =============================== + file (setup-file) + page (thf/current-page file) + blue1 (thf/get-shape file :blue1) + yellow (thf/get-shape file :frame-yellow) + + ;; ============================== Action ============================== + ;; Move blue1 into yellow + changes (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id blue1)} ;; ids + (:id yellow) ;; frame-id + (:id page) ;; page-id + (:objects page) ;; objects + 0 ;; drop-index + nil) ;; cell + + file' (thf/apply-changes file changes) + page' (thf/current-page file') + yellow' (thf/get-shape file' :frame-yellow) + b2' (thf/get-shape file' :frame-b2) + + ;; Move yellow into b2 + changes' (cflh/generate-move-shapes-to-frame (pcb/empty-changes nil) + #{(:id yellow')} ;; ids + (:id b2') ;; frame-id + (:id page') ;; page-id + (:objects page') ;; objects + 0 ;; drop-index + nil) ;; cell + + file'' (thf/apply-changes file' changes') + + ;; ============================== Get ================================= + blue1'' (thf/get-shape file'' :blue1)] + + ;; ================================== Check =============================== + ;; blue1 had swap-id before move + (t/is (some? (ctk/get-swap-slot blue1))) + + ;; blue1 has not swap-id after move + (t/is (some? blue1'')) + (t/is (nil? (ctk/get-swap-slot blue1''))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 4fc56d2ce..310a79c58 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -11,6 +11,7 @@ [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.common.files.helpers :as cfh] + [app.common.files.libraries-helpers :as cflh] [app.common.geom.matrix :as gmt] [app.common.geom.modifiers :as gm] [app.common.geom.point :as gpt] @@ -832,137 +833,13 @@ :ignore-snap-pixel true})))))) (defn move-shapes-to-frame - [ids frame-id drop-index [row column :as cell]] + [ids frame-id drop-index cell] (ptk/reify ::move-shapes-to-frame ptk/WatchEvent (watch [it state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - lookup (d/getf objects) - frame (get objects frame-id) - layout? (:layout frame) - - component-main-frame (ctn/find-component-main objects frame false) - - shapes (->> ids - (cfh/clean-loops objects) - (keep lookup) - ;;remove shapes inside copies, because we can't change the structure of copies - (remove #(ctk/in-component-copy? (get objects (:parent-id %))))) - - moving-shapes - (cond->> shapes - (not layout?) - (remove #(= (:frame-id %) frame-id)) - - layout? - (remove #(and (= (:frame-id %) frame-id) - (not= (:parent-id %) frame-id)))) - - ordered-indexes (cfh/order-by-indexed-shapes objects (map :id moving-shapes)) - moving-shapes (map (d/getf objects) ordered-indexes) - - all-parents - (reduce (fn [res id] - (into res (cfh/get-parent-ids objects id))) - (d/ordered-set) - ids) - - find-all-empty-parents - (fn recursive-find-empty-parents [empty-parents] - (let [all-ids (into empty-parents ids) - contains? (partial contains? all-ids) - xform (comp (map lookup) - (filter cfh/group-shape?) - (remove #(->> (:shapes %) (remove contains?) seq)) - (map :id)) - parents (into #{} xform all-parents)] - (if (= empty-parents parents) - empty-parents - (recursive-find-empty-parents parents)))) - - empty-parents - ;; Any empty parent whose children are moved to another frame should be deleted - (if (empty? moving-shapes) - #{} - (into (d/ordered-set) (find-all-empty-parents #{}))) - - ;; Not move absolute shapes that won't change parent - moving-shapes - (->> moving-shapes - (remove (fn [shape] - (and (ctl/position-absolute? shape) - (= frame-id (:parent-id shape)))))) - - frame-component - (ctn/get-component-shape objects frame) - - shape-ids-to-detach - (reduce (fn [result shape] - (if (and (some? shape) (ctk/in-component-copy-not-head? shape)) - (let [shape-component (ctn/get-component-shape objects shape)] - (if (= (:id frame-component) (:id shape-component)) - result - (into result (cfh/get-children-ids-with-self objects (:id shape))))) - result)) - #{} - moving-shapes) - - moving-shapes-ids - (map :id moving-shapes) - - moving-shapes-children-ids - (->> moving-shapes-ids - (mapcat #(cfh/get-children-ids-with-self objects %))) - - child-heads - (->> moving-shapes-ids - (mapcat #(ctn/get-child-heads objects %)) - (map :id)) - - changes - (-> (pcb/empty-changes it page-id) - (pcb/with-objects objects) - - ;; Remove layout-item properties when moving a shape outside a layout - (cond-> (not (ctl/any-layout? objects frame-id)) - (pcb/update-shapes moving-shapes-ids ctl/remove-layout-item-data)) - - ;; Remove the swap slots if it is moving to a different component - (pcb/update-shapes - child-heads - (fn [shape] - (cond-> shape - (not= component-main-frame (ctn/find-component-main objects shape false)) - (ctk/remove-swap-slot)))) - - ;; Remove component-root property when moving a shape inside a component - (cond-> (ctn/get-instance-root objects frame) - (pcb/update-shapes moving-shapes-children-ids #(dissoc % :component-root))) - - ;; Add component-root property when moving a component outside a component - (cond-> (not (ctn/get-instance-root objects frame)) - (pcb/update-shapes child-heads #(assoc % :component-root true))) - - (pcb/update-shapes moving-shapes-ids #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true))) - (pcb/update-shapes shape-ids-to-detach ctk/detach-shape) - (pcb/change-parent frame-id moving-shapes drop-index) - - ;; Change the grid cell in a grid layout - (cond-> (ctl/grid-layout? objects frame-id) - (-> (pcb/update-shapes - [frame-id] - (fn [frame objects] - (-> frame - ;; Assign the cell when pushing into a specific grid cell - (cond-> (some? cell) - (-> (ctl/free-cell-shapes moving-shapes-ids) - (ctl/push-into-cell moving-shapes-ids row column) - (ctl/assign-cells objects))) - (ctl/assign-cell-positions objects))) - {:with-objects? true}) - (pcb/reorder-grid-children [frame-id]))) - (pcb/remove-objects empty-parents))] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + changes (cflh/generate-move-shapes-to-frame (pcb/empty-changes it) ids frame-id page-id objects drop-index cell)] (when (and (some? frame-id) (d/not-empty? changes)) (rx/of (dch/commit-changes changes)