From 98038b10a03786755c78ddd79425d061af19ab5b Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 30 May 2024 11:15:27 +0200 Subject: [PATCH 1/6] :tada: Add a/b test for onboarding questions --- .../styles/common/refactor/basic-rules.scss | 3 + .../styles/common/refactor/color-defs.scss | 2 + .../common/refactor/themes/default-theme.scss | 1 + .../common/refactor/themes/light-theme.scss | 2 + frontend/src/app/main/ui/onboarding.cljs | 8 +- .../app/main/ui/onboarding/newsletter.cljs | 7 +- .../src/app/main/ui/onboarding/questions.cljs | 6 +- .../app/main/ui/onboarding/team_choice.cljs | 13 +- frontend/src/app/main/ui/releases/v2_0.cljs | 321 +++++++++--------- 9 files changed, 195 insertions(+), 168 deletions(-) diff --git a/frontend/resources/styles/common/refactor/basic-rules.scss b/frontend/resources/styles/common/refactor/basic-rules.scss index 12c7961c8..858838d05 100644 --- a/frontend/resources/styles/common/refactor/basic-rules.scss +++ b/frontend/resources/styles/common/refactor/basic-rules.scss @@ -593,6 +593,9 @@ width: 100%; z-index: $z-index-modal; background-color: var(--overlay-color); + &.onboarding-a-b-test { + background-color: var(--overlay-color-onboarding-a-b-test); + } } .modal-container-base { diff --git a/frontend/resources/styles/common/refactor/color-defs.scss b/frontend/resources/styles/common/refactor/color-defs.scss index da1f0d784..c7048003d 100644 --- a/frontend/resources/styles/common/refactor/color-defs.scss +++ b/frontend/resources/styles/common/refactor/color-defs.scss @@ -11,6 +11,7 @@ // Dark background --db-primary: #18181a; --db-primary-60: #{color.change(#18181a, $alpha: 0.6)}; + --db-primary-90: #{color.change(#18181a, $alpha: 0.9)}; --db-secondary: #000000; --db-secondary-30: #{color.change(#000000, $alpha: 0.3)}; --db-secondary-80: #{color.change(#000000, $alpha: 0.8)}; @@ -35,6 +36,7 @@ // Light background --lb-primary: #ffffff; --lb-primary-60: #{color.change(#ffffff, $alpha: 0.6)}; + --lb-primary-90: #{color.change(#ffffff, $alpha: 0.9)}; --lb-secondary: #e8eaee; --lb-secondary-30: #{color.change(#e8eaee, $alpha: 0.3)}; --lb-secondary-80: #{color.change(#e8eaee, $alpha: 0.8)}; diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss index 432906c9e..2b5feb06a 100644 --- a/frontend/resources/styles/common/refactor/themes/default-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss @@ -37,6 +37,7 @@ --color-info-foreground: var(--status-color-info-500); --overlay-color: var(--db-primary-60); + --overlay-color-onboarding-a-b-test: var(--db-primary-90); --shadow-color: var(--db-secondary-30); --radio-button-box-shadow: 0 0 0 1px var(--db-secondary-30) inset; diff --git a/frontend/resources/styles/common/refactor/themes/light-theme.scss b/frontend/resources/styles/common/refactor/themes/light-theme.scss index cd9b6e61c..01e98c6cb 100644 --- a/frontend/resources/styles/common/refactor/themes/light-theme.scss +++ b/frontend/resources/styles/common/refactor/themes/light-theme.scss @@ -37,6 +37,8 @@ --color-info-foreground: var(--status-color-info-500); --overlay-color: var(--lb-primary-60); + --overlay-color-onboarding-a-b-test: var(--lb-primary-90); + --shadow-color: var(--lf-secondary-40); --radio-button-box-shadow: 0 0 0 1px var(--lb-secondary) inset; diff --git a/frontend/src/app/main/ui/onboarding.cljs b/frontend/src/app/main/ui/onboarding.cljs index 3788ac3f5..f79b2e81a 100644 --- a/frontend/src/app/main/ui/onboarding.cljs +++ b/frontend/src/app/main/ui/onboarding.cljs @@ -142,7 +142,9 @@ (modal/show! {:type :onboarding-newsletter}) (contains? cf/flags :onboarding-team) - (modal/show! {:type :onboarding-team}))))] + (modal/show! {:type :onboarding-team})))) + + onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] (mf/with-effect [@slide] (when (not= :start @slide) @@ -151,8 +153,8 @@ (fn [] (reset! klass nil) (tm/dispose! sem)))) - - [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} [:div.animated {:class (dm/str @klass " " (stl/css :animated))} (case @slide :start [:& onboarding-welcome {:next #(navigate :opensource)}] diff --git a/frontend/src/app/main/ui/onboarding/newsletter.cljs b/frontend/src/app/main/ui/onboarding/newsletter.cljs index e0336641e..4de6caf2f 100644 --- a/frontend/src/app/main/ui/onboarding/newsletter.cljs +++ b/frontend/src/app/main/ui/onboarding/newsletter.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.onboarding.newsletter (:require-macros [app.main.style :as stl]) (:require + [app.config :as cf] [app.main.data.messages :as msg] [app.main.data.modal :as modal] [app.main.data.users :as du] @@ -35,9 +36,11 @@ (st/emit! (when (or @newsletter-updates @newsletter-news) (msg/success message)) (modal/show {:type :onboarding-team}) - (du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news}))))] + (du/update-profile-props {:newsletter-updates @newsletter-updates :newsletter-news @newsletter-news})))) + onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] - [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} [:div.animated.fadeInDown {:class (stl/css :modal-container)} [:div {:class (stl/css :modal-left)} [:img {:src "images/deco-newsletter.png" diff --git a/frontend/src/app/main/ui/onboarding/questions.cljs b/frontend/src/app/main/ui/onboarding/questions.cljs index ae9f5d427..2c05f7ef5 100644 --- a/frontend/src/app/main/ui/onboarding/questions.cljs +++ b/frontend/src/app/main/ui/onboarding/questions.cljs @@ -287,9 +287,11 @@ (modal/show! {:type :onboarding-team}) :else - (modal/hide!)))))] + (modal/hide!))))) + onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] - [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} [:div {:class (stl/css :modal-container) :ref container} (case @step diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index 86b710bcf..a9b4bbc4b 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dmc] [app.common.spec :as us] + [app.config :as cf] [app.main.data.dashboard :as dd] [app.main.data.events :as ev] [app.main.data.messages :as msg] @@ -84,14 +85,16 @@ ::ev/origin "onboarding" :step 1})))) - teams (mf/deref refs/teams)] + teams (mf/deref refs/teams) + onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] (mf/with-effect [teams] (when (> (count teams) 1) (st/emit! (modal/hide)))) (when (< (count teams) 2) - [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} [:div.animated.fadeIn {:class (stl/css :modal-container)} [:& team-modal-left] [:div {:class (stl/css :separator)}] @@ -212,9 +215,11 @@ (if (> (count emails) 0) (on-invite-now form) (on-invite-later form)) - (modal/hide!))))] + (modal/hide!)))) + onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] - [:div {:class (stl/css :modal-overlay)} + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} [:div.animated.fadeIn {:class (stl/css :modal-container)} [:& team-modal-left] diff --git a/frontend/src/app/main/ui/releases/v2_0.cljs b/frontend/src/app/main/ui/releases/v2_0.cljs index 0c3af3060..511307544 100644 --- a/frontend/src/app/main/ui/releases/v2_0.cljs +++ b/frontend/src/app/main/ui/releases/v2_0.cljs @@ -8,196 +8,203 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data.macros :as dm] + [app.config :as cf] [app.main.ui.releases.common :as c] [rumext.v2 :as mf])) ;; TODO: Review all copies and alt text (defmethod c/render-release-notes "2.0" [{:keys [slide klass next finish navigate version]}] - (mf/html - (case slide - :start - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class klass} - [:div {:class (stl/css :modal-container)} - [:img {:src "images/features/2.0-intro-image.png" - :class (stl/css :start-image) - :border "0" - :alt "A graphic illustration with Penpot style"}] + (let [onboarding-a-b-test? (cf/external-feature-flag "signup-background" "test")] + (mf/html + (case slide + :start + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} + [:div.animated {:class klass} + [:div {:class (stl/css :modal-container)} + [:img {:src "images/features/2.0-intro-image.png" + :class (stl/css :start-image) + :border "0" + :alt "A graphic illustration with Penpot style"}] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h1 {:class (stl/css :modal-title)} - "Welcome to Penpot 2.0! "] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h1 {:class (stl/css :modal-title)} + "Welcome to Penpot 2.0! "] - [:div {:class (stl/css :version-tag)} - (dm/str "Version " version)]] + [:div {:class (stl/css :version-tag)} + (dm/str "Version " version)]] - [:div {:class (stl/css :features-block)} - [:p {:class (stl/css :feature-content)} - [:spam {:class (stl/css :feature-title)} - "CSS Grid Layout: "] - "Bring your designs to life, knowing that what you create is what developers code."] + [:div {:class (stl/css :features-block)} + [:p {:class (stl/css :feature-content)} + [:spam {:class (stl/css :feature-title)} + "CSS Grid Layout: "] + "Bring your designs to life, knowing that what you create is what developers code."] - [:p {:class (stl/css :feature-content)} - [:spam {:class (stl/css :feature-title)} - "Sleeker UI: "] - "We’ve polished Penpot to make your experience smoother and more enjoyable."] + [:p {:class (stl/css :feature-content)} + [:spam {:class (stl/css :feature-title)} + "Sleeker UI: "] + "We’ve polished Penpot to make your experience smoother and more enjoyable."] - [:p {:class (stl/css :feature-content)} - [:spam {:class (stl/css :feature-title)} - "New Components System: "] - "Managing and using your design components got a whole lot better."] + [:p {:class (stl/css :feature-content)} + [:spam {:class (stl/css :feature-title)} + "New Components System: "] + "Managing and using your design components got a whole lot better."] - [:p {:class (stl/css :feature-content)} - "And that’s not all - we’ve fined tuned performance and " - "accessibility to give you a better and more fluid design experience."] + [:p {:class (stl/css :feature-content)} + "And that’s not all - we’ve fined tuned performance and " + "accessibility to give you a better and more fluid design experience."] - [:p {:class (stl/css :feature-content)} - " Ready to dive in? Let 's get started!"]] + [:p {:class (stl/css :feature-content)} + " Ready to dive in? Let 's get started!"]] - [:div {:class (stl/css :navigation)} - [:button {:class (stl/css :next-btn) - :on-click next} "Continue"]]]]]] + [:div {:class (stl/css :navigation)} + [:button {:class (stl/css :next-btn) + :on-click next} "Continue"]]]]]] - 0 - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class klass} - [:div {:class (stl/css :modal-container)} - [:img {:src "images/features/2.0-css-grid.gif" - :class (stl/css :start-image) - :border "0" - :alt "Penpot's CSS Grid Layout"}] + 0 + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} + [:div.animated {:class klass} + [:div {:class (stl/css :modal-container)} + [:img {:src "images/features/2.0-css-grid.gif" + :class (stl/css :start-image) + :border "0" + :alt "Penpot's CSS Grid Layout"}] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h1 {:class (stl/css :modal-title)} - "CSS Grid Layout - Design Meets Development"]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h1 {:class (stl/css :modal-title)} + "CSS Grid Layout - Design Meets Development"]] - [:div {:class (stl/css :feature)} - [:p {:class (stl/css :feature-content)} - "The much-awaited Grid Layout introduces 2-dimensional" - " layout capabilities to Penpot, allowing for the creation" - " of adaptive layouts by leveraging the power of CSS properties."] + [:div {:class (stl/css :feature)} + [:p {:class (stl/css :feature-content)} + "The much-awaited Grid Layout introduces 2-dimensional" + " layout capabilities to Penpot, allowing for the creation" + " of adaptive layouts by leveraging the power of CSS properties."] - [:p {:class (stl/css :feature-content)} - "It’s a host of new features, including columns and" - " rows management, flexible units such as FR (fractions)," - " the ability to create and name areas, and tons of new " - "and unique possibilities within a design tool."] + [:p {:class (stl/css :feature-content)} + "It’s a host of new features, including columns and" + " rows management, flexible units such as FR (fractions)," + " the ability to create and name areas, and tons of new " + "and unique possibilities within a design tool."] - [:p {:class (stl/css :feature-content)} - "Designers will learn CSS basics while working, " - "and as always with Penpot, developers can pick" - " up the design as code to take it from there."]] + [:p {:class (stl/css :feature-content)} + "Designers will learn CSS basics while working, " + "and as always with Penpot, developers can pick" + " up the design as code to take it from there."]] - [:div {:class (stl/css :navigation)} - [:& c/navigation-bullets - {:slide slide - :navigate navigate - :total 4}] + [:div {:class (stl/css :navigation)} + [:& c/navigation-bullets + {:slide slide + :navigate navigate + :total 4}] - [:button {:on-click next - :class (stl/css :next-btn)} "Continue"]]]]]] + [:button {:on-click next + :class (stl/css :next-btn)} "Continue"]]]]]] - 1 - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class klass} - [:div {:class (stl/css :modal-container)} - [:img {:src "images/features/2.0-new-ui.gif" - :class (stl/css :start-image) - :border "0" - :alt "Penpot's UI Makeover"}] + 1 + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} + [:div.animated {:class klass} + [:div {:class (stl/css :modal-container)} + [:img {:src "images/features/2.0-new-ui.gif" + :class (stl/css :start-image) + :border "0" + :alt "Penpot's UI Makeover"}] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h1 {:class (stl/css :modal-title)} - "UI Makeover - Smoother, Sharper, and Simply More Fun"]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h1 {:class (stl/css :modal-title)} + "UI Makeover - Smoother, Sharper, and Simply More Fun"]] - [:div {:class (stl/css :feature)} - [:p {:class (stl/css :feature-content)} - "We've completely overhauled Penpot's user interface. " - "The improvements in consistency, the introduction of " - "new microinteractions, and attention to countless details" - " will significantly enhance the productivity and enjoyment of using Penpot."] - [:p {:class (stl/css :feature-content)} - "Furthermore, we’ve made several accessibility improvements, " - "with better color contrast, keyboard navigation," - " and adherence to other best practices."]] + [:div {:class (stl/css :feature)} + [:p {:class (stl/css :feature-content)} + "We've completely overhauled Penpot's user interface. " + "The improvements in consistency, the introduction of " + "new microinteractions, and attention to countless details" + " will significantly enhance the productivity and enjoyment of using Penpot."] + [:p {:class (stl/css :feature-content)} + "Furthermore, we’ve made several accessibility improvements, " + "with better color contrast, keyboard navigation," + " and adherence to other best practices."]] - [:div {:class (stl/css :navigation)} - [:& c/navigation-bullets - {:slide slide - :navigate navigate - :total 4}] + [:div {:class (stl/css :navigation)} + [:& c/navigation-bullets + {:slide slide + :navigate navigate + :total 4}] - [:button {:on-click next - :class (stl/css :next-btn)} "Continue"]]]]]] + [:button {:on-click next + :class (stl/css :next-btn)} "Continue"]]]]]] - 2 - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class klass} - [:div {:class (stl/css :modal-container)} - [:img {:src "images/features/2.0-components.gif" - :class (stl/css :start-image) - :border "0" - :alt "Penpot's new components system"}] + 2 + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} + [:div.animated {:class klass} + [:div {:class (stl/css :modal-container)} + [:img {:src "images/features/2.0-components.gif" + :class (stl/css :start-image) + :border "0" + :alt "Penpot's new components system"}] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h1 {:class (stl/css :modal-title)} - "New Components System"]] - [:div {:class (stl/css :feature)} - [:p {:class (stl/css :feature-content)} - "The new Penpot components system improves" - " control over instances, including their " - "inheritances and properties overrides. " - "Main components are now accessible as design" - " elements, allowing a better updating " - "workflow through instant changes synchronization."] - [:p {:class (stl/css :feature-content)} - "And that’s not all, there are new capabilities " - "such as component swapping and annotations " - "that will help you to better manage your design systems."]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h1 {:class (stl/css :modal-title)} + "New Components System"]] + [:div {:class (stl/css :feature)} + [:p {:class (stl/css :feature-content)} + "The new Penpot components system improves" + " control over instances, including their " + "inheritances and properties overrides. " + "Main components are now accessible as design" + " elements, allowing a better updating " + "workflow through instant changes synchronization."] + [:p {:class (stl/css :feature-content)} + "And that’s not all, there are new capabilities " + "such as component swapping and annotations " + "that will help you to better manage your design systems."]] - [:div {:class (stl/css :navigation)} - [:& c/navigation-bullets - {:slide slide - :navigate navigate - :total 4}] + [:div {:class (stl/css :navigation)} + [:& c/navigation-bullets + {:slide slide + :navigate navigate + :total 4}] - [:button {:on-click next - :class (stl/css :next-btn)} "Continue"]]]]]] + [:button {:on-click next + :class (stl/css :next-btn)} "Continue"]]]]]] - 3 - [:div {:class (stl/css :modal-overlay)} - [:div.animated {:class klass} - [:div {:class (stl/css :modal-container)} - [:img {:src "images/features/2.0-html.gif" - :class (stl/css :start-image) - :border "0" - :alt " Penpot's HTML code generator"}] + 3 + [:div {:class (stl/css-case :modal-overlay true + :onboarding-a-b-test onboarding-a-b-test?)} + [:div.animated {:class klass} + [:div {:class (stl/css :modal-container)} + [:img {:src "images/features/2.0-html.gif" + :class (stl/css :start-image) + :border "0" + :alt " Penpot's HTML code generator"}] - [:div {:class (stl/css :modal-content)} - [:div {:class (stl/css :modal-header)} - [:h1 {:class (stl/css :modal-title)} - "And much more"]] - [:div {:class (stl/css :feature)} - [:p {:class (stl/css :feature-content)} - "In addition to all of this, we’ve included several other requested improvements:"] - [:ul {:class (stl/css :feature-list)} - [:li "Access HTML markup code directly in inspect mode"] - [:li "Images are now treated as element fills, maintaining their aspect ratio on resize, ideal for flexible designs"] - [:li "Enjoy new color themes with options for both dark and light modes"] - [:li "Feel the speed boost! Enjoy a smoother experience with a bunch of performance improvements"]]] + [:div {:class (stl/css :modal-content)} + [:div {:class (stl/css :modal-header)} + [:h1 {:class (stl/css :modal-title)} + "And much more"]] + [:div {:class (stl/css :feature)} + [:p {:class (stl/css :feature-content)} + "In addition to all of this, we’ve included several other requested improvements:"] + [:ul {:class (stl/css :feature-list)} + [:li "Access HTML markup code directly in inspect mode"] + [:li "Images are now treated as element fills, maintaining their aspect ratio on resize, ideal for flexible designs"] + [:li "Enjoy new color themes with options for both dark and light modes"] + [:li "Feel the speed boost! Enjoy a smoother experience with a bunch of performance improvements"]]] - [:div {:class (stl/css :navigation)} + [:div {:class (stl/css :navigation)} - [:& c/navigation-bullets - {:slide slide - :navigate navigate - :total 4}] + [:& c/navigation-bullets + {:slide slide + :navigate navigate + :total 4}] - [:button {:on-click finish - :class (stl/css :next-btn)} "Let's go"]]]]]]))) + [:button {:on-click finish + :class (stl/css :next-btn)} "Let's go"]]]]]])))) From 347235916879cf2c75f4751406a379bea2bac3aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Fri, 31 May 2024 17:13:40 +0200 Subject: [PATCH 2/6] :bug: Add validate and repair for :misplaced-slot --- common/src/app/common/files/repair.cljc | 13 +++++++++++++ common/src/app/common/files/validate.cljc | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/common/src/app/common/files/repair.cljc b/common/src/app/common/files/repair.cljc index 98e1642a9..cd2a656d2 100644 --- a/common/src/app/common/files/repair.cljc +++ b/common/src/app/common/files/repair.cljc @@ -460,6 +460,19 @@ (pcb/with-library-data file-data) (pcb/update-component (:id shape) repair-component)))) +(defmethod repair-error :misplaced-slot + [_ {:keys [shape page-id] :as error} file-data _] + (let [repair-shape + (fn [shape] + ;; Remove the swap slot + (log/debug :hint (str " -> remove swap-slot")) + (ctk/remove-swap-slot shape))] + + (log/dbg :hint "repairing shape :misplaced-slot" :id (:id shape) :name (:name shape) :page-id page-id) + (-> (pcb/empty-changes nil page-id) + (pcb/with-file-data file-data) + (pcb/update-shapes [(:id shape)] repair-shape)))) + (defmethod repair-error :missing-slot [_ {:keys [shape page-id args] :as error} file-data _] (let [repair-shape diff --git a/common/src/app/common/files/validate.cljc b/common/src/app/common/files/validate.cljc index 7959c5f31..7caceed49 100644 --- a/common/src/app/common/files/validate.cljc +++ b/common/src/app/common/files/validate.cljc @@ -52,6 +52,7 @@ :not-component-not-allowed :component-nil-objects-not-allowed :instance-head-not-frame + :misplaced-slot :missing-slot}) (def ^:private @@ -287,6 +288,14 @@ "Shape inside main instance should not have shape-ref" shape file page))) +(defn- check-empty-swap-slot + "Validate that this shape does not have any swap slot." + [shape file page] + (when (some? (ctk/get-swap-slot shape)) + (report-error :misplaced-slot + "This shape should not have swap slot" + shape file page))) + (defn- check-shape-main-root-top "Root shape of a top main instance: @@ -298,6 +307,7 @@ (check-component-main-head shape file page libraries) (check-component-root shape file page) (check-component-not-ref shape file page) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :main-top) (:shapes shape))) (defn- check-shape-main-root-nested @@ -309,6 +319,7 @@ (check-component-main-head shape file page libraries) (check-component-not-root shape file page) (check-component-not-ref shape file page) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :main-nested) (:shapes shape))) (defn- check-shape-copy-root-top @@ -323,6 +334,7 @@ (check-component-not-main-head shape file page libraries) (check-component-root shape file page) (check-component-ref shape file page libraries) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :copy-top :library-exists library-exists) (:shapes shape)))) (defn- check-shape-copy-root-nested @@ -345,6 +357,7 @@ (check-component-not-main-not-head shape file page) (check-component-not-root shape file page) (check-component-not-ref shape file page) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :main-any) (:shapes shape))) (defn- check-shape-copy-not-root @@ -353,6 +366,7 @@ (check-component-not-main-not-head shape file page) (check-component-not-root shape file page) (check-component-ref shape file page libraries) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :copy-any) (:shapes shape))) (defn- check-shape-not-component @@ -362,6 +376,7 @@ (check-component-not-main-not-head shape file page) (check-component-not-root shape file page) (check-component-not-ref shape file page) + (check-empty-swap-slot shape file page) (run! #(check-shape % file page libraries :context :not-component) (:shapes shape))) (defn- check-shape From 5e8c164a441a97994fcb87381e749d237ac799e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Moya?= Date: Mon, 3 Jun 2024 11:37:13 +0200 Subject: [PATCH 3/6] :bug: Add migration to remove all misplaced slots --- common/src/app/common/files/defaults.cljc | 2 +- common/src/app/common/files/migrations.cljc | 17 ++++++++++++++++- common/src/app/common/types/component.cljc | 10 +++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/common/src/app/common/files/defaults.cljc b/common/src/app/common/files/defaults.cljc index 721adab70..5c15fc10d 100644 --- a/common/src/app/common/files/defaults.cljc +++ b/common/src/app/common/files/defaults.cljc @@ -6,4 +6,4 @@ (ns app.common.files.defaults) -(def version 47) +(def version 48) diff --git a/common/src/app/common/files/migrations.cljc b/common/src/app/common/files/migrations.cljc index 363311564..3b7803156 100644 --- a/common/src/app/common/files/migrations.cljc +++ b/common/src/app/common/files/migrations.cljc @@ -923,6 +923,20 @@ (-> data (update :pages-index update-vals update-page)))) +(defn migrate-up-48 + [data] + (letfn [(fix-shape [shape] + (let [swap-slot (ctk/get-swap-slot shape)] + (if (and (some? swap-slot) + (not (ctk/subcopy-head? shape))) + (ctk/remove-swap-slot shape) + shape))) + + (update-page [page] + (d/update-when page :objects update-vals fix-shape))] + (-> data + (update :pages-index update-vals update-page)))) + (def migrations "A vector of all applicable migrations" [{:id 2 :migrate-up migrate-up-2} @@ -961,4 +975,5 @@ {:id 44 :migrate-up migrate-up-44} {:id 45 :migrate-up migrate-up-45} {:id 46 :migrate-up migrate-up-46} - {:id 47 :migrate-up migrate-up-47}]) + {:id 47 :migrate-up migrate-up-47} + {:id 48 :migrate-up migrate-up-48}]) diff --git a/common/src/app/common/types/component.cljc b/common/src/app/common/types/component.cljc index 7c48e7f30..95bf3016a 100644 --- a/common/src/app/common/types/component.cljc +++ b/common/src/app/common/types/component.cljc @@ -130,6 +130,15 @@ (and (some? (:component-id shape)) (nil? (:component-root shape)))) +(defn subcopy-head? + "Check if this shape is the head of a subinstance that is a copy." + [shape] + ;; This is redundant with the previous one, but may give more security + ;; in case of bugs. + (and (some? (:component-id shape)) + (nil? (:component-root shape)) + (some? (:shape-ref shape)))) + (defn instance-of? [shape file-id component-id] (and (some? (:component-id shape)) @@ -227,7 +236,6 @@ :shape-ref :touched)) - (defn- extract-ids [shape] (if (map? shape) (let [current-id (:id shape) From 3294058e169f170acd20971743d232c5f5b2a41b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 3 Jun 2024 11:15:00 +0200 Subject: [PATCH 4/6] :sparkles: Add stricter validation for audit events --- backend/src/app/rpc/commands/audit.clj | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/app/rpc/commands/audit.clj b/backend/src/app/rpc/commands/audit.clj index 5db758b46..6af5f5b62 100644 --- a/backend/src/app/rpc/commands/audit.clj +++ b/backend/src/app/rpc/commands/audit.clj @@ -77,10 +77,19 @@ (when (seq events) (db/insert-many! pool :audit-log event-columns events)))) +(def valid-event-types + #{"action" "identify"}) + (def schema:event [:map {:title "Event"} - [:name [:string {:max 250}]] - [:type [:string {:max 250}]] + [:name + [:and {:gen/elements ["update-file", "get-profile"]} + [:string {:max 250}] + [:re #"[\d\w-]{1,50}"]]] + [:type + [:and {:gen/elements valid-event-types} + [:string {:max 250}] + [::sm/one-of {:format "string"} valid-event-types]]] [:props [:map-of :keyword :any]] [:context {:optional true} From 7c64ed84f1ed495133b707e2c3767e70f1d69341 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Mon, 3 Jun 2024 19:52:00 +0200 Subject: [PATCH 5/6] :bug: Fix swap slot is not removed on parent detach --- frontend/src/app/main/data/workspace/libraries_helpers.cljs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index ff03da46e..4c3b9d803 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -233,6 +233,10 @@ ; If the initial shape was component-root, first level subinstances are converted in top instances (pcb/update-shapes [shape-id] #(assoc % :component-root true)) + component-root? + ; If the initial shape was component-root, first level subinstances can't have swap-slot + (pcb/update-shapes [shape-id] ctk/remove-swap-slot) + :always ; Near shape-refs need to be advanced one level (generate-advance-nesting-level nil container libraries (:id shape))) From 54c506100da7a553ec6fa9064594ee0b6409f378 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Tue, 4 Jun 2024 10:53:53 +0200 Subject: [PATCH 6/6] :bug: Fix swap slot is not removed on parent detach (2) --- frontend/src/app/main/data/workspace/libraries_helpers.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index 4c3b9d803..35585af2e 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -233,8 +233,8 @@ ; If the initial shape was component-root, first level subinstances are converted in top instances (pcb/update-shapes [shape-id] #(assoc % :component-root true)) - component-root? - ; If the initial shape was component-root, first level subinstances can't have swap-slot + :always + ; First level subinstances of a detached component can't have swap-slot (pcb/update-shapes [shape-id] ctk/remove-swap-slot) :always