From 243e29fdb45e1b7f8d15e6dde7da655ba42cf3db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 30 Sep 2022 14:24:18 +0200 Subject: [PATCH] :bug: Fix delete component from assets panel in v2 --- .../app/main/data/workspace/libraries.cljs | 24 +- .../data/workspace/libraries_helpers.cljs | 49 ++-- .../src/app/main/data/workspace/shapes.cljs | 241 +++++++++--------- 3 files changed, 167 insertions(+), 147 deletions(-) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 3888a2e80..9729dd89a 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -16,6 +16,7 @@ [app.common.pages.helpers :as cph] [app.common.spec :as us] [app.common.types.color :as ctc] + [app.common.types.components-list :as ctkl] [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.types.pages-list :as ctpl] @@ -29,6 +30,7 @@ [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.libraries-helpers :as dwlh] [app.main.data.workspace.selection :as dws] + [app.main.data.workspace.shapes :as dwsh] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] @@ -402,13 +404,16 @@ (ptk/reify ::delete-component ptk/WatchEvent (watch [it state _] - (let [data (get state :workspace-data) - components-v2 (features/active-feature? state :components-v2) - changes (-> (pcb/empty-changes it) - (pcb/with-library-data data) - (pcb/delete-component id components-v2))] - - (rx/of (dch/commit-changes changes)))))) + (let [data (get state :workspace-data)] + (if (features/active-feature? state :components-v2) + (let [component (ctkl/get-component data id) + page (ctpl/get-page data (:main-instance-page component)) + shape (ctn/get-shape page (:main-instance-id component))] + (rx/of (dwsh/delete-shapes (:id page) #{(:id shape)}))) + (let [changes (-> (pcb/empty-changes it) + (pcb/with-library-data data) + (pcb/delete-component id false))] + (rx/of (dch/commit-changes changes)))))))) (defn restore-component "Restore a deleted component, with the given id, on the current file library." @@ -554,11 +559,14 @@ page-id (:current-page-id state) container (cph/get-container file :page page-id) + components-v2 + (features/active-feature? state :components-v2) + changes (-> (pcb/empty-changes it) (pcb/with-container container) (pcb/with-objects (:objects container)) - (dwlh/generate-sync-shape-direct libraries container id true))] + (dwlh/generate-sync-shape-direct libraries container id true components-v2))] (log/debug :msg "RESET-COMPONENT finished" :js/rchanges (log-changes (:redo-changes changes) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 2702226f3..58326c740 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -177,7 +177,8 @@ :file (pretty-file file-id state) :library (pretty-file library-id state)) - (let [file (wsh/get-file state file-id)] + (let [file (wsh/get-file state file-id) + components-v2 (get-in file [:options :components-v2])] (loop [pages (vals (get file :pages-index)) changes (pcb/empty-changes it)] (if-let [page (first pages)] @@ -189,7 +190,8 @@ asset-id library-id state - (cph/make-container page :page)))) + (cph/make-container page :page) + components-v2))) changes)))) (defn generate-sync-library @@ -198,7 +200,7 @@ the given library. If an asset id is given, only shapes linked to this particular asset will - be syncrhonized." + be synchronized." [it file-id asset-type asset-id library-id state] (s/assert #{:colors :components :typographies} asset-type) (s/assert (s/nilable ::us/uuid) asset-id) @@ -211,7 +213,8 @@ :file (pretty-file file-id state) :library (pretty-file library-id state)) - (let [file (wsh/get-file state file-id)] + (let [file (wsh/get-file state file-id) + components-v2 (get-in file [:options :components-v2])] (loop [local-components (vals (get file :components)) changes (pcb/empty-changes it)] (if-let [local-component (first local-components)] @@ -223,13 +226,14 @@ asset-id library-id state - (cph/make-container local-component :component)))) + (cph/make-container local-component :component) + components-v2))) changes)))) (defn- generate-sync-container "Generate changes to synchronize all shapes in a particular container (a page or a component) that use assets of the given type in the given library." - [it asset-type asset-id library-id state container] + [it asset-type asset-id library-id state container components-v2] (if (cph/page? container) (log/debug :msg "Sync page in local file" :page-id (:id container)) @@ -248,7 +252,8 @@ library-id state container - shape)) + shape + components-v2)) changes)))) (defmulti uses-assets? @@ -276,16 +281,16 @@ (defmulti generate-sync-shape "Generate changes to synchronize one shape from all assets of the given type that is using, in the given library." - (fn [asset-type _changes _library-id _state _container _shape] asset-type)) + (fn [asset-type _changes _library-id _state _container _shape _components-v2] asset-type)) (defmethod generate-sync-shape :components - [_ changes _library-id state container shape] + [_ changes _library-id state container shape components-v2] (let [shape-id (:id shape) libraries (wsh/get-libraries state)] - (generate-sync-shape-direct changes libraries container shape-id false))) + (generate-sync-shape-direct changes libraries container shape-id false components-v2))) (defmethod generate-sync-shape :colors - [_ changes library-id state _ shape] + [_ changes library-id state _ shape _] (log/debug :msg "Sync colors of shape" :shape (:name shape)) ;; Synchronize a shape that uses some colors of the library. The value of the @@ -296,7 +301,7 @@ #(ctc/sync-shape-colors % library-id library-colors)))) (defmethod generate-sync-shape :typographies - [_ changes library-id state container shape] + [_ changes library-id state container shape _] (log/debug :msg "Sync typographies of shape" :shape (:name shape)) ;; Synchronize a shape that uses some typographies of the library. The attributes @@ -442,7 +447,7 @@ (defn generate-sync-shape-direct "Generate changes to synchronize one shape that the root of a component instance, and all its children, from the given component." - [changes libraries container shape-id reset?] + [changes libraries container shape-id reset? components-v2] (log/debug :msg "Sync shape direct" :shape (str shape-id) :reset? reset?) (let [shape-inst (ctn/get-shape container shape-id) component (cph/get-component libraries @@ -466,20 +471,25 @@ root-inst root-main reset? - initial-root?) + initial-root? + components-v2) ; If the component is not found, because the master component has been - ; deleted or the library unlinked, detach the instance. - (generate-detach-instance changes container shape-id)))) + ; deleted or the library unlinked, do nothing in v2 or detach in v1. + (if components-v2 + changes + (generate-detach-instance changes container shape-id))))) (defn- generate-sync-shape-direct-recursive - [changes container shape-inst component shape-main root-inst root-main reset? initial-root?] + [changes container shape-inst component shape-main root-inst root-main reset? initial-root? components-v2] (log/debug :msg "Sync shape direct recursive" :shape (str (:name shape-inst)) :component (:name component)) (if (nil? shape-main) ;; This should not occur, but protect against it in any case - (generate-detach-instance changes container (:id shape-inst)) + (if components-v2 + changes + (generate-detach-instance changes container (:id shape-inst))) (let [omit-touched? (not reset?) clear-remote-synced? (and initial-root? reset?) set-remote-synced? (and (not initial-root?) reset?) @@ -545,7 +555,8 @@ root-inst root-main reset? - initial-root?)) + initial-root? + components-v2)) moved (fn [changes child-inst child-main] (move-shape diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index abeafaf67..e7c8e6705 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -131,141 +131,142 @@ (rx/empty)))))) (defn delete-shapes - [ids] - (us/assert ::us/set-of-uuid ids) - (ptk/reify ::delete-shapes - ptk/WatchEvent - (watch [it state _] - (let [file-id (:current-file-id state) - page-id (:current-page-id state) - file (wsh/get-file state file-id) - page (wsh/lookup-page state page-id) - objects (wsh/lookup-page-objects state page-id) + ([ids] (delete-shapes nil ids)) + ([page-id ids] + (us/assert ::us/set-of-uuid ids) + (ptk/reify ::delete-shapes + ptk/WatchEvent + (watch [it state _] + (let [file-id (:current-file-id state) + page-id (or page-id (:current-page-id state)) + file (wsh/get-file state file-id) + page (wsh/lookup-page state page-id) + objects (wsh/lookup-page-objects state page-id) - ids (cph/clean-loops objects ids) - lookup (d/getf objects) + ids (cph/clean-loops objects ids) + lookup (d/getf objects) - components-v2 (features/active-feature? state :components-v2) + components-v2 (features/active-feature? state :components-v2) - groups-to-unmask - (reduce (fn [group-ids id] - ;; When the shape to delete is the mask of a masked group, - ;; the mask condition must be removed, and it must be - ;; converted to a normal group. - (let [obj (lookup id) - parent (lookup (:parent-id obj))] - (if (and (:masked-group? parent) - (= id (first (:shapes parent)))) - (conj group-ids (:id parent)) - group-ids))) - #{} - ids) + groups-to-unmask + (reduce (fn [group-ids id] + ;; When the shape to delete is the mask of a masked group, + ;; the mask condition must be removed, and it must be + ;; converted to a normal group. + (let [obj (lookup id) + parent (lookup (:parent-id obj))] + (if (and (:masked-group? parent) + (= id (first (:shapes parent)))) + (conj group-ids (:id parent)) + group-ids))) + #{} + ids) - interacting-shapes - (filter (fn [shape] - ;; If any of the deleted shapes is the destination of - ;; some interaction, this must be deleted, too. - (let [interactions (:interactions shape)] - (some #(and (ctsi/has-destination %) - (contains? ids (:destination %))) - interactions))) - (vals objects)) + interacting-shapes + (filter (fn [shape] + ;; If any of the deleted shapes is the destination of + ;; some interaction, this must be deleted, too. + (let [interactions (:interactions shape)] + (some #(and (ctsi/has-destination %) + (contains? ids (:destination %))) + interactions))) + (vals objects)) - ;; If any of the deleted shapes is a frame with guides - guides (into {} - (comp (map second) - (remove #(contains? ids (:frame-id %))) - (map (juxt :id identity))) - (dm/get-in page [:options :guides])) + ;; If any of the deleted shapes is a frame with guides + guides (into {} + (comp (map second) + (remove #(contains? ids (:frame-id %))) + (map (juxt :id identity))) + (dm/get-in page [:options :guides])) - starting-flows - (filter (fn [flow] - ;; If any of the deleted is a frame that starts a flow, - ;; this must be deleted, too. - (contains? ids (:starting-frame flow))) - (-> page :options :flows)) + starting-flows + (filter (fn [flow] + ;; If any of the deleted is a frame that starts a flow, + ;; this must be deleted, too. + (contains? ids (:starting-frame flow))) + (-> page :options :flows)) - all-parents - (reduce (fn [res id] - ;; All parents of any deleted shape must be resized. - (into res (cph/get-parent-ids objects id))) - (d/ordered-set) - ids) + all-parents + (reduce (fn [res id] + ;; All parents of any deleted shape must be resized. + (into res (cph/get-parent-ids objects id))) + (d/ordered-set) + ids) - all-children - (->> ids ;; Children of deleted shapes must be also deleted. - (reduce (fn [res id] - (into res (cph/get-children-ids objects id))) - []) - (reverse) - (into (d/ordered-set))) + all-children + (->> ids ;; Children of deleted shapes must be also deleted. + (reduce (fn [res id] + (into res (cph/get-children-ids objects id))) + []) + (reverse) + (into (d/ordered-set))) - 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 cph/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)))) + 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 cph/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 parent whose children are all deleted, must be deleted too. - (into (d/ordered-set) (find-all-empty-parents #{})) + empty-parents + ;; Any parent whose children are all deleted, must be deleted too. + (into (d/ordered-set) (find-all-empty-parents #{})) - components-to-delete - (if components-v2 - (reduce (fn [components id] - (let [shape (get objects id)] - (if (and (= (:component-file shape) file-id) ;; Main instances should exist only in local file - (:main-instance? shape)) ;; but check anyway - (conj components (:component-id shape)) - components))) - [] - (into ids all-children)) - []) + components-to-delete + (if components-v2 + (reduce (fn [components id] + (let [shape (get objects id)] + (if (and (= (:component-file shape) file-id) ;; Main instances should exist only in local file + (:main-instance? shape)) ;; but check anyway + (conj components (:component-id shape)) + components))) + [] + (into ids all-children)) + []) - changes (-> (pcb/empty-changes it page-id) - (pcb/with-page page) - (pcb/with-objects objects) - (pcb/with-library-data file) - (pcb/set-page-option :guides guides)) + changes (-> (pcb/empty-changes it page-id) + (pcb/with-page page) + (pcb/with-objects objects) + (pcb/with-library-data file) + (pcb/set-page-option :guides guides)) - changes (reduce (fn [changes component-id] - ;; It's important to delete the component before the main instance, because we - ;; need to store the instance position if we want to restore it later. - (pcb/delete-component changes component-id components-v2)) - changes - components-to-delete) + changes (reduce (fn [changes component-id] + ;; It's important to delete the component before the main instance, because we + ;; need to store the instance position if we want to restore it later. + (pcb/delete-component changes component-id components-v2)) + changes + components-to-delete) - changes (-> changes - (pcb/remove-objects all-children) - (pcb/remove-objects ids) - (pcb/remove-objects empty-parents) - (pcb/resize-parents all-parents) - (pcb/update-shapes groups-to-unmask - (fn [shape] - (assoc shape :masked-group? false))) - (pcb/update-shapes (map :id interacting-shapes) - (fn [shape] - (d/update-when shape :interactions - (fn [interactions] - (into [] - (remove #(and (ctsi/has-destination %) - (contains? ids (:destination %)))) - interactions))))) - (cond-> (seq starting-flows) - (pcb/update-page-option :flows (fn [flows] - (->> (map :id starting-flows) - (reduce ctp/remove-flow flows))))))] + changes (-> changes + (pcb/remove-objects all-children) + (pcb/remove-objects ids) + (pcb/remove-objects empty-parents) + (pcb/resize-parents all-parents) + (pcb/update-shapes groups-to-unmask + (fn [shape] + (assoc shape :masked-group? false))) + (pcb/update-shapes (map :id interacting-shapes) + (fn [shape] + (d/update-when shape :interactions + (fn [interactions] + (into [] + (remove #(and (ctsi/has-destination %) + (contains? ids (:destination %)))) + interactions))))) + (cond-> (seq starting-flows) + (pcb/update-page-option :flows (fn [flows] + (->> (map :id starting-flows) + (reduce ctp/remove-flow flows))))))] - (rx/of (dc/detach-comment-thread ids) - (dwsl/update-layout-positions all-parents) - (dch/commit-changes changes)))))) + (rx/of (dc/detach-comment-thread ids) + (dwsl/update-layout-positions all-parents) + (dch/commit-changes changes))))))) (defn- viewport-center [state]