diff --git a/backend/src/app/loggers/database.clj b/backend/src/app/loggers/database.clj index 196845a967..d15d5704f1 100644 --- a/backend/src/app/loggers/database.clj +++ b/backend/src/app/loggers/database.clj @@ -41,7 +41,7 @@ (if (or (instance? java.util.concurrent.CompletionException cause) (instance? java.util.concurrent.ExecutionException cause)) (-> record - (assoc ::trace (ex/format-throwable cause :data? false :explain? false :header? false :summary? false)) + (assoc ::trace (ex/format-throwable cause :data? true :explain? false :header? false :summary? false)) (assoc ::l/cause (ex-cause cause)) (record->report)) @@ -64,18 +64,18 @@ message)) @message) :trace (or (::trace record) - (some-> cause (ex/format-throwable :data? false :explain? false :header? false :summary? false)))} + (some-> cause (ex/format-throwable :data? true :explain? false :header? false :summary? false)))} (when-let [params (or (:request/params context) (:params context))] - {:params (pp/pprint-str params :length 30 :level 13)}) + {:params (pp/pprint-str params :length 20 :level 15)}) (when-let [value (:value context)] - {:value (pp/pprint-str value :length 30 :level 12)}) + {:value (pp/pprint-str value :length 30 :level 13)}) (when-let [data (some-> data (dissoc ::s/problems ::s/value ::s/spec ::sm/explain :hint))] - {:data (pp/pprint-str data :length 30 :level 12)}) + {:data (pp/pprint-str data :length 30 :level 13)}) - (when-let [explain (ex/explain data :length 30 :level 12)] + (when-let [explain (ex/explain data :length 30 :level 13)] {:explain explain}))))) (defn error-record? diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 83140780fd..16a53e8b5b 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -559,6 +559,8 @@ f.project_id, f.created_at, f.modified_at, + f.data_backend, + f.data_ref_id, f.name, f.version, f.is_shared, diff --git a/common/src/app/common/exceptions.cljc b/common/src/app/common/exceptions.cljc index 5cceeb7222..4bb36461ea 100644 --- a/common/src/app/common/exceptions.cljc +++ b/common/src/app/common/exceptions.cljc @@ -47,10 +47,26 @@ `(try ~@exprs (catch Throwable e# nil)))) (defmacro try! - [& exprs] - (if (:ns &env) - `(try ~@exprs (catch :default e# e#)) - `(try ~@exprs (catch Throwable e# e#)))) + [expr & {:keys [reraise-with on-exception]}] + (let [ex-sym + (gensym "exc") + + generate-catch + (fn [] + (cond + (map? reraise-with) + `(ex/raise ~@(mapcat identity reraise-with) :cause ~ex-sym) + + on-exception + `(let [handler# ~on-exception] + (handler# ~ex-sym)) + + :else + ex-sym))] + + (if (:ns &env) + `(try ~expr (catch :default ~ex-sym ~(generate-catch))) + `(try ~expr (catch Throwable ~ex-sym ~(generate-catch)))))) (defn ex-info? [v] diff --git a/common/src/app/common/files/changes.cljc b/common/src/app/common/files/changes.cljc index 0b8abb0463..278f4eb15a 100644 --- a/common/src/app/common/files/changes.cljc +++ b/common/src/app/common/files/changes.cljc @@ -487,7 +487,9 @@ (cts/shape? shape-new)) (ex/raise :type :assertion :code :data-validation - :hint "invalid shape found after applying changes" + :hint (str "invalid shape found after applying changes on file " + (:id data-new)) + :file-id (:id data-new) ::sm/explain (cts/explain-shape shape-new))))))] (->> (into #{} (map :page-id) items) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 8255fd18d5..3165d0a28b 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1320,18 +1320,35 @@ (d/update-when :components d/update-vals update-container) (d/without-nils)))) -(defmethod migrate-data "0003-convert-path-content" +(defmethod migrate-data "0003-convert-path-content-v2" [data _] (some-> cfeat/*new* (swap! conj "fdata/path-data")) - (letfn [(update-object [object] - (if (or (cfh/bool-shape? object) - (cfh/path-shape? object)) - (update object :content path/content) - object)) + (let [decode-segments + (sm/decoder path/schema:segments sm/json-transformer) - (update-container [container] - (d/update-when container :objects d/update-vals update-object))] + update-object + (fn [object] + (if (or (cfh/bool-shape? object) + (cfh/path-shape? object)) + (let [content (get object :content) + content (cond + (path/content? content) + content + + (nil? content) + (path/content []) + + :else + (-> content + (decode-segments) + (path/content)))] + (assoc object :content content)) + object)) + + update-container + (fn [container] + (d/update-when container :objects d/update-vals update-object))] (-> data (update :pages-index d/update-vals update-container) @@ -1584,7 +1601,7 @@ "0002-normalize-bool-content-v2" "0002-clean-shape-interactions" "0003-fix-root-shape" - "0003-convert-path-content" + "0003-convert-path-content-v2" "0004-clean-shadow-color" "0005-deprecate-image-type" "0006-fix-old-texts-fills" diff --git a/common/src/app/common/types/path.cljc b/common/src/app/common/types/path.cljc index 65336fe2d5..bcfa323c82 100644 --- a/common/src/app/common/types/path.cljc +++ b/common/src/app/common/types/path.cljc @@ -8,6 +8,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.exceptions :as ex] [app.common.files.helpers :as cpf] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] @@ -26,6 +27,9 @@ (def ^:const bool-style-properties bool/style-properties) (def ^:const default-bool-fills bool/default-fills) +(def schema:content impl/schema:content) +(def schema:segments impl/schema:segments) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TRANSFORMATIONS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -48,9 +52,9 @@ [data] (impl/from-string data)) -(defn check-path-content +(defn check-content [content] - (impl/check-content-like content)) + (impl/check-content content)) (defn get-byte-size "Get byte size of a path content" @@ -76,7 +80,7 @@ (defn apply-content-modifiers "Apply delta modifiers over the path content" [content modifiers] - (assert (impl/check-content-like content)) + (assert (impl/check-content content)) (letfn [(apply-to-index [content [index params]] (if (contains? content index) @@ -202,8 +206,18 @@ "Calculate the boolean content from shape and objects. Returns a packed PathData instance" [shape objects] - (-> (calc-bool-content* shape objects) - (impl/path-data))) + (ex/try! + (-> (calc-bool-content* shape objects) + (impl/path-data)) + + :on-exception + (fn [cause] + (ex/raise :type :internal + :code :invalid-path-content + :hint (str "unable to create bool content for shape " (:id shape)) + :content (str (:content shape)) + :shape-id (:id shape) + :cause cause)))) (defn update-bool-shape "Calculates the selrect+points for the boolean shape" diff --git a/common/src/app/common/types/path/bool.cljc b/common/src/app/common/types/path/bool.cljc index 9be2c5a792..af9be976b2 100644 --- a/common/src/app/common/types/path/bool.cljc +++ b/common/src/app/common/types/path/bool.cljc @@ -412,7 +412,7 @@ (defn calculate-content "Create a bool content from a collection of contents and specified - type." + type. Returns plain segments" [bool-type contents] ;; We apply the boolean operation in to each pair and the result to the next ;; element diff --git a/common/src/app/common/types/path/impl.cljc b/common/src/app/common/types/path/impl.cljc index bc948d9f5c..5ec185f1a4 100644 --- a/common/src/app/common/types/path/impl.cljc +++ b/common/src/app/common/types/path/impl.cljc @@ -507,18 +507,6 @@ (= (:command e1) :move-to))))} schema:segment]) -(def schema:content-like - [:sequential schema:segment]) - -(def check-content-like - (sm/check-fn schema:content-like)) - -(def check-segment - (sm/check-fn schema:segment)) - -(def ^:private check-segments - (sm/check-fn schema:segments)) - (defn path-data? [o] (instance? PathData o)) @@ -526,37 +514,40 @@ (declare from-string) (declare from-plain) -;; Mainly used on backend: features/components_v2.clj -(sm/register! ::path/segment schema:segment) -(sm/register! ::path/segments schema:segments) +(def schema:content + (sm/type-schema + {:type ::path/content + :compile + (fn [_ _ _] + (let [decoder (delay (sm/decoder schema:segments sm/json-transformer)) + generator (->> (sg/generator schema:segments) + (sg/filter not-empty) + (sg/fmap from-plain))] + {:pred path-data? + :type-properties + {:gen/gen generator + :encode/json identity + :decode/json (fn [s] + (cond + (string? s) + (from-string s) -(sm/register! - {:type ::path/content - :compile - (fn [_ _ _] - (let [decoder (delay (sm/decoder schema:segments sm/json-transformer)) - generator (->> (sg/generator schema:segments) - (sg/filter not-empty) - (sg/fmap from-plain))] - {:pred path-data? - :type-properties - {:gen/gen generator - :encode/json identity - :decode/json (fn [s] - (cond - (string? s) - (from-string s) + (vector? s) + (let [decode-fn (deref decoder)] + (-> (decode-fn s) + (from-plain))) - (vector? s) - (let [decode-fn (deref decoder)] - (-> (decode-fn s) - (from-plain))) + :else + s))}}))})) - :else - s))}}))}) +(def check-plain-content + (sm/check-fn schema:segments)) -(def check-path-content - (sm/check-fn ::path/content)) +(def check-segment + (sm/check-fn schema:segment)) + +(def check-content + (sm/check-fn schema:content)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; CONSTRUCTORS & PREDICATES @@ -617,7 +608,7 @@ (defn from-plain "Create a PathData instance from plain data structures" [segments] - (assert (check-segments segments)) + (assert (check-plain-content segments)) (let [total (count segments) buffer (buf/allocate (* total SEGMENT-BYTE-SIZE))] diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index ed0ba5ae3a..9f3b055c2a 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -246,7 +246,7 @@ [:map {:title "BoolAttrs"} [:shapes [:vector {:gen/max 10 :gen/min 1} ::sm/uuid]] [:bool-type [::sm/one-of bool-types]] - [:content ::path/content]]) + [:content path/schema:content]]) (def ^:private schema:rect-attrs [:map {:title "RectAttrs"}]) @@ -271,7 +271,7 @@ (def ^:private schema:path-attrs [:map {:title "PathAttrs"} - [:content ::path/content]]) + [:content path/schema:content]]) (def ^:private schema:text-attrs [:map {:title "TextAttrs"} diff --git a/common/test/common_tests/types/shape_decode_encode_test.cljc b/common/test/common_tests/types/shape_decode_encode_test.cljc index 6098f82e17..1c5d2be0e8 100644 --- a/common/test/common_tests/types/shape_decode_encode_test.cljc +++ b/common/test/common_tests/types/shape_decode_encode_test.cljc @@ -113,10 +113,10 @@ {:num 500}))) (t/deftest shape-path-content-json-roundtrip - (let [encode (sm/encoder ::path/content (sm/json-transformer)) - decode (sm/decoder ::path/content (sm/json-transformer))] + (let [encode (sm/encoder path/schema:content (sm/json-transformer)) + decode (sm/decoder path/schema:content (sm/json-transformer))] (smt/check! - (smt/for [path-content (sg/generator ::path/content)] + (smt/for [path-content (sg/generator path/schema:content)] (let [path-content-1 (encode path-content) path-content-2 (json-roundtrip path-content-1) path-content-3 (decode path-content-2)] diff --git a/frontend/src/app/main/data/plugins.cljs b/frontend/src/app/main/data/plugins.cljs index 8f423cdc4e..f45bb6cb6c 100644 --- a/frontend/src/app/main/data/plugins.cljs +++ b/frontend/src/app/main/data/plugins.cljs @@ -9,6 +9,7 @@ [app.common.data.macros :as dm] [app.common.files.changes-builder :as pcb] [app.main.data.changes :as dch] + [app.main.data.event :as ev] [app.main.data.modal :as modal] [app.main.data.notifications :as ntf] [app.main.store :as st] @@ -144,8 +145,13 @@ (watch [_ state _] (let [user-can-edit? (dm/get-in state [:permissions :can-edit])] (when-let [pid (::open-plugin state)] - (open-plugin! (preg/get-plugin pid) user-can-edit?) - (rx/of #(dissoc % ::open-plugin))))))) + (let [plugin (preg/get-plugin pid)] + (open-plugin! plugin user-can-edit?) + (rx/of (ev/event {::ev/name "start-plugin" + ::ev/origin "workspace" + :name (:name plugin) + :host (:host plugin)}) + #(dissoc % ::open-plugin)))))))) (defn- update-plugin-permissions-peek [{:keys [plugin-id url]}] diff --git a/frontend/src/app/main/data/workspace/clipboard.cljs b/frontend/src/app/main/data/workspace/clipboard.cljs index 448b8658ca..39efb0e616 100644 --- a/frontend/src/app/main/data/workspace/clipboard.cljs +++ b/frontend/src/app/main/data/workspace/clipboard.cljs @@ -909,16 +909,17 @@ (ev/event {::ev/name "use-library-component" ::ev/origin origin :is-external-library external-lib? - :parent-shape-type parent-type}) + :type (get shape :type) + :parent-type parent-type}) (if (cfh/has-layout? objects (:parent-id shape)) (ev/event {::ev/name "layout-add-element" ::ev/origin origin - :element-type (get shape :type) + :type (get shape :type) :parent-type parent-type}) (ev/event {::ev/name "create-shape" ::ev/origin origin - :shape-type (get shape :type) - :parent-shape-type parent-type}))))))) + :type (get shape :type) + :parent-type parent-type}))))))) (rx/of (dwu/start-undo-transaction undo-id) (dch/commit-changes changes) diff --git a/frontend/src/app/main/data/workspace/path/changes.cljs b/frontend/src/app/main/data/workspace/path/changes.cljs index eb032c68d7..d766487e7e 100644 --- a/frontend/src/app/main/data/workspace/path/changes.cljs +++ b/frontend/src/app/main/data/workspace/path/changes.cljs @@ -19,8 +19,8 @@ "Generates changes to update the new content of the shape" [it objects page-id shape old-content new-content] - (assert (path/check-path-content old-content)) - (assert (path/check-path-content new-content)) + (assert (path/content? old-content)) + (assert (path/content? new-content)) (let [shape-id (:id shape) diff --git a/frontend/src/app/main/data/workspace/path/drawing.cljs b/frontend/src/app/main/data/workspace/path/drawing.cljs index eab307ff44..ceb9a8872f 100644 --- a/frontend/src/app/main/data/workspace/path/drawing.cljs +++ b/frontend/src/app/main/data/workspace/path/drawing.cljs @@ -305,7 +305,7 @@ ptk/UpdateEvent (update [_ state] (let [content (some-> (dm/get-in state [:workspace-drawing :object :content]) - (path/check-path-content))] + (path/check-content))] (if (> (count content) 1) (assoc-in state [:workspace-drawing :object :initialized?] true) state))) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index 884f2e85d3..0ead5fd13d 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -493,16 +493,17 @@ (ev/event {::ev/name "use-library-component" ::ev/origin origin :is-external-library external-lib? - :parent-shape-type parent-type}) + :type (get shape :type) + :parent-type parent-type}) (if (cfh/has-layout? objects (:parent-id shape)) (ev/event {::ev/name "layout-add-element" ::ev/origin origin - :element-type (get shape :type) + :type (get shape :type) :parent-type parent-type}) (ev/event {::ev/name "create-shape" ::ev/origin origin - :shape-type (get shape :type) - :parent-shape-type parent-type}))))))) + :type (get shape :type) + :parent-type parent-type}))))))) ;; Warning: This order is important for the focus mode. (->> (rx/of diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index f755a3eb22..ad2bd88379 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -129,7 +129,10 @@ (pcb/set-undo-group (:id shape))) undo-id - (js/Symbol)] + (js/Symbol) + + parent-type + (cfh/get-shape-type objects (:parent-id shape))] (rx/concat (rx/of (dwu/start-undo-transaction undo-id) @@ -146,12 +149,13 @@ (rx/of (ev/event {::ev/name "create-shape" ::ev/origin "workspace:add-shape" :type (get shape :type) - :parent-type (cfh/get-shape-type objects (:parent-id shape))})) + :parent-type parent-type})) (when (cfh/has-layout? objects (:parent-id shape)) (rx/of (ev/event {::ev/name "layout-add-element" ::ev/origin "workspace:add-shape" - :element-type (get shape :type)}))))))))) + :type (get shape :type) + :parent-type parent-type}))))))))) (defn move-shapes-into-frame [frame-id shapes]