mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
🔧 Avoid copies with wrong component-id and repair if needed
This commit is contained in:
@@ -1777,6 +1777,28 @@
|
||||
component))]
|
||||
(d/update-when data :components check-component)))
|
||||
|
||||
(defmethod migrate-data "0018-sync-component-id-with-near-main"
|
||||
[data _]
|
||||
(letfn [(fix-shape [page shape]
|
||||
(if (and (ctk/subcopy-head? shape)
|
||||
(nil? (ctk/get-swap-slot shape)))
|
||||
(let [file {:id (:id data) :data data}
|
||||
libs (some-> (:libs data) deref)
|
||||
ref-shape (ctf/find-ref-shape file page libs shape {:include-deleted? true :with-context? true})]
|
||||
(if (and (some? ref-shape)
|
||||
(or (not= (:component-id shape) (:component-id ref-shape))
|
||||
(not= (:component-file shape) (:component-file ref-shape))))
|
||||
(assoc shape
|
||||
:component-id (:component-id ref-shape)
|
||||
:component-file (:component-file ref-shape))
|
||||
shape))
|
||||
shape))
|
||||
|
||||
(update-page [page]
|
||||
(d/update-when page :objects d/update-vals (partial fix-shape page)))]
|
||||
(-> data
|
||||
(update :pages-index d/update-vals update-page))))
|
||||
|
||||
(def available-migrations
|
||||
(into (d/ordered-set)
|
||||
["legacy-2"
|
||||
@@ -1850,4 +1872,6 @@
|
||||
"0014-clear-components-nil-objects"
|
||||
"0015-fix-text-attrs-blank-strings"
|
||||
"0015-clean-shadow-color"
|
||||
"0016-copy-fills-from-position-data-to-text-node"]))
|
||||
"0016-copy-fills-from-position-data-to-text-node"
|
||||
"0017-remove-unneeded-objects-from-components"
|
||||
"0018-sync-component-id-with-near-main"]))
|
||||
|
||||
@@ -333,6 +333,22 @@
|
||||
(pcb/with-file-data file-data)
|
||||
(pcb/update-shapes [(:id shape)] repair-shape))))
|
||||
|
||||
(defmethod repair-error :component-id-mismatch
|
||||
[_ {:keys [shape page-id args] :as error} file-data _]
|
||||
(let [repair-shape
|
||||
(fn [shape]
|
||||
; Set the component-id and component-file to the ones of the near main
|
||||
(log/debug :hint (str " -> set component-id to " (:component-id args)))
|
||||
(log/debug :hint (str " -> set component-file to " (:component-file args)))
|
||||
(assoc shape
|
||||
:component-id (:component-id args)
|
||||
:component-file (:component-file args)))]
|
||||
|
||||
(log/dbg :hint "repairing shape :component-id-mismatch" :id (:id shape) :name (:name shape) :page-id page-id)
|
||||
(-> (pcb/empty-changes nil page-id)
|
||||
(pcb/with-file-data file-data)
|
||||
(pcb/update-shapes [(:id shape)] repair-shape))))
|
||||
|
||||
(defmethod repair-error :ref-shape-is-head
|
||||
[_ {:keys [shape page-id args] :as error} file-data _]
|
||||
(let [repair-shape
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
:ref-shape-is-head
|
||||
:ref-shape-is-not-head
|
||||
:shape-ref-in-main
|
||||
:component-id-mismatch
|
||||
:root-main-not-allowed
|
||||
:nested-main-not-allowed
|
||||
:root-copy-not-allowed
|
||||
@@ -327,6 +328,20 @@
|
||||
:component-file (:component-file ref-shape)
|
||||
:component-id (:component-id ref-shape)))))
|
||||
|
||||
(defn- check-ref-component-id
|
||||
"Validate that if the copy has not been swwpped, the component-id and component-file are
|
||||
the same as in the referenced shape in the near main."
|
||||
[shape file page libraries]
|
||||
(when (nil? (ctk/get-swap-slot shape))
|
||||
(when-let [ref-shape (ctf/find-ref-shape file page libraries shape :include-deleted? true)]
|
||||
(when (or (not= (:component-id shape) (:component-id ref-shape))
|
||||
(not= (:component-file shape) (:component-file ref-shape)))
|
||||
(report-error :component-id-mismatch
|
||||
"Nested copy component-id and component-file must be the same as the near main"
|
||||
shape file page
|
||||
:component-id (:component-id ref-shape)
|
||||
:component-file (:component-file ref-shape))))))
|
||||
|
||||
(defn- check-empty-swap-slot
|
||||
"Validate that this shape does not have any swap slot."
|
||||
[shape file page]
|
||||
@@ -419,6 +434,7 @@
|
||||
(check-component-not-main-head shape file page libraries)
|
||||
(check-component-not-root shape file page)
|
||||
(check-valid-touched shape file page)
|
||||
(check-ref-component-id shape file page libraries)
|
||||
;; We can have situations where the nested copy and the ancestor copy come from different libraries and some of them have been dettached
|
||||
;; so we only validate the shape-ref if the ancestor is from a valid library
|
||||
(when library-exists
|
||||
|
||||
@@ -1769,6 +1769,23 @@
|
||||
(pcb/update-shapes changes [(:id dest-shape)] ctk/unhead-shape {:ignore-touched true})
|
||||
changes))
|
||||
|
||||
(defn- check-swapped-main
|
||||
[changes dest-shape origin-shape]
|
||||
;; Only for direct updates (from main to copy). Check if the main shape
|
||||
;; has been swapped. If so, the new component-id and component-file must
|
||||
;; be put into the copy.
|
||||
(if (and (= (:shape-ref dest-shape) (:id origin-shape))
|
||||
(ctk/instance-head? dest-shape)
|
||||
(ctk/instance-head? origin-shape)
|
||||
(or (not= (:component-id dest-shape) (:component-id origin-shape))
|
||||
(not= (:component-file dest-shape) (:component-file origin-shape))))
|
||||
(pcb/update-shapes changes [(:id dest-shape)]
|
||||
#(assoc %
|
||||
:component-id (:component-id origin-shape)
|
||||
:coponent-file (:component-file origin-shape))
|
||||
{:ignore-touched true})
|
||||
changes))
|
||||
|
||||
(defn- update-attrs
|
||||
"The main function that implements the attribute sync algorithm. Copy
|
||||
attributes that have changed in the origin shape to the dest shape.
|
||||
@@ -1811,6 +1828,8 @@
|
||||
:always
|
||||
(check-detached-main dest-shape origin-shape)
|
||||
:always
|
||||
(check-swapped-main dest-shape origin-shape)
|
||||
:always
|
||||
(generate-update-tokens container dest-shape origin-shape touched omit-touched? nil))
|
||||
|
||||
(let [attr-group (get ctk/sync-attrs attr)
|
||||
|
||||
Reference in New Issue
Block a user