0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-06 12:01:19 -05:00

Tests for remove swap slot on move shapes to frame

This commit is contained in:
Pablo Alba 2024-05-06 15:37:21 +02:00 committed by Andrés Moya
parent e666127b57
commit 7280dfd3f7
3 changed files with 278 additions and 129 deletions

View file

@ -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))))

View file

@ -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'')))))

View file

@ -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)