From 89153eef23f9b9ee20d6790a47708e79ac079f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=BAelhombretecla?= Date: Thu, 10 Apr 2025 10:01:52 +0200 Subject: [PATCH 01/38] :tada: Increase height presets dropdown (#6185) * :tada: Add new measures dropdown height * :tada: Add enhancement to CHANGES.md --- CHANGES.md | 7 +++++++ .../main/ui/workspace/sidebar/options/menus/measures.scss | 1 + 2 files changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index ff6096035c..a53d83f05a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.6.2 + +### :bug: Bugs fixed + +- Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615) + ## 2.6.1 ### :bug: Bugs fixed @@ -58,6 +64,7 @@ - Add character limitation to asset inputs [Taiga #10669](https://tree.taiga.io/project/penpot/issue/10669) - Fix Storybook link 'list of all available icons' wrong path [Taiga #10705](https://tree.taiga.io/project/penpot/issue/10705) + ## 2.5.4 ### :heart: Community contributions (Thank you!) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss index 2660148083..22d3b7914b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.scss @@ -55,6 +55,7 @@ .custom-select-dropdown { @extend .dropdown-wrapper; margin-top: $s-2; + max-height: 70vh; width: $s-252; .dropdown-element { @extend .dropdown-element-base; From e5db66351ecf1329473ab2cff41661ea27c38c73 Mon Sep 17 00:00:00 2001 From: Eva Marco Date: Thu, 10 Apr 2025 10:25:08 +0200 Subject: [PATCH 02/38] :bug: Fix scroll on token themes modal (#6251) * :bug: Fix scroll on token themes modal * :bug: Fix collapse set group error --- CHANGES.md | 1 + frontend/src/app/main/ui/workspace/tokens/modals/themes.scss | 1 + frontend/src/app/main/ui/workspace/tokens/sets.cljs | 1 + 3 files changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index a53d83f05a..ec306c8829 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ ### :bug: Bugs fixed - Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615) +- Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745) ## 2.6.1 diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss index 9277b720be..f7e15d6abc 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.scss @@ -190,6 +190,7 @@ border: $s-1 solid color-mix(in hsl, var(--color-foreground-secondary) 30%, transparent); border-radius: $s-8; overflow-y: auto; + max-height: $s-452; } .sets-count-empty-button { diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs index dc8f5364dc..94dff84af1 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs @@ -171,6 +171,7 @@ on-collapse-click (mf/use-fn (fn [event] + (dom/prevent-default event) (dom/stop-propagation event) (on-toggle-collapse tree-path))) From e9755d437e9d4edf905be5f4f66ca1c88666d1ef Mon Sep 17 00:00:00 2001 From: Florian Schroedl Date: Thu, 10 Apr 2025 10:31:01 +0200 Subject: [PATCH 03/38] :bug: Fix sets and set groups with same name cannot be renamed --- frontend/playwright/ui/specs/tokens.spec.js | 43 +++++++++++++++++-- .../app/main/ui/workspace/tokens/sets.cljs | 11 ++++- .../workspace/tokens/sets_context_menu.cljs | 7 +-- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/frontend/playwright/ui/specs/tokens.spec.js b/frontend/playwright/ui/specs/tokens.spec.js index 9988fe1ead..73e8488316 100644 --- a/frontend/playwright/ui/specs/tokens.spec.js +++ b/frontend/playwright/ui/specs/tokens.spec.js @@ -511,9 +511,7 @@ test.describe("Tokens: Sets Tab", () => { // Creates nesting by renaming set with double click await tokenThemesSetsSidebar .getByRole("button", { name: "light-renamed" }) - .click({ button: "right" }); - await expect(tokenContextMenuForSet).toBeVisible(); - await tokenContextMenuForSet.getByText("Rename").click(); + .dblclick(); await changeSetInput(tokenThemesSetsSidebar, "nested/light"); await assertSetsList(tokenThemesSetsSidebar, [ @@ -558,6 +556,45 @@ test.describe("Tokens: Sets Tab", () => { ]); }); + test("User can create & edit sets and set groups with an identical name", async ({ + page, + }) => { + const { tokenThemesSetsSidebar, tokenContextMenuForSet } = + await setupEmptyTokensFile(page); + + const tokensTabButton = tokenThemesSetsSidebar + .getByRole("button", { name: "Add set" }) + .click(); + + await createSet(tokenThemesSetsSidebar, "core/colors"); + await createSet(tokenThemesSetsSidebar, "core"); + await assertSetsList(tokenThemesSetsSidebar, ["core", "colors", "core"]); + await tokenThemesSetsSidebar + .getByRole("button", { name: "core" }) + .nth(0) + .dblclick(); + await changeSetInput(tokenThemesSetsSidebar, "core-group-renamed"); + await assertSetsList(tokenThemesSetsSidebar, [ + "core-group-renamed", + "colors", + "core", + ]); + + await page.keyboard.press(`ControlOrMeta+z`); + await assertSetsList(tokenThemesSetsSidebar, ["core", "colors", "core"]); + + await tokenThemesSetsSidebar + .getByRole("button", { name: "core" }) + .nth(1) + .dblclick(); + await changeSetInput(tokenThemesSetsSidebar, "core-set-renamed"); + await assertSetsList(tokenThemesSetsSidebar, [ + "core", + "colors", + "core-set-renamed", + ]); + }); + test("Fold/Unfold set", async ({ page }) => { const { tokenThemesSetsSidebar, tokenSetGroupItems } = await setupTokensFile(page); diff --git a/frontend/src/app/main/ui/workspace/tokens/sets.cljs b/frontend/src/app/main/ui/workspace/tokens/sets.cljs index 94dff84af1..0ff9f15831 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets.cljs @@ -65,6 +65,11 @@ (st/emit! (ptk/data-event ::ev/event {::ev/name "create-token-set" :name name}) (dt/create-token-set name)))) +(defn group-edition-id + "Prefix editing groups `edition-id` so it can be differentiated from sets with the same id." + [edition-id] + (str "group-" edition-id)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; COMPONENTS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -166,6 +171,7 @@ {:position (dom/get-client-position event) :is-group true :id id + :edition-id (group-edition-id id) :path tree-path}))))) on-collapse-click @@ -176,7 +182,7 @@ (on-toggle-collapse tree-path))) on-double-click - (mf/use-fn (mf/deps id) #(on-start-edition id)) + (mf/use-fn (mf/deps id) #(on-start-edition (group-edition-id id))) on-checkbox-click (mf/use-fn @@ -268,6 +274,7 @@ {:position (dom/get-client-position event) :is-group false :id id + :edition-id id :path tree-path}))))) on-double-click @@ -399,7 +406,7 @@ :is-active (is-token-set-group-active path) :is-selected false :is-draggable is-draggable - :is-editing (= edition-id id) + :is-editing (= edition-id (group-edition-id id)) :is-collapsed (collapsed? path) :on-select on-select diff --git a/frontend/src/app/main/ui/workspace/tokens/sets_context_menu.cljs b/frontend/src/app/main/ui/workspace/tokens/sets_context_menu.cljs index b4b4f5015e..029244de5b 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets_context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets_context_menu.cljs @@ -34,7 +34,7 @@ (mf/defc menu* {::mf/private true} - [{:keys [is-group id path]}] + [{:keys [is-group id edition-id path]}] (let [create-set-at-path (mf/use-fn (mf/deps path) #(st/emit! (dt/start-token-set-creation path))) @@ -42,7 +42,7 @@ (mf/use-fn (mf/deps id) (fn [] - (st/emit! (dt/start-token-set-edition id)))) + (st/emit! (dt/start-token-set-edition edition-id)))) on-delete (mf/use-fn @@ -57,7 +57,7 @@ (mf/defc token-set-context-menu* [] - (let [{:keys [position is-group id path]} + (let [{:keys [position is-group id edition-id path]} (mf/deref ref:token-sets-context-menu) position-top @@ -78,4 +78,5 @@ :on-context-menu prevent-default} [:> menu* {:is-group is-group :id id + :edition-id edition-id :path path}]]])) From a7c1f7ba69a1ce7262d41c73efe3eb07cb5189ee Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 11 Apr 2025 08:54:02 +0200 Subject: [PATCH 04/38] :bug: Fix incorrect undo handling on path edition --- CHANGES.md | 3 ++- common/src/app/common/data/undo_stack.cljc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ec306c8829..6c020ebb18 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,12 @@ # CHANGELOG -## 2.6.2 +## 2.6.2 (Unreleased) ### :bug: Bugs fixed - Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615) - Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745) +- Fix unexpected exception on path editor on merge segments when undo stack is empty ## 2.6.1 diff --git a/common/src/app/common/data/undo_stack.cljc b/common/src/app/common/data/undo_stack.cljc index 61117cb2ee..dbcae0db14 100644 --- a/common/src/app/common/data/undo_stack.cljc +++ b/common/src/app/common/data/undo_stack.cljc @@ -47,7 +47,7 @@ (defn undo [stack] - (update stack :index dec)) + (update stack :index #(max 0 (dec %)))) (defn redo [{index :index items :items :as stack}] From 38e5c161e7a56452246173497c87840535c3abcc Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 11 Apr 2025 12:21:36 +0200 Subject: [PATCH 05/38] :sparkles: Sanitize plugins uuid parsing --- common/src/app/common/uuid.cljc | 16 +++++++++++++--- frontend/src/app/main/ui/dashboard/sidebar.cljs | 3 +-- frontend/src/app/plugins/library.cljs | 2 +- frontend/src/app/plugins/page.cljs | 2 +- frontend/src/app/plugins/parser.cljs | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/common/src/app/common/uuid.cljc b/common/src/app/common/uuid.cljc index 707770fcd9..7a3c054dc1 100644 --- a/common/src/app/common/uuid.cljc +++ b/common/src/app/common/uuid.cljc @@ -17,9 +17,14 @@ java.util.UUID java.nio.ByteBuffer))) +(def ^:private uuid-regex + #"^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$") + (defn uuid "Creates an UUID instance from string, expectes valid uuid strings, - the existense of validation is implementation detail" + the existense of validation is implementation detail. + + UNSAFE: this can accept invalid uuids or incomplete uuids" [s] #?(:clj (UUID/fromString s) :cljs (c/uuid s))) @@ -27,8 +32,13 @@ (defn parse "Parse string uuid representation into proper UUID instance, validates input" [s] - #?(:clj (UUID/fromString s) - :cljs (c/parse-uuid s))) + (if (and (string? s) ^boolean (re-matches uuid-regex s)) + #?(:clj (UUID/fromString s) + :cljs (uuid s)) + + (let [message (str "invalid string '" s "' for uuid")] + (throw #?(:clj (IllegalArgumentException. message) + :cljs (js/Error. message)))))) (defn next [] diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 46dd0d270a..5ee1c1d4a9 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -283,8 +283,7 @@ (fn [event] (let [team-id (-> (dom/get-current-target event) (dom/get-data "value") - (uuid/parse))] - + (uuid/uuid))] (st/emit! (dcm/go-to-dashboard-recent :team-id team-id))))) handle-select-default diff --git a/frontend/src/app/plugins/library.cljs b/frontend/src/app/plugins/library.cljs index a269d2ab52..bd430ce729 100644 --- a/frontend/src/app/plugins/library.cljs +++ b/frontend/src/app/plugins/library.cljs @@ -969,7 +969,7 @@ :else (let [file-id (:current-file-id @st/state) - library-id (uuid/uuid library-id)] + library-id (uuid/parse library-id)] (->> st/stream (rx/filter (ptk/type? ::dwl/attach-library-finished)) (rx/take 1) diff --git a/frontend/src/app/plugins/page.cljs b/frontend/src/app/plugins/page.cljs index 373a9b93c5..ba7713f42b 100644 --- a/frontend/src/app/plugins/page.cljs +++ b/frontend/src/app/plugins/page.cljs @@ -160,7 +160,7 @@ (u/display-not-valid :getShapeById shape-id) :else - (let [shape-id (uuid/uuid shape-id) + (let [shape-id (uuid/parse shape-id) shape (u/locate-shape file-id id shape-id)] (when (some? shape) (shape/shape-proxy plugin-id file-id id shape-id))))) diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs index 0ce6aad418..caaa697f74 100644 --- a/frontend/src/app/plugins/parser.cljs +++ b/frontend/src/app/plugins/parser.cljs @@ -13,7 +13,7 @@ (defn parse-id [id] - (when id (uuid/uuid id))) + (when id (uuid/parse id))) (defn parse-keyword [kw] From a4145a30f52d59119b978384a74bcfe861cb760c Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 11 Apr 2025 12:39:11 +0200 Subject: [PATCH 06/38] :bug: Fix uuid encode/decode on schema --- common/src/app/common/schema.cljc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 6d89efd89e..b6f1a49c48 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -395,9 +395,15 @@ (defn parse-uuid [s] - (if (string? s) - (some->> (re-matches uuid-rx s) uuid/uuid) - s)) + (try + (uuid/parse s) + (catch #?(:clj Exception :cljs :default) _cause + s))) + +(defn encode-uuid + [v] + (when (uuid? v) + (str v))) (register! {:type ::uuid @@ -409,8 +415,8 @@ :gen/gen (sg/uuid) :decode/string parse-uuid :decode/json parse-uuid - :encode/string str - :encode/json str + :encode/string encode-uuid + :encode/json encode-uuid ::oapi/type "string" ::oapi/format "uuid"}}) From 422a9db07b9c47c0cfa8a0f0ace1e5e97ec2167d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 11 Apr 2025 12:40:00 +0200 Subject: [PATCH 07/38] :sparkles: Sanitize uuid parsing on legacy zip import code --- common/src/app/common/uuid.cljc | 4 +-- frontend/src/app/worker/import.cljs | 16 ++++----- frontend/src/app/worker/import/parser.cljs | 41 ++++++++++------------ 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/common/src/app/common/uuid.cljc b/common/src/app/common/uuid.cljc index 7a3c054dc1..3d3d2291d0 100644 --- a/common/src/app/common/uuid.cljc +++ b/common/src/app/common/uuid.cljc @@ -17,7 +17,7 @@ java.util.UUID java.nio.ByteBuffer))) -(def ^:private uuid-regex +(def regex #"^[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]-[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$") (defn uuid @@ -32,7 +32,7 @@ (defn parse "Parse string uuid representation into proper UUID instance, validates input" [s] - (if (and (string? s) ^boolean (re-matches uuid-regex s)) + (if (and (string? s) ^boolean (re-matches regex s)) #?(:clj (UUID/fromString s) :cljs (uuid s)) diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 950c98ffba..f2ea47fabe 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -43,14 +43,14 @@ (defn read-json-key [m] - (or (sm/parse-uuid m) + (or (uuid/parse m) (json/read-kebab-key m))) (defn read-json-val [m] (cond (and (string? m) - (re-matches sm/uuid-rx m)) + (re-matches uuid/regex m)) (uuid/uuid m) (and (string? m) @@ -521,8 +521,8 @@ id (resolve old-id) path (get-in node [:attrs :penpot:path] "") type (parser/get-type content) - main-instance-id (resolve (uuid (get-in node [:attrs :penpot:main-instance-id] ""))) - main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] ""))) + main-instance-id (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-id] ""))) + main-instance-page (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-page] ""))) data (-> (parser/parse-data type content) (assoc :path path) (assoc :id id) @@ -547,12 +547,12 @@ old-id (parser/get-id node) id (resolve old-id) path (get-in node [:attrs :penpot:path] "") - main-instance-id (resolve (uuid (get-in node [:attrs :penpot:main-instance-id] ""))) - main-instance-page (resolve (uuid (get-in node [:attrs :penpot:main-instance-page] ""))) + main-instance-id (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-id] ""))) + main-instance-page (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-page] ""))) main-instance-x (-> (get-in node [:attrs :penpot:main-instance-x] "") (d/parse-double)) main-instance-y (-> (get-in node [:attrs :penpot:main-instance-y] "") (d/parse-double)) - main-instance-parent (resolve (uuid (get-in node [:attrs :penpot:main-instance-parent] ""))) - main-instance-frame (resolve (uuid (get-in node [:attrs :penpot:main-instance-frame] ""))) + main-instance-parent (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-parent] ""))) + main-instance-frame (resolve (uuid/parse (get-in node [:attrs :penpot:main-instance-frame] ""))) type (parser/get-type content) data (-> (parser/parse-data type content) diff --git a/frontend/src/app/worker/import/parser.cljs b/frontend/src/app/worker/import/parser.cljs index 27ad5f1149..8bf5158eee 100644 --- a/frontend/src/app/worker/import/parser.cljs +++ b/frontend/src/app/worker/import/parser.cljs @@ -20,9 +20,6 @@ (def url-regex #"url\(#([^\)]*)\)") -(def uuid-regex - #"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}") - (def uuid-regex-prefix #"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}-") @@ -84,7 +81,7 @@ (defn get-id [node] (let [attr-id (get-in node [:attrs :id]) - id (when (string? attr-id) (re-find uuid-regex attr-id))] + id (when (string? attr-id) (re-find uuid/regex attr-id))] (when (some? id) (uuid/uuid id)))) @@ -189,10 +186,10 @@ [m] (letfn [(convert [value] (cond - (and (string? value) (re-matches uuid-regex value)) + (and (string? value) (re-matches uuid/regex value)) (uuid/uuid value) - (and (keyword? value) (re-matches uuid-regex (d/name value))) + (and (keyword? value) (re-matches uuid/regex (d/name value))) (uuid/uuid (d/name value)) (vector? value) @@ -429,11 +426,11 @@ (defn add-library-refs [props node] - (let [stroke-color-ref-id (get-meta node :stroke-color-ref-id uuid/uuid) - stroke-color-ref-file (get-meta node :stroke-color-ref-file uuid/uuid) - component-id (get-meta node :component-id uuid/uuid) - component-file (get-meta node :component-file uuid/uuid) - shape-ref (get-meta node :shape-ref uuid/uuid) + (let [stroke-color-ref-id (get-meta node :stroke-color-ref-id uuid/parse) + stroke-color-ref-file (get-meta node :stroke-color-ref-file uuid/parse) + component-id (get-meta node :component-id uuid/parse) + component-file (get-meta node :component-file uuid/parse) + shape-ref (get-meta node :shape-ref uuid/parse) component-root? (get-meta node :component-root str->bool) main-instance? (get-meta node :main-instance str->bool) touched (get-meta node :touched parse-touched)] @@ -463,8 +460,8 @@ [props node svg-data] (let [fill (:fill svg-data) - fill-color-ref-id (get-meta node :fill-color-ref-id uuid/uuid) - fill-color-ref-file (get-meta node :fill-color-ref-file uuid/uuid) + fill-color-ref-id (get-meta node :fill-color-ref-id uuid/parse) + fill-color-ref-file (get-meta node :fill-color-ref-file uuid/parse) meta-fill-color (get-meta node :fill-color) meta-fill-opacity (get-meta node :fill-opacity) meta-fill-color-gradient (if (str/starts-with? meta-fill-color "url#fill-color-gradient") @@ -627,7 +624,7 @@ (let [attrs (-> node :attrs remove-penpot-prefix)] {:id (uuid/next) :name (-> attrs :name) - :starting-frame (-> attrs :starting-frame uuid)})) + :starting-frame (-> attrs :starting-frame uuid/parse)})) (defn parse-flows [node] (let [flows-node (get-data node :penpot:flows)] @@ -638,7 +635,7 @@ id (uuid/next)] [id {:id id - :frame-id (when (:frame-id attrs) (-> attrs :frame-id uuid)) + :frame-id (when (:frame-id attrs) (-> attrs :frame-id uuid/parse)) :axis (-> attrs :axis keyword) :position (-> attrs :position d/parse-double)}])) @@ -775,8 +772,8 @@ (parse-gradient node (get-meta fill-node :fill-color))) :fill-image (when fill-image-id (get images fill-image-id)) - :fill-color-ref-file (get-meta fill-node :fill-color-ref-file uuid/uuid) - :fill-color-ref-id (get-meta fill-node :fill-color-ref-id uuid/uuid) + :fill-color-ref-file (get-meta fill-node :fill-color-ref-file uuid/parse) + :fill-color-ref-id (get-meta fill-node :fill-color-ref-id uuid/parse) :fill-opacity (get-meta fill-node :fill-opacity d/parse-double)}))) (mapv d/without-nils) (filterv #(not= (:fill-color %) "none")))] @@ -800,8 +797,8 @@ (parse-gradient node (get-meta stroke-node :stroke-color))) :stroke-image (when stroke-image-id (get images stroke-image-id)) - :stroke-color-ref-file (get-meta stroke-node :stroke-color-ref-file uuid/uuid) - :stroke-color-ref-id (get-meta stroke-node :stroke-color-ref-id uuid/uuid) + :stroke-color-ref-file (get-meta stroke-node :stroke-color-ref-file uuid/parse) + :stroke-color-ref-id (get-meta stroke-node :stroke-color-ref-id uuid/parse) :stroke-opacity (get-meta stroke-node :stroke-opacity d/parse-double) :stroke-style (get-meta stroke-node :stroke-style keyword) :stroke-width (get-meta stroke-node :stroke-width d/parse-double) @@ -993,7 +990,7 @@ align-self justify-self shapes]} (-> cell-node :attrs remove-penpot-prefix) - id (uuid/uuid id)] + id (uuid/parse id)] [id (d/without-nils {:id id :area-name area-name @@ -1006,7 +1003,7 @@ :justify-self (keyword justify-self) :shapes (if (and (some? shapes) (d/not-empty? shapes)) (->> (str/split shapes " ") - (mapv uuid/uuid)) + (mapv uuid/parse)) [])})]))) (into {})))) @@ -1154,7 +1151,7 @@ (assoc :delay (get-meta node :delay d/parse-double)) (ctsi/has-destination interaction) - (assoc :destination (get-meta node :destination uuid/uuid) + (assoc :destination (get-meta node :destination uuid/parse) :preserve-scroll (get-meta node :preserve-scroll str->bool)) (ctsi/has-url interaction) From fa3fc12594754e9ab9340895c6690ab5e6ad74fc Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 11 Apr 2025 13:05:22 +0200 Subject: [PATCH 08/38] :sparkles: Sanitize uuid on the rest of code --- common/src/app/common/uuid.cljc | 8 +++++ frontend/src/app/libs/file_builder.cljs | 6 ++-- frontend/src/app/libs/render.cljs | 2 +- frontend/src/app/main/data/comments.cljs | 2 +- frontend/src/app/main/data/viewer.cljs | 4 +-- frontend/src/app/main/data/workspace.cljs | 11 ++----- frontend/src/app/main/ui.cljs | 29 ++++++++++--------- frontend/src/app/main/ui/comments.cljs | 2 +- frontend/src/app/main/ui/dashboard/fonts.cljs | 11 +++---- .../src/app/main/ui/dashboard/sidebar.cljs | 2 +- .../src/app/main/ui/viewer/share_link.cljs | 3 +- .../ui/workspace/colorpicker/libraries.cljs | 3 +- .../src/app/main/ui/workspace/libraries.cljs | 6 ++-- .../src/app/main/ui/workspace/palette.cljs | 3 +- .../sidebar/options/menus/interactions.cljs | 4 +-- .../main/ui/workspace/sidebar/versions.cljs | 4 +-- .../main/ui/workspace/viewport/actions.cljs | 2 +- frontend/src/debug.cljs | 23 ++++++++++----- 18 files changed, 70 insertions(+), 55 deletions(-) diff --git a/common/src/app/common/uuid.cljc b/common/src/app/common/uuid.cljc index 3d3d2291d0..9b21f8f796 100644 --- a/common/src/app/common/uuid.cljc +++ b/common/src/app/common/uuid.cljc @@ -40,6 +40,14 @@ (throw #?(:clj (IllegalArgumentException. message) :cljs (js/Error. message)))))) +(defn parse* + "Exception safe version of `parse`." + [s] + (try + (parse s) + (catch #?(:clj Exception :cljs :default) _cause + nil))) + (defn next [] #?(:clj (UUIDv8/create) diff --git a/frontend/src/app/libs/file_builder.cljs b/frontend/src/app/libs/file_builder.cljs index 05be149ac8..36e22caef7 100644 --- a/frontend/src/app/libs/file_builder.cljs +++ b/frontend/src/app/libs/file_builder.cljs @@ -239,15 +239,15 @@ (str (:last-id file))) (lookupShape [_ shape-id] - (clj->js (fb/lookup-shape file (uuid/uuid shape-id)))) + (clj->js (fb/lookup-shape file (uuid/parse shape-id)))) (updateObject [_ id new-obj] - (let [old-obj (fb/lookup-shape file (uuid/uuid id)) + (let [old-obj (fb/lookup-shape file (uuid/parse id)) new-obj (d/deep-merge old-obj (parse-data new-obj))] (set! file (fb/update-object file old-obj new-obj)))) (deleteObject [_ id] - (set! file (fb/delete-object file (uuid/uuid id)))) + (set! file (fb/delete-object file (uuid/parse id)))) (getId [_] (:id file)) diff --git a/frontend/src/app/libs/render.cljs b/frontend/src/app/libs/render.cljs index 26e6cfe5d6..7ece057c01 100644 --- a/frontend/src/app/libs/render.cljs +++ b/frontend/src/app/libs/render.cljs @@ -15,7 +15,7 @@ [file ^string page-id] ;; Better to expose the api as a promise to be consumed from JS - (let [page-id (uuid/uuid page-id) + (let [page-id (uuid/parse page-id) file-data (.-file file) data (get-in file-data [:data :pages-index page-id])] (p/create diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index 0d7677f821..e4205f9bd7 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -69,7 +69,7 @@ "Retrieves the mentions in the content as an array of uuids" [content] (->> (re-seq r-mentions content) - (mapv (fn [[_ _ id]] (uuid/uuid id))))) + (mapv (fn [[_ _ id]] (uuid/parse id))))) (defn update-mentions "Updates the params object with the mentiosn" diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index dbd96a2900..c18444623a 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -248,7 +248,7 @@ (defn fetch-comments [{:keys [thread-id]}] - (dm/assert! (uuid thread-id)) + (assert (uuid? thread-id)) (letfn [(fetched [comments state] (update state :comments assoc thread-id (d/index-by :id comments)))] (ptk/reify ::retrieve-comments @@ -413,7 +413,7 @@ (watch [_ state _] (let [params (rt/get-params state) index (some-> params :index parse-long) - page-id (some-> params :page-id parse-uuid) + page-id (some-> params :page-id uuid/parse) total (count (get-in state [:viewer :pages page-id :frames]))] diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 3e1fcba1ba..01dc099c8a 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -369,7 +369,7 @@ (rx/take 1) (rx/map dwc/set-workspace-visited)) - (when-let [component-id (some-> rparams :component-id parse-uuid)] + (when-let [component-id (some-> rparams :component-id uuid/parse)] (->> stream (rx/filter (ptk/type? ::workspace-initialized)) (rx/observe-on :async) @@ -382,7 +382,7 @@ (rx/take 1) (rx/map zoom-to-frame))) - (when-let [comment-id (some-> rparams :comment-id parse-uuid)] + (when-let [comment-id (some-> rparams :comment-id uuid/parse)] (->> stream (rx/filter (ptk/type? ::workspace-initialized)) (rx/observe-on :async) @@ -2445,13 +2445,6 @@ (js/console.log "Copies no ref" (count copies-no-ref) (clj->js copies-no-ref)) (js/console.log "Childs no ref" (count childs-no-ref) (clj->js childs-no-ref)))))) -(defn set-shape-ref - [id shape-ref] - (ptk/reify ::set-shape-ref - ptk/WatchEvent - (watch [_ _ _] - (rx/of (update-shape (uuid/uuid id) {:shape-ref (uuid/uuid shape-ref)}))))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Exports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index f67fb755a3..8d4299a3af 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -7,6 +7,7 @@ (ns app.main.ui (:require [app.common.data :as d] + [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.common :as dcm] [app.main.data.team :as dtm] @@ -212,8 +213,8 @@ :dashboard-webhooks :dashboard-settings) (let [params (get params :query) - team-id (some-> params :team-id uuid) - project-id (some-> params :project-id uuid) + team-id (some-> params :team-id uuid/parse*) + project-id (some-> params :project-id uuid/parse*) search-term (some-> params :search-term) plugin-url (some-> params :plugin) template-url (some-> params :template)] @@ -247,9 +248,9 @@ :workspace (let [params (get params :query) - team-id (some-> params :team-id uuid) - file-id (some-> params :file-id uuid) - page-id (some-> params :page-id uuid) + team-id (some-> params :team-id uuid/parse*) + file-id (some-> params :file-id uuid/parse*) + page-id (some-> params :page-id uuid/parse*) layout (some-> params :layout keyword)] [:? {} (when (cf/external-feature-flag "onboarding-03" "test") @@ -276,15 +277,15 @@ :viewer (let [params (get params :query) index (some-> (:index params) parse-long) - share-id (some-> (:share-id params) parse-uuid) + share-id (some-> (:share-id params) uuid/parse*) section (or (some-> (:section params) keyword) :interactions) - file-id (some-> (:file-id params) parse-uuid) - page-id (some-> (:page-id params) parse-uuid) + file-id (some-> (:file-id params) uuid/parse*) + page-id (some-> (:page-id params) uuid/parse*) imode (or (some-> (:interactions-mode params) keyword) :show-on-click) - frame-id (some-> (:frame-id params) parse-uuid) + frame-id (some-> (:frame-id params) uuid/parse*) share (:share params)] [:? {} @@ -300,9 +301,9 @@ :workspace-legacy - (let [project-id (some-> params :path :project-id uuid) - file-id (some-> params :path :file-id uuid) - page-id (some-> params :query :page-id uuid) + (let [project-id (some-> params :path :project-id uuid/parse*) + file-id (some-> params :path :file-id uuid/parse*) + page-id (some-> params :query :page-id uuid/parse*) layout (some-> params :query :layout keyword)] [:> workspace-legacy-redirect* @@ -321,8 +322,8 @@ :dashboard-legacy-team-invitations :dashboard-legacy-team-webhooks :dashboard-legacy-team-settings) - (let [team-id (some-> params :path :team-id uuid) - project-id (some-> params :path :project-id uuid) + (let [team-id (some-> params :path :team-id uuid/parse*) + project-id (some-> params :path :project-id uuid/parse*) search-term (some-> params :query :search-term) plugin-url (some-> params :query :plugin) template-url (some-> params :template)] diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index 2955543540..1aa3c833e3 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -487,7 +487,7 @@ (dom/stop-propagation event) (let [id (-> (dom/get-current-target event) (dom/get-data "user-id") - (uuid/uuid)) + (uuid/parse)) user (d/seek #(= (:id %) id) members)] diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index bcda5f4b0a..c03aa5bebf 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dm] [app.common.media :as cm] + [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.fonts :as df] [app.main.data.modal :as modal] @@ -121,7 +122,7 @@ (fn [event] (let [id (-> (dom/get-current-target event) (dom/get-data "id") - (parse-uuid)) + (uuid/parse)) item (get fonts id)] (on-upload* item)))) @@ -132,7 +133,7 @@ (let [target (dom/get-current-target event) id (-> target (dom/get-data "id") - (parse-uuid)) + (uuid/parse)) name (dom/get-value target)] (when-not (str/blank? name) (swap! fonts* df/rename-and-regroup id name installed-fonts))))) @@ -143,7 +144,7 @@ (let [target (dom/get-current-target event) id (-> target (dom/get-data "id") - (parse-uuid)) + (uuid/parse)) name (dom/get-value target)] (swap! fonts* update id assoc :font-family-tmp name)))) @@ -153,7 +154,7 @@ (fn [event] (let [id (-> (dom/get-current-target event) (dom/get-data "id") - (parse-uuid))] + (uuid/parse))] (swap! fonts* dissoc id)))) on-upload-all @@ -344,7 +345,7 @@ (fn [event] (let [id (-> (dom/get-current-target event) (dom/get-data "id") - (parse-uuid)) + (uuid/parse)) options {:type :confirm :title (tr "modals.delete-font-variant.title") :message (tr "modals.delete-font-variant.message") diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 5ee1c1d4a9..1a0d85b747 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -283,7 +283,7 @@ (fn [event] (let [team-id (-> (dom/get-current-target event) (dom/get-data "value") - (uuid/uuid))] + (uuid/parse))] (st/emit! (dcm/go-to-dashboard-recent :team-id team-id))))) handle-select-default diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index ddda62a0fb..1db0b902b0 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -10,6 +10,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.logging :as log] + [app.common.uuid :as uuid] [app.config :as cf] [app.main.data.common :as dc] [app.main.data.event :as ev] @@ -104,7 +105,7 @@ (fn [event] (let [target (dom/get-target event) checked? (dom/checked? target) - page-id (parse-uuid (dom/get-data target "page-id")) + page-id (uuid/parse (dom/get-data target "page-id")) dif-pages? (not= page-id (first (:pages options))) no-one-page (< 1 (count (:pages options))) should-change? (or ^boolean no-one-page diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index cb703ef5a9..4996eb9d14 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -11,6 +11,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.types.color :as ctc] + [app.common.uuid :as uuid] [app.main.data.event :as ev] [app.main.data.workspace :as dw] [app.main.data.workspace.colors :as mdc] @@ -62,7 +63,7 @@ (if (or (= event "recent") (= event "file")) (keyword event) - (parse-uuid event))))) + (uuid/parse event))))) valid-color? (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 0c6a8b8feb..40de66b24a 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -228,7 +228,7 @@ (fn [event] (let [library-id (some-> (dom/get-current-target event) (dom/get-data "library-id") - (parse-uuid))] + (uuid/parse))] (reset! selected library-id) (st/emit! (dwl/link-file-to-library file-id library-id))))) @@ -238,7 +238,7 @@ (fn [event] (let [library-id (some-> (dom/get-current-target event) (dom/get-data "library-id") - (parse-uuid))] + (uuid/parse))] (when (= library-id @selected) (reset! selected :file)) (st/emit! (dwl/unlink-file-from-library file-id library-id) @@ -451,7 +451,7 @@ (when-not updating? (let [library-id (some-> (dom/get-target event) (dom/get-data "library-id") - (parse-uuid))] + (uuid/parse))] (st/emit! (dwl/set-updating-library true) (dwl/sync-file file-id library-id))))))] diff --git a/frontend/src/app/main/ui/workspace/palette.cljs b/frontend/src/app/main/ui/workspace/palette.cljs index 431f97935c..ff13a57b13 100644 --- a/frontend/src/app/main/ui/workspace/palette.cljs +++ b/frontend/src/app/main/ui/workspace/palette.cljs @@ -9,6 +9,7 @@ (:require [app.common.data :as d] [app.common.data.macros :as dm] + [app.common.uuid :as uuid] [app.main.data.event :as ev] [app.main.data.workspace :as dw] [app.main.data.workspace.colors :as mdc] @@ -87,7 +88,7 @@ value (dom/get-attribute node "data-palette")] (on-select (if (or (= "file" value) (= "recent" value)) (keyword value) - (parse-uuid value)))))) + (uuid/parse value)))))) on-select-text-palette-menu (mf/use-fn diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs index 22e2421fc7..ae2193a23b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs @@ -251,14 +251,14 @@ (mf/deps index update-interaction) (fn [event] (let [value event - value (when (not= value "") (uuid/uuid value))] + value (when (not= value "") (uuid/parse value))] (update-interaction index #(ctsi/set-destination % value))))) change-position-relative-to (mf/use-fn (mf/deps index update-interaction) (fn [event] - (let [value (uuid/uuid event)] + (let [value (uuid/parse event)] (update-interaction index #(ctsi/set-position-relative-to % value))))) change-preserve-scroll diff --git a/frontend/src/app/main/ui/workspace/sidebar/versions.cljs b/frontend/src/app/main/ui/workspace/sidebar/versions.cljs index 323d60a433..a4173adabc 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/versions.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/versions.cljs @@ -153,7 +153,7 @@ (mf/deps on-pin-snapshot) (fn [event] (let [node (dom/get-current-target event) - id (-> (dom/get-data node "id") uuid/uuid)] + id (-> (dom/get-data node "id") uuid/parse)] (when on-pin-snapshot (on-pin-snapshot id))))) handle-restore-snapshot @@ -161,7 +161,7 @@ (mf/deps on-restore-snapshot) (fn [event] (let [node (dom/get-current-target event) - id (-> (dom/get-data node "id") uuid/uuid)] + id (-> (dom/get-data node "id") uuid/parse)] (when on-restore-snapshot (on-restore-snapshot id))))) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index b22a8bda79..80702d5846 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -469,7 +469,7 @@ (dom/prevent-default event) (let [point (gpt/point (.-clientX event) (.-clientY event)) viewport-coord (uwvv/point->viewport point) - asset-id (-> (dnd/get-data event "text/asset-id") uuid/uuid) + asset-id (-> (dnd/get-data event "text/asset-id") uuid/parse) asset-name (dnd/get-data event "text/asset-name") asset-type (dnd/get-data event "text/asset-type")] (cond diff --git a/frontend/src/debug.cljs b/frontend/src/debug.cljs index 4d635b99b5..e934f851b5 100644 --- a/frontend/src/debug.cljs +++ b/frontend/src/debug.cljs @@ -179,7 +179,7 @@ [state name] (let [objects (dsh/lookup-page-objects state) result (or (d/seek (fn [shape] (= name (:name shape))) (vals objects)) - (get objects (uuid/uuid name)))] + (get objects (uuid/parse name)))] result)) (defn ^:export dump-object @@ -222,12 +222,12 @@ (defn ^:export select-by-object-id [object-id] (let [[_ page-id shape-id _] (str/split object-id #"/")] - (st/emit! (dcm/go-to-workspace :page-id (uuid/uuid page-id))) - (st/emit! (dws/select-shape (uuid/uuid shape-id))))) + (st/emit! (dcm/go-to-workspace :page-id (uuid/parse page-id))) + (st/emit! (dws/select-shape (uuid/parse shape-id))))) (defn ^:export select-by-id [shape-id] - (st/emit! (dws/select-shape (uuid/uuid shape-id)))) + (st/emit! (dws/select-shape (uuid/parse shape-id)))) (defn dump-tree' ([state] (dump-tree' state false false false)) @@ -255,7 +255,7 @@ file (dsh/lookup-file state) libraries (get state :files) shape-id (if (some? shape-id) - (uuid/uuid shape-id) + (uuid/parse shape-id) (first (dsh/lookup-selected state)))] (if (some? shape-id) (ctf/dump-subtree file page-id shape-id libraries {:show-ids show-ids @@ -369,7 +369,7 @@ (let [file (dsh/lookup-file @st/state) libraries (get @st/state :files)] (try - (->> (if-let [shape-id (some-> shape-id parse-uuid)] + (->> (if-let [shape-id (some-> shape-id uuid/parse)] (let [page (dm/get-in file [:data :pages-index (get @st/state :current-page-id)])] (cfv/validate-shape shape-id file page libraries)) (cfv/validate-file file libraries)) @@ -426,6 +426,15 @@ [] (st/emit! (dw/find-components-norefs))) +(defn- set-shape-ref* + [id shape-ref] + (ptk/reify ::set-shape-ref + ptk/WatchEvent + (watch [_ _ _] + (let [shape-id (uuid/parse id) + shape-ref (uuid/parse shape-ref)] + (rx/of (dw/update-shape shape-id {:shape-ref shape-ref})))))) + (defn ^:export set-shape-ref [id shape-ref] - (st/emit! (dw/set-shape-ref id shape-ref))) + (st/emit! (set-shape-ref* id shape-ref))) From 80d719353cf40f433eacd562eab07811256e2ac4 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 14 Apr 2025 09:23:41 +0200 Subject: [PATCH 09/38] :sparkles: Make auth data available before request parsing For properly report profile-id --- backend/src/app/http.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/app/http.clj b/backend/src/app/http.clj index 0668a4a0b2..4cb0aea3e0 100644 --- a/backend/src/app/http.clj +++ b/backend/src/app/http.clj @@ -155,9 +155,9 @@ [["" {:middleware [[mw/server-timing] [mw/params] [mw/format-response] - [mw/parse-request] [session/soft-auth cfg] [actoken/soft-auth cfg] + [mw/parse-request] [mw/errors errors/handle] [mw/restrict-methods]]} From be0814cdacdb7b2a1fe46151ae09591ea95350be Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 14 Apr 2025 13:26:12 +0200 Subject: [PATCH 10/38] :sparkles: Improve internal error reporting --- frontend/src/app/main/ui/static.cljs | 145 ++++++++++++++------------- 1 file changed, 77 insertions(+), 68 deletions(-) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index ebe78c50d7..d81d5959ac 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -202,9 +202,8 @@ cancel-text]) [:button {:on-click on-click} button-text]]]])) -(mf/defc request-access - {::mf/props :obj} - [{:keys [file-id team-id is-default workspace?]}] +(mf/defc request-access* + [{:keys [file-id team-id is-default is-workspace]}] (let [profile (mf/deref refs/profile) requested* (mf/use-state {:sent false :already-requested false}) requested (deref requested*) @@ -227,11 +226,11 @@ on-request-access (mf/use-fn - (mf/deps file-id team-id workspace?) + (mf/deps file-id team-id is-workspace) (fn [] (let [params (if (some? file-id) {:file-id file-id - :is-viewer (not workspace?)} + :is-viewer (not is-workspace)} {:team-id team-id}) mdata {:on-success on-success :on-error on-error}] @@ -240,7 +239,7 @@ [:* (if (some? file-id) - (if workspace? + (if is-workspace [:div {:class (stl/css :workspace)} [:div {:class (stl/css :workspace-left)} i/logo-icon @@ -341,7 +340,7 @@ [:div {:class (stl/css :sign-info)} [:button {:on-click handle-retry} (tr "labels.retry")]]])) -(mf/defc service-unavailable +(mf/defc service-unavailable* [] (let [on-click (mf/use-fn #(st/emit! (rt/assign-exception nil)))] [:> error-container* {} @@ -350,58 +349,55 @@ [:div {:class (stl/css :sign-info)} [:button {:on-click on-click} (tr "labels.retry")]]])) -(defn generate-report +(defn- generate-report [data] (try (let [team-id (:current-team-id @st/state) profile-id (:profile-id @st/state) trace (:app.main.errors/trace data) - instance (:app.main.errors/instance data) - content (with-out-str - (println "Hint: " (or (:hint data) (ex-message instance) "--")) - (println "Prof ID:" (str (or profile-id "--"))) - (println "Team ID:" (str (or team-id "--"))) + instance (:app.main.errors/instance data)] + (with-out-str + (println "Hint: " (or (:hint data) (ex-message instance) "--")) + (println "Prof ID:" (str (or profile-id "--"))) + (println "Team ID:" (str (or team-id "--"))) - (when-let [file-id (:file-id data)] - (println "File ID:" (str file-id))) + (when-let [file-id (:file-id data)] + (println "File ID:" (str file-id))) - (println) + (println) - (println "Data:") - (loop [data data] - (-> (d/without-qualified data) - (dissoc :explain) - (d/update-when :data (constantly "(...)")) - (pp/pprint {:level 8 :length 10})) + (println "Data:") + (loop [data data] + (-> (d/without-qualified data) + (dissoc :explain) + (d/update-when :data (constantly "(...)")) + (pp/pprint {:level 8 :length 10})) - (println) + (println) - (when-let [explain (:explain data)] - (print explain)) + (when-let [explain (:explain data)] + (print explain)) - (when (and (= :server-error (:type data)) - (contains? data :data)) - (recur (:data data)))) + (when (and (= :server-error (:type data)) + (contains? data :data)) + (recur (:data data)))) - (println "Trace:") - (println trace) - (println) + (println "Trace:") + (println trace) + (println) - (println "Last events:") - (pp/pprint @st/last-events {:length 200}) + (println "Last events:") + (pp/pprint @st/last-events {:length 200}) - (println))] - (wapi/create-blob content "text/plain")) + (println))) (catch :default cause (.error js/console "error on generating report.txt" cause) nil))) (mf/defc internal-error* - {::mf/props :obj} - [{:keys [data on-reset] :as props}] + [{:keys [on-reset report] :as props}] (let [report-uri (mf/use-ref nil) - report (mf/use-memo (mf/deps data) #(generate-report data)) on-reset (or on-reset #(st/emit! (rt/assign-exception nil))) on-download @@ -413,8 +409,8 @@ (mf/with-effect [report] (when (some? report) - - (let [uri (wapi/create-uri report)] + (let [report (wapi/create-blob report "text/plain") + uri (wapi/create-uri report)] (mf/set-ref-val! report-uri uri) (fn [] (wapi/revoke-uri uri))))) @@ -455,6 +451,38 @@ (rx/of default) (rx/throw cause))))))) +(mf/defc exception-section* + {::mf/private true} + [{:keys [data route] :as props}] + (let [type (get data :type) + report (mf/with-memo [data] + (generate-report data)) + props (mf/spread-props props {:report report})] + + (mf/with-effect [data route report] + (let [params (:query-params route) + params (u/map->query-string params)] + (st/emit! (ptk/data-event ::ev/event + {::ev/name "exception-page" + :type (get data :type :unknown) + :hint (get data :hint) + :path (get route :path) + :report report + :params params})))) + (case type + :not-found + [:> not-found* {}] + + :authentication + [:> not-found* {}] + + :bad-gateway + [:> bad-gateway* props] + + :service-unavailable + [:> service-unavailable*] + + [:> internal-error* props]))) (mf/defc exception-page* {::mf/props :obj} @@ -477,42 +505,23 @@ request-access? (and - (or (= (:type data) :not-found) - (= (:type data) :authentication)) + (or (= type :not-found) + (= type :authentication)) (or workspace? dashboard? view?) (or (:file-id info) (:team-id info)))] - (mf/with-effect [type path params] - (st/emit! (ptk/data-event ::ev/event - {::ev/name "exception-page" - :type type - :path path - :params (u/map->query-string params)}))) - (mf/with-effect [params info] (when-not (:loaded info) (->> (load-info params) - (rx/subs! (partial reset! info*))))) + (rx/subs! (partial reset! info*) + (partial reset! info* {:loaded true}))))) (when loaded? (if request-access? - [:& request-access {:file-id (:file-id info) - :team-id (:team-id info) - :is-default (:team-default info) - :workspace? workspace?}] + [:> request-access* {:file-id (:file-id info) + :team-id (:team-id info) + :is-default (:team-default info) + :is-workspace workspace?}] + [:> exception-section* props])))) - (case (:type data) - :not-found - [:> not-found* {}] - - :authentication - [:> not-found* {}] - - :bad-gateway - [:> bad-gateway* props] - - :service-unavailable - [:& service-unavailable] - - [:> internal-error* props]))))) From 2aaa2f3033875eaef31a34f2c2e8f9338db86026 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 15 Apr 2025 10:39:22 +0200 Subject: [PATCH 11/38] :bug: Fix template import (#6299) --- docker/devenv/files/nginx.conf | 9 +++-- docker/images/files/nginx.conf | 9 +++-- frontend/src/app/main/ui.cljs | 12 +++--- frontend/src/app/main/ui/dashboard.cljs | 49 +++++++++++-------------- frontend/src/app/main/ui/routes.cljs | 2 +- 5 files changed, 41 insertions(+), 40 deletions(-) diff --git a/docker/devenv/files/nginx.conf b/docker/devenv/files/nginx.conf index 1777f8a88e..c24c2c7685 100644 --- a/docker/devenv/files/nginx.conf +++ b/docker/devenv/files/nginx.conf @@ -156,10 +156,13 @@ http { } location / { - location ~ ^/github/penpot-files/(?[a-zA-Z0-9\-\_\.]+) { - proxy_pass https://raw.githubusercontent.com/penpot/penpot-files/main/$template_file; + location ~ ^/github/penpot-files/(.+)$ { + rewrite ^/github/penpot-files/(.+) /penpot/penpot-files/refs/heads/main/$1 break; + proxy_pass https://raw.githubusercontent.com; + proxy_hide_header Access-Control-Allow-Origin; - proxy_set_header User-Agent "curl/7.74.0"; + proxy_hide_header Cookies; + proxy_set_header User-Agent "curl/8.5.0"; proxy_set_header Host "raw.githubusercontent.com"; proxy_set_header Accept "*/*"; add_header Access-Control-Allow-Origin $http_origin; diff --git a/docker/images/files/nginx.conf b/docker/images/files/nginx.conf index 72e231c261..38278d2875 100644 --- a/docker/images/files/nginx.conf +++ b/docker/images/files/nginx.conf @@ -135,10 +135,13 @@ http { } location / { - location ~ ^/github/penpot-files/(?[a-zA-Z0-9\-\_\.]+) { - proxy_pass https://raw.githubusercontent.com/penpot/penpot-files/main/$template_file; + location ~ ^/github/penpot-files/(.+)$ { + rewrite ^/github/penpot-files/(.+) /penpot/penpot-files/refs/heads/main/$1 break; + proxy_pass https://raw.githubusercontent.com; + proxy_hide_header Access-Control-Allow-Origin; - proxy_set_header User-Agent "curl/7.74.0"; + proxy_hide_header Cookies; + proxy_set_header User-Agent "curl/8.5.0"; proxy_set_header Host "raw.githubusercontent.com"; proxy_set_header Accept "*/*"; add_header Access-Control-Allow-Origin $http_origin; diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 8d4299a3af..143dec77a1 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -70,7 +70,7 @@ (mf/defc dashboard-legacy-redirect* {::mf/props :obj ::mf/private true} - [{:keys [section team-id project-id search-term plugin-url template-url]}] + [{:keys [section team-id project-id search-term plugin-url template]}] (let [section (case section :dashboard-legacy-search :dashboard-search @@ -98,7 +98,7 @@ :project-id project-id :search-term search-term :plugin plugin-url - :template-url template-url}] + :template template}] (st/emit! (rt/nav section (d/without-nils params))))) [:> loader* @@ -217,7 +217,7 @@ project-id (some-> params :project-id uuid/parse*) search-term (some-> params :search-term) plugin-url (some-> params :plugin) - template-url (some-> params :template)] + template (some-> params :template)] [:? #_[:& app.main.ui.releases/release-notes-modal {:version "2.5"}] #_[:& app.main.ui.onboarding/onboarding-templates-modal] @@ -244,7 +244,7 @@ :search-term search-term :plugin-url plugin-url :project-id project-id - :template-url template-url}]]]) + :template template}]]]) :workspace (let [params (get params :query) @@ -326,14 +326,14 @@ project-id (some-> params :path :project-id uuid/parse*) search-term (some-> params :query :search-term) plugin-url (some-> params :query :plugin) - template-url (some-> params :template)] + template (some-> params :template)] [:> dashboard-legacy-redirect* {:team-id team-id :section section :project-id project-id :search-term search-term :plugin-url plugin-url - :template-url template-url}]) + :template template}]) :viewer-legacy (let [{:keys [query-params path-params]} route diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 438597de7d..ad42a3738b 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -34,12 +34,10 @@ [app.main.ui.workspace.plugins] [app.plugins.register :as preg] [app.util.dom :as dom] - [app.util.http :as http] [app.util.i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.object :as obj] [app.util.storage :as storage] - [app.util.webapi :as wapi] [beicon.v2.core :as rx] [cuerdas.core :as str] [goog.events :as events] @@ -211,17 +209,22 @@ (swap! storage/session dissoc :plugin-url)))))) (defn use-templates-import - [can-edit? template-url project] + [can-edit? template project] (let [project-id (get project :id) team-id (get project :team-id)] - (mf/with-layout-effect [can-edit? template-url project-id team-id] - (when (and (some? template-url) + (mf/with-layout-effect [can-edit? template project-id team-id] + (when (and (some? template) (some? project-id) (some? team-id)) (if can-edit? - (let [valid-url? (and (str/ends-with? template-url ".penpot") - (str/starts-with? template-url cf/templates-uri)) - template-name (when valid-url? (subs template-url (count cf/templates-uri))) + (let [valid-url? (str/ends-with? template ".penpot") + + ;; Backwards compatibility, ideally the template should be only the .penpot file name, not the full url + template-name (if (str/starts-with? template "http") + (subs template (count cf/templates-uri)) + template) + + template-url (str "/github/penpot-files/" template-name) on-import #(st/emit! (dpj/fetch-files project-id) (dd/fetch-recent-files team-id) (dd/fetch-projects team-id) @@ -230,30 +233,22 @@ :name template-name :url template-url}))] (if valid-url? - (do - (st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})) - (->> (http/send! {:method :get - :uri template-url - :response-type :blob - :omit-default-headers true}) - (rx/subs! - (fn [result] - (if (or (< (:status result) 200) (>= (:status result) 300)) - (st/emit! (notif/error (tr "dashboard.import.error"))) - (st/emit! (modal/show - {:type :import - :project-id project-id - :entries [{:name template-name :uri (wapi/create-uri (:body result))}] - :on-finish-import on-import}))))))) + (st/emit! + (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url}) + (modal/show + {:type :import + :project-id project-id + :entries [{:name template-name :uri template-url}] + :on-finish-import on-import})) (st/emit! (notif/error (tr "dashboard.import.bad-url"))))) (st/emit! (notif/error (tr "dashboard.import.no-perms")))) (binding [storage/*sync* true] - (swap! storage/session dissoc :template-url)))))) + (swap! storage/session dissoc :template)))))) (mf/defc dashboard* {::mf/props :obj} - [{:keys [profile project-id team-id search-term plugin-url template-url section]}] + [{:keys [profile project-id team-id search-term plugin-url template section]}] (let [team (mf/deref refs/team) projects (mf/deref refs/projects) @@ -263,7 +258,7 @@ (filterv #(= team-id (:team-id %))))) can-edit? (dm/get-in team [:permissions :can-edit]) - template-url (or template-url (:template-url storage/session)) + template (or template (:template storage/session)) plugin-url (or plugin-url (:plugin-url storage/session)) default-project @@ -289,7 +284,7 @@ (events/unlistenByKey key)))) (use-plugin-register plugin-url team-id (:id default-project)) - (use-templates-import can-edit? template-url default-project) + (use-templates-import can-edit? template default-project) [:& (mf/provider ctx/current-project-id) {:value project-id} [:> modal-container*] diff --git a/frontend/src/app/main/ui/routes.cljs b/frontend/src/app/main/ui/routes.cljs index f2a5df0005..57886b1e30 100644 --- a/frontend/src/app/main/ui/routes.cljs +++ b/frontend/src/app/main/ui/routes.cljs @@ -82,7 +82,7 @@ (binding [storage/*sync* true] (when (some? template) (swap! storage/session assoc - :template-url template)) + :template template)) (when (some? plugin) (swap! storage/session assoc :plugin-url plugin)))) From b49a4734ff2861500ab66a40ce7fb587695b3218 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 15 Apr 2025 10:30:27 +0200 Subject: [PATCH 12/38] :bug: Fix srepl helper for restore file snapshots --- backend/src/app/srepl/main.clj | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 6914ff54dd..e55a0bfdc2 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -337,14 +337,23 @@ (db/tx-run! main/system fsnap/create-file-snapshot! {:file-id file-id :label label}))) (defn restore-file-snapshot! - [file-id label] - (let [file-id (h/parse-uuid file-id)] + [file-id & {:keys [label id]}] + (let [file-id (h/parse-uuid file-id) + snapshot-id (some-> id h/parse-uuid)] (db/tx-run! main/system (fn [{:keys [::db/conn] :as system}] - (when-let [snapshot (->> (h/search-file-snapshots conn #{file-id} label) - (map :id) - (first))] - (fsnap/restore-file-snapshot! system file-id (:id snapshot))))))) + (cond + (uuid? snapshot-id) + (fsnap/restore-file-snapshot! system file-id snapshot-id) + + (string? label) + (->> (h/search-file-snapshots conn #{file-id} label) + (map :id) + (first) + (fsnap/restore-file-snapshot! system file-id)) + + :else + (throw (ex-info "snapshot id or label should be provided" {}))))))) (defn list-file-snapshots! [file-id & {:as _}] From 4f931fbe6a8763d6224ac1bb1f7373a648bf5966 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Wed, 16 Apr 2025 12:58:56 +0200 Subject: [PATCH 13/38] :bug: Fix error while drag an drop a component to the canvas --- .../main/ui/workspace/viewport/actions.cljs | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 80702d5846..42d23a2bff 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -468,10 +468,7 @@ (fn [event] (dom/prevent-default event) (let [point (gpt/point (.-clientX event) (.-clientY event)) - viewport-coord (uwvv/point->viewport point) - asset-id (-> (dnd/get-data event "text/asset-id") uuid/parse) - asset-name (dnd/get-data event "text/asset-name") - asset-type (dnd/get-data event "text/asset-type")] + viewport-coord (uwvv/point->viewport point)] (cond (dnd/has-type? event "penpot/shape") (let [shape (dnd/get-data event "penpot/shape") @@ -516,25 +513,6 @@ (assoc params :blobs (map wapi/data-uri->blob data)))] (st/emit! (dwm/upload-media-workspace params))) - ;; Will trigger when the user drags an SVG asset from the assets panel - (and (dnd/has-type? event "text/asset-id") (= asset-type "image/svg+xml")) - (let [path (cfg/resolve-file-media {:id asset-id}) - params {:file-id (:id file) - :position viewport-coord - :uris [path] - :name asset-name - :mtype asset-type}] - (st/emit! (dwm/upload-media-workspace params))) - - ;; Will trigger when the user drags an image from the assets SVG - (dnd/has-type? event "text/asset-id") - (let [params {:file-id (:id file) - :object-id asset-id - :name asset-name}] - (st/emit! (dwm/clone-media-object - (with-meta params - {:on-success #(st/emit! (dwm/image-uploaded % viewport-coord))})))) - ;; Will trigger when the user drags a file from their file explorer into the viewport ;; Or the user pastes an image ;; Or the user uploads an image using the image tool From 93c81ea49c7edd580183e1859297d2ab040341ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marina=20L=C3=B3pez?= Date: Wed, 16 Apr 2025 17:17:47 +0200 Subject: [PATCH 14/38] :bug: Fix pricing CTA to be under a config flag (#6304) --- CHANGES.md | 1 + backend/scripts/repl | 3 ++- backend/scripts/start-dev | 3 ++- common/src/app/common/flags.cljc | 3 ++- frontend/src/app/main/ui/dashboard/sidebar.cljs | 15 ++++++++------- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 6c020ebb18..c20143fa18 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615) - Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745) - Fix unexpected exception on path editor on merge segments when undo stack is empty +- Fix pricing CTA to be under a config flag [Taiga #10808](https://tree.taiga.io/project/penpot/issue/10808) ## 2.6.1 diff --git a/backend/scripts/repl b/backend/scripts/repl index 6da57ebcc1..558a68b955 100755 --- a/backend/scripts/repl +++ b/backend/scripts/repl @@ -30,7 +30,8 @@ export PENPOT_FLAGS="\ enable-access-tokens \ enable-tiered-file-data-storage \ enable-file-validation \ - enable-file-schema-validation"; + enable-file-schema-validation \ + enable-subscriptions-old"; # Default deletion delay for devenv export PENPOT_DELETION_DELAY="24h" diff --git a/backend/scripts/start-dev b/backend/scripts/start-dev index 9fe2ccb1b4..dae3af23a7 100755 --- a/backend/scripts/start-dev +++ b/backend/scripts/start-dev @@ -23,7 +23,8 @@ export PENPOT_FLAGS="\ enable-access-tokens \ enable-tiered-file-data-storage \ enable-file-validation \ - enable-file-schema-validation"; + enable-file-schema-validation \ + enable-subscriptions-old"; export OPTIONS=" -A:jmx-remote -A:dev \ diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc index cba12a9cde..dbc39e5041 100644 --- a/common/src/app/common/flags.cljc +++ b/common/src/app/common/flags.cljc @@ -124,7 +124,8 @@ ;; TODO: deprecate this flag and consolidate the code :export-file-v3 :render-wasm-dpr - :hide-release-modal}) + :hide-release-modal + :subscriptions-old}) (def all-flags (set/union email login varia)) diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 1a0d85b747..0a6d07c8b9 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -962,13 +962,14 @@ (dom/open-new-window "https://penpot.app/pricing")))] [:* - [:button {:class (stl/css :upgrade-plan-section) - :on-click on-power-up-click} - [:div {:class (stl/css :penpot-free)} - [:span (tr "dashboard.upgrade-plan.penpot-free")] - [:span {:class (stl/css :no-limits)} (tr "dashboard.upgrade-plan.no-limits")]] - [:div {:class (stl/css :power-up)} - (tr "dashboard.upgrade-plan.power-up")]] + (when (contains? cf/flags :subscriptions-old) + [:button {:class (stl/css :upgrade-plan-section) + :on-click on-power-up-click} + [:div {:class (stl/css :penpot-free)} + [:span (tr "dashboard.upgrade-plan.penpot-free")] + [:span {:class (stl/css :no-limits)} (tr "dashboard.upgrade-plan.no-limits")]] + [:div {:class (stl/css :power-up)} + (tr "dashboard.upgrade-plan.power-up")]]) (when (and team profile) [:& comments-section {:profile profile From 70a23a14c44d1af52489d4da8435298bb51d955b Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Wed, 16 Apr 2025 17:20:52 +0200 Subject: [PATCH 15/38] :bug: Fix allow moving a main component into another --- CHANGES.md | 1 + common/src/app/common/types/container.cljc | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c20143fa18..84515126b5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ - Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745) - Fix unexpected exception on path editor on merge segments when undo stack is empty - Fix pricing CTA to be under a config flag [Taiga #10808](https://tree.taiga.io/project/penpot/issue/10808) +- Fix allow moving a main component into another [Taiga #10818](https://tree.taiga.io/project/penpot/issue/10818) ## 2.6.1 diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 372b0ce1b0..6b714fb465 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -543,14 +543,23 @@ ;; We can always move the children to the parent they already have. ;; But if we are pasting, those are new items, so it is considered a change no-changes? - (and (->> children (every? #(= parent-id (:parent-id %)))) + (and (every? #(= parent-id (:parent-id %)) children) (not pasting?)) all-main? - (->> children (every? #(ctk/main-instance? %)))] + (every? ctk/main-instance? children) + + any-main-descendant + (some + (fn [shape] + (some ctk/main-instance? (cfh/get-children-with-self objects (:id shape)))) + children)] + (if (or no-changes? (and (not (invalid-structure-for-component? objects parent children pasting? libraries)) ;; If we are moving into a variant-container, all the items should be main - (or all-main? (not (ctk/is-variant-container? parent))))) + (or all-main? (not (ctk/is-variant-container? parent))) + ;; If we are moving into a main component, no descendant can be main + (or (nil? any-main-descendant) (not (ctk/main-instance? parent))))) [parent-id (get-frame parent-id)] (recur (:parent-id parent) objects children pasting? libraries)))))) From d5abbd422026a484ac5496af63a0f3ce8c3dfdb6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 09:47:13 +0200 Subject: [PATCH 16/38] :paperclip: Add missing entries on the changelog --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 84515126b5..0663499eff 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,9 @@ - Fix unexpected exception on path editor on merge segments when undo stack is empty - Fix pricing CTA to be under a config flag [Taiga #10808](https://tree.taiga.io/project/penpot/issue/10808) - Fix allow moving a main component into another [Taiga #10818](https://tree.taiga.io/project/penpot/issue/10818) +- Fix several issues with internal srepl helpers +- Fix unexpected exception on template import from libraries +- Fix incorrect uuid parsing from different parts of code ## 2.6.1 From a209966427770e8f72b7e84cae885978f26d4e9d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 09:47:32 +0200 Subject: [PATCH 17/38] :bug: Don't use schema uuid parsing function on websocket ns --- backend/src/app/http/websocket.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/app/http/websocket.clj b/backend/src/app/http/websocket.clj index bcedf31cea..a93fd33cb3 100644 --- a/backend/src/app/http/websocket.clj +++ b/backend/src/app/http/websocket.clj @@ -273,7 +273,7 @@ (defn- http-handler [cfg {:keys [params ::session/profile-id] :as request}] - (let [session-id (some-> params :session-id sm/parse-uuid)] + (let [session-id (some-> params :session-id uuid/parse*)] (when-not (uuid? session-id) (ex/raise :type :validation :code :missing-session-id From e69c0c3e27005a98dff5c48db2880e5c74cde061 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 09:51:55 +0200 Subject: [PATCH 18/38] :sparkles: Make schema uuid parsing fns private --- common/src/app/common/schema.cljc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index b6f1a49c48..cb84052d03 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -390,17 +390,16 @@ (register! :merge (mu/-merge)) (register! :union (mu/-union)) -(def uuid-rx - #"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$") - -(defn parse-uuid +(defn- parse-uuid [s] - (try - (uuid/parse s) - (catch #?(:clj Exception :cljs :default) _cause - s))) + (if (str/empty? s) + nil + (try + (uuid/parse s) + (catch #?(:clj Exception :cljs :default) _cause + s)))) -(defn encode-uuid +(defn- encode-uuid [v] (when (uuid? v) (str v))) From cc7f0b145c476dba3bdc4eb8550ab7a6c87032cc Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 17:40:29 +0200 Subject: [PATCH 19/38] :bug: Make shape interaction properly decode on binfile import --- common/src/app/common/schema.cljc | 19 ++++--- .../app/common/types/shape/interactions.cljc | 52 ++++++++++++------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index cb84052d03..23d32e3e73 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -392,17 +392,20 @@ (defn- parse-uuid [s] - (if (str/empty? s) - nil - (try - (uuid/parse s) - (catch #?(:clj Exception :cljs :default) _cause - s)))) + (if (uuid? s) + s + (if (str/empty? s) + nil + (try + (uuid/parse s) + (catch #?(:clj Exception :cljs :default) _cause + s))))) (defn- encode-uuid [v] - (when (uuid? v) - (str v))) + (if (uuid? v) + (str v) + v)) (register! {:type ::uuid diff --git a/common/src/app/common/types/shape/interactions.cljc b/common/src/app/common/types/shape/interactions.cljc index 111bba5cbc..2547f5528a 100644 --- a/common/src/app/common/types/shape/interactions.cljc +++ b/common/src/app/common/types/shape/interactions.cljc @@ -109,13 +109,27 @@ (def check-animation! (sm/check-fn schema:animation)) +(def schema:interaction-attrs + [:map {:title "InteractionAttrs"} + [:action-type {:optional true} [::sm/one-of action-types]] + [:event-type {:optional true} [::sm/one-of event-types]] + [:destination {:optional true} [:maybe ::sm/uuid]] + [:preserve-scroll {:optional true} :boolean] + [:animation {:optional true} schema:animation] + [:overlay-position {:optional true} ::gpt/point] + [:overlay-pos-type {:optional true} [::sm/one-of overlay-positioning-types]] + [:close-click-outside {:optional true} :boolean] + [:background-overlay {:optional true} :boolean] + [:position-relative-to {:optional true} [:maybe ::sm/uuid]] + [:url {:optional true} :string]]) + (def schema:navigate-interaction [:map [:action-type [:= :navigate]] [:event-type [::sm/one-of event-types]] [:destination {:optional true} [:maybe ::sm/uuid]] [:preserve-scroll {:optional true} :boolean] - [:animation {:optional true} ::animation]]) + [:animation {:optional true} schema:animation]]) (def schema:open-overlay-interaction [:map @@ -126,7 +140,7 @@ [:destination {:optional true} [:maybe ::sm/uuid]] [:close-click-outside {:optional true} :boolean] [:background-overlay {:optional true} :boolean] - [:animation {:optional true} ::animation] + [:animation {:optional true} schema:animation] [:position-relative-to {:optional true} [:maybe ::sm/uuid]]]) (def schema:toggle-overlay-interaction @@ -138,7 +152,7 @@ [:destination {:optional true} [:maybe ::sm/uuid]] [:close-click-outside {:optional true} :boolean] [:background-overlay {:optional true} :boolean] - [:animation {:optional true} ::animation] + [:animation {:optional true} schema:animation] [:position-relative-to {:optional true} [:maybe ::sm/uuid]]]) (def schema:close-overlay-interaction @@ -146,7 +160,7 @@ [:action-type [:= :close-overlay]] [:event-type [::sm/one-of event-types]] [:destination {:optional true} [:maybe ::sm/uuid]] - [:animation {:optional true} ::animation] + [:animation {:optional true} schema:animation] [:position-relative-to {:optional true} [:maybe ::sm/uuid]]]) (def schema:prev-scren-interaction @@ -161,21 +175,21 @@ [:url :string]]) (def schema:interaction - [:multi {:dispatch :action-type - :title "Interaction" - :gen/gen (sg/one-of (sg/generator schema:navigate-interaction) - (sg/generator schema:open-overlay-interaction) - (sg/generator schema:close-overlay-interaction) - (sg/generator schema:toggle-overlay-interaction) - (sg/generator schema:prev-scren-interaction) - (sg/generator schema:open-url-interaction)) - :decode/json #(update % :action-type keyword)} - [:navigate schema:navigate-interaction] - [:open-overlay schema:open-overlay-interaction] - [:toggle-overlay schema:toggle-overlay-interaction] - [:close-overlay schema:close-overlay-interaction] - [:prev-screen schema:prev-scren-interaction] - [:open-url schema:open-url-interaction]]) + [:and {:title "Interaction" + :gen/gen (sg/one-of (sg/generator schema:navigate-interaction) + (sg/generator schema:open-overlay-interaction) + (sg/generator schema:close-overlay-interaction) + (sg/generator schema:toggle-overlay-interaction) + (sg/generator schema:prev-scren-interaction) + (sg/generator schema:open-url-interaction))} + schema:interaction-attrs + [:multi {:dispatch :action-type} + [:navigate schema:navigate-interaction] + [:open-overlay schema:open-overlay-interaction] + [:toggle-overlay schema:toggle-overlay-interaction] + [:close-overlay schema:close-overlay-interaction] + [:prev-screen schema:prev-scren-interaction] + [:open-url schema:open-url-interaction]]]) (sm/register! ::interaction schema:interaction) From 29cc6b4f9cd17c6dad66882ddca8df8a4e63bdf7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 17:40:34 +0200 Subject: [PATCH 20/38] :sparkles: Print the current seed on test.check fail --- common/src/app/common/schema/test.cljc | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/app/common/schema/test.cljc b/common/src/app/common/schema/test.cljc index 7fa774dd15..c3b38b0a2b 100644 --- a/common/src/app/common/schema/test.cljc +++ b/common/src/app/common/schema/test.cljc @@ -60,6 +60,7 @@ (let [smallest (-> params :shrunk :smallest vec)] (println) (println "Condition failed with the following params:") + (println "Seed:" (:seed params)) (println) (pp/pprint smallest))) From 1305ab3cc698ba2958bae3f7c8864aa39eab16ad Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 18:19:34 +0200 Subject: [PATCH 21/38] :bug: Fix issue with empty placeholder on team change --- frontend/src/app/main/ui/dashboard/grid.cljs | 2 ++ .../app/main/ui/dashboard/placeholder.cljs | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index fd5804760b..0cfa341b56 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -534,6 +534,7 @@ :create-fn create-fn :origin origin :project-id project-id + :team-id team-id :on-finish-import on-finish-import}])])) (mf/defc line-grid-row @@ -662,4 +663,5 @@ :can-edit can-edit :create-fn create-fn :project-id project-id + :team-id team-id :on-finish-import on-finish-import}])])) diff --git a/frontend/src/app/main/ui/dashboard/placeholder.cljs b/frontend/src/app/main/ui/dashboard/placeholder.cljs index ce6177dacc..adfc3b42e0 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.cljs +++ b/frontend/src/app/main/ui/dashboard/placeholder.cljs @@ -8,7 +8,6 @@ (:require-macros [app.main.style :as stl]) (:require [app.main.data.event :as ev] - [app.main.refs :as refs] [app.main.store :as st] [app.main.ui.dashboard.import :as udi] [app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]] @@ -16,12 +15,13 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] + [okulary.core :as l] [potok.v2.core :as ptk] [rumext.v2 :as mf])) (mf/defc empty-placeholder-projects* {::mf/wrap-props false} - [{:keys [on-create on-finish-import project-id] :as props}] + [{:keys [on-create on-finish-import project-id]}] (let [file-input (mf/use-ref nil) on-add-library (mf/use-fn (fn [_] @@ -48,17 +48,38 @@ :project-id project-id :on-finish-import on-finish-import}]])) +(defn- make-has-other-files-or-projects-ref + "Return a ref that resolves to true or false if there are at least some + file or some project (a part of the default) exists; this determines + if we need to show a complete placeholder or the small one." + [team-id] + (l/derived (fn [state] + (or (let [projects (get state :projects)] + (some (fn [[_ project]] + (and (= (:team-id project) team-id) + (not (:is-default project)))) + projects)) + (let [files (get state :files)] + (some (fn [[_ file]] + (= (:team-id file) team-id)) + files)))) + st/state)) + (mf/defc empty-placeholder - [{:keys [dragging? limit origin create-fn can-edit project-id on-finish-import]}] + [{:keys [dragging? limit origin create-fn can-edit team-id project-id on-finish-import]}] (let [on-click (mf/use-fn (mf/deps create-fn) (fn [_] (create-fn "dashboard:empty-folder-placeholder"))) + show-text (mf/use-state nil) on-mouse-enter (mf/use-fn #(reset! show-text true)) on-mouse-leave (mf/use-fn #(reset! show-text nil)) - files (mf/deref refs/files)] + + has-other* (mf/with-memo [team-id] + (make-has-other-files-or-projects-ref team-id)) + has-other? (mf/deref has-other*)] (cond (true? dragging?) [:ul @@ -80,7 +101,7 @@ :tag-name "span"}])] :else - (if (= (count files) 0) + (if-not has-other? [:> empty-placeholder-projects* {:on-create on-click :on-finish-import on-finish-import :project-id project-id}] [:div {:class (stl/css :grid-empty-placeholder)} [:button {:class (stl/css :create-new) From 708492afeb2deb9606f323d25263c892d4867976 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 16 Apr 2025 18:30:04 +0200 Subject: [PATCH 22/38] :lipstick: Add mainly cosmetic changes to dashboard placeholder components --- frontend/src/app/main/ui/dashboard/grid.cljs | 12 +-- .../app/main/ui/dashboard/placeholder.cljs | 81 ++++++++++++------- .../src/app/main/ui/dashboard/projects.cljs | 1 + 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 0cfa341b56..a8e731ff1c 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -28,7 +28,7 @@ [app.main.ui.dashboard.file-menu :refer [file-menu*]] [app.main.ui.dashboard.import :refer [use-import-file]] [app.main.ui.dashboard.inline-edition :refer [inline-edition]] - [app.main.ui.dashboard.placeholder :refer [empty-placeholder loading-placeholder]] + [app.main.ui.dashboard.placeholder :refer [empty-grid-placeholder* loading-placeholder*]] [app.main.ui.ds.product.loader :refer [loader*]] [app.main.ui.hooks :as h] [app.main.ui.icons :as i] @@ -511,7 +511,7 @@ :ref node-ref} (cond (nil? files) - [:& loading-placeholder] + [:> loading-placeholder*] (seq files) (for [[index slice] (d/enumerate (partition-all limit files))] @@ -528,7 +528,7 @@ :can-edit can-edit}])]) :else - [:& empty-placeholder + [:> empty-grid-placeholder* {:limit limit :can-edit can-edit :create-fn create-fn @@ -646,7 +646,7 @@ :on-drop on-drop} (cond (nil? files) - [:& loading-placeholder] + [:> loading-placeholder*] (seq files) [:& line-grid-row {:files files @@ -657,8 +657,8 @@ :limit limit}] :else - [:& empty-placeholder - {:dragging? @dragging? + [:> empty-grid-placeholder* + {:is-dragging @dragging? :limit limit :can-edit can-edit :create-fn create-fn diff --git a/frontend/src/app/main/ui/dashboard/placeholder.cljs b/frontend/src/app/main/ui/dashboard/placeholder.cljs index adfc3b42e0..8d6f369561 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.cljs +++ b/frontend/src/app/main/ui/dashboard/placeholder.cljs @@ -19,30 +19,46 @@ [potok.v2.core :as ptk] [rumext.v2 :as mf])) -(mf/defc empty-placeholder-projects* - {::mf/wrap-props false} +(mf/defc empty-project-placeholder* + {::mf/private true} [{:keys [on-create on-finish-import project-id]}] (let [file-input (mf/use-ref nil) - on-add-library (mf/use-fn - (fn [_] - (st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click" - ::ev/origin "dashboard" - :section "empty-placeholder-projects"})) - (dom/open-new-window "https://penpot.app/penpothub/libraries-templates"))) - on-import-files (mf/use-fn #(dom/click (mf/ref-val file-input)))] + + on-add-library + (mf/use-fn + (fn [_] + (st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click" + ::ev/origin "dashboard" + :section "empty-placeholder-projects"})) + (dom/open-new-window "https://penpot.app/penpothub/libraries-templates"))) + + on-import + (mf/use-fn #(dom/click (mf/ref-val file-input)))] [:div {:class (stl/css :empty-project-container)} - [:div {:class (stl/css :empty-project-card) :on-click on-create :title (tr "dashboard.add-file")} - [:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.create")] - [:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.start")]] + [:div {:class (stl/css :empty-project-card) + :on-click on-create + :title (tr "dashboard.add-file")} + [:div {:class (stl/css :empty-project-card-title)} + (tr "dashboard.empty-project.create")] + [:div {:class (stl/css :empty-project-card-subtitle)} + (tr "dashboard.empty-project.start")]] - [:div {:class (stl/css :empty-project-card) :on-click on-import-files :title (tr "dashboard.empty-project.import")} - [:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.import")] - [:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.import-penpot")]] + [:div {:class (stl/css :empty-project-card) + :on-click on-import + :title (tr "dashboard.empty-project.import")} + [:div {:class (stl/css :empty-project-card-title)} + (tr "dashboard.empty-project.import")] + [:div {:class (stl/css :empty-project-card-subtitle)} + (tr "dashboard.empty-project.import-penpot")]] - [:div {:class (stl/css :empty-project-card) :on-click on-add-library :title (tr "dashboard.empty-project.go-to-libraries")} - [:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.add-library")] - [:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.explore")]] + [:div {:class (stl/css :empty-project-card) + :on-click on-add-library + :title (tr "dashboard.empty-project.go-to-libraries")} + [:div {:class (stl/css :empty-project-card-title)} + (tr "dashboard.empty-project.add-library")] + [:div {:class (stl/css :empty-project-card-subtitle)} + (tr "dashboard.empty-project.explore")]] [:& udi/import-form {:ref file-input :project-id project-id @@ -65,23 +81,26 @@ files)))) st/state)) -(mf/defc empty-placeholder - [{:keys [dragging? limit origin create-fn can-edit team-id project-id on-finish-import]}] +(mf/defc empty-grid-placeholder* + [{:keys [is-dragging limit origin create-fn can-edit team-id project-id on-finish-import]}] (let [on-click (mf/use-fn (mf/deps create-fn) (fn [_] (create-fn "dashboard:empty-folder-placeholder"))) - show-text (mf/use-state nil) - on-mouse-enter (mf/use-fn #(reset! show-text true)) - on-mouse-leave (mf/use-fn #(reset! show-text nil)) + show-text* (mf/use-state nil) + show-text? (deref show-text*) + + on-mouse-enter (mf/use-fn #(reset! show-text* true)) + on-mouse-leave (mf/use-fn #(reset! show-text* nil)) has-other* (mf/with-memo [team-id] (make-has-other-files-or-projects-ref team-id)) has-other? (mf/deref has-other*)] + (cond - (true? dragging?) + (true? is-dragging) [:ul {:class (stl/css :grid-row :no-wrap) :style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} @@ -102,17 +121,23 @@ :else (if-not has-other? - [:> empty-placeholder-projects* {:on-create on-click :on-finish-import on-finish-import :project-id project-id}] + [:> empty-project-placeholder* + {:on-create on-click + :on-finish-import on-finish-import + :project-id project-id}] [:div {:class (stl/css :grid-empty-placeholder)} [:button {:class (stl/css :create-new) :on-click on-click :on-mouse-enter on-mouse-enter :on-mouse-leave on-mouse-leave} - (if @show-text (tr "dashboard.empty-project.create") i/add)]])))) + (if show-text? + (tr "dashboard.empty-project.create") + i/add)]])))) -(mf/defc loading-placeholder +(mf/defc loading-placeholder* [] [:> loader* {:width 32 :title (tr "labels.loading") :class (stl/css :placeholder-loader)} - [:span {:class (stl/css :placeholder-text)} (tr "dashboard.loading-files")]]) + [:span {:class (stl/css :placeholder-text)} + (tr "dashboard.loading-files")]]) diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 3aaa590f81..cf013de2ab 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -371,6 +371,7 @@ show-team-hero? can-invite))} (for [{:keys [id] :as project} projects] + ;; FIXME: refactor this, looks inneficient (let [files (when recent-map (->> (vals recent-map) (filterv #(= id (:project-id %))) From 95c4d95fd324724a6ffed11551209574a502b336 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 15:01:33 +0200 Subject: [PATCH 23/38] :paperclip: Use d/update-vals instead of update-vals on migrations --- common/src/app/common/files/migrations.cljc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 734b3e4299..b0c806103c 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1207,11 +1207,11 @@ object)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (update :components d/update-vals update-container)))) (defmethod migrate-data "legacy-67" [data _] @@ -1222,8 +1222,8 @@ (d/update-when container :objects update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (update :components d/update-vals update-container)))) (defmethod migrate-data "0001-remove-tokens-from-groups" [data _] @@ -1237,8 +1237,10 @@ (dissoc :applied-tokens))) (update-page [page] - (d/update-when page :objects update-vals update-object))] - (update data :pages-index update-vals update-page))) + (d/update-when page :objects d/update-vals update-object))] + + (update data :pages-index d/update-vals update-page))) + (def available-migrations (into (d/ordered-set) From ccbf17106d470085b49978cbcc5228c9bef852aa Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 15:04:22 +0200 Subject: [PATCH 24/38] :bug: Add migration for decoding and cleaning shape interactions --- common/src/app/common/files/migrations.cljc | 27 ++++++++++++++++++++- common/src/app/common/schema.cljc | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index b0c806103c..47426305fc 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -28,6 +28,7 @@ [app.common.types.container :as ctn] [app.common.types.file :as ctf] [app.common.types.shape :as cts] + [app.common.types.shape.interactions :as ctsi] [app.common.types.shape.shadow :as ctss] [app.common.uuid :as uuid] [clojure.set :as set] @@ -1241,6 +1242,29 @@ (update data :pages-index d/update-vals update-page))) +(defmethod migrate-data "0002-clean-shape-interactions" + [data _] + (let [decode-fn (sm/decoder ctsi/schema:interaction sm/json-transformer) + validate-fn (sm/validator ctsi/schema:interaction) + + xform + (comp + (map decode-fn) + (filter validate-fn)) + + update-object + (fn [object] + (d/update-when object :interactions + (fn [interactions] + (into [] xform interactions)))) + + update-container + (fn [container] + (d/update-when container :objects d/update-vals update-object))] + + (-> data + (update :pages-index d/update-vals update-container) + (update :components d/update-vals update-container)))) (def available-migrations (into (d/ordered-set) @@ -1296,4 +1320,5 @@ "legacy-65" "legacy-66" "legacy-67" - "0001-remove-tokens-from-groups"])) + "0001-remove-tokens-from-groups" + "0002-clean-shape-interactions"])) diff --git a/common/src/app/common/schema.cljc b/common/src/app/common/schema.cljc index 23d32e3e73..64eaa1f9b9 100644 --- a/common/src/app/common/schema.cljc +++ b/common/src/app/common/schema.cljc @@ -864,7 +864,7 @@ choices))] {:pred pred :type-properties - {:title "contains" + {:title "contains any" :description "contains predicate"}}))}) (register! From 151dc352c8bf622fe128e1fce7e293384d177518 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 17:21:52 +0200 Subject: [PATCH 25/38] :sparkles: Don't register shadow schema It is not really necessary, we can use the schema var directly. --- common/src/app/common/files/migrations.cljc | 7 ++----- common/src/app/common/types/shape.cljc | 2 +- common/src/app/common/types/shape/shadow.cljc | 6 ++++-- frontend/src/app/plugins/shape.cljs | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 47426305fc..1c08ad4743 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -848,9 +848,6 @@ (update :pages-index update-vals update-container) (update :components update-vals update-container)))) -(def ^:private valid-shadow? - (sm/lazy-validator ::ctss/shadow)) - (defmethod migrate-data "legacy-44" [data _] (letfn [(fix-shadow [shadow] @@ -862,7 +859,7 @@ (update-object [object] (let [xform (comp (map fix-shadow) - (filter valid-shadow?))] + (filter ctss/valid-shadow?))] (d/update-when object :shadow #(into [] xform %)))) (update-container [container] @@ -1037,7 +1034,7 @@ (update-shape [shape] (let [xform (comp (map fix-shadow) - (filter valid-shadow?))] + (filter ctss/valid-shadow?))] (d/update-when shape :shadow #(into [] xform %)))) (update-container [container] diff --git a/common/src/app/common/types/shape.cljc b/common/src/app/common/types/shape.cljc index 5033965dba..fc70ff61e1 100644 --- a/common/src/app/common/types/shape.cljc +++ b/common/src/app/common/types/shape.cljc @@ -211,7 +211,7 @@ [:interactions {:optional true} [:vector {:gen/max 2} ::ctsi/interaction]] [:shadow {:optional true} - [:vector {:gen/max 1} ::ctss/shadow]] + [:vector {:gen/max 1} ctss/schema:shadow]] [:blur {:optional true} ::ctsb/blur] [:grow-type {:optional true} [::sm/one-of grow-types]] diff --git a/common/src/app/common/types/shape/shadow.cljc b/common/src/app/common/types/shape/shadow.cljc index 1b37dd3e98..c00a1ce829 100644 --- a/common/src/app/common/types/shape/shadow.cljc +++ b/common/src/app/common/types/shape/shadow.cljc @@ -26,7 +26,9 @@ [:hidden :boolean] [:color ::ctc/color]]) -(sm/register! ::shadow schema:shadow) - (def check-shadow (sm/check-fn schema:shadow)) + +(def valid-shadow? + (sm/validator schema:shadow)) + diff --git a/frontend/src/app/plugins/shape.cljs b/frontend/src/app/plugins/shape.cljs index 5b1fe0467d..f05981d1d4 100644 --- a/frontend/src/app/plugins/shape.cljs +++ b/frontend/src/app/plugins/shape.cljs @@ -432,7 +432,7 @@ (let [id (obj/get self "$id") value (mapv #(shadow-defaults (parser/parse-shadow %)) value)] (cond - (not (sm/validate [:vector ::ctss/shadow] value)) + (not (sm/validate [:vector ctss/schema:shadow] value)) (u/display-not-valid :shadows value) (not (r/check-permission plugin-id "content:write")) From bd208c31e25d9e3d3bb3c8eb27e823683c4f27c0 Mon Sep 17 00:00:00 2001 From: Alonso Torres Date: Tue, 22 Apr 2025 18:46:21 +0200 Subject: [PATCH 26/38] :bug: Fix update layout on component restore (#6348) --- CHANGES.md | 1 + frontend/src/app/main/data/workspace/libraries.cljs | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0663499eff..527ad7b275 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - Fix several issues with internal srepl helpers - Fix unexpected exception on template import from libraries - Fix incorrect uuid parsing from different parts of code +- Fix update layout on component restore [Taiga #10637](https://tree.taiga.io/project/penpot/issue/10637) ## 2.6.1 diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 2f73ce76cc..9c98fcd939 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -586,8 +586,13 @@ ldata (dsh/lookup-file-data state library-id) changes (-> (pcb/empty-changes it) - (cll/generate-restore-component ldata component-id library-id page objects))] - (rx/of (dch/commit-changes changes)))))) + (cll/generate-restore-component ldata component-id library-id page objects)) + + frames + (->> changes :redo-changes (keep :frame-id))] + + (rx/of (dch/commit-changes changes) + (ptk/data-event :layout/update {:ids frames})))))) (defn restore-components From b7d7cf233ac68943866cb2800b1c0075932f6a39 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 19:58:10 +0200 Subject: [PATCH 27/38] :sparkles: Fix shadow colors on import penpot files --- backend/src/app/binfile/cleaner.clj | 44 +++++++++++++++++++++++++++++ backend/src/app/binfile/v3.clj | 32 ++++++++++++++------- 2 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 backend/src/app/binfile/cleaner.clj diff --git a/backend/src/app/binfile/cleaner.clj b/backend/src/app/binfile/cleaner.clj new file mode 100644 index 0000000000..1f4d29ea1f --- /dev/null +++ b/backend/src/app/binfile/cleaner.clj @@ -0,0 +1,44 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + +(ns app.binfile.cleaner + "A collection of helpers for perform cleaning of artifacts; mainly + for recently imported shapes." + (:require + [app.common.data :as d] + [app.common.uuid :as uuid])) + +(defn- fix-shape-shadow-color + "Some shapes can come with invalid `id` property on shadow colors + caused by incorrect uuid parsing bug that should be already fixed; + this function removes the invalid id from the data structure." + [shape] + (let [fix-color + (fn [{:keys [id] :as color}] + (if (uuid? id) + color + (if (and (string? id) + (re-matches uuid/regex id)) + (assoc color :id (uuid/uuid id)) + (dissoc color :id)))) + + fix-shadow + (fn [shadow] + (d/update-when shadow :color fix-color)) + + xform + (map fix-shadow)] + + (d/update-when shape :shadow + (fn [shadows] + (into [] xform shadows))))) + +(defn clean-shape-post-decode + "A shape procesor that expected to be executed after schema decoding + process but before validation." + [shape] + (-> shape + (fix-shape-shadow-color))) diff --git a/backend/src/app/binfile/v3.clj b/backend/src/app/binfile/v3.clj index dc6bf7b80b..07e953d68d 100644 --- a/backend/src/app/binfile/v3.clj +++ b/backend/src/app/binfile/v3.clj @@ -8,6 +8,7 @@ "A ZIP based binary file exportation" (:refer-clojure :exclude [read]) (:require + [app.binfile.cleaner :as bfl] [app.binfile.common :as bfc] [app.binfile.migrations :as bfm] [app.common.data :as d] @@ -594,16 +595,25 @@ (defn- read-file-components [{:keys [::bfc/input ::file-id ::entries]}] - (->> (keep (match-component-entry-fn file-id) entries) - (reduce (fn [result {:keys [id entry]}] - (let [object (->> (read-entry input entry) - (decode-component) - (validate-component))] - (if (= id (:id object)) - (assoc result id object) - result))) - {}) - (not-empty))) + (let [clean-component-post-decode + (fn [component] + (d/update-when component :objects + (fn [objects] + (reduce-kv (fn [objects id shape] + (assoc objects id (bfl/clean-shape-post-decode shape))) + objects + objects))))] + (->> (keep (match-component-entry-fn file-id) entries) + (reduce (fn [result {:keys [id entry]}] + (let [object (->> (read-entry input entry) + (decode-component) + (clean-component-post-decode) + (validate-component))] + (if (= id (:id object)) + (assoc result id object) + result))) + {}) + (not-empty)))) (defn- read-file-typographies [{:keys [::bfc/input ::file-id ::entries]}] @@ -631,7 +641,9 @@ (reduce (fn [result {:keys [id entry]}] (let [object (->> (read-entry input entry) (decode-shape) + (bfl/clean-shape-post-decode) (validate-shape))] + (if (= id (:id object)) (assoc result id object) result))) From ee0f8ad19a247bf19de9355789c5620bb26b21b6 Mon Sep 17 00:00:00 2001 From: Alonso Torres Date: Tue, 22 Apr 2025 21:03:45 +0200 Subject: [PATCH 28/38] :bug: Fix horizontal scroll in viewer (#6347) --- CHANGES.md | 1 + frontend/src/app/main/ui/viewer.scss | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 527ad7b275..824cbf4088 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ - Fix unexpected exception on template import from libraries - Fix incorrect uuid parsing from different parts of code - Fix update layout on component restore [Taiga #10637](https://tree.taiga.io/project/penpot/issue/10637) +- Fix horizontal scroll in viewer [Github #6290](https://github.com/penpot/penpot/issues/6290) ## 2.6.1 diff --git a/frontend/src/app/main/ui/viewer.scss b/frontend/src/app/main/ui/viewer.scss index 7e475a227b..31194da31b 100644 --- a/frontend/src/app/main/ui/viewer.scss +++ b/frontend/src/app/main/ui/viewer.scss @@ -117,6 +117,7 @@ padding-right: 0 $s-8 $s-40 $s-8; transition: transform 400ms ease 300ms; z-index: $z-index-2; + pointer-events: none; } .reset-button { From 3f85e89f624e3f23d4bf7d8a16d96e04c6cb9c72 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 21:26:51 +0200 Subject: [PATCH 29/38] :bug: Send frontend version on worker http requests --- frontend/src/app/util/http.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/util/http.cljs b/frontend/src/app/util/http.cljs index 47f3823668..98177688cd 100644 --- a/frontend/src/app/util/http.cljs +++ b/frontend/src/app/util/http.cljs @@ -50,7 +50,8 @@ [headers] (into {} (map vec) (seq (.entries ^js headers)))) -(def default-headers +(defn default-headers + [] {"x-frontend-version" (:full cfg/version)}) (defn fetch @@ -74,7 +75,7 @@ headers (cond-> headers (not omit-default-headers) - (d/merge default-headers)) + (merge (default-headers))) headers (-update-headers body headers) From 05fac415345716bd9d82dcd1cf568c8499b94f49 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 21:38:40 +0200 Subject: [PATCH 30/38] :bug: Remove feature checking from get-file-data-for-thumbnail rpc method The prev code has feature resolution race condition and it in reallity does not need that check. --- backend/src/app/rpc/commands/files_thumbnails.clj | 4 +--- frontend/src/app/worker/thumbnails.cljs | 9 ++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/backend/src/app/rpc/commands/files_thumbnails.clj b/backend/src/app/rpc/commands/files_thumbnails.clj index f4c5e3d140..2455807dd8 100644 --- a/backend/src/app/rpc/commands/files_thumbnails.clj +++ b/backend/src/app/rpc/commands/files_thumbnails.clj @@ -180,8 +180,7 @@ (def ^:private schema:get-file-data-for-thumbnail [:map {:title "get-file-data-for-thumbnail"} - [:file-id ::sm/uuid] - [:features {:optional true} ::cfeat/features]]) + [:file-id ::sm/uuid]]) (def ^:private schema:partial-file @@ -211,7 +210,6 @@ (fmg/migrate-file)))] (-> (cfeat/get-team-enabled-features cf/flags team) - (cfeat/check-client-features! (:features params)) (cfeat/check-file-features! (:features file))) {:file-id file-id diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 658429c198..cca294cb0e 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -42,12 +42,11 @@ :http-body body}))) (defn- request-data-for-thumbnail - [file-id revn features] + [file-id revn] (let [path "api/rpc/command/get-file-data-for-thumbnail" params {:file-id file-id :revn revn - :strip-frames-with-thumbnails true - :features features} + :strip-frames-with-thumbnails true} request {:method :get :uri (u/join cf/public-uri path) :credentials "include" @@ -86,6 +85,6 @@ nil))) (defmethod impl/handler :thumbnails/generate-for-file - [{:keys [file-id revn features] :as message} _] - (->> (request-data-for-thumbnail file-id revn features) + [{:keys [file-id revn] :as message} _] + (->> (request-data-for-thumbnail file-id revn) (rx/map render-thumbnail))) From 1194e4022272279ed71846da4bed631c0873f0f8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 22 Apr 2025 21:39:57 +0200 Subject: [PATCH 31/38] :bug: Properly dispose rx subscription on grid thumbnail component --- frontend/src/app/main/ui/dashboard/grid.cljs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index a8e731ff1c..450bcd0f33 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -89,14 +89,16 @@ (mf/with-effect [file-id revn visible? thumbnail-id] (when (and visible? (not thumbnail-id)) - (->> (ask-for-thumbnail file-id revn) - (rx/subs! (fn [thumbnail-id] - (st/emit! (dd/set-file-thumbnail file-id thumbnail-id))) - (fn [cause] - (log/error :hint "unable to render thumbnail" - :file-if file-id - :revn revn - :message (ex-message cause))))))) + (let [subscription + (->> (ask-for-thumbnail file-id revn) + (rx/subs! (fn [thumbnail-id] + (st/emit! (dd/set-file-thumbnail file-id thumbnail-id))) + (fn [cause] + (log/error :hint "unable to render thumbnail" + :file-if file-id + :revn revn + :message (ex-message cause)))))] + (partial rx/dispose! subscription)))) [:div {:class (stl/css :grid-item-th) :style {:background-color bg-color} From 1dd23a3f475ce2581f922a9b99f3a37cd50cf233 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 23 Apr 2025 07:57:56 +0200 Subject: [PATCH 32/38] :bug: Invalidate http cache on apply migrations to file on read operation --- backend/src/app/rpc/commands/files.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 39b3d6c029..58a37810cc 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -238,6 +238,7 @@ (db/update! conn :file {:data (blob/encode (:data file)) :version (:version file) + :modified-at (dt/now) :features (db/create-array conn "text" (:features file))} {:id id}) From f65518f865863ccc6fa66ce95374d8f462c7de45 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 23 Apr 2025 17:22:22 +0200 Subject: [PATCH 33/38] :bug: Fix incorrect migration application after binfile import --- backend/src/app/binfile/v3.clj | 10 +++++++++- common/src/app/common/files/migrations.cljc | 2 -- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/src/app/binfile/v3.clj b/backend/src/app/binfile/v3.clj index 07e953d68d..07ba4618dd 100644 --- a/backend/src/app/binfile/v3.clj +++ b/backend/src/app/binfile/v3.clj @@ -15,6 +15,7 @@ [app.common.data.macros :as dm] [app.common.exceptions :as ex] [app.common.features :as cfeat] + [app.common.files.migrations :as-alias fmg] [app.common.json :as json] [app.common.logging :as l] [app.common.schema :as sm] @@ -745,7 +746,14 @@ (assoc :name file-name) (assoc :project-id project-id) (dissoc :options) - (bfc/process-file))] + (bfc/process-file) + + ;; NOTE: this is necessary because when we just + ;; creating a new file from imported artifact, + ;; there are no migrations registered on the + ;; database, so we need to persist all of them, not + ;; only the applied + (vary-meta dissoc ::fmg/migrated))] (bfm/register-pending-migrations! cfg file) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 1c08ad4743..4d9a80e235 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -37,8 +37,6 @@ #?(:cljs (l/set-level! :info)) (declare ^:private available-migrations) -(declare ^:private migration-up-index) -(declare ^:private migration-down-index) (def version cfd/version) From 80308ceafa24271303c93179522300dae0dadf99 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 23 Apr 2025 18:14:10 +0200 Subject: [PATCH 34/38] :bug: Make http cache aware of missing file data migrations --- backend/src/app/rpc/commands/files.clj | 3 +-- common/src/app/common/files/migrations.cljc | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index 58a37810cc..117a432ab8 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -238,7 +238,6 @@ (db/update! conn :file {:data (blob/encode (:data file)) :version (:version file) - :modified-at (dt/now) :features (db/create-array conn "text" (:features file))} {:id id}) @@ -293,7 +292,7 @@ (defn get-file-etag [{:keys [::rpc/profile-id]} {:keys [modified-at revn vern permissions]}] - (str profile-id "/" revn "/" vern "/" + (str profile-id "/" revn "/" vern "/" (hash fmg/available-migrations) "/" (dt/format-instant modified-at :iso) "/" (uri/map->query-string permissions))) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 4d9a80e235..31d61e58c4 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -36,7 +36,7 @@ #?(:cljs (l/set-level! :info)) -(declare ^:private available-migrations) +(declare available-migrations) (def version cfd/version) @@ -48,7 +48,10 @@ [file] (or (nil? (:version file)) (not= cfd/version (:version file)) - (not= available-migrations (:migrations file)))) + (boolean + (->> (:migrations file #{}) + (set/difference available-migrations) + (not-empty))))) (def xf:map-name (map :name)) From ab5e01e54a7bf988e76853d77791d140af33423d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 24 Apr 2025 08:53:30 +0200 Subject: [PATCH 35/38] :sparkles: Ensure we don't leave :components with nil on file data after aplying migrations --- common/src/app/common/files/migrations.cljc | 66 ++++++++++----------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 31d61e58c4..9a35b50f6d 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -218,7 +218,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) ;; Remove interactions pointing to deleted frames (defmethod migrate-data "legacy-7" @@ -272,7 +272,7 @@ (-> data (update :pages-index update-vals clean-container) - (update :components update-vals clean-container)))) + (d/update-when :components update-vals clean-container)))) (defmethod migrate-data "legacy-9" [data _] @@ -383,7 +383,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-16" [data _] @@ -429,7 +429,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-17" [data _] @@ -458,7 +458,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) ;; Remove position-data to solve a bug with the text positioning (defmethod migrate-data "legacy-18" @@ -473,7 +473,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-19" [data _] @@ -489,7 +489,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-25" [data _] @@ -504,7 +504,7 @@ (d/update-when container :objects update-vals update-object))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-26" [data _] @@ -521,7 +521,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-27" [data _] @@ -552,7 +552,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-28" [data _] @@ -578,7 +578,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-29" [data _] @@ -613,7 +613,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-31" [data _] @@ -627,7 +627,7 @@ (d/update-when container :objects update-vals update-object))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-32" [data _] @@ -646,7 +646,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-33" [data _] @@ -679,7 +679,7 @@ (d/update-when container :objects update-vals update-object))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-36" [data _] @@ -690,7 +690,7 @@ objects))))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-37" [data _] @@ -722,7 +722,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-39" [data _] @@ -744,7 +744,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-40" [data _] @@ -768,7 +768,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-41" [data _] @@ -801,7 +801,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-42" [data _] @@ -818,7 +818,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (def ^:private valid-fill? (sm/lazy-validator ::cts/fill)) @@ -847,7 +847,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-44" [data _] @@ -867,7 +867,7 @@ (d/update-when container :objects update-vals update-object))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-45" [data _] @@ -893,7 +893,7 @@ (d/update-when container :objects update-vals update-object))] (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-47" [data _] @@ -997,7 +997,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (def ^:private valid-color? (sm/lazy-validator ::ctc/color)) @@ -1043,7 +1043,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) ;; This migration moves page options to the page level (defmethod migrate-data "legacy-55" @@ -1099,7 +1099,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-57" @@ -1141,7 +1141,7 @@ (-> data (update :pages-index update-vals update-container) - (update :components update-vals update-container)))) + (d/update-when :components update-vals update-container)))) (defmethod migrate-data "legacy-62" [data _] @@ -1174,7 +1174,7 @@ ;; so the relevant objects are inside the component (d/update-when component :objects remove-cycles))] - (update data :components update-vals update-component))) + (d/update-when data :components update-vals update-component))) (defmethod migrate-data "legacy-65" [data _] @@ -1189,7 +1189,7 @@ (-> data (update-object) - (d/update-when :pages-index update-vals update-page) + (update :pages-index update-vals update-page) (d/update-when :colors update-vals update-object) (d/update-when :typographies update-vals update-object) (d/update-when :components update-vals update-object)))) @@ -1210,7 +1210,7 @@ (-> data (update :pages-index d/update-vals update-container) - (update :components d/update-vals update-container)))) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-67" [data _] @@ -1222,7 +1222,7 @@ (-> data (update :pages-index d/update-vals update-container) - (update :components d/update-vals update-container)))) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "0001-remove-tokens-from-groups" [data _] @@ -1262,7 +1262,7 @@ (-> data (update :pages-index d/update-vals update-container) - (update :components d/update-vals update-container)))) + (d/update-when :components d/update-vals update-container)))) (def available-migrations (into (d/ordered-set) From 283cdee5d6f259dcc4504c1c5e4a2a92d050d5f2 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 24 Apr 2025 08:55:54 +0200 Subject: [PATCH 36/38] :sparkles: Ensure consistency on using d/update-vals on file migrations --- common/src/app/common/files/migrations.cljc | 228 ++++++++++---------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 9a35b50f6d..1beb5ff101 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -121,9 +121,9 @@ (into [] shapes) shapes)))) (update-page [page] - (update page :objects update-vals update-object))] + (update page :objects d/update-vals update-object))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) (defmethod migrate-data "legacy-3" [data _] @@ -174,9 +174,9 @@ (fix-empty-points))) (update-page [page] - (update page :objects update-vals update-object))] + (update page :objects d/update-vals update-object))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) ;; Put the id of the local file in :component-file in instances of ;; local components @@ -189,9 +189,9 @@ object)) (update-page [page] - (update page :objects update-vals update-object))] + (update page :objects d/update-vals update-object))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) ;; Fixes issues with selrect/points for shapes with width/height = ;; 0 (line-like paths) @@ -214,11 +214,11 @@ shape)) (update-container [container] - (update container :objects update-vals fix-line-paths))] + (update container :objects d/update-vals fix-line-paths))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) ;; Remove interactions pointing to deleted frames (defmethod migrate-data "legacy-7" @@ -229,9 +229,9 @@ (filterv #(get-in page [:objects (:destination %)]) interactions)))) (update-page [page] - (update page :objects update-vals (partial update-object page)))] + (update page :objects d/update-vals (partial update-object page)))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) ;; Remove groups without any shape, both in pages and components (defmethod migrate-data "legacy-8" @@ -271,8 +271,8 @@ (assoc container :objects objects)))))] (-> data - (update :pages-index update-vals clean-container) - (d/update-when :components update-vals clean-container)))) + (update :pages-index d/update-vals clean-container) + (d/update-when :components d/update-vals clean-container)))) (defmethod migrate-data "legacy-9" [data _] @@ -306,7 +306,7 @@ [data _] (letfn [(update-page [page] (d/update-in-when page [:objects uuid/zero] dissoc :points :selrect))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) (defmethod migrate-data "legacy-11" [data _] @@ -320,7 +320,7 @@ (update page :objects (fn [objects] (update-vals objects (partial update-object objects)))))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) (defmethod migrate-data "legacy-12" [data _] @@ -330,9 +330,9 @@ (assoc :size nil))) (update-page [page] - (d/update-in-when page [:options :saved-grids] update-vals update-grid))] + (d/update-in-when page [:options :saved-grids] d/update-vals update-grid))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) ;; Add rx and ry to images (defmethod migrate-data "legacy-13" @@ -350,9 +350,9 @@ (fix-radius))) (update-page [page] - (update page :objects update-vals update-object))] + (update page :objects d/update-vals update-object))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) (defmethod migrate-data "legacy-14" [data _] @@ -382,8 +382,8 @@ container))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-16" [data _] @@ -425,11 +425,11 @@ (assign-fills))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-17" [data _] @@ -454,11 +454,11 @@ (assoc :fills []))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) ;; Remove position-data to solve a bug with the text positioning (defmethod migrate-data "legacy-18" @@ -469,11 +469,11 @@ (dissoc :position-data))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-19" [data _] @@ -485,11 +485,11 @@ (dissoc :position-data))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-25" [data _] @@ -501,10 +501,10 @@ (update :selrect grc/make-rect) (cts/create-shape)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-26" [data _] @@ -517,11 +517,11 @@ (assoc :transform-inverse (gmt/matrix)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-27" [data _] @@ -548,11 +548,11 @@ (dissoc :saved-component-root?)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-28" [data _] @@ -577,8 +577,8 @@ (d/update-when container :objects #(update-vals % (partial update-object %))))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-29" [data _] @@ -609,11 +609,11 @@ (update :content #(txt/transform-nodes invalid-node? fix-node %))))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-31" [data _] @@ -624,10 +624,10 @@ (dissoc :use-for-thumbnail?)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-32" [data _] @@ -642,11 +642,11 @@ object))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-33" [data _] @@ -664,9 +664,9 @@ object)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container)))) + (update :pages-index d/update-vals update-container)))) (defmethod migrate-data "legacy-34" [data _] @@ -676,10 +676,10 @@ (dissoc object :x :y :width :height) object)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-36" [data _] @@ -689,8 +689,8 @@ (dissoc objects nil) objects))))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-37" [data _] @@ -718,11 +718,11 @@ shape))) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-39" [data _] @@ -740,11 +740,11 @@ shape)) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-40" [data _] @@ -764,11 +764,11 @@ shape)) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-41" [data _] @@ -797,11 +797,11 @@ shape)) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-42" [data _] @@ -814,11 +814,11 @@ object)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (def ^:private valid-fill? (sm/lazy-validator ::cts/fill)) @@ -843,11 +843,11 @@ object)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-44" [data _] @@ -864,10 +864,10 @@ (d/update-when object :shadow #(into [] xform %)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-45" [data _] @@ -880,9 +880,9 @@ :parent-id parent-id))) (update-container [container] - (d/update-when container :objects update-vals fix-shape))] + (d/update-when container :objects d/update-vals fix-shape))] (-> data - (update :pages-index update-vals update-container)))) + (update :pages-index d/update-vals update-container)))) (defmethod migrate-data "legacy-46" [data _] @@ -890,10 +890,10 @@ (dissoc object :thumbnail)) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-47" [data _] @@ -914,9 +914,9 @@ shape))) (update-page [page] - (d/update-when page :objects update-vals (partial fix-shape page)))] + (d/update-when page :objects d/update-vals (partial fix-shape page)))] (-> data - (update :pages-index update-vals update-page)))) + (update :pages-index d/update-vals update-page)))) (defmethod migrate-data "legacy-48" [data _] @@ -928,9 +928,9 @@ shape))) (update-page [page] - (d/update-when page :objects update-vals fix-shape))] + (d/update-when page :objects d/update-vals fix-shape))] (-> data - (update :pages-index update-vals update-page)))) + (update :pages-index d/update-vals update-page)))) ;; Remove hide-in-viewer for shapes that are origin or destination of an interaction (defmethod migrate-data "legacy-49" @@ -948,9 +948,9 @@ (mapcat :interactions) (map :destination) (set))] - (update page :objects update-vals (partial update-object destinations))))] + (update page :objects d/update-vals (partial update-object destinations))))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) ;; This migration mainly fixes paths with curve-to segments ;; without :c1x :c1y :c2x :c2y properties. Additionally, we found a @@ -993,11 +993,11 @@ update-container (fn [page] - (d/update-when page :objects update-vals update-shape))] + (d/update-when page :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (def ^:private valid-color? (sm/lazy-validator ::ctc/color)) @@ -1017,9 +1017,9 @@ shape)) (update-page [page] - (d/update-when page :objects update-vals update-shape))] + (d/update-when page :objects d/update-vals update-shape))] - (update data :pages-index update-vals update-page))) + (update data :pages-index d/update-vals update-page))) (defmethod migrate-data "legacy-53" @@ -1039,11 +1039,11 @@ (d/update-when shape :shadow #(into [] xform %)))) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) ;; This migration moves page options to the page level (defmethod migrate-data "legacy-55" @@ -1095,11 +1095,11 @@ (update :content (partial txt/transform-nodes identity fix-fills))))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-57" @@ -1126,7 +1126,7 @@ (-> data (update :pages (fn [pages] (into [] (remove nil?) pages))) (update :pages-index dissoc nil) - (update :pages-index update-vals update-page)))) + (update :pages-index d/update-vals update-page)))) (defmethod migrate-data "legacy-59" [data _] @@ -1137,11 +1137,11 @@ (d/update-when shape :touched #(into #{} (map fix-touched) %))) (update-container [container] - (d/update-when container :objects update-vals update-shape))] + (d/update-when container :objects d/update-vals update-shape))] (-> data - (update :pages-index update-vals update-container) - (d/update-when :components update-vals update-container)))) + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container)))) (defmethod migrate-data "legacy-62" [data _] @@ -1174,7 +1174,7 @@ ;; so the relevant objects are inside the component (d/update-when component :objects remove-cycles))] - (d/update-when data :components update-vals update-component))) + (d/update-when data :components d/update-vals update-component))) (defmethod migrate-data "legacy-65" [data _] @@ -1185,14 +1185,14 @@ update-page (fn [page] (-> (update-object page) - (update :objects update-vals update-object)))] + (update :objects d/update-vals update-object)))] (-> data (update-object) - (update :pages-index update-vals update-page) - (d/update-when :colors update-vals update-object) - (d/update-when :typographies update-vals update-object) - (d/update-when :components update-vals update-object)))) + (update :pages-index d/update-vals update-page) + (d/update-when :colors d/update-vals update-object) + (d/update-when :typographies d/update-vals update-object) + (d/update-when :components d/update-vals update-object)))) (defmethod migrate-data "legacy-66" [data _] @@ -1218,7 +1218,7 @@ (d/update-when object :shadow #(into [] (reverse %)))) (update-container [container] - (d/update-when container :objects update-vals update-object))] + (d/update-when container :objects d/update-vals update-object))] (-> data (update :pages-index d/update-vals update-container) From 3e0c2bf1a1bf0546e7dd02f798f1caf8c98685a9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 24 Apr 2025 09:10:52 +0200 Subject: [PATCH 37/38] :bug: Add migration for fix root shape --- common/src/app/common/files/migrations.cljc | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 1beb5ff101..d307756f05 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -1264,6 +1264,28 @@ (update :pages-index d/update-vals update-container) (d/update-when :components d/update-vals update-container)))) +(defmethod migrate-data "0003-fix-root-shape" + [data _] + (letfn [(update-object [shape] + (if (= (:id shape) uuid/zero) + (-> shape + (assoc :parent-id uuid/zero) + (assoc :frame-id uuid/zero) + ;; We explicitly dissoc them and let the shape-setup + ;; to regenerate it with valid values. + (dissoc :selrect) + (dissoc :points) + (cts/setup-shape)) + shape)) + + (update-container [container] + (d/update-when container :objects d/update-vals update-object))] + + (-> data + (update :pages-index d/update-vals update-container) + (d/update-when :components d/update-vals update-container) + (d/without-nils)))) + (def available-migrations (into (d/ordered-set) ["legacy-2" @@ -1319,4 +1341,5 @@ "legacy-66" "legacy-67" "0001-remove-tokens-from-groups" - "0002-clean-shape-interactions"])) + "0002-clean-shape-interactions" + "0003-fix-root-shape"])) From c96fbfdcd6e612d7886e320303f272d3aa16b00b Mon Sep 17 00:00:00 2001 From: Xaviju Date: Thu, 24 Apr 2025 13:29:56 +0200 Subject: [PATCH 38/38] :books: Update tokens changelog for 2.6.2 (#6364) Co-authored-by: Xavier Julian --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 824cbf4088..e8fb2aa482 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ - Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615) - Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745) +- Fix collapsing grouped sets in "edit Theme" closes the dialog [Taiga #10771](https://tree.taiga.io/project/penpot/issue/10771) - Fix unexpected exception on path editor on merge segments when undo stack is empty - Fix pricing CTA to be under a config flag [Taiga #10808](https://tree.taiga.io/project/penpot/issue/10808) - Fix allow moving a main component into another [Taiga #10818](https://tree.taiga.io/project/penpot/issue/10818)