mirror of
https://github.com/penpot/penpot.git
synced 2025-06-14 08:42:56 +02:00
🐛 Fix duplicate ids bug.
Caused by :mov-object bad frame-id assignation.
This commit is contained in:
parent
9eed0eedeb
commit
b3770963b0
3 changed files with 118 additions and 101 deletions
|
@ -213,15 +213,15 @@
|
||||||
))
|
))
|
||||||
|
|
||||||
(t/deftest process-changes-move-objects
|
(t/deftest process-changes-move-objects
|
||||||
(let [frame-a-id (uuid/next)
|
(let [frame-a-id (uuid/custom 1)
|
||||||
frame-b-id (uuid/next)
|
frame-b-id (uuid/custom 2)
|
||||||
group-a-id (uuid/next)
|
group-a-id (uuid/custom 3)
|
||||||
group-b-id (uuid/next)
|
group-b-id (uuid/custom 4)
|
||||||
rect-a-id (uuid/next)
|
rect-a-id (uuid/custom 5)
|
||||||
rect-b-id (uuid/next)
|
rect-b-id (uuid/custom 6)
|
||||||
rect-c-id (uuid/next)
|
rect-c-id (uuid/custom 7)
|
||||||
rect-d-id (uuid/next)
|
rect-d-id (uuid/custom 8)
|
||||||
rect-e-id (uuid/next)
|
rect-e-id (uuid/custom 9)
|
||||||
data (-> cp/default-page-data
|
data (-> cp/default-page-data
|
||||||
(assoc-in [cp/root :shapes] [frame-a-id])
|
(assoc-in [cp/root :shapes] [frame-a-id])
|
||||||
(assoc-in [:objects frame-a-id]
|
(assoc-in [:objects frame-a-id]
|
||||||
|
@ -356,12 +356,47 @@
|
||||||
(t/is (= data res))))))
|
(t/is (= data res))))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest process-changes-move-objects-3
|
||||||
|
(let [shape-2-id (uuid/custom 1 2)
|
||||||
|
shape-3-id (uuid/custom 1 3)
|
||||||
|
frame-id (uuid/custom 1 1)
|
||||||
|
changes [{:type :add-obj
|
||||||
|
:id frame-id
|
||||||
|
:frame-id uuid/zero
|
||||||
|
:obj {:type :frame
|
||||||
|
:name "Frame"}}
|
||||||
|
{:type :add-obj
|
||||||
|
:frame-id frame-id
|
||||||
|
:id shape-2-id
|
||||||
|
:obj {:type :shape
|
||||||
|
:name "Shape"}}
|
||||||
|
{:type :add-obj
|
||||||
|
:id shape-3-id
|
||||||
|
:frame-id uuid/zero
|
||||||
|
:obj {:type :rect
|
||||||
|
:name "Shape"}}]
|
||||||
|
data (cp/process-changes cp/default-page-data changes)]
|
||||||
|
(t/testing "move inside->outside-inside"
|
||||||
|
(let [changes [{:type :mov-objects
|
||||||
|
:shapes [shape-3-id]
|
||||||
|
:parent-id frame-id}
|
||||||
|
{:type :mov-objects
|
||||||
|
:shapes [shape-3-id]
|
||||||
|
:parent-id uuid/zero}]
|
||||||
|
res (cp/process-changes data changes)]
|
||||||
|
|
||||||
|
(t/is (= (get-in res [:objects shape-2-id :frame-id])
|
||||||
|
(get-in data [:objects shape-2-id :frame-id])))
|
||||||
|
(t/is (= (get-in res [:objects shape-3-id :frame-id])
|
||||||
|
(get-in data [:objects shape-3-id :frame-id])))))))
|
||||||
|
|
||||||
|
|
||||||
(t/deftest process-changes-move-objects-2
|
(t/deftest process-changes-move-objects-2
|
||||||
(let [shape-1-id (uuid/custom 1 1)
|
(let [shape-1-id (uuid/custom 1 1)
|
||||||
shape-2-id (uuid/custom 1 2)
|
shape-2-id (uuid/custom 1 2)
|
||||||
shape-3-id (uuid/custom 1 3)
|
shape-3-id (uuid/custom 1 3)
|
||||||
shape-4-id (uuid/custom 1 4)
|
shape-4-id (uuid/custom 1 4)
|
||||||
group-1-id (uuid/custom 2 1)
|
group-1-id (uuid/custom 1 5)
|
||||||
changes [{:type :add-obj
|
changes [{:type :add-obj
|
||||||
:id shape-1-id
|
:id shape-1-id
|
||||||
:frame-id cp/root
|
:frame-id cp/root
|
||||||
|
|
|
@ -222,7 +222,6 @@
|
||||||
|
|
||||||
(defmethod process-change :mod-obj
|
(defmethod process-change :mod-obj
|
||||||
[data {:keys [id operations] :as change}]
|
[data {:keys [id operations] :as change}]
|
||||||
(assert (contains? (:objects data) id) "process-change/mod-obj")
|
|
||||||
(update data :objects
|
(update data :objects
|
||||||
(fn [objects]
|
(fn [objects]
|
||||||
(if-let [obj (get objects id)]
|
(if-let [obj (get objects id)]
|
||||||
|
@ -293,7 +292,12 @@
|
||||||
(let [prev-shapes (or prev-shapes [])]
|
(let [prev-shapes (or prev-shapes [])]
|
||||||
(if index
|
(if index
|
||||||
(insert-at-index prev-shapes index shapes)
|
(insert-at-index prev-shapes index shapes)
|
||||||
(into prev-shapes shapes))))
|
(reduce (fn [acc id]
|
||||||
|
(if (some #{id} acc)
|
||||||
|
acc
|
||||||
|
(conj acc id)))
|
||||||
|
prev-shapes
|
||||||
|
shapes))))
|
||||||
|
|
||||||
strip-id
|
strip-id
|
||||||
(fn [id]
|
(fn [id]
|
||||||
|
@ -326,17 +330,18 @@
|
||||||
|
|
||||||
;; Updates the frame-id references that might be outdated
|
;; Updates the frame-id references that might be outdated
|
||||||
update-frame-ids
|
update-frame-ids
|
||||||
(fn update-frame-ids [data shape-id]
|
(fn update-frame-ids [data id]
|
||||||
(as-> data $
|
(let [data (assoc-in data [:objects id :frame-id] frame-id)
|
||||||
(assoc-in $ [:objects shape-id :frame-id] frame-id)
|
obj (get-in data [:objects id])]
|
||||||
(reduce update-frame-ids $ (get-in $ [:objects shape-id :shapes]))))]
|
(cond-> data
|
||||||
|
(not= :frame (:type obj))
|
||||||
|
(as-> $$ (reduce update-frame-ids $$ (:shapes obj))))))]
|
||||||
|
|
||||||
(if valid?
|
(when valid?
|
||||||
(as-> data $
|
(as-> data $
|
||||||
(update-in $ [:objects parent-id :shapes] insert-items)
|
(update-in $ [:objects parent-id :shapes] insert-items)
|
||||||
(reduce remove-in-parent $ shapes)
|
(reduce remove-in-parent $ shapes)
|
||||||
(reduce update-frame-ids $ (get-in $ [:objects parent-id :shapes])))
|
(reduce update-frame-ids $ (get-in $ [:objects parent-id :shapes]))))))
|
||||||
data)))
|
|
||||||
|
|
||||||
(defmethod process-operation :set
|
(defmethod process-operation :set
|
||||||
[shape op]
|
[shape op]
|
||||||
|
|
|
@ -1403,7 +1403,7 @@
|
||||||
(us/verify ::us/uuid ref-id)
|
(us/verify ::us/uuid ref-id)
|
||||||
(us/verify number? index)
|
(us/verify number? index)
|
||||||
|
|
||||||
(ptk/reify ::reloacate-shape
|
(ptk/reify ::relocate-shape
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [page-id (::page-id state)
|
(let [page-id (::page-id state)
|
||||||
|
@ -1417,28 +1417,6 @@
|
||||||
[]
|
[]
|
||||||
{:commit-local? true}))))))
|
{:commit-local? true}))))))
|
||||||
|
|
||||||
(defn commit-shape-order-change
|
|
||||||
[id]
|
|
||||||
(ptk/reify ::commit-shape-order-change
|
|
||||||
ptk/WatchEvent
|
|
||||||
(watch [_ state stream]
|
|
||||||
(let [pid (::page-id state)
|
|
||||||
obj (get-in state [:workspace-data pid :objects id])
|
|
||||||
|
|
||||||
cfrm (get-in state [:workspace-data pid :objects (:frame-id obj)])
|
|
||||||
pfrm (get-in state [:pages-data pid :objects (:frame-id obj)])
|
|
||||||
|
|
||||||
cindex (d/index-of (:shapes cfrm) id)
|
|
||||||
pindex (d/index-of (:shapes pfrm) id)
|
|
||||||
|
|
||||||
rchange {:type :mod-obj
|
|
||||||
:id (:id cfrm)
|
|
||||||
:operations [{:type :abs-order :id id :index cindex}]}
|
|
||||||
uchange {:type :mod-obj
|
|
||||||
:id (:id cfrm)
|
|
||||||
:operations [{:type :abs-order :id id :index pindex}]}]
|
|
||||||
(rx/of (commit-changes [rchange] [uchange]))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; --- Shape / Selection Alignment and Distribution
|
;; --- Shape / Selection Alignment and Distribution
|
||||||
|
|
||||||
|
@ -1491,40 +1469,64 @@
|
||||||
|
|
||||||
;; --- Temportal displacement for Shape / Selection
|
;; --- Temportal displacement for Shape / Selection
|
||||||
|
|
||||||
(defn- rehash-shape-frame-relationship
|
(defn- retrieve-toplevel-shapes
|
||||||
[ids]
|
[objects]
|
||||||
(letfn [(impl-diff [state]
|
(let [lookup #(get objects %)
|
||||||
|
root (lookup uuid/zero)
|
||||||
|
childs (:shapes root)]
|
||||||
|
(loop [id (first childs)
|
||||||
|
ids (rest childs)
|
||||||
|
res []]
|
||||||
|
(if (nil? id)
|
||||||
|
res
|
||||||
|
(let [obj (lookup id)
|
||||||
|
typ (:type obj)]
|
||||||
|
(recur (first ids)
|
||||||
|
(rest ids)
|
||||||
|
(if (= :frame typ)
|
||||||
|
(into res (:shapes obj))
|
||||||
|
(conj res id))))))))
|
||||||
|
|
||||||
|
(defn- calculate-shape-to-frame-relationship-changes
|
||||||
|
[objects ids]
|
||||||
(loop [id (first ids)
|
(loop [id (first ids)
|
||||||
ids (rest ids)
|
ids (rest ids)
|
||||||
rch []
|
rch []
|
||||||
uch []]
|
uch []]
|
||||||
(if (nil? id)
|
(if (nil? id)
|
||||||
[rch uch]
|
[rch uch]
|
||||||
(let [pid (::page-id state)
|
(let [obj (get objects id)
|
||||||
objects (get-in state [:workspace-data pid :objects])
|
|
||||||
obj (get objects id)
|
|
||||||
fid (calculate-frame-overlap objects obj)]
|
fid (calculate-frame-overlap objects obj)]
|
||||||
(if (not= fid (:frame-id obj))
|
(if (not= fid (:frame-id obj))
|
||||||
(recur (first ids)
|
(recur (first ids)
|
||||||
(rest ids)
|
(rest ids)
|
||||||
(conj rch {:type :mov-obj
|
(conj rch {:type :mov-objects
|
||||||
:id id
|
:parent-id fid
|
||||||
:frame-id fid})
|
:shapes [id]})
|
||||||
(conj uch {:type :mov-obj
|
(conj uch {:type :mov-objects
|
||||||
:id id
|
:parent-id (:frame-id obj)
|
||||||
:frame-id (:frame-id obj)}))
|
:shapes [id]}))
|
||||||
(recur (first ids)
|
(recur (first ids)
|
||||||
(rest ids)
|
(rest ids)
|
||||||
rch
|
rch
|
||||||
uch))))))]
|
uch))))))
|
||||||
|
|
||||||
|
(defn- rehash-shape-frame-relationship
|
||||||
|
[ids]
|
||||||
(ptk/reify ::rehash-shape-frame-relationship
|
(ptk/reify ::rehash-shape-frame-relationship
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state stream]
|
(watch [_ state stream]
|
||||||
(let [[rch uch] (impl-diff state)]
|
(let [page-id (::page-id state)
|
||||||
(when-not (empty? rch)
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
(rx/of (commit-changes rch uch {:commit-local? true}))))))))
|
ids (retrieve-toplevel-shapes objects)
|
||||||
|
[rch uch] (calculate-shape-to-frame-relationship-changes objects ids)
|
||||||
|
]
|
||||||
|
|
||||||
(defn- adjust-group-shapes [state ids]
|
(when-not (empty? rch)
|
||||||
|
(rx/of (commit-changes rch uch {:commit-local? true})))))))
|
||||||
|
|
||||||
|
(defn- adjust-group-shapes
|
||||||
|
[state ids]
|
||||||
(let [page-id (::page-id state)
|
(let [page-id (::page-id state)
|
||||||
objects (get-in state [:workspace-data page-id :objects])
|
objects (get-in state [:workspace-data page-id :objects])
|
||||||
groups-to-adjust (->> ids
|
groups-to-adjust (->> ids
|
||||||
|
@ -1930,25 +1932,6 @@
|
||||||
(let [page-id (::page-id state)]
|
(let [page-id (::page-id state)]
|
||||||
(update-in state [:workspace-data page-id :objects id :segments index] gpt/add delta)))))
|
(update-in state [:workspace-data page-id :objects id :segments index] gpt/add delta)))))
|
||||||
|
|
||||||
;; --- Initial Path Point Alignment
|
|
||||||
|
|
||||||
;; ;; TODO: revisit on alignemt refactor
|
|
||||||
;; (deftype InitialPathPointAlign [id index]
|
|
||||||
;; ptk/WatchEvent
|
|
||||||
;; (watch [_ state s]
|
|
||||||
;; (let [shape (get-in state [:workspace-data :objects id])
|
|
||||||
;; point (get-in shape [:segments index])]
|
|
||||||
;; (->> (uwrk/align-point point)
|
|
||||||
;; (rx/map #(update-path id index %))))))
|
|
||||||
|
|
||||||
;; (defn initial-path-point-align
|
|
||||||
;; "Event responsible of align a specified point of the
|
|
||||||
;; shape by `index` with the grid."
|
|
||||||
;; [id index]
|
|
||||||
;; {:pre [(uuid? id)
|
|
||||||
;; (number? index)
|
|
||||||
;; (not (neg? index))]}
|
|
||||||
;; (InitialPathPointAlign. id index))
|
|
||||||
|
|
||||||
;; --- Shape Visibility
|
;; --- Shape Visibility
|
||||||
|
|
||||||
|
@ -2216,14 +2199,8 @@
|
||||||
;; GROUPS
|
;; GROUPS
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn get-parent [object-id objects]
|
(defn group-shape
|
||||||
(let [include-object
|
[id frame-id selected selection-rect]
|
||||||
(fn [object]
|
|
||||||
(and (:shapes object)
|
|
||||||
(some #(= object-id %) (:shapes object))))]
|
|
||||||
(first (filter include-object objects))))
|
|
||||||
|
|
||||||
(defn group-shape [id frame-id selected selection-rect]
|
|
||||||
{:id id
|
{:id id
|
||||||
:type :group
|
:type :group
|
||||||
:name (name (gensym "Group-"))
|
:name (name (gensym "Group-"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue