From 4ddd3811b2d1c6174661c2385099498560d5c669 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Thu, 13 Apr 2023 19:23:00 +0200 Subject: [PATCH] :bug: Fix copy and paste components between files --- .../src/app/common/types/components_list.cljc | 10 ++- common/src/app/common/types/file.cljc | 12 ++- frontend/src/app/main/data/workspace.cljs | 13 +-- .../data/workspace/libraries_helpers.cljs | 51 ++++++------ .../app/main/data/workspace/selection.cljs | 80 +++++++++++-------- 5 files changed, 100 insertions(+), 66 deletions(-) diff --git a/common/src/app/common/types/components_list.cljc b/common/src/app/common/types/components_list.cljc index 1a9b40f0b..c9a8292b5 100644 --- a/common/src/app/common/types/components_list.cljc +++ b/common/src/app/common/types/components_list.cljc @@ -61,10 +61,14 @@ (assoc :objects objects))))))) (defn get-component - [file-data component-id] + ([file-data component-id] + (get-component file-data component-id false)) + + ([file-data component-id include-deleted?] (let [component (get-in file-data [:components component-id])] - (when-not (:deleted component) - component))) + (when (or include-deleted? + (not (:deleted component))) + component)))) (defn get-deleted-component [file-data component-id] diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 8632b8563..5886233b7 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -171,6 +171,16 @@ (cph/get-children-with-self (:objects instance-page) (:main-instance-id component))) (vals (:objects component))))) +;; Return true if the object is a component that exists on the file or its libraries (even a deleted one) +(defn is-known-component? + [shape libraries] + (let [main-instance? (ctk/main-instance? shape) + component-id (:component-id shape) + file-id (:component-file shape) + component (ctkl/get-component (dm/get-in libraries [file-id :data]) component-id true)] + (and main-instance? + component))) + (defn load-component-objects "Add an :objects property to the component, with only the shapes that belong to it" [file-data component] @@ -356,7 +366,7 @@ (recur (add-main-instance file-data component position) (rest components-seq) (rest position-seq))))))) - + root-to-board (fn [shape] (cond-> shape diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 65fb4acf1..d33cfbdad 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1649,13 +1649,14 @@ process-shape (fn [_ shape] (-> shape - (assoc :frame-id frame-id) - (assoc :parent-id parent-id) + (assoc :frame-id frame-id :parent-id parent-id) ;; if foreign instance, detach the shape (cond-> (foreign-instance? shape paste-objects state) - (dissoc :component-id :component-file :component-root? - :remote-synced? :shape-ref :touched)) + (-> + (assoc :saved-component-root? (:component-root? shape)) ;; this is used later, if the paste needs to create a new component from the detached shape + (dissoc :component-id :component-file :component-root? + :remote-synced? :shape-ref :touched))) ;; if is a text, remove references to external typographies (cond-> (= (:type shape) :text) (ctt/remove-external-typographies file-id)))) @@ -1666,7 +1667,7 @@ library-data (wsh/get-file state file-id) - changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries library-data) + changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries library-data file-id) (pcb/amend-changes (partial process-rchange media-idx)) (pcb/amend-changes (partial change-add-obj-index paste-objects selected index))) @@ -1927,7 +1928,7 @@ shape-grid (ctst/generate-shape-grid media-points start-pos grid-gap) - + stoper (rx/filter (ptk/type? ::finalize-file) stream)] (rx/concat diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index d6b0c17f7..9761dfc66 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -61,6 +61,33 @@ ;; ---- Components and instances creation ---- +(defn generate-add-component-changes + [changes root objects file-id page-id components-v2] + (let [name (:name root) + [path name] (cph/parse-path-name name) + + [root-shape new-shapes updated-shapes] + (if-not components-v2 + (ctn/make-component-shape root objects file-id components-v2) + (let [new-id (uuid/next)] + [(assoc root :id new-id) + nil + [(assoc root + :component-id new-id + :component-file file-id + :component-root? true + :main-instance? true)]])) + + changes (-> changes + (pcb/add-component (:id root-shape) + path + name + new-shapes + updated-shapes + (:id root) + page-id))] + [root-shape changes])) + (defn generate-add-component "If there is exactly one id, and it's a frame (or a group in v1), and not already a component, use it as root. Otherwise, create a frame (v2) or group (v1) that contains all ids. Then, make a @@ -94,29 +121,7 @@ root-name true)))) - name (:name root) - [path name] (cph/parse-path-name name) - - [root-shape new-shapes updated-shapes] - (if-not components-v2 - (ctn/make-component-shape root objects file-id components-v2) - (let [new-id (uuid/next)] - [(assoc root :id new-id) - nil - [(assoc root - :component-id new-id - :component-file file-id - :component-root? true - :main-instance? true)]])) - - changes (-> changes - (pcb/add-component (:id root-shape) - path - name - new-shapes - updated-shapes - (:id root) - page-id))] + [root-shape changes] (generate-add-component-changes changes root objects file-id page-id components-v2)] [root (:id root-shape) changes])) (defn duplicate-component diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index b8f88f106..a05d46c5c 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -7,6 +7,7 @@ (ns app.main.data.workspace.selection (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.common.math :as mth] @@ -14,7 +15,6 @@ [app.common.pages.changes-builder :as pcb] [app.common.pages.helpers :as cph] [app.common.spec :as us] - [app.common.types.component :as ctk] [app.common.types.file :as ctf] [app.common.types.page :as ctp] [app.common.types.shape.interactions :as ctsi] @@ -333,14 +333,14 @@ (defn prepare-duplicate-changes "Prepare objects to duplicate: generate new id, give them unique names, move to the desired position, and recalculate parents and frames as needed." - ([all-objects page ids delta it libraries library-data] + ([all-objects page ids delta it libraries library-data file-id] (let [init-changes (-> (pcb/empty-changes it) (pcb/with-page page) (pcb/with-objects all-objects))] - (prepare-duplicate-changes all-objects page ids delta it libraries library-data init-changes))) + (prepare-duplicate-changes all-objects page ids delta it libraries library-data file-id init-changes))) - ([all-objects page ids delta it libraries library-data init-changes] + ([all-objects page ids delta it libraries library-data file-id init-changes] (let [shapes (map (d/getf all-objects) ids) unames (volatile! (cp/retrieve-used-names (:objects page))) update-unames! (fn [new-name] (vswap! unames conj new-name)) @@ -359,7 +359,8 @@ delta libraries library-data - it) + it + file-id) init-changes))] (-> changes @@ -367,42 +368,42 @@ (prepare-duplicate-guides shapes page ids-map delta))))) (defn- prepare-duplicate-component-change - ([changes page component-root delta libraries library-data it] - (let [component-id (:component-id component-root) - file-id (:component-file component-root) - main-component (ctf/get-component libraries file-id component-id) - moved-component (gsh/move component-root delta) - pos (gpt/point (:x moved-component) (:y moved-component)) + [changes page component-root delta libraries library-data it] + (let [component-id (:component-id component-root) + file-id (:component-file component-root) + main-component (ctf/get-component libraries file-id component-id) + moved-component (gsh/move component-root delta) + pos (gpt/point (:x moved-component) (:y moved-component)) - instantiate-component - #(dwlh/generate-instantiate-component changes - file-id - (:component-id component-root) - pos - page - libraries - (:id component-root)) + instantiate-component + #(dwlh/generate-instantiate-component changes + file-id + (:component-id component-root) + pos + page + libraries + (:id component-root)) - restore-component - #(let [restore (dwlh/prepare-restore-component library-data (:component-id component-root) it page delta (:id component-root) changes)] - [(:shape restore) (:changes restore)]) + restore-component + #(let [restore (dwlh/prepare-restore-component library-data (:component-id component-root) it page delta (:id component-root) changes)] + [(:shape restore) (:changes restore)]) - [_shape changes] - (if (nil? main-component) - (restore-component) - (instantiate-component))] - changes))) + [_shape changes] + (if (nil? main-component) + (restore-component) + (instantiate-component))] + changes)) (defn- prepare-duplicate-shape-change - ([changes objects page unames update-unames! ids-map obj delta libraries library-data it] - (prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it (:frame-id obj) (:parent-id obj))) + ([changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id] + (prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id (:frame-id obj) (:parent-id obj))) - ([changes objects page unames update-unames! ids-map obj delta libraries library-data it frame-id parent-id] + ([changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id frame-id parent-id] (cond (nil? obj) changes - (ctk/main-instance? obj) + (ctf/is-known-component? obj libraries) (prepare-duplicate-component-change changes page obj delta libraries library-data it) :else @@ -411,6 +412,14 @@ parent-id (or parent-id frame-id) name (:name obj) + is-component-root? (:saved-component-root? obj) + is-component-main? (:main-instance? obj) + regenerate-component + (fn [changes shape] + (let [components-v2 (dm/get-in library-data [:options :components-v2]) + [_ changes] (dwlh/generate-add-component-changes changes shape objects file-id (:id page) components-v2)] + changes)) + new-obj (-> obj (assoc :id new-id :name name @@ -423,7 +432,11 @@ (d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))) changes (-> (pcb/add-object changes new-obj {:ignore-touched true}) - (pcb/amend-last-change #(assoc % :old-id (:id obj))))] + (pcb/amend-last-change #(assoc % :old-id (:id obj)))) + + changes (cond-> changes + (and is-component-root? is-component-main?) + (regenerate-component new-obj))] (reduce (fn [changes child] (prepare-duplicate-shape-change changes @@ -437,6 +450,7 @@ libraries library-data it + file-id (if frame? new-id frame-id) new-id)) changes @@ -593,7 +607,7 @@ libraries (wsh/get-libraries state) library-data (wsh/get-file state file-id) - changes (->> (prepare-duplicate-changes objects page selected delta it libraries library-data) + changes (->> (prepare-duplicate-changes objects page selected delta it libraries library-data file-id) (duplicate-changes-update-indices objects selected)) tags (or (:tags changes) #{})