From 041ecf67fe7f01a7f9bbf433a131ced1b303ba04 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 21 Sep 2022 11:07:54 +0200 Subject: [PATCH 01/19] :fire: Remove sentry from codebase --- backend/src/app/config.clj | 9 -- backend/src/app/loggers/sentry.clj | 170 ----------------------------- frontend/src/app/config.cljs | 1 - frontend/src/app/main.cljs | 2 - frontend/src/app/main/sentry.cljs | 60 ---------- 5 files changed, 242 deletions(-) delete mode 100644 backend/src/app/loggers/sentry.clj delete mode 100644 frontend/src/app/main/sentry.cljs diff --git a/backend/src/app/config.clj b/backend/src/app/config.clj index e80be8f80..b718bdeeb 100644 --- a/backend/src/app/config.clj +++ b/backend/src/app/config.clj @@ -198,11 +198,6 @@ (s/def ::telemetry-with-taiga ::us/boolean) (s/def ::tenant ::us/string) -(s/def ::sentry-trace-sample-rate ::us/number) -(s/def ::sentry-attach-stack-trace ::us/boolean) -(s/def ::sentry-debug ::us/boolean) -(s/def ::sentry-dsn ::us/string) - (s/def ::config (s/keys :opt-un [::secret-key ::flags @@ -283,10 +278,6 @@ ::semaphore-auth ::rpc-rlimit-config - ::sentry-dsn - ::sentry-debug - ::sentry-attach-stack-trace - ::sentry-trace-sample-rate ::smtp-default-from ::smtp-default-reply-to ::smtp-host diff --git a/backend/src/app/loggers/sentry.clj b/backend/src/app/loggers/sentry.clj deleted file mode 100644 index 4fc9c2821..000000000 --- a/backend/src/app/loggers/sentry.clj +++ /dev/null @@ -1,170 +0,0 @@ -;; 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.loggers.sentry - "A mattermost integration for error reporting." - (:require - [app.common.logging :as l] - [app.common.uuid :as uuid] - [app.config :as cf] - [app.db :as db] - [app.util.async :as aa] - [app.worker :as wrk] - [clojure.core.async :as a] - [clojure.spec.alpha :as s] - [cuerdas.core :as str] - [integrant.core :as ig]) - (:import - io.sentry.Scope - io.sentry.IHub - io.sentry.Hub - io.sentry.NoOpHub - io.sentry.protocol.User - io.sentry.SentryOptions - io.sentry.SentryLevel - io.sentry.ScopeCallback)) - -(defonce enabled (atom true)) - -(defn- parse-context - [event] - (reduce-kv - (fn [acc k v] - (cond - (= k :id) (assoc acc k (uuid/uuid v)) - (= k :profile-id) (assoc acc k (uuid/uuid v)) - (str/blank? v) acc - :else (assoc acc k v))) - {} - (:context event))) - -(defn- parse-event - [event] - (assoc event :context (parse-context event))) - -(defn- build-sentry-options - [cfg] - (let [version (:base cf/version)] - (doto (SentryOptions.) - (.setDebug (:debug cfg false)) - (.setTracesSampleRate (:traces-sample-rate cfg 1.0)) - (.setDsn (:dsn cfg)) - (.setServerName (cf/get :host)) - (.setEnvironment (cf/get :tenant)) - (.setAttachServerName true) - (.setAttachStacktrace (:attach-stack-trace cfg false)) - (.setRelease (str "backend@" (if (= version "0.0.0") "develop" version)))))) - -(defn handle-event - [^IHub shub event] - (letfn [(set-user! [^Scope scope {:keys [context] :as event}] - (let [user (User.)] - (.setIpAddress ^User user ^String (:ip-addr context)) - (when-let [pid (:profile-id context)] - (.setId ^User user ^String (str pid))) - (.setUser scope ^User user))) - - (set-level! [^Scope scope] - (.setLevel scope SentryLevel/ERROR)) - - (set-context! [^Scope scope {:keys [context] :as event}] - (let [uri (str (cf/get :public-uri) "/dbg/error-by-id/" (:id context))] - (.setContexts scope "detailed_error_uri" ^String uri)) - (when-let [vers (:frontend-version event)] - (.setContexts scope "frontend_version" ^String vers)) - (when-let [puri (:public-uri event)] - (.setContexts scope "public_uri" ^String (str puri))) - (when-let [uagent (:user-agent context)] - (.setContexts scope "user_agent" ^String uagent)) - (when-let [tenant (:tenant event)] - (.setTag scope "tenant" ^String tenant)) - (when-let [type (:error-type context)] - (.setTag scope "error_type" ^String (str type))) - (when-let [code (:error-code context)] - (.setTag scope "error_code" ^String (str code))) - ) - - (capture [^Scope scope {:keys [context error] :as event}] - (let [msg (str (:message error) "\n\n" - - "======================================================\n" - "=================== Params ===========================\n" - "======================================================\n" - - (:params context) "\n" - - (when (:explain context) - (str "======================================================\n" - "=================== Explain ==========================\n" - "======================================================\n" - (:explain context) "\n")) - - (when (:data context) - (str "======================================================\n" - "=================== Error Data =======================\n" - "======================================================\n" - (:data context) "\n")) - - (str "======================================================\n" - "=================== Stack Trace ======================\n" - "======================================================\n" - (:trace error)) - - "\n")] - (set-user! scope event) - (set-level! scope) - (set-context! scope event) - (.captureMessage ^IHub shub msg) - )) - ] - (when @enabled - (.withScope ^IHub shub (reify ScopeCallback - (run [_ scope] - (->> event - (parse-event) - (capture scope)))))) - - )) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Error Listener -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(s/def ::receiver any?) -(s/def ::dsn ::cf/sentry-dsn) -(s/def ::trace-sample-rate ::cf/sentry-trace-sample-rate) -(s/def ::attach-stack-trace ::cf/sentry-attach-stack-trace) -(s/def ::debug ::cf/sentry-debug) - -(defmethod ig/pre-init-spec ::reporter [_] - (s/keys :req-un [::wrk/executor ::db/pool ::receiver] - :opt-un [::dsn ::trace-sample-rate ::attach-stack-trace])) - -(defmethod ig/init-key ::reporter - [_ {:keys [receiver dsn executor] :as cfg}] - (l/info :msg "initializing sentry reporter" :dsn dsn) - (let [opts (build-sentry-options cfg) - shub (if dsn - (Hub. ^SentryOptions opts) - (NoOpHub/getInstance)) - output (a/chan (a/sliding-buffer 128) - (filter #(= (:level %) "error")))] - (receiver :sub output) - (a/go-loop [] - (let [event (a/js (ex-data err)))) - (sentry/captureException err)) - err) - - - From 65afa2a8331ed7eb956d0d5c4f73e5d15abb81d8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 21 Sep 2022 11:08:13 +0200 Subject: [PATCH 02/19] :arrow_up: Update dependencies --- backend/deps.edn | 25 +++++++++++-------------- common/deps.edn | 23 ++++++++++++----------- exporter/deps.edn | 2 +- exporter/package.json | 2 +- frontend/deps.edn | 2 +- frontend/package.json | 2 +- 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/backend/deps.edn b/backend/deps.edn index fa1287599..e08b9e422 100644 --- a/backend/deps.edn +++ b/backend/deps.edn @@ -6,26 +6,26 @@ ;; Logging org.zeromq/jeromq {:mvn/version "0.5.2"} - com.github.luben/zstd-jni {:mvn/version "1.5.2-3"} + com.github.luben/zstd-jni {:mvn/version "1.5.2-4"} org.clojure/data.fressian {:mvn/version "1.0.0"} - io.prometheus/simpleclient {:mvn/version "0.15.0"} - io.prometheus/simpleclient_hotspot {:mvn/version "0.15.0"} - io.prometheus/simpleclient_jetty {:mvn/version "0.15.0" + io.prometheus/simpleclient {:mvn/version "0.16.0"} + io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} + io.prometheus/simpleclient_jetty {:mvn/version "0.16.0" :exclusions [org.eclipse.jetty/jetty-server org.eclipse.jetty/jetty-servlet]} - io.prometheus/simpleclient_httpserver {:mvn/version "0.15.0"} + io.prometheus/simpleclient_httpserver {:mvn/version "0.16.0"} - io.lettuce/lettuce-core {:mvn/version "6.1.8.RELEASE"} + io.lettuce/lettuce-core {:mvn/version "6.2.0.RELEASE"} java-http-clj/java-http-clj {:mvn/version "0.4.3"} funcool/yetti {:git/tag "v9.8" :git/sha "fbe1d7d" :git/url "https://github.com/funcool/yetti.git" :exclusions [org.slf4j/slf4j-api]} - com.github.seancorfield/next.jdbc {:mvn/version "1.2.780"} + com.github.seancorfield/next.jdbc {:mvn/version "1.3.828"} metosin/reitit-core {:mvn/version "0.5.18"} - org.postgresql/postgresql {:mvn/version "42.4.0"} + org.postgresql/postgresql {:mvn/version "42.5.0"} com.zaxxer/HikariCP {:mvn/version "5.0.1"} io.whitfin/siphash {:mvn/version "2.0.0"} @@ -42,14 +42,12 @@ org.clojars.pntblnk/clj-ldap {:mvn/version "0.0.17"} integrant/integrant {:mvn/version "0.8.0"} - io.sentry/sentry {:mvn/version "5.6.1"} - dawran6/emoji {:mvn/version "0.1.5"} - markdown-clj/markdown-clj {:mvn/version "1.11.1"} + markdown-clj/markdown-clj {:mvn/version "1.11.3"} ;; Pretty Print specs pretty-spec/pretty-spec {:mvn/version "0.1.4"} - software.amazon.awssdk/s3 {:mvn/version "2.17.272"}} + software.amazon.awssdk/s3 {:mvn/version "2.17.278"}} :paths ["src" "resources" "target/classes"] :aliases @@ -65,8 +63,7 @@ :extra-paths ["test" "dev"]} :build - {:extra-deps - {io.github.clojure/tools.build {:git/tag "v0.8.2" :git/sha "ba1a2bf"}} + {:extra-deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"}} :ns-default build} :test diff --git a/common/deps.edn b/common/deps.edn index 0c1b1b271..25ff87865 100644 --- a/common/deps.edn +++ b/common/deps.edn @@ -3,22 +3,22 @@ org.clojure/data.json {:mvn/version "2.4.0"} org.clojure/tools.cli {:mvn/version "1.0.206"} metosin/jsonista {:mvn/version "0.3.6"} - org.clojure/clojurescript {:mvn/version "1.11.57"} + org.clojure/clojurescript {:mvn/version "1.11.60"} ;; Logging - org.apache.logging.log4j/log4j-api {:mvn/version "2.17.2"} - org.apache.logging.log4j/log4j-core {:mvn/version "2.17.2"} - org.apache.logging.log4j/log4j-web {:mvn/version "2.17.2"} - org.apache.logging.log4j/log4j-jul {:mvn/version "2.17.2"} - org.apache.logging.log4j/log4j-slf4j18-impl {:mvn/version "2.17.2"} + org.apache.logging.log4j/log4j-api {:mvn/version "2.19.0"} + org.apache.logging.log4j/log4j-core {:mvn/version "2.19.0"} + org.apache.logging.log4j/log4j-web {:mvn/version "2.19.0"} + org.apache.logging.log4j/log4j-jul {:mvn/version "2.19.0"} + org.apache.logging.log4j/log4j-slf4j18-impl {:mvn/version "2.18.0"} org.slf4j/slf4j-api {:mvn/version "2.0.0-alpha1"} - selmer/selmer {:mvn/version "1.12.51"} + selmer/selmer {:mvn/version "1.12.55"} criterium/criterium {:mvn/version "0.4.6"} expound/expound {:mvn/version "0.9.0"} com.cognitect/transit-clj {:mvn/version "1.0.329"} - com.cognitect/transit-cljs {:mvn/version "0.8.269"} + com.cognitect/transit-cljs {:mvn/version "0.8.280"} java-http-clj/java-http-clj {:mvn/version "0.4.3"} funcool/promesa {:mvn/version "8.0.450"} @@ -42,21 +42,22 @@ {:extra-deps {org.clojure/tools.namespace {:mvn/version "RELEASE"} org.clojure/test.check {:mvn/version "RELEASE"} - thheller/shadow-cljs {:mvn/version "2.19.8"} + thheller/shadow-cljs {:mvn/version "2.20.2"} com.bhauman/rebel-readline {:mvn/version "RELEASE"} criterium/criterium {:mvn/version "RELEASE"} mockery/mockery {:mvn/version "RELEASE"}} :extra-paths ["test" "dev"]} :build - {:extra-deps {io.github.clojure/tools.build {:git/tag "v0.8.1" :git/sha "7d40500"}} + {:extra-deps {io.github.clojure/tools.build {:git/tag "v0.8.3" :git/sha "0d20256"}} :ns-default build} :test {:extra-paths ["test"] :extra-deps {io.github.cognitect-labs/test-runner - {:git/tag "v0.5.0" :git/sha "b3fd0d2"}} + {:git/tag "v0.5.1" :git/sha "dfb30dd"}} + :main-opts ["-m" "cognitect.test-runner"] :exec-fn cognitect.test-runner.api/test} :shadow-cljs diff --git a/exporter/deps.edn b/exporter/deps.edn index ed25f8ec4..ade109ab8 100644 --- a/exporter/deps.edn +++ b/exporter/deps.edn @@ -15,7 +15,7 @@ :dev {:extra-deps - {thheller/shadow-cljs {:mvn/version "2.19.8"}}} + {thheller/shadow-cljs {:mvn/version "2.20.2"}}} :shadow-cljs {:main-opts ["-m" "shadow.cljs.devtools.cli"]} diff --git a/exporter/package.json b/exporter/package.json index 9d2918379..099952009 100644 --- a/exporter/package.json +++ b/exporter/package.json @@ -21,7 +21,7 @@ "xregexp": "^5.0.2" }, "devDependencies": { - "shadow-cljs": "^2.19.8", + "shadow-cljs": "^2.20.2", "source-map-support": "^0.5.21" } } diff --git a/frontend/deps.edn b/frontend/deps.edn index e6090eaa8..2ebb646ae 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -32,7 +32,7 @@ :dev {:extra-paths ["dev"] :extra-deps - {thheller/shadow-cljs {:mvn/version "2.19.9"} + {thheller/shadow-cljs {:mvn/version "2.20.2"} org.clojure/tools.namespace {:mvn/version "RELEASE"} cider/cider-nrepl {:mvn/version "0.28.4"}}} diff --git a/frontend/package.json b/frontend/package.json index c52657959..9fe5b314b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -48,7 +48,7 @@ "prettier": "^2.7.1", "rimraf": "^3.0.0", "sass": "^1.53.0", - "shadow-cljs": "2.19.9" + "shadow-cljs": "2.20.2" }, "dependencies": { "@sentry/browser": "^6.17.4", From 395a7096bf25dda5878539eabdf042cf24cc2548 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 21 Sep 2022 11:30:00 +0200 Subject: [PATCH 03/19] :sparkles: Minor improvements on error report template --- backend/src/app/http/debug.clj | 2 +- backend/src/app/loggers/database.clj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj index 20ef40a6c..1133cd2a9 100644 --- a/backend/src/app/http/debug.clj +++ b/backend/src/app/http/debug.clj @@ -213,7 +213,7 @@ (render-template [report] (let [context (dissoc report - :trace :cause :params :data :spec-problems + :trace :cause :params :data :spec-problems :message :spec-explain :spec-value :error :explain :hint) params {:context (pp/pprint-str context :width 200) :hint (:hint report) diff --git a/backend/src/app/loggers/database.clj b/backend/src/app/loggers/database.clj index e34e36ada..92720f26f 100644 --- a/backend/src/app/loggers/database.clj +++ b/backend/src/app/loggers/database.clj @@ -46,6 +46,7 @@ (defn parse-event [event] (-> (parse-event-data event) + (assoc :hint (or (:hint event) (:message event))) (assoc :tenant (cf/get :tenant)) (assoc :host (cf/get :host)) (assoc :public-uri (cf/get :public-uri)) From 37e2fe5c6571e1fe69cb9542693ce641f447ad6b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 21 Sep 2022 14:20:26 +0200 Subject: [PATCH 04/19] :sparkles: Allow repeated registers after small delay Helps users with expired tokens proceed with a new register --- backend/src/app/rpc.clj | 1 + backend/src/app/rpc/commands/auth.clj | 83 +++++-- backend/src/app/rpc/commands/verify_token.clj | 191 +++++++++++++++ backend/src/app/rpc/mutations/teams.clj | 7 +- .../src/app/rpc/mutations/verify_token.clj | 161 +------------ backend/test/app/bounce_handling_test.clj | 9 +- backend/test/app/services_files_test.clj | 8 +- backend/test/app/services_profile_test.clj | 218 +++++++++++++----- backend/test/app/test_helpers.clj | 51 ++-- .../src/app/main/ui/auth/verify_token.cljs | 51 ++-- 10 files changed, 487 insertions(+), 293 deletions(-) create mode 100644 backend/src/app/rpc/commands/verify_token.clj diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index b2da55318..11acedc7c 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -222,6 +222,7 @@ (->> (sv/scan-ns 'app.rpc.commands.binfile 'app.rpc.commands.comments 'app.rpc.commands.management + 'app.rpc.commands.verify-token 'app.rpc.commands.auth 'app.rpc.commands.ldap 'app.rpc.commands.demo diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 5129100a1..f307d653d 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -6,6 +6,7 @@ (ns app.rpc.commands.auth (:require + [app.common.data :as d] [app.common.exceptions :as ex] [app.common.spec :as us] [app.common.uuid :as uuid] @@ -184,8 +185,9 @@ ;; ---- COMMAND: Prepare Register -(defn prepare-register - [{:keys [pool sprops] :as cfg} params] +(defn validate-register-attempt! + [{:keys [pool sprops]} params] + (when-not (contains? cf/flags :registration) (if-not (contains? params :invitation-token) (ex/raise :type :restriction @@ -208,20 +210,46 @@ :code :email-has-permanent-bounces :hint "looks like the email has one or many bounces reported")) - (check-profile-existence! pool params) - + ;; Perform a basic validation of email & password (when (= (str/lower (:email params)) (str/lower (:password params))) (ex/raise :type :validation :code :email-as-password - :hint "you can't use your email as password")) + :hint "you can't use your email as password"))) - (let [params {:email (:email params) - :password (:password params) - :invitation-token (:invitation-token params) - :backend "penpot" - :iss :prepared-register - :exp (dt/in-future "48h")} +(def register-retry-threshold + (dt/duration "15m")) + +(defn- elapsed-register-retry-threshold? + [profile] + (let [elapsed (dt/diff (:modified-at profile) (dt/now))] + (pos? (compare elapsed register-retry-threshold)))) + +(defn prepare-register + [{:keys [pool sprops] :as cfg} params] + + (validate-register-attempt! cfg params) + + (let [profile (when-let [profile (profile/retrieve-profile-data-by-email pool (:email params))] + (if (:is-active profile) + (ex/raise :type :validation + :code :email-already-exists + :hint "profile already exists and correctly validated") + (if (elapsed-register-retry-threshold? profile) + profile + (ex/raise :type :validation + :code :email-already-exists + :hint "profile already exists")))) + + params {:email (:email params) + :password (:password params) + :invitation-token (:invitation-token params) + :backend "penpot" + :iss :prepared-register + :profile-id (:id profile) + :exp (dt/in-future {:days 7})} + + params (d/without-nils params) token (tokens/generate sprops params)] (with-meta {:token token} @@ -240,11 +268,10 @@ ;; ---- COMMAND: Register Profile (defn create-profile - "Create the profile entry on the database with limited input filling - all the other fields with defaults." + "Create the profile entry on the database with limited set of input + attrs (all the other attrs are filled with default values)." [conn params] (let [id (or (:id params) (uuid/next)) - props (-> (audit/extract-utm-params params) (merge (:props params)) (merge {:viewed-tutorial? false @@ -320,22 +347,36 @@ (defn register-profile [{:keys [conn sprops session] :as cfg} {:keys [token] :as params}] - (let [claims (tokens/verify sprops {:token token :iss :prepared-register}) - params (merge params claims)] - (check-profile-existence! conn params) + (let [claims (tokens/verify sprops {:token token :iss :prepared-register}) + params (merge params claims)] + (let [is-active (or (:is-active params) (not (contains? cf/flags :email-verification)) ;; DEPRECATED: v1.15 (contains? cf/flags :insecure-register)) - profile (->> (assoc params :is-active is-active) - (create-profile conn) - (create-profile-relations conn) - (profile/decode-profile-row)) + profile (if-let [profile-id (:profile-id claims)] + (profile/retrieve-profile conn profile-id) + (->> (assoc params :is-active is-active) + (create-profile conn) + (create-profile-relations conn) + (profile/decode-profile-row))) + audit-fn (:audit cfg) invitation (when-let [token (:invitation-token params)] (tokens/verify sprops {:token token :iss :team-invitation}))] + + ;; If profile is filled in claims, means it tries to register + ;; again, so we proceed to update the modified-at attr + ;; accordingly. + (when-let [id (:profile-id claims)] + (db/update! conn :profile {:modified-at (dt/now)} {:id id}) + (audit-fn :cmd :submit + :type "fact" + :name "register-profile-retry" + :profile-id id)) + (cond ;; If invitation token comes in params, this is because the ;; user comes from team-invitation process; in this case, diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj new file mode 100644 index 000000000..4a93b9bce --- /dev/null +++ b/backend/src/app/rpc/commands/verify_token.clj @@ -0,0 +1,191 @@ +;; 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.rpc.commands.verify-token + (:require + [app.common.exceptions :as ex] + [app.common.spec :as us] + [app.db :as db] + [app.loggers.audit :as audit] + [app.rpc.mutations.teams :as teams] + [app.rpc.queries.profile :as profile] + [app.tokens :as tokens] + [app.rpc.doc :as-alias doc] + [app.tokens.spec.team-invitation :as-alias spec.team-invitation] + [app.util.services :as sv] + [clojure.spec.alpha :as s] + [cuerdas.core :as str])) + +(s/def ::iss keyword?) +(s/def ::exp ::us/inst) + +(defmulti process-token (fn [_ _ claims] (:iss claims))) + +(s/def ::verify-token + (s/keys :req-un [::token] + :opt-un [::profile-id])) + +(sv/defmethod ::verify-token + {:auth false + ::doc/added "1.15"} + [{:keys [pool sprops] :as cfg} {:keys [token] :as params}] + (db/with-atomic [conn pool] + (let [claims (tokens/verify sprops {:token token}) + cfg (assoc cfg :conn conn)] + (process-token cfg params claims)))) + +(defmethod process-token :change-email + [{:keys [conn] :as cfg} _params {:keys [profile-id email] :as claims}] + (when (profile/retrieve-profile-data-by-email conn email) + (ex/raise :type :validation + :code :email-already-exists)) + + (db/update! conn :profile + {:email email} + {:id profile-id}) + + (with-meta claims + {::audit/name "update-profile-email" + ::audit/props {:email email} + ::audit/profile-id profile-id})) + +(defmethod process-token :verify-email + [{:keys [conn session] :as cfg} _ {:keys [profile-id] :as claims}] + (let [profile (profile/retrieve-profile conn profile-id) + claims (assoc claims :profile profile)] + + (when-not (:is-active profile) + (when (not= (:email profile) + (:email claims)) + (ex/raise :type :validation + :code :invalid-token)) + + (db/update! conn :profile + {:is-active true} + {:id (:id profile)})) + + (with-meta claims + {:transform-response ((:create session) profile-id) + ::audit/name "verify-profile-email" + ::audit/props (audit/profile->props profile) + ::audit/profile-id (:id profile)}))) + +(defmethod process-token :auth + [{:keys [conn] :as cfg} _params {:keys [profile-id] :as claims}] + (let [profile (profile/retrieve-profile conn profile-id)] + (assoc claims :profile profile))) + +;; --- Team Invitation + +(defn- accept-invitation + [{:keys [conn] :as cfg} {:keys [member-id team-id role member-email] :as claims} invitation] + (let [member (profile/retrieve-profile conn member-id) + + ;; Update the role if there is an invitation + role (or (some-> invitation :role keyword) role) + params (merge + {:team-id team-id + :profile-id member-id} + (teams/role->params role))] + + ;; Insert the invited member to the team + (db/insert! conn :team-profile-rel params {:on-conflict-do-nothing true}) + + ;; If profile is not yet verified, mark it as verified because + ;; accepting an invitation link serves as verification. + (when-not (:is-active member) + (db/update! conn :profile + {:is-active true} + {:id member-id})) + + ;; Delete the invitation + (db/delete! conn :team-invitation + {:team-id team-id :email-to member-email}) + + (assoc member :is-active true))) + + +(s/def ::spec.team-invitation/profile-id ::us/uuid) +(s/def ::spec.team-invitation/role ::us/keyword) +(s/def ::spec.team-invitation/team-id ::us/uuid) +(s/def ::spec.team-invitation/member-email ::us/email) +(s/def ::spec.team-invitation/member-id (s/nilable ::us/uuid)) + +(s/def ::team-invitation-claims + (s/keys :req-un [::iss ::exp + ::spec.team-invitation/profile-id + ::spec.team-invitation/role + ::spec.team-invitation/team-id + ::spec.team-invitation/member-email] + :opt-un [::spec.team-invitation/member-id])) + +(defmethod process-token :team-invitation + [{:keys [conn session] :as cfg} {:keys [profile-id token]} {:keys [member-id team-id member-email] :as claims}] + (us/assert ::team-invitation-claims claims) + + (let [invitation (db/get-by-params conn :team-invitation + {:team-id team-id :email-to member-email} + {:check-not-found false})] + (when (nil? invitation) + (ex/raise :type :validation + :code :invalid-token + :hint "no invitation associated with the token")) + + (cond + ;; This happens when token is filled with member-id and current + ;; user is already logged in with exactly invited account. + (and (uuid? profile-id) (uuid? member-id)) + (if (= member-id profile-id) + (let [profile (accept-invitation cfg claims invitation)] + (with-meta + (assoc claims :state :created) + {::audit/name "accept-team-invitation" + ::audit/props (merge + (audit/profile->props profile) + {:team-id (:team-id claims) + :role (:role claims)}) + ::audit/profile-id member-id})) + (ex/raise :type :validation + :code :invalid-token + :hint "logged-in user does not matches the invitation")) + + ;; This happens when an unlogged user, uses an invitation link. + (and (not profile-id) (uuid? member-id)) + (let [profile (accept-invitation cfg claims invitation)] + (with-meta + (assoc claims :state :created) + {:transform-response ((:create session) (:id profile)) + ::audit/name "accept-team-invitation" + ::audit/props (merge + (audit/profile->props profile) + {:team-id (:team-id claims) + :role (:role claims)}) + ::audit/profile-id member-id})) + + ;; This case means that invitation token does not match with + ;; registred user, so we need to indicate to frontend to redirect + ;; it to register page. + (and (not profile-id) (nil? member-id)) + {:invitation-token token + :iss :team-invitation + :redirect-to :auth-register + :state :pending} + + ;; In all other cases, just tell to fontend to redirect the user + ;; to the login page. + :else + {:invitation-token token + :iss :team-invitation + :redirect-to :auth-login + :state :pending}))) + +;; --- Default + +(defmethod process-token :default + [_ _ _] + (ex/raise :type :validation + :code :invalid-token)) + diff --git a/backend/src/app/rpc/mutations/teams.clj b/backend/src/app/rpc/mutations/teams.clj index 9370c6506..393ebad8b 100644 --- a/backend/src/app/rpc/mutations/teams.clj +++ b/backend/src/app/rpc/mutations/teams.clj @@ -399,6 +399,7 @@ [{:keys [conn sprops team profile role email] :as cfg}] (let [member (profile/retrieve-profile-data-by-email conn email) token-exp (dt/in-future "168h") ;; 7 days + email (str/lower email) itoken (tokens/generate sprops {:iss :team-invitation :exp token-exp @@ -412,9 +413,6 @@ :profile-id (:id profile) :exp (dt/in-future {:days 30})})] - (when (contains? cf/flags :log-invitation-tokens) - (l/trace :hint "invitation token" :token itoken)) - (when (and member (not (eml/allow-send-emails? conn member))) (ex/raise :type :validation :code :member-is-muted @@ -428,6 +426,9 @@ :email email :hint "the email you invite has been repeatedly reported as spam or bounce")) + (when (contains? cf/flags :log-invitation-tokens) + (l/trace :hint "invitation token" :token itoken)) + ;; When we have email verification disabled and invitation user is ;; already present in the database, we proceed to add it to the ;; team as-is, without email roundtrip. diff --git a/backend/src/app/rpc/mutations/verify_token.clj b/backend/src/app/rpc/mutations/verify_token.clj index 31bcddcd8..9befd4e0f 100644 --- a/backend/src/app/rpc/mutations/verify_token.clj +++ b/backend/src/app/rpc/mutations/verify_token.clj @@ -6,170 +6,23 @@ (ns app.rpc.mutations.verify-token (:require - [app.common.exceptions :as ex] - [app.common.spec :as us] [app.db :as db] - [app.loggers.audit :as audit] - [app.rpc.mutations.teams :as teams] - [app.rpc.queries.profile :as profile] [app.tokens :as tokens] - [app.tokens.spec.team-invitation :as-alias spec.team-invitation] + [app.rpc.doc :as-alias doc] + [app.rpc.commands.verify-token :refer [process-token]] [app.util.services :as sv] - [clojure.spec.alpha :as s] - [cuerdas.core :as str])) - -(defmulti process-token (fn [_ _ claims] (:iss claims))) + [clojure.spec.alpha :as s])) (s/def ::verify-token (s/keys :req-un [::token] :opt-un [::profile-id])) -(sv/defmethod ::verify-token {:auth false} +(sv/defmethod ::verify-token + {:auth false + ::doc/added "1.1" + ::doc/deprecated "1.15"} [{:keys [pool sprops] :as cfg} {:keys [token] :as params}] (db/with-atomic [conn pool] (let [claims (tokens/verify sprops {:token token}) cfg (assoc cfg :conn conn)] (process-token cfg params claims)))) - -(defmethod process-token :change-email - [{:keys [conn] :as cfg} _params {:keys [profile-id email] :as claims}] - (when (profile/retrieve-profile-data-by-email conn email) - (ex/raise :type :validation - :code :email-already-exists)) - - (db/update! conn :profile - {:email email} - {:id profile-id}) - - (with-meta claims - {::audit/name "update-profile-email" - ::audit/props {:email email} - ::audit/profile-id profile-id})) - -(defmethod process-token :verify-email - [{:keys [conn session] :as cfg} _ {:keys [profile-id] :as claims}] - (let [profile (profile/retrieve-profile conn profile-id) - claims (assoc claims :profile profile)] - - (when-not (:is-active profile) - (when (not= (:email profile) - (:email claims)) - (ex/raise :type :validation - :code :invalid-token)) - - (db/update! conn :profile - {:is-active true} - {:id (:id profile)})) - - (with-meta claims - {:transform-response ((:create session) profile-id) - ::audit/name "verify-profile-email" - ::audit/props (audit/profile->props profile) - ::audit/profile-id (:id profile)}))) - -(defmethod process-token :auth - [{:keys [conn] :as cfg} _params {:keys [profile-id] :as claims}] - (let [profile (profile/retrieve-profile conn profile-id)] - (assoc claims :profile profile))) - - -;; --- Team Invitation - -(s/def ::iss keyword?) -(s/def ::exp ::us/inst) - -(s/def ::spec.team-invitation/profile-id ::us/uuid) -(s/def ::spec.team-invitation/role ::us/keyword) -(s/def ::spec.team-invitation/team-id ::us/uuid) -(s/def ::spec.team-invitation/member-email ::us/email) -(s/def ::spec.team-invitation/member-id (s/nilable ::us/uuid)) - -(s/def ::team-invitation-claims - (s/keys :req-un [::iss ::exp - ::spec.team-invitation/profile-id - ::spec.team-invitation/role - ::spec.team-invitation/team-id - ::spec.team-invitation/member-email] - :opt-un [::spec.team-invitation/member-id])) - -(defn- accept-invitation - [{:keys [conn] :as cfg} {:keys [member-id team-id role member-email] :as claims}] - (let [ - member (profile/retrieve-profile conn member-id) - invitation (db/get-by-params conn :team-invitation - {:team-id team-id :email-to (str/lower member-email)} - {:check-not-found false}) - ;; Update the role if there is an invitation - role (or (some-> invitation :role keyword) role) - params (merge {:team-id team-id - :profile-id member-id} - (teams/role->params role)) - ] - - ;; Insert the invited member to the team - (db/insert! conn :team-profile-rel params {:on-conflict-do-nothing true}) - - ;; If profile is not yet verified, mark it as verified because - ;; accepting an invitation link serves as verification. - (when-not (:is-active member) - (db/update! conn :profile - {:is-active true} - {:id member-id})) - (assoc member :is-active true) - - ;; Delete the invitation - (db/delete! conn :team-invitation - {:team-id team-id :email-to (str/lower member-email)}))) - - -(defmethod process-token :team-invitation - [cfg {:keys [profile-id token]} {:keys [member-id] :as claims}] - (us/assert ::team-invitation-claims claims) - (let [conn (:conn cfg) - team-id (:team-id claims) - member-email (:member-email claims) - invitation (db/get-by-params conn :team-invitation - {:team-id team-id :email-to (str/lower member-email)} - {:check-not-found false})] - (when (nil? invitation) - (ex/raise :type :validation - :code :invalid-token))) - - (cond - ;; This happens when token is filled with member-id and current - ;; user is already logged in with exactly invited account. - (and (uuid? profile-id) (uuid? member-id) (= member-id profile-id)) - (let [profile (accept-invitation cfg claims)] - (with-meta - (assoc claims :state :created) - {::audit/name "accept-team-invitation" - ::audit/props (merge - (audit/profile->props profile) - {:team-id (:team-id claims) - :role (:role claims)}) - ::audit/profile-id member-id})) - - ;; This case means that invitation token does not match with - ;; registred user, so we need to indicate to frontend to redirect - ;; it to register page. - (nil? member-id) - {:invitation-token token - :iss :team-invitation - :redirect-to :auth-register - :state :pending} - - ;; In all other cases, just tell to fontend to redirect the user - ;; to the login page. - :else - {:invitation-token token - :iss :team-invitation - :redirect-to :auth-login - :state :pending})) - -;; --- Default - -(defmethod process-token :default - [_ _ _] - (ex/raise :type :validation - :code :invalid-token)) - diff --git a/backend/test/app/bounce_handling_test.clj b/backend/test/app/bounce_handling_test.clj index 87a1854e0..2e22c1fa8 100644 --- a/backend/test/app/bounce_handling_test.clj +++ b/backend/test/app/bounce_handling_test.clj @@ -250,9 +250,10 @@ (t/deftest test-allow-send-messages-predicate-with-bounces (with-mocks [mock {:target 'app.config/get - :return (th/mock-config-get-with + :return (th/config-get-mock {:profile-bounce-threshold 3 :profile-complaint-threshold 2})}] + (let [profile (th/create-profile* 1) pool (:app.db/pool th/*system*)] (th/create-complaint-for pool {:type :bounce :id (:id profile) :created-at (dt/in-past {:days 8})}) @@ -260,7 +261,7 @@ (th/create-complaint-for pool {:type :bounce :id (:id profile)}) (t/is (true? (emails/allow-send-emails? pool profile))) - (t/is (= 4 (:call-count (deref mock)))) + (t/is (= 4 (:call-count @mock))) (th/create-complaint-for pool {:type :bounce :id (:id profile)}) (t/is (false? (emails/allow-send-emails? pool profile)))))) @@ -268,7 +269,7 @@ (t/deftest test-allow-send-messages-predicate-with-complaints (with-mocks [mock {:target 'app.config/get - :return (th/mock-config-get-with + :return (th/config-get-mock {:profile-bounce-threshold 3 :profile-complaint-threshold 2})}] (let [profile (th/create-profile* 1) @@ -280,7 +281,7 @@ (th/create-complaint-for pool {:type :complaint :id (:id profile)}) (t/is (true? (emails/allow-send-emails? pool profile))) - (t/is (= 4 (:call-count (deref mock)))) + (t/is (= 4 (:call-count @mock))) (th/create-complaint-for pool {:type :complaint :id (:id profile)}) (t/is (false? (emails/allow-send-emails? pool profile)))))) diff --git a/backend/test/app/services_files_test.clj b/backend/test/app/services_files_test.clj index 423f05603..e15884ad1 100644 --- a/backend/test/app/services_files_test.clj +++ b/backend/test/app/services_files_test.clj @@ -539,8 +539,8 @@ :components-v2 true} {:keys [error result] :as out} (th/query! data)] ;; (th/print-result! out) - (t/is (= :validation (th/ex-type error))) - (t/is (= :spec-validation (th/ex-code error))))) + (t/is (th/ex-of-type? error :validation)) + (t/is (th/ex-of-code? error :spec-validation (th/ex-code error))))) (t/testing "RPC :file-data-for-thumbnail" ;; Insert a thumbnail data for the frame-id @@ -728,8 +728,8 @@ ;; Then query the specific revn (let [{:keys [result error] :as out} (th/query! (assoc data :revn 1))] - (t/is (= :not-found (th/ex-type error))) - (t/is (= :file-thumbnail-not-found (th/ex-code error))))) + (t/is (th/ex-of-type? error :not-found)) + (t/is (th/ex-of-code? error :file-thumbnail-not-found)))) )) diff --git a/backend/test/app/services_profile_test.clj b/backend/test/app/services_profile_test.clj index 0c8aeaf82..884707598 100644 --- a/backend/test/app/services_profile_test.clj +++ b/backend/test/app/services_profile_test.clj @@ -119,15 +119,14 @@ )) (t/deftest profile-deletion-simple - (let [task (:app.tasks.objects-gc/handler th/*system*) - prof (th/create-profile* 1) + (let [prof (th/create-profile* 1) file (th/create-file* 1 {:profile-id (:id prof) :project-id (:default-project-id prof) :is-shared false})] ;; profile is not deleted because it does not meet all ;; conditions to be deleted. - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] (t/is (= 0 (:processed result)))) ;; Request profile to be deleted @@ -146,7 +145,7 @@ (t/is (= 1 (count (:result out))))) ;; execute permanent deletion task - (let [result (task {:min-age (dt/duration "-1m")})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration "-1m")})] (t/is (= 1 (:processed result)))) ;; query profile after delete @@ -166,7 +165,7 @@ (t/testing "not allowed email domain" (t/is (false? (cauth/email-domain-in-whitelist? whitelist "username@somedomain.com")))))) -(t/deftest prepare-register-and-register-profile +(t/deftest prepare-register-and-register-profile-1 (let [data {::th/type :prepare-register-profile :email "user@example.com" :password "foobar"} @@ -195,6 +194,100 @@ (t/is (nil? error)))) )) +(t/deftest prepare-register-and-register-profile-1 + (let [data {::th/type :prepare-register-profile + :email "user@example.com" + :password "foobar"} + out (th/mutation! data) + token (get-in out [:result :token])] + (t/is (string? token)) + + + ;; try register without token + (let [data {::th/type :register-profile + :fullname "foobar" + :accept-terms-and-privacy true} + out (th/mutation! data)] + (let [error (:error out)] + (t/is (th/ex-info? error)) + (t/is (th/ex-of-type? error :validation)) + (t/is (th/ex-of-code? error :spec-validation)))) + + ;; try correct register + (let [data {::th/type :register-profile + :token token + :fullname "foobar" + :accept-terms-and-privacy true + :accept-newsletter-subscription true}] + (let [{:keys [result error]} (th/mutation! data)] + (t/is (nil? error)))) + )) + +(t/deftest prepare-register-and-register-profile-2 + (with-redefs [app.rpc.commands.auth/register-retry-threshold (dt/duration 500)] + (with-mocks [mock {:target 'app.emails/send! :return nil}] + (let [current-token (atom nil)] + + ;; PREPARE REGISTER + (let [data {::th/type :prepare-register-profile + :email "hello@example.com" + :password "foobar"} + out (th/command! data) + token (get-in out [:result :token])] + (t/is (string? token)) + (reset! current-token token)) + + ;; DO REGISTRATION: try correct register attempt 1 + (let [data {::th/type :register-profile + :token @current-token + :fullname "foobar" + :accept-terms-and-privacy true + :accept-newsletter-subscription true} + out (th/command! data)] + (t/is (nil? (:error out))) + (t/is (= 1 (:call-count @mock)))) + + (th/reset-mock! mock) + + ;; PREPARE REGISTER without waiting for threshold + (let [data {::th/type :prepare-register-profile + :email "hello@example.com" + :password "foobar"} + out (th/command! data)] + (t/is (not (th/success? out))) + (t/is (= :validation (-> out :error th/ex-type))) + (t/is (= :email-already-exists (-> out :error th/ex-code)))) + + (th/sleep {:millis 500}) + (th/reset-mock! mock) + + ;; PREPARE REGISTER waiting the threshold + (let [data {::th/type :prepare-register-profile + :email "hello@example.com" + :password "foobar"} + out (th/command! data)] + + (t/is (th/success? out)) + (t/is (= 0 (:call-count @mock))) + + (let [result (:result out)] + (t/is (contains? result :token)) + (reset! current-token (:token result)))) + + ;; DO REGISTRATION: try correct register attempt 1 + (let [data {::th/type :register-profile + :token @current-token + :fullname "foobar" + :accept-terms-and-privacy true + :accept-newsletter-subscription true} + out (th/command! data)] + (t/is (th/success? out)) + (t/is (= 1 (:call-count @mock)))) + + )) + )) + + (t/deftest prepare-and-register-with-invitation-and-disabled-registration-1 (with-redefs [app.config/flags [:disable-registration]] (let [sprops (:app.setup/props th/*system*) @@ -239,34 +332,39 @@ :invitation-token itoken :email "user@example.com" :password "foobar"} - {:keys [result error] :as out} (th/mutation! data)] - (t/is (th/ex-info? error)) - (t/is (= :restriction (th/ex-type error))) - (t/is (= :email-does-not-match-invitation (th/ex-code error)))))) + out (th/command! data)] + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :restriction (:type edata))) + (t/is (= :email-does-not-match-invitation (:code edata)))) + ))) (t/deftest prepare-register-with-registration-disabled - (th/with-mocks {#'app.config/flags nil} + (with-redefs [app.config/flags #{}] (let [data {::th/type :prepare-register-profile :email "user@example.com" - :password "foobar"}] - (let [{:keys [result error] :as out} (th/mutation! data)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :restriction)) - (t/is (th/ex-of-code? error :registration-disabled)))))) + :password "foobar"} + out (th/command! data)] + + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :restriction (:type edata))) + (t/is (= :registration-disabled (:code edata))))))) (t/deftest prepare-register-with-existing-user (let [profile (th/create-profile* 1) data {::th/type :prepare-register-profile :email (:email profile) - :password "foobar"}] - (let [{:keys [result error] :as out} (th/mutation! data)] - ;; (th/print-result! out) - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :email-already-exists))))) + :password "foobar"} + out (th/command! data)] -(t/deftest test-register-profile-with-bounced-email + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :email-already-exists (:code edata)))))) + +(t/deftest register-profile-with-bounced-email (let [pool (:app.db/pool th/*system*) data {::th/type :prepare-register-profile :email "user@example.com" @@ -274,34 +372,38 @@ (th/create-global-complaint-for pool {:type :bounce :email "user@example.com"}) - (let [{:keys [result error] :as out} (th/mutation! data)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :email-has-permanent-bounces))))) + (let [out (th/command! data)] + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :email-has-permanent-bounces (:code edata))))))) -(t/deftest test-register-profile-with-complained-email +(t/deftest register-profile-with-complained-email (let [pool (:app.db/pool th/*system*) data {::th/type :prepare-register-profile :email "user@example.com" :password "foobar"}] (th/create-global-complaint-for pool {:type :complaint :email "user@example.com"}) - (let [{:keys [result error] :as out} (th/mutation! data)] - (t/is (nil? error)) - (t/is (string? (:token result)))))) -(t/deftest test-register-profile-with-email-as-password - (let [data {::th/type :prepare-register-profile - :email "user@example.com" - :password "USER@example.com"}] + (let [out (th/command! data)] + (t/is (th/success? out)) + (let [result (:result out)] + (t/is (contains? result :token)))))) - (let [{:keys [result error] :as out} (th/mutation! data)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :email-as-password))))) +(t/deftest register-profile-with-email-as-password + (let [data {::th/type :prepare-register-profile + :email "user@example.com" + :password "USER@example.com"} + out (th/command! data)] -(t/deftest test-email-change-request - (with-mocks [email-send-mock {:target 'app.emails/send! :return nil}] + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :email-as-password (:code edata)))))) + +(t/deftest email-change-request + (with-mocks [mock {:target 'app.emails/send! :return nil}] (let [profile (th/create-profile* 1) pool (:app.db/pool th/*system*) data {::th/type :request-email-change @@ -312,7 +414,7 @@ (let [out (th/mutation! data)] ;; (th/print-result! out) (t/is (nil? (:result out))) - (let [mock (deref email-send-mock)] + (let [mock @mock] (t/is (= 1 (:call-count mock))) (t/is (true? (:called? mock))))) @@ -321,7 +423,7 @@ (let [out (th/mutation! data)] ;; (th/print-result! out) (t/is (nil? (:result out))) - (t/is (= 2 (:call-count (deref email-send-mock))))) + (t/is (= 2 (:call-count @mock)))) ;; with bounces (th/create-global-complaint-for pool {:type :bounce :email (:email data)}) @@ -331,28 +433,26 @@ (t/is (th/ex-info? error)) (t/is (th/ex-of-type? error :validation)) (t/is (th/ex-of-code? error :email-has-permanent-bounces)) - (t/is (= 2 (:call-count (deref email-send-mock)))))))) + (t/is (= 2 (:call-count @mock))))))) -(t/deftest test-email-change-request-without-smtp - (with-mocks [email-send-mock {:target 'app.emails/send! :return nil}] +(t/deftest email-change-request-without-smtp + (with-mocks [mock {:target 'app.emails/send! :return nil}] (with-redefs [app.config/flags #{}] (let [profile (th/create-profile* 1) pool (:app.db/pool th/*system*) data {::th/type :request-email-change :profile-id (:id profile) - :email "user1@example.com"}] + :email "user1@example.com"} + out (th/mutation! data)] - (let [out (th/mutation! data) - res (:result out)] - - ;; (th/print-result! out) - (t/is (= {:changed true} res)) - (let [mock (deref email-send-mock)] - (t/is (false? (:called? mock))))))))) + ;; (th/print-result! out) + (t/is (false? (:called? @mock))) + (let [res (:result out)] + (t/is (= {:changed true} res))))))) -(t/deftest test-request-profile-recovery +(t/deftest request-profile-recovery (with-mocks [mock {:target 'app.emails/send! :return nil}] (let [profile1 (th/create-profile* 1) profile2 (th/create-profile* 2 {:is-active true}) @@ -363,13 +463,13 @@ (let [data (assoc data :email "foo@bar.com") out (th/mutation! data)] (t/is (nil? (:result out))) - (t/is (= 0 (:call-count (deref mock))))) + (t/is (= 0 (:call-count @mock)))) ;; with valid email inactive user (let [data (assoc data :email (:email profile1)) out (th/mutation! data) error (:error out)] - (t/is (= 0 (:call-count (deref mock)))) + (t/is (= 0 (:call-count @mock))) (t/is (th/ex-info? error)) (t/is (th/ex-of-type? error :validation)) (t/is (th/ex-of-code? error :profile-not-verified))) @@ -379,7 +479,7 @@ out (th/mutation! data)] ;; (th/print-result! out) (t/is (nil? (:result out))) - (t/is (= 1 (:call-count (deref mock))))) + (t/is (= 1 (:call-count @mock)))) ;; with valid email and active user with global complaints (th/create-global-complaint-for pool {:type :complaint :email (:email profile2)}) @@ -387,7 +487,7 @@ out (th/mutation! data)] ;; (th/print-result! out) (t/is (nil? (:result out))) - (t/is (= 2 (:call-count (deref mock))))) + (t/is (= 2 (:call-count @mock)))) ;; with valid email and active user with global bounce (th/create-global-complaint-for pool {:type :bounce :email (:email profile2)}) @@ -395,7 +495,7 @@ out (th/mutation! data) error (:error out)] ;; (th/print-result! out) - (t/is (= 2 (:call-count (deref mock)))) + (t/is (= 2 (:call-count @mock))) (t/is (th/ex-info? error)) (t/is (th/ex-of-type? error :validation)) (t/is (th/ex-of-code? error :email-has-permanent-bounces))) diff --git a/backend/test/app/test_helpers.clj b/backend/test/app/test_helpers.clj index d32c6f093..f91e22aa6 100644 --- a/backend/test/app/test_helpers.clj +++ b/backend/test/app/test_helpers.clj @@ -26,6 +26,7 @@ [app.util.time :as dt] [clojure.java.io :as io] [clojure.spec.alpha :as s] + [clojure.test :as t] [cuerdas.core :as str] [datoteka.core :as fs] [environ.core :refer [env]] @@ -299,6 +300,14 @@ (let [method-fn (get-in *system* [:app.rpc/methods :queries type])] (try-on! (method-fn (dissoc data ::type))))) +(defn run-task! + ([name] + (run-task! name {})) + ([name params] + (let [tasks (:app.worker/registry *system*)] + (let [task-fn (get tasks name)] + (task-fn params))))) + ;; --- UTILS (defn print-error! @@ -358,6 +367,10 @@ (let [data (ex-data e)] (= code (:code data)))) +(defn success? + [{:keys [result error]}] + (nil? error)) + (defn tempfile [source] (let [rsc (io/resource source) @@ -366,29 +379,6 @@ (io/file tmp)) tmp)) -(defn sleep - [ms] - (Thread/sleep ms)) - -(defn mock-config-get-with - "Helper for mock app.config/get" - [data] - (fn - ([key] - (get data key (get cf/config key))) - ([key default] - (get data key (get cf/config key default))))) - - -(defmacro with-mocks - [rebinds & body] - `(with-redefs-fn ~rebinds - (fn [] ~@body))) - -(defn reset-mock! - [m] - (reset! m @(mk/make-mock {}))) - (defn pause [] (let [^java.io.Console cnsl (System/console)] @@ -408,3 +398,18 @@ [& params] (apply db/query *pool* params)) +(defn sleep + [ms-or-duration] + (Thread/sleep (inst-ms (dt/duration ms-or-duration)))) + +(defn config-get-mock + [data] + (fn + ([key] + (get data key (get cf/config key))) + ([key default] + (get data key (get cf/config key default))))) + +(defn reset-mock! + [m] + (reset! m @(mk/make-mock {}))) diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index f607950cb..52f8bb0a3 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -62,33 +62,34 @@ [{:keys [route] :as props}] (let [token (get-in route [:query-params :token]) bad-token (mf/use-state false)] - (mf/use-effect - (fn [] - (dom/set-html-title (tr "title.default")) - (->> (rp/mutation :verify-token {:token token}) - (rx/subs - (fn [tdata] - (handle-token tdata)) - (fn [{:keys [type code] :as error}] - (cond - (or (= :validation type) - (= :invalid-token code) - (= :token-expired (:reason error))) - (reset! bad-token true) - (= :email-already-exists code) - (let [msg (tr "errors.email-already-exists")] - (ts/schedule 100 #(st/emit! (dm/error msg))) - (st/emit! (rt/nav :auth-login))) - (= :email-already-validated code) - (let [msg (tr "errors.email-already-validated")] - (ts/schedule 100 #(st/emit! (dm/warn msg))) - (st/emit! (rt/nav :auth-login))) + (mf/with-effect [] + (dom/set-html-title (tr "title.default")) + (->> (rp/command! :verify-token {:token token}) + (rx/subs + (fn [tdata] + (handle-token tdata)) + (fn [{:keys [type code] :as error}] + (cond + (or (= :validation type) + (= :invalid-token code) + (= :token-expired (:reason error))) + (reset! bad-token true) - :else - (let [msg (tr "errors.generic")] - (ts/schedule 100 #(st/emit! (dm/error msg))) - (st/emit! (rt/nav :auth-login))))))))) + (= :email-already-exists code) + (let [msg (tr "errors.email-already-exists")] + (ts/schedule 100 #(st/emit! (dm/error msg))) + (st/emit! (rt/nav :auth-login))) + + (= :email-already-validated code) + (let [msg (tr "errors.email-already-validated")] + (ts/schedule 100 #(st/emit! (dm/warn msg))) + (st/emit! (rt/nav :auth-login))) + + :else + (let [msg (tr "errors.generic")] + (ts/schedule 100 #(st/emit! (dm/error msg))) + (st/emit! (rt/nav :auth-login)))))))) (if @bad-token [:> static/static-header {} From 757cee67fb9c6e39c2b7a516749b8f544ebb3d99 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 22 Sep 2022 16:48:16 +0200 Subject: [PATCH 05/19] :tada: Add the ability to completly block access to a profile --- backend/src/app/auth/oidc.clj | 4 +++ backend/src/app/migrations.clj | 3 ++ .../migrations/sql/0079-mod-profile-table.sql | 2 ++ backend/src/app/rpc/commands/auth.clj | 28 ++++++++++++------- backend/src/app/rpc/commands/ldap.clj | 5 ++++ backend/src/app/srepl/main.clj | 27 ++++++++++++++---- frontend/src/app/main/ui/auth/login.cljs | 16 +++++++++-- frontend/src/app/main/ui/auth/register.cljs | 15 ++++++---- frontend/translations/en.po | 5 +++- frontend/translations/es.po | 5 +++- 10 files changed, 83 insertions(+), 27 deletions(-) create mode 100644 backend/src/app/migrations/sql/0079-mod-profile-table.sql diff --git a/backend/src/app/auth/oidc.clj b/backend/src/app/auth/oidc.clj index 4d8551076..464c44197 100644 --- a/backend/src/app/auth/oidc.clj +++ b/backend/src/app/auth/oidc.clj @@ -434,6 +434,10 @@ (assoc :path "/#/auth/verify-token") (assoc :query (u/map->query-string params)))] + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) + (when (fn? audit) (audit :cmd :submit :type "command" diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index 0a43b15cd..009593e39 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -244,6 +244,9 @@ {:name "0078-mod-file-media-object-table-drop-cascade" :fn (mg/resource "app/migrations/sql/0078-mod-file-media-object-table-drop-cascade.sql")} + + {:name "0079-mod-profile-table" + :fn (mg/resource "app/migrations/sql/0079-mod-profile-table.sql")} ]) diff --git a/backend/src/app/migrations/sql/0079-mod-profile-table.sql b/backend/src/app/migrations/sql/0079-mod-profile-table.sql new file mode 100644 index 000000000..8bfe93b80 --- /dev/null +++ b/backend/src/app/migrations/sql/0079-mod-profile-table.sql @@ -0,0 +1,2 @@ +ALTER TABLE profile + ADD COLUMN is_blocked boolean DEFAULT false; diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index f307d653d..486755e39 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -97,15 +97,19 @@ (:valid (verify-password password (:password profile)))) (validate-profile [profile] - (when-not (:is-active profile) - (ex/raise :type :validation - :code :wrong-credentials)) (when-not profile (ex/raise :type :validation :code :wrong-credentials)) + (when-not (:is-active profile) + (ex/raise :type :validation + :code :wrong-credentials)) + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) (when-not (check-password profile password) (ex/raise :type :validation :code :wrong-credentials)) + profile)] (db/with-atomic [conn pool] @@ -231,15 +235,19 @@ (validate-register-attempt! cfg params) (let [profile (when-let [profile (profile/retrieve-profile-data-by-email pool (:email params))] - (if (:is-active profile) + (cond + (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked) + + (and (not (:is-active profile)) + (elapsed-register-retry-threshold? profile)) + profile + + :else (ex/raise :type :validation :code :email-already-exists - :hint "profile already exists and correctly validated") - (if (elapsed-register-retry-threshold? profile) - profile - (ex/raise :type :validation - :code :email-already-exists - :hint "profile already exists")))) + :hint "profile already exists"))) params {:email (:email params) :password (:password params) diff --git a/backend/src/app/rpc/commands/ldap.clj b/backend/src/app/rpc/commands/ldap.clj index 6f14a5068..a0eab43e9 100644 --- a/backend/src/app/rpc/commands/ldap.clj +++ b/backend/src/app/rpc/commands/ldap.clj @@ -46,6 +46,11 @@ :code :wrong-credentials)) (let [profile (login-or-register cfg info)] + + (when (:is-blocked profile) + (ex/raise :type :restriction + :code :profile-blocked)) + (if-let [token (:invitation-token params)] ;; If invitation token comes in params, this is because the ;; user comes from team-invitation process; in this case, diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index 0569fa285..bcc0c0847 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -64,7 +64,7 @@ (defn update-profile "Update a limited set of profile attrs." - [system & {:keys [email id active? deleted?]}] + [system & {:keys [email id active? deleted? blocked?]}] (us/verify! :expr (some? system) @@ -74,15 +74,30 @@ :expr (or (string? email) (uuid? id)) :hint "email or id should be provided") - (let [pool (:app.db/pool system) - params (cond-> {} + (let [params (cond-> {} (true? active?) (assoc :is-active true) (false? active?) (assoc :is-active false) - (true? deleted?) (assoc :deleted-at (dt/now))) + (true? deleted?) (assoc :deleted-at (dt/now)) + (true? blocked?) (assoc :is-blocked true) + (false? blocked?) (assoc :is-blocked false)) opts (cond-> {} (some? email) (assoc :email (str/lower email)) (some? id) (assoc :id id))] - (some-> (db/update! pool :profile params opts) - (profile/decode-profile-row)))) + (db/with-atomic [conn (:app.db/pool system)] + (some-> (db/update! conn :profile params opts) + (profile/decode-profile-row))))) +(defn mark-profile-as-blocked! + "Mark the profile blocked and removes all the http sessiones + associated with the profile-id." + [system email] + (db/with-atomic [conn (:app.db/pool system)] + (when-let [profile (db/get-by-params conn :profile + {:email (str/lower email)} + {:columns [:id :email] + :check-not-found false})] + (when-not (:is-blocked profile) + (db/update! conn :profile {:is-blocked true} {:id (:id profile)}) + (db/delete! conn :http-session {:profile-id (:id profile)}) + :blocked)))) diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 886b8cf73..72fe95705 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -83,14 +83,24 @@ form (fm/use-form :spec ::login-form :initial initial) on-error - (fn [_] - (reset! error (tr "errors.wrong-credentials"))) + (fn [cause] + (cond + (and (= :restriction (:type cause)) + (= :profile-blocked (:code cause))) + (reset! error (tr "errors.profile-blocked")) + + (and (= :validation (:type cause)) + (= :wrong-credentials (:code cause))) + (reset! error (tr "errors.wrong-credentials")) + + :else + (reset! error (tr "errors.generic")))) on-success-default (fn [data] (when-let [token (:invitation-token data)] (st/emit! (rt/nav :auth-verify-token {} {:token token})))) - + on-success (fn [data] (if (nil? on-success-callback) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index d738e1c6d..d70f00afd 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -48,20 +48,23 @@ :opt-un [::invitation-token])) (defn- handle-prepare-register-error - [form error] - (case (:code error) - :registration-disabled + [form {:keys [type code] :as cause}] + (condp = [type code] + [:restriction :registration-disabled] (st/emit! (dm/error (tr "errors.registration-disabled"))) - :email-has-permanent-bounces + [:restriction :profile-blocked] + (st/emit! (dm/error (tr "errors.profile-blocked"))) + + [:validation :email-has-permanent-bounces] (let [email (get @form [:data :email])] (st/emit! (dm/error (tr "errors.email-has-permanent-bounces" email)))) - :email-already-exists + [:validation :email-already-exists] (swap! form assoc-in [:errors :email] {:message "errors.email-already-exists"}) - :email-as-password + [:validation :email-as-password] (swap! form assoc-in [:errors :password] {:message "errors.email-as-password"}) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 3c53e4754..374a9cc61 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -4558,4 +4558,7 @@ msgid "workspace.updates.update" msgstr "Update" msgid "workspace.viewport.click-to-close-path" -msgstr "Click to close the path" \ No newline at end of file +msgstr "Click to close the path" + +msgid "errors.profile-blocked" +msgstr "The profile is blocked" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 85ee471b2..84d0d8f29 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -4765,4 +4765,7 @@ msgid "workspace.updates.update" msgstr "Actualizar" msgid "workspace.viewport.click-to-close-path" -msgstr "Pulsar para cerrar la ruta" \ No newline at end of file +msgstr "Pulsar para cerrar la ruta" + +msgid "errors.profile-blocked" +msgstr "El perfil esta blockeado" From 06bce92cdca1225b0e0b28e2d66960dbe9267092 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 22 Sep 2022 16:52:48 +0200 Subject: [PATCH 06/19] :paperclip: Fix linter issues on backend --- backend/src/app/rpc/commands/auth.clj | 120 +++++++++--------- backend/src/app/rpc/commands/verify_token.clj | 5 +- .../src/app/rpc/mutations/verify_token.clj | 4 +- 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 486755e39..5c0a3e801 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -355,76 +355,76 @@ (defn register-profile [{:keys [conn sprops session] :as cfg} {:keys [token] :as params}] - (let [claims (tokens/verify sprops {:token token :iss :prepared-register}) - params (merge params claims)] + (let [claims (tokens/verify sprops {:token token :iss :prepared-register}) + params (merge params claims) - (let [is-active (or (:is-active params) - (not (contains? cf/flags :email-verification)) + is-active (or (:is-active params) + (not (contains? cf/flags :email-verification)) - ;; DEPRECATED: v1.15 - (contains? cf/flags :insecure-register)) + ;; DEPRECATED: v1.15 + (contains? cf/flags :insecure-register)) - profile (if-let [profile-id (:profile-id claims)] - (profile/retrieve-profile conn profile-id) - (->> (assoc params :is-active is-active) - (create-profile conn) - (create-profile-relations conn) - (profile/decode-profile-row))) - audit-fn (:audit cfg) + profile (if-let [profile-id (:profile-id claims)] + (profile/retrieve-profile conn profile-id) + (->> (assoc params :is-active is-active) + (create-profile conn) + (create-profile-relations conn) + (profile/decode-profile-row))) + audit-fn (:audit cfg) - invitation (when-let [token (:invitation-token params)] - (tokens/verify sprops {:token token :iss :team-invitation}))] + invitation (when-let [token (:invitation-token params)] + (tokens/verify sprops {:token token :iss :team-invitation}))] - ;; If profile is filled in claims, means it tries to register - ;; again, so we proceed to update the modified-at attr - ;; accordingly. - (when-let [id (:profile-id claims)] - (db/update! conn :profile {:modified-at (dt/now)} {:id id}) - (audit-fn :cmd :submit - :type "fact" - :name "register-profile-retry" - :profile-id id)) + ;; If profile is filled in claims, means it tries to register + ;; again, so we proceed to update the modified-at attr + ;; accordingly. + (when-let [id (:profile-id claims)] + (db/update! conn :profile {:modified-at (dt/now)} {:id id}) + (audit-fn :cmd :submit + :type "fact" + :name "register-profile-retry" + :profile-id id)) - (cond - ;; If invitation token comes in params, this is because the - ;; user comes from team-invitation process; in this case, - ;; regenerate token and send back to the user a new invitation - ;; token (and mark current session as logged). This happens - ;; only if the invitation email matches with the register - ;; email. - (and (some? invitation) (= (:email profile) (:member-email invitation))) - (let [claims (assoc invitation :member-id (:id profile)) - token (tokens/generate sprops claims) - resp {:invitation-token token}] - (with-meta resp - {:transform-response ((:create session) (:id profile)) - ::audit/replace-props (audit/profile->props profile) - ::audit/profile-id (:id profile)})) - - ;; If auth backend is different from "penpot" means user is - ;; registering using third party auth mechanism; in this case - ;; we need to mark this session as logged. - (not= "penpot" (:auth-backend profile)) - (with-meta (profile/strip-private-attrs profile) + (cond + ;; If invitation token comes in params, this is because the + ;; user comes from team-invitation process; in this case, + ;; regenerate token and send back to the user a new invitation + ;; token (and mark current session as logged). This happens + ;; only if the invitation email matches with the register + ;; email. + (and (some? invitation) (= (:email profile) (:member-email invitation))) + (let [claims (assoc invitation :member-id (:id profile)) + token (tokens/generate sprops claims) + resp {:invitation-token token}] + (with-meta resp {:transform-response ((:create session) (:id profile)) ::audit/replace-props (audit/profile->props profile) - ::audit/profile-id (:id profile)}) + ::audit/profile-id (:id profile)})) - ;; If the `:enable-insecure-register` flag is set, we proceed - ;; to sign in the user directly, without email verification. - (true? is-active) - (with-meta (profile/strip-private-attrs profile) - {:transform-response ((:create session) (:id profile)) - ::audit/replace-props (audit/profile->props profile) - ::audit/profile-id (:id profile)}) + ;; If auth backend is different from "penpot" means user is + ;; registering using third party auth mechanism; in this case + ;; we need to mark this session as logged. + (not= "penpot" (:auth-backend profile)) + (with-meta (profile/strip-private-attrs profile) + {:transform-response ((:create session) (:id profile)) + ::audit/replace-props (audit/profile->props profile) + ::audit/profile-id (:id profile)}) - ;; In all other cases, send a verification email. - :else - (do - (send-email-verification! conn sprops profile) - (with-meta profile - {::audit/replace-props (audit/profile->props profile) - ::audit/profile-id (:id profile)})))))) + ;; If the `:enable-insecure-register` flag is set, we proceed + ;; to sign in the user directly, without email verification. + (true? is-active) + (with-meta (profile/strip-private-attrs profile) + {:transform-response ((:create session) (:id profile)) + ::audit/replace-props (audit/profile->props profile) + ::audit/profile-id (:id profile)}) + + ;; In all other cases, send a verification email. + :else + (do + (send-email-verification! conn sprops profile) + (with-meta profile + {::audit/replace-props (audit/profile->props profile) + ::audit/profile-id (:id profile)}))))) (s/def ::register-profile (s/keys :req-un [::token ::fullname])) diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj index 4a93b9bce..27f453464 100644 --- a/backend/src/app/rpc/commands/verify_token.clj +++ b/backend/src/app/rpc/commands/verify_token.clj @@ -10,14 +10,13 @@ [app.common.spec :as us] [app.db :as db] [app.loggers.audit :as audit] + [app.rpc.doc :as-alias doc] [app.rpc.mutations.teams :as teams] [app.rpc.queries.profile :as profile] [app.tokens :as tokens] - [app.rpc.doc :as-alias doc] [app.tokens.spec.team-invitation :as-alias spec.team-invitation] [app.util.services :as sv] - [clojure.spec.alpha :as s] - [cuerdas.core :as str])) + [clojure.spec.alpha :as s])) (s/def ::iss keyword?) (s/def ::exp ::us/inst) diff --git a/backend/src/app/rpc/mutations/verify_token.clj b/backend/src/app/rpc/mutations/verify_token.clj index 9befd4e0f..a8551847b 100644 --- a/backend/src/app/rpc/mutations/verify_token.clj +++ b/backend/src/app/rpc/mutations/verify_token.clj @@ -7,9 +7,9 @@ (ns app.rpc.mutations.verify-token (:require [app.db :as db] - [app.tokens :as tokens] - [app.rpc.doc :as-alias doc] [app.rpc.commands.verify-token :refer [process-token]] + [app.rpc.doc :as-alias doc] + [app.tokens :as tokens] [app.util.services :as sv] [clojure.spec.alpha :as s])) From 278f6685b602acaec38d4e9227fdcbe6e20f8283 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 22 Sep 2022 17:47:05 +0200 Subject: [PATCH 07/19] :sparkles: Improve object deletion process on profile deletion --- backend/src/app/rpc/mutations/profile.clj | 45 +++++++++------- backend/src/app/srepl/main.clj | 2 +- backend/src/app/tasks/objects_gc.clj | 62 +++++++++-------------- backend/test/app/services_files_test.clj | 10 ++-- 4 files changed, 57 insertions(+), 62 deletions(-) diff --git a/backend/src/app/rpc/mutations/profile.clj b/backend/src/app/rpc/mutations/profile.clj index 9d4d998e6..e026fafaa 100644 --- a/backend/src/app/rpc/mutations/profile.clj +++ b/backend/src/app/rpc/mutations/profile.clj @@ -252,6 +252,7 @@ ;; --- MUTATION: Delete Profile +(declare get-owned-teams-with-participants) (declare check-can-delete-profile!) (declare mark-profile-as-deleted!) @@ -261,14 +262,29 @@ (sv/defmethod ::delete-profile [{:keys [pool session] :as cfg} {:keys [profile-id] :as params}] (db/with-atomic [conn pool] - (check-can-delete-profile! conn profile-id) + (let [teams (get-owned-teams-with-participants conn profile-id) + deleted-at (dt/now)] - (db/update! conn :profile - {:deleted-at (dt/now)} - {:id profile-id}) + ;; If we found owned teams with participants, we don't allow + ;; delete profile until the user properly transfer ownership or + ;; explicitly removes all participants from the team + (when (some pos? (map :participants teams)) + (ex/raise :type :validation + :code :owner-teams-with-people + :hint "The user need to transfer ownership of owned teams." + :context {:teams (mapv :id teams)})) - (with-meta {} - {:transform-response (:delete session)}))) + (doseq [{:keys [id]} teams] + (db/update! conn :team + {:deleted-at deleted-at} + {:id id})) + + (db/update! conn :profile + {:deleted-at deleted-at} + {:id profile-id}) + + (with-meta {} + {:transform-response (:delete session)})))) (def sql:owned-teams "with owner_teams as ( @@ -277,23 +293,16 @@ where tpr.is_owner is true and tpr.profile_id = ? ) - select tpr.team_id, - count(tpr.profile_id) as num_profiles + select tpr.team_id as id, + count(tpr.profile_id) - 1 as participants from team_profile_rel as tpr where tpr.team_id in (select id from owner_teams) + and tpr.profile_id != ? group by 1") -(defn- check-can-delete-profile! +(defn- get-owned-teams-with-participants [conn profile-id] - (let [rows (db/exec! conn [sql:owned-teams profile-id])] - ;; If we found owned teams with more than one profile we don't - ;; allow delete profile until the user properly transfer ownership - ;; or explicitly removes all participants from the team. - (when (some #(> (:num-profiles %) 1) rows) - (ex/raise :type :validation - :code :owner-teams-with-people - :hint "The user need to transfer ownership of owned teams." - :context {:teams (mapv :team-id rows)})))) + (db/exec! conn [sql:owned-teams profile-id profile-id])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DEPRECATED METHODS (TO BE REMOVED ON 1.16.x) diff --git a/backend/src/app/srepl/main.clj b/backend/src/app/srepl/main.clj index bcc0c0847..4c788d01c 100644 --- a/backend/src/app/srepl/main.clj +++ b/backend/src/app/srepl/main.clj @@ -62,7 +62,7 @@ (cmd.auth/send-email-verification! pool sprops profile) :email-sent)) -(defn update-profile +(defn update-profile! "Update a limited set of profile attrs." [system & {:keys [email id active? deleted? blocked?]}] diff --git a/backend/src/app/tasks/objects_gc.clj b/backend/src/app/tasks/objects_gc.clj index e7d0d5667..3cf6b9b4a 100644 --- a/backend/src/app/tasks/objects_gc.clj +++ b/backend/src/app/tasks/objects_gc.clj @@ -69,8 +69,7 @@ (defmethod delete-objects "team_font_variant" [{:keys [conn min-age storage table] :as cfg}] - (let [sql (str/fmt sql:delete-objects - {:table table :limit 50}) + (let [sql (str/fmt sql:delete-objects {:table table :limit 50}) fonts (db/exec! conn [sql min-age]) storage (media/configure-assets-storage storage conn)] (doseq [{:keys [id] :as font} fonts] @@ -85,10 +84,9 @@ (defmethod delete-objects "team" [{:keys [conn min-age storage table] :as cfg}] - (let [sql (str/fmt sql:delete-objects - {:table table :limit 50}) + (let [sql (str/fmt sql:delete-objects {:table table :limit 50}) teams (db/exec! conn [sql min-age]) - storage (assoc storage :conn conn)] + storage (media/configure-assets-storage storage conn)] (doseq [{:keys [id] :as team} teams] (l/debug :hint "permanently delete object" :table table :id id) @@ -103,32 +101,17 @@ where deleted_at is not null and deleted_at < now() - ?::interval order by deleted_at - limit %(limit)s + limit ? for update") -(def sql:mark-owned-teams-deleted - "with owned as ( - select tpr.team_id as id - from team_profile_rel as tpr - where tpr.is_owner is true - and tpr.profile_id = ? - ) - update team set deleted_at = now() - ?::interval - where id in (select id from owned)") - (defmethod delete-objects "profile" [{:keys [conn min-age storage table] :as cfg}] - (let [sql (str/fmt sql:retrieve-deleted-profiles {:limit 50}) - profiles (db/exec! conn [sql min-age]) - storage (assoc storage :conn conn)] + (let [profiles (db/exec! conn [sql:retrieve-deleted-profiles min-age 50]) + storage (media/configure-assets-storage storage conn)] (doseq [{:keys [id] :as profile} profiles] (l/debug :hint "permanently delete object" :table table :id id) - ;; Mark the owned teams as deleted; this enables them to be processed - ;; in the same transaction in the "team" table step. - (db/exec-one! conn [sql:mark-owned-teams-deleted id min-age]) - ;; Mark as deleted the storage object related with the photo-id ;; field. (some->> (:photo-id profile) (sto/touch-object! storage) deref) @@ -164,22 +147,23 @@ (defmethod ig/init-key ::handler [_ {:keys [pool] :as cfg}] (fn [params] - ;; Checking first on task argument allows properly testing it. - (let [min-age (or (:min-age params) (:min-age cfg))] - (db/with-atomic [conn pool] - (let [cfg (-> cfg - (assoc :min-age (db/interval min-age)) - (assoc :conn conn))] - (loop [tables (seq target-tables) - total 0] - (if-let [table (first tables)] - (recur (rest tables) - (+ total (process-table (assoc cfg :table table)))) - (do - (l/info :hint "task finished" :min-age (dt/format-duration min-age) :total total) + (db/with-atomic [conn pool] + (let [min-age (or (:min-age params) (:min-age cfg)) + cfg (-> cfg + (assoc :min-age (db/interval min-age)) + (assoc :conn conn))] + (loop [tables (seq target-tables) + total 0] + (if-let [table (first tables)] + (recur (rest tables) + (+ total (process-table (assoc cfg :table table)))) + (do + (l/info :hint "objects gc finished succesfully" + :min-age (dt/format-duration min-age) + :total total) - (when (:rollback? params) - (db/rollback! conn)) + (when (:rollback? params) + (db/rollback! conn)) - {:processed total})))))))) + {:processed total}))))))) diff --git a/backend/test/app/services_files_test.clj b/backend/test/app/services_files_test.clj index e15884ad1..b400d217f 100644 --- a/backend/test/app/services_files_test.clj +++ b/backend/test/app/services_files_test.clj @@ -537,10 +537,12 @@ :file-id (:id file) :object-id frame1-id :components-v2 true} - {:keys [error result] :as out} (th/query! data)] - ;; (th/print-result! out) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :spec-validation (th/ex-code error))))) + out (th/query! data)] + + (t/is (not (th/success? out))) + (let [{:keys [type code]} (-> out :error ex-data)] + (t/is (= :validation type)) + (t/is (= :spec-validation code))))) (t/testing "RPC :file-data-for-thumbnail" ;; Insert a thumbnail data for the frame-id From 8bdfd188d8088440ac40a1571e8c019dbb13da72 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Sun, 25 Sep 2022 19:24:45 +0200 Subject: [PATCH 08/19] :arrow_up: Upgrade shadow-cljs and rumext dependency --- .clj-kondo/config.edn | 4 ++-- frontend/deps.edn | 6 +++++- frontend/src/app/main.cljs | 2 +- frontend/src/app/main/features.cljs | 2 +- frontend/src/app/main/render.cljs | 2 +- frontend/src/app/main/ui.cljs | 2 +- frontend/src/app/main/ui/alert.cljs | 2 +- frontend/src/app/main/ui/auth.cljs | 2 +- frontend/src/app/main/ui/auth/login.cljs | 2 +- frontend/src/app/main/ui/auth/recovery.cljs | 2 +- frontend/src/app/main/ui/auth/recovery_request.cljs | 2 +- frontend/src/app/main/ui/auth/register.cljs | 2 +- frontend/src/app/main/ui/auth/verify_token.cljs | 2 +- frontend/src/app/main/ui/comments.cljs | 2 +- frontend/src/app/main/ui/components/code_block.cljs | 2 +- frontend/src/app/main/ui/components/color_bullet.cljs | 2 +- frontend/src/app/main/ui/components/color_input.cljs | 2 +- frontend/src/app/main/ui/components/context_menu.cljs | 2 +- frontend/src/app/main/ui/components/copy_button.cljs | 2 +- frontend/src/app/main/ui/components/dropdown.cljs | 2 +- frontend/src/app/main/ui/components/editable_label.cljs | 2 +- frontend/src/app/main/ui/components/editable_select.cljs | 2 +- frontend/src/app/main/ui/components/file_uploader.cljs | 2 +- frontend/src/app/main/ui/components/forms.cljs | 2 +- frontend/src/app/main/ui/components/numeric_input.cljs | 2 +- frontend/src/app/main/ui/components/select.cljs | 2 +- frontend/src/app/main/ui/components/shape_icon.cljs | 2 +- frontend/src/app/main/ui/components/tab_container.cljs | 2 +- frontend/src/app/main/ui/confirm.cljs | 2 +- frontend/src/app/main/ui/context.cljs | 2 +- frontend/src/app/main/ui/cursors.cljs | 2 +- frontend/src/app/main/ui/dashboard.cljs | 2 +- frontend/src/app/main/ui/dashboard/change_owner.cljs | 2 +- frontend/src/app/main/ui/dashboard/comments.cljs | 2 +- frontend/src/app/main/ui/dashboard/export.cljs | 2 +- frontend/src/app/main/ui/dashboard/file_menu.cljs | 2 +- frontend/src/app/main/ui/dashboard/files.cljs | 2 +- frontend/src/app/main/ui/dashboard/fonts.cljs | 2 +- frontend/src/app/main/ui/dashboard/grid.cljs | 2 +- frontend/src/app/main/ui/dashboard/import.cljs | 2 +- frontend/src/app/main/ui/dashboard/inline_edition.cljs | 2 +- frontend/src/app/main/ui/dashboard/libraries.cljs | 2 +- frontend/src/app/main/ui/dashboard/placeholder.cljs | 2 +- frontend/src/app/main/ui/dashboard/project_menu.cljs | 2 +- frontend/src/app/main/ui/dashboard/projects.cljs | 2 +- frontend/src/app/main/ui/dashboard/search.cljs | 2 +- frontend/src/app/main/ui/dashboard/sidebar.cljs | 2 +- frontend/src/app/main/ui/dashboard/team.cljs | 2 +- frontend/src/app/main/ui/dashboard/team_form.cljs | 2 +- frontend/src/app/main/ui/delete_shared.cljs | 2 +- frontend/src/app/main/ui/export.cljs | 2 +- frontend/src/app/main/ui/hooks.cljs | 2 +- frontend/src/app/main/ui/hooks/mutable_observer.cljs | 2 +- frontend/src/app/main/ui/hooks/resize.cljs | 2 +- frontend/src/app/main/ui/icons.clj | 4 ++-- frontend/src/app/main/ui/icons.cljs | 2 +- frontend/src/app/main/ui/loader.cljs | 2 +- frontend/src/app/main/ui/measurements.cljs | 2 +- frontend/src/app/main/ui/messages.cljs | 2 +- frontend/src/app/main/ui/modal.cljs | 2 +- frontend/src/app/main/ui/onboarding.cljs | 2 +- frontend/src/app/main/ui/onboarding/newsletter.cljs | 2 +- frontend/src/app/main/ui/onboarding/questions.cljs | 2 +- frontend/src/app/main/ui/onboarding/team_choice.cljs | 2 +- frontend/src/app/main/ui/onboarding/templates.cljs | 2 +- frontend/src/app/main/ui/releases.cljs | 2 +- frontend/src/app/main/ui/releases/common.cljs | 2 +- frontend/src/app/main/ui/releases/v1_10.cljs | 2 +- frontend/src/app/main/ui/releases/v1_11.cljs | 2 +- frontend/src/app/main/ui/releases/v1_12.cljs | 2 +- frontend/src/app/main/ui/releases/v1_13.cljs | 2 +- frontend/src/app/main/ui/releases/v1_14.cljs | 2 +- frontend/src/app/main/ui/releases/v1_15.cljs | 2 +- frontend/src/app/main/ui/releases/v1_4.cljs | 2 +- frontend/src/app/main/ui/releases/v1_5.cljs | 2 +- frontend/src/app/main/ui/releases/v1_6.cljs | 2 +- frontend/src/app/main/ui/releases/v1_7.cljs | 2 +- frontend/src/app/main/ui/releases/v1_8.cljs | 2 +- frontend/src/app/main/ui/releases/v1_9.cljs | 2 +- frontend/src/app/main/ui/settings.cljs | 2 +- frontend/src/app/main/ui/settings/change_email.cljs | 2 +- frontend/src/app/main/ui/settings/delete_account.cljs | 2 +- frontend/src/app/main/ui/settings/feedback.cljs | 2 +- frontend/src/app/main/ui/settings/options.cljs | 2 +- frontend/src/app/main/ui/settings/password.cljs | 2 +- frontend/src/app/main/ui/settings/profile.cljs | 2 +- frontend/src/app/main/ui/settings/sidebar.cljs | 2 +- frontend/src/app/main/ui/shapes/attrs.cljs | 2 +- frontend/src/app/main/ui/shapes/bool.cljs | 2 +- frontend/src/app/main/ui/shapes/circle.cljs | 2 +- frontend/src/app/main/ui/shapes/custom_stroke.cljs | 2 +- frontend/src/app/main/ui/shapes/embed.cljs | 2 +- frontend/src/app/main/ui/shapes/export.cljs | 2 +- frontend/src/app/main/ui/shapes/fills.cljs | 2 +- frontend/src/app/main/ui/shapes/filters.cljs | 2 +- frontend/src/app/main/ui/shapes/frame.cljs | 2 +- frontend/src/app/main/ui/shapes/gradients.cljs | 2 +- frontend/src/app/main/ui/shapes/group.cljs | 2 +- frontend/src/app/main/ui/shapes/image.cljs | 2 +- frontend/src/app/main/ui/shapes/mask.cljs | 2 +- frontend/src/app/main/ui/shapes/path.cljs | 2 +- frontend/src/app/main/ui/shapes/rect.cljs | 2 +- frontend/src/app/main/ui/shapes/shape.cljs | 2 +- frontend/src/app/main/ui/shapes/svg_defs.cljs | 2 +- frontend/src/app/main/ui/shapes/svg_raw.cljs | 2 +- frontend/src/app/main/ui/shapes/text.cljs | 2 +- frontend/src/app/main/ui/shapes/text/fo_text.cljs | 2 +- frontend/src/app/main/ui/shapes/text/fontfaces.cljs | 2 +- frontend/src/app/main/ui/shapes/text/html_text.cljs | 2 +- frontend/src/app/main/ui/shapes/text/svg_text.cljs | 2 +- frontend/src/app/main/ui/static.cljs | 2 +- frontend/src/app/main/ui/viewer.cljs | 2 +- frontend/src/app/main/ui/viewer/comments.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff/attributes.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/blur.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/common.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/fill.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/image.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/layout.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/shadow.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/stroke.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/svg.cljs | 2 +- .../src/app/main/ui/viewer/handoff/attributes/text.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff/code.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff/exports.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs | 2 +- frontend/src/app/main/ui/viewer/handoff/render.cljs | 2 +- .../src/app/main/ui/viewer/handoff/right_sidebar.cljs | 2 +- .../app/main/ui/viewer/handoff/selection_feedback.cljs | 2 +- frontend/src/app/main/ui/viewer/header.cljs | 2 +- frontend/src/app/main/ui/viewer/interactions.cljs | 2 +- frontend/src/app/main/ui/viewer/login.cljs | 2 +- frontend/src/app/main/ui/viewer/shapes.cljs | 2 +- frontend/src/app/main/ui/viewer/share_link.cljs | 2 +- frontend/src/app/main/ui/viewer/thumbnails.cljs | 2 +- frontend/src/app/main/ui/workspace.cljs | 2 +- frontend/src/app/main/ui/workspace/colorpalette.cljs | 2 +- frontend/src/app/main/ui/workspace/colorpicker.cljs | 2 +- .../app/main/ui/workspace/colorpicker/color_inputs.cljs | 2 +- .../src/app/main/ui/workspace/colorpicker/gradients.cljs | 2 +- .../src/app/main/ui/workspace/colorpicker/harmony.cljs | 2 +- frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs | 2 +- .../src/app/main/ui/workspace/colorpicker/libraries.cljs | 2 +- frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs | 2 +- .../main/ui/workspace/colorpicker/slider_selector.cljs | 2 +- frontend/src/app/main/ui/workspace/comments.cljs | 2 +- frontend/src/app/main/ui/workspace/context_menu.cljs | 2 +- frontend/src/app/main/ui/workspace/coordinates.cljs | 2 +- frontend/src/app/main/ui/workspace/effects.cljs | 2 +- frontend/src/app/main/ui/workspace/header.cljs | 2 +- frontend/src/app/main/ui/workspace/left_toolbar.cljs | 2 +- frontend/src/app/main/ui/workspace/libraries.cljs | 2 +- frontend/src/app/main/ui/workspace/nudge.cljs | 2 +- frontend/src/app/main/ui/workspace/presence.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/bool.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/common.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/frame.cljs | 2 +- .../main/ui/workspace/shapes/frame/dynamic_modifiers.cljs | 2 +- .../app/main/ui/workspace/shapes/frame/node_store.cljs | 2 +- .../main/ui/workspace/shapes/frame/thumbnail_render.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/group.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/path.cljs | 2 +- .../src/app/main/ui/workspace/shapes/path/common.cljs | 2 +- .../src/app/main/ui/workspace/shapes/path/editor.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/svg_raw.cljs | 2 +- frontend/src/app/main/ui/workspace/shapes/text.cljs | 2 +- .../src/app/main/ui/workspace/shapes/text/editor.cljs | 2 +- .../ui/workspace/shapes/text/text_edition_outline.cljs | 2 +- .../ui/workspace/shapes/text/viewport_texts_html.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/assets.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/history.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/layers.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/options.cljs | 2 +- .../src/app/main/ui/workspace/sidebar/options/common.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/align.cljs | 2 +- .../app/main/ui/workspace/sidebar/options/menus/blur.cljs | 2 +- .../app/main/ui/workspace/sidebar/options/menus/bool.cljs | 2 +- .../workspace/sidebar/options/menus/color_selection.cljs | 2 +- .../ui/workspace/sidebar/options/menus/component.cljs | 2 +- .../ui/workspace/sidebar/options/menus/constraints.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/exports.cljs | 2 +- .../app/main/ui/workspace/sidebar/options/menus/fill.cljs | 2 +- .../ui/workspace/sidebar/options/menus/frame_grid.cljs | 2 +- .../ui/workspace/sidebar/options/menus/interactions.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/layer.cljs | 2 +- .../workspace/sidebar/options/menus/layout_container.cljs | 2 +- .../ui/workspace/sidebar/options/menus/layout_item.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/measures.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/shadow.cljs | 2 +- .../main/ui/workspace/sidebar/options/menus/stroke.cljs | 2 +- .../ui/workspace/sidebar/options/menus/svg_attrs.cljs | 2 +- .../app/main/ui/workspace/sidebar/options/menus/text.cljs | 2 +- .../ui/workspace/sidebar/options/menus/typography.cljs | 2 +- .../src/app/main/ui/workspace/sidebar/options/page.cljs | 2 +- .../main/ui/workspace/sidebar/options/rows/color_row.cljs | 2 +- .../main/ui/workspace/sidebar/options/rows/input_row.cljs | 2 +- .../ui/workspace/sidebar/options/rows/stroke_row.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/bool.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/circle.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/frame.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/group.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/image.cljs | 2 +- .../ui/workspace/sidebar/options/shapes/multiple.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/path.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/rect.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/svg_raw.cljs | 2 +- .../main/ui/workspace/sidebar/options/shapes/text.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs | 2 +- frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs | 2 +- frontend/src/app/main/ui/workspace/textpalette.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/actions.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/comments.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/drawarea.cljs | 2 +- .../src/app/main/ui/workspace/viewport/frame_grid.cljs | 2 +- .../src/app/main/ui/workspace/viewport/gradients.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/guides.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/hooks.cljs | 2 +- .../src/app/main/ui/workspace/viewport/interactions.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/outline.cljs | 4 ++-- .../src/app/main/ui/workspace/viewport/path_actions.cljs | 2 +- .../src/app/main/ui/workspace/viewport/pixel_overlay.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/presence.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/rules.cljs | 2 +- .../src/app/main/ui/workspace/viewport/scroll_bars.cljs | 2 +- .../src/app/main/ui/workspace/viewport/selection.cljs | 4 ++-- .../app/main/ui/workspace/viewport/snap_distances.cljs | 2 +- .../src/app/main/ui/workspace/viewport/snap_points.cljs | 2 +- frontend/src/app/main/ui/workspace/viewport/widgets.cljs | 2 +- frontend/src/app/render.cljs | 2 +- frontend/src/app/util/forms.cljs | 2 +- frontend/src/app/util/i18n.cljs | 2 +- frontend/src/app/util/perf.cljs | 2 +- frontend/src/app/util/theme.cljs | 2 +- frontend/src/app/worker/thumbnails.cljs | 2 +- frontend/yarn.lock | 8 ++++---- 239 files changed, 250 insertions(+), 246 deletions(-) diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index 5aec7c30f..7b0b571f2 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -2,8 +2,8 @@ {promesa.core/let clojure.core/let promesa.core/->> clojure.core/->> promesa.core/-> clojure.core/-> - rumext.alpha/defc clojure.core/defn - rumext.alpha/fnc clojure.core/fn + rumext.v2/defc clojure.core/defn + rumext.v2/fnc clojure.core/fn app.common.data/export clojure.core/def app.db/with-atomic clojure.core/with-open app.common.data.macros/get-in clojure.core/get-in diff --git a/frontend/deps.edn b/frontend/deps.edn index 2ebb646ae..6040a678e 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -10,9 +10,13 @@ funcool/beicon {:mvn/version "2021.07.05-1"} funcool/okulary {:mvn/version "2022.04.11-16"} funcool/potok {:mvn/version "2022.04.28-67"} - funcool/rumext {:mvn/version "2022.04.19-148"} funcool/tubax {:mvn/version "2021.05.20-0"} + funcool/rumext + {:git/tag "v2.0" + :git/sha "fc617a8" + :git/url "https://github.com/funcool/rumext.git"} + instaparse/instaparse {:mvn/version "1.4.12"} garden/garden {:git/url "https://github.com/noprompt/garden" :git/sha "05590ecb5f6fa670856f3d1ab400aa4961047480"} diff --git a/frontend/src/app/main.cljs b/frontend/src/app/main.cljs index 9524bb0a6..2eda90ba0 100644 --- a/frontend/src/app/main.cljs +++ b/frontend/src/app/main.cljs @@ -28,7 +28,7 @@ [debug] [features] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/initialize!) (log/set-level! :root :warn) diff --git a/frontend/src/app/main/features.cljs b/frontend/src/app/main/features.cljs index 43a931121..3642edc94 100644 --- a/frontend/src/app/main/features.cljs +++ b/frontend/src/app/main/features.cljs @@ -12,7 +12,7 @@ [app.main.store :as st] [okulary.core :as l] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :debug) diff --git a/frontend/src/app/main/render.cljs b/frontend/src/app/main/render.cljs index e6924e823..c750538dc 100644 --- a/frontend/src/app/main/render.cljs +++ b/frontend/src/app/main/render.cljs @@ -45,7 +45,7 @@ [beicon.core :as rx] [clojure.set :as set] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def ^:const viewbox-decimal-precision 3) (def ^:private default-color clr/canvas) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 8ab1dc6e1..e78100a1a 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -24,7 +24,7 @@ [app.main.ui.viewer :as viewer] [app.main.ui.workspace :as workspace] [app.util.router :as rt] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc on-main-error [{:keys [error] :as props}] diff --git a/frontend/src/app/main/ui/alert.cljs b/frontend/src/app/main/ui/alert.cljs index 796ed3be2..29e4d9393 100644 --- a/frontend/src/app/main/ui/alert.cljs +++ b/frontend/src/app/main/ui/alert.cljs @@ -13,7 +13,7 @@ [app.util.i18n :as i18n :refer [tr t]] [app.util.keyboard :as k] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc alert-dialog diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs index c6b6e7a3f..67a8e8d6f 100644 --- a/frontend/src/app/main/ui/auth.cljs +++ b/frontend/src/app/main/ui/auth.cljs @@ -14,7 +14,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc terms-login [] diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs index 72fe95705..437a60999 100644 --- a/frontend/src/app/main/ui/auth/login.cljs +++ b/frontend/src/app/main/ui/auth/login.cljs @@ -20,7 +20,7 @@ [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def show-alt-login-buttons? (some (partial contains? @cf/flags) diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs index d850ea3a7..f72bf420a 100644 --- a/frontend/src/app/main/ui/auth/recovery.cljs +++ b/frontend/src/app/main/ui/auth/recovery.cljs @@ -14,7 +14,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::password-1 ::us/not-empty-string) (s/def ::password-2 ::us/not-empty-string) diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs index c09d3e094..783d2fb95 100644 --- a/frontend/src/app/main/ui/auth/recovery_request.cljs +++ b/frontend/src/app/main/ui/auth/recovery_request.cljs @@ -16,7 +16,7 @@ [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::email ::us/email) (s/def ::recovery-request-form (s/keys :req-un [::email])) diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs index d70f00afd..87ab67dde 100644 --- a/frontend/src/app/main/ui/auth/register.cljs +++ b/frontend/src/app/main/ui/auth/register.cljs @@ -20,7 +20,7 @@ [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc demo-warning [_] diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs index 52f8bb0a3..5a4fcbc67 100644 --- a/frontend/src/app/main/ui/auth/verify_token.cljs +++ b/frontend/src/app/main/ui/auth/verify_token.cljs @@ -17,7 +17,7 @@ [app.util.router :as rt] [app.util.timers :as ts] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmulti handle-token (fn [token] (:iss token))) diff --git a/frontend/src/app/main/ui/comments.cljs b/frontend/src/app/main/ui/comments.cljs index 57d621cbe..48281ae40 100644 --- a/frontend/src/app/main/ui/comments.cljs +++ b/frontend/src/app/main/ui/comments.cljs @@ -22,7 +22,7 @@ [app.util.time :as dt] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc resizing-textarea {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/components/code_block.cljs b/frontend/src/app/main/ui/components/code_block.cljs index 91758e908..a446e83ca 100644 --- a/frontend/src/app/main/ui/components/code_block.cljs +++ b/frontend/src/app/main/ui/components/code_block.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.components.code-block (:require ["highlight.js" :as hljs] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc code-block [{:keys [code type]}] (let [block-ref (mf/use-ref)] diff --git a/frontend/src/app/main/ui/components/color_bullet.cljs b/frontend/src/app/main/ui/components/color_bullet.cljs index 8db2af7a6..2cb1382e9 100644 --- a/frontend/src/app/main/ui/components/color_bullet.cljs +++ b/frontend/src/app/main/ui/components/color_bullet.cljs @@ -9,7 +9,7 @@ [app.util.color :as uc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn gradient-type->string [type] (case type diff --git a/frontend/src/app/main/ui/components/color_input.cljs b/frontend/src/app/main/ui/components/color_input.cljs index acfccddfc..380a93802 100644 --- a/frontend/src/app/main/ui/components/color_input.cljs +++ b/frontend/src/app/main/ui/components/color_input.cljs @@ -13,7 +13,7 @@ [app.util.keyboard :as kbd] [app.util.object :as obj] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn clean-color diff --git a/frontend/src/app/main/ui/components/context_menu.cljs b/frontend/src/app/main/ui/components/context_menu.cljs index d7b7b7669..d64ab95d8 100644 --- a/frontend/src/app/main/ui/components/context_menu.cljs +++ b/frontend/src/app/main/ui/components/context_menu.cljs @@ -15,7 +15,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.object :as obj] [goog.object :as gobj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc context-menu {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/components/copy_button.cljs b/frontend/src/app/main/ui/components/copy_button.cljs index 7b5e8919f..571c37551 100644 --- a/frontend/src/app/main/ui/components/copy_button.cljs +++ b/frontend/src/app/main/ui/components/copy_button.cljs @@ -10,7 +10,7 @@ [app.util.timers :as timers] [app.util.webapi :as wapi] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc copy-button [{:keys [data on-copied]}] (let [just-copied (mf/use-state false)] diff --git a/frontend/src/app/main/ui/components/dropdown.cljs b/frontend/src/app/main/ui/components/dropdown.cljs index 56dcb6204..8be2f498d 100644 --- a/frontend/src/app/main/ui/components/dropdown.cljs +++ b/frontend/src/app/main/ui/components/dropdown.cljs @@ -12,7 +12,7 @@ [app.util.keyboard :as kbd] [goog.events :as events] [goog.object :as gobj] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc dropdown' diff --git a/frontend/src/app/main/ui/components/editable_label.cljs b/frontend/src/app/main/ui/components/editable_label.cljs index 814bc4e7f..de24d8848 100644 --- a/frontend/src/app/main/ui/components/editable_label.cljs +++ b/frontend/src/app/main/ui/components/editable_label.cljs @@ -10,7 +10,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.timers :as timers] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc editable-label [{:keys [value on-change on-cancel editing? disable-dbl-click? class-name] :as props}] diff --git a/frontend/src/app/main/ui/components/editable_select.cljs b/frontend/src/app/main/ui/components/editable_select.cljs index 09cbdaf14..4c1b0d6ed 100644 --- a/frontend/src/app/main/ui/components/editable_select.cljs +++ b/frontend/src/app/main/ui/components/editable_select.cljs @@ -15,7 +15,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [app.util.timers :as timers] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc editable-select [{:keys [value type options class on-change placeholder on-blur] :as params}] diff --git a/frontend/src/app/main/ui/components/file_uploader.cljs b/frontend/src/app/main/ui/components/file_uploader.cljs index 2394b25e6..3587e17fe 100644 --- a/frontend/src/app/main/ui/components/file_uploader.cljs +++ b/frontend/src/app/main/ui/components/file_uploader.cljs @@ -8,7 +8,7 @@ (:require [app.main.store :as st] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc file-uploader {::mf/forward-ref true} diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs index f84887600..4102c36d9 100644 --- a/frontend/src/app/main/ui/components/forms.cljs +++ b/frontend/src/app/main/ui/components/forms.cljs @@ -17,7 +17,7 @@ [cljs.core :as c] [clojure.string] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def form-ctx (mf/create-context nil)) (def use-form fm/use-form) diff --git a/frontend/src/app/main/ui/components/numeric_input.cljs b/frontend/src/app/main/ui/components/numeric_input.cljs index 6ba9eeaeb..45bb33e76 100644 --- a/frontend/src/app/main/ui/components/numeric_input.cljs +++ b/frontend/src/app/main/ui/components/numeric_input.cljs @@ -16,7 +16,7 @@ [app.util.simple-math :as sm] [cuerdas.core :as str] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc numeric-input diff --git a/frontend/src/app/main/ui/components/select.cljs b/frontend/src/app/main/ui/components/select.cljs index 0df56afec..344ea38e0 100644 --- a/frontend/src/app/main/ui/components/select.cljs +++ b/frontend/src/app/main/ui/components/select.cljs @@ -10,7 +10,7 @@ [app.common.uuid :as uuid] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.icons :as i] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc select [{:keys [default-value options class on-change]}] (let [state (mf/use-state {:id (uuid/next) diff --git a/frontend/src/app/main/ui/components/shape_icon.cljs b/frontend/src/app/main/ui/components/shape_icon.cljs index a39b6f2f8..27a8794b9 100644 --- a/frontend/src/app/main/ui/components/shape_icon.cljs +++ b/frontend/src/app/main/ui/components/shape_icon.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.components.shape-icon (:require [app.main.ui.icons :as i] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc element-icon diff --git a/frontend/src/app/main/ui/components/tab_container.cljs b/frontend/src/app/main/ui/components/tab_container.cljs index 41c0915b8..579014fbb 100644 --- a/frontend/src/app/main/ui/components/tab_container.cljs +++ b/frontend/src/app/main/ui/components/tab_container.cljs @@ -8,7 +8,7 @@ (:require [app.common.data :as d] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc tab-element {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/confirm.cljs b/frontend/src/app/main/ui/confirm.cljs index c1093d76a..3e78635e2 100644 --- a/frontend/src/app/main/ui/confirm.cljs +++ b/frontend/src/app/main/ui/confirm.cljs @@ -13,7 +13,7 @@ [app.util.i18n :as i18n :refer [tr t]] [app.util.keyboard :as k] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc confirm-dialog diff --git a/frontend/src/app/main/ui/context.cljs b/frontend/src/app/main/ui/context.cljs index 82c0c75d8..51f0bb182 100644 --- a/frontend/src/app/main/ui/context.cljs +++ b/frontend/src/app/main/ui/context.cljs @@ -6,7 +6,7 @@ (ns app.main.ui.context (:require - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def render-id (mf/create-context nil)) diff --git a/frontend/src/app/main/ui/cursors.cljs b/frontend/src/app/main/ui/cursors.cljs index 6798fe6bc..4a0f323e1 100644 --- a/frontend/src/app/main/ui/cursors.cljs +++ b/frontend/src/app/main/ui/cursors.cljs @@ -9,7 +9,7 @@ (:require [app.util.timers :as ts] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; Static cursors (def comments (cursor-ref :comments 0 2 20)) diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index ec07a45ac..a1154ec93 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -37,7 +37,7 @@ [goog.events :as events] [okulary.core :as l] [potok.core :as ptk] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn ^boolean uuid-str? diff --git a/frontend/src/app/main/ui/dashboard/change_owner.cljs b/frontend/src/app/main/ui/dashboard/change_owner.cljs index b84f3ea1d..f836f4182 100644 --- a/frontend/src/app/main/ui/dashboard/change_owner.cljs +++ b/frontend/src/app/main/ui/dashboard/change_owner.cljs @@ -14,7 +14,7 @@ [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::member-id ::us/uuid) (s/def ::leave-modal-form diff --git a/frontend/src/app/main/ui/dashboard/comments.cljs b/frontend/src/app/main/ui/dashboard/comments.cljs index 5b7dffe4d..eaf699ad9 100644 --- a/frontend/src/app/main/ui/dashboard/comments.cljs +++ b/frontend/src/app/main/ui/dashboard/comments.cljs @@ -17,7 +17,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc comments-section [{:keys [profile team]}] diff --git a/frontend/src/app/main/ui/dashboard/export.cljs b/frontend/src/app/main/ui/dashboard/export.cljs index f92c50a2b..8b7a9d610 100644 --- a/frontend/src/app/main/ui/dashboard/export.cljs +++ b/frontend/src/app/main/ui/dashboard/export.cljs @@ -15,7 +15,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def ^:const options [:all :merge :detach]) diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index 86c074b1f..e7f70c225 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -19,7 +19,7 @@ [app.util.router :as rt] [beicon.core :as rx] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn get-project-name [project] diff --git a/frontend/src/app/main/ui/dashboard/files.cljs b/frontend/src/app/main/ui/dashboard/files.cljs index 79d1aa903..d298e2fb1 100644 --- a/frontend/src/app/main/ui/dashboard/files.cljs +++ b/frontend/src/app/main/ui/dashboard/files.cljs @@ -20,7 +20,7 @@ [app.util.webapi :as wapi] [beicon.core :as rx] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc header [{:keys [project on-create-clicked] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/fonts.cljs b/frontend/src/app/main/ui/dashboard/fonts.cljs index 987c5f190..286224208 100644 --- a/frontend/src/app/main/ui/dashboard/fonts.cljs +++ b/frontend/src/app/main/ui/dashboard/fonts.cljs @@ -20,7 +20,7 @@ [app.util.keyboard :as kbd] [beicon.core :as rx] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- use-set-page-title [team section] diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 833452087..0d4e84a91 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -28,7 +28,7 @@ [app.util.time :as dt] [app.util.timers :as ts] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :warn) diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index 7aed54536..0500f628f 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -24,7 +24,7 @@ [app.util.webapi :as wapi] [beicon.core :as rx] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :debug) diff --git a/frontend/src/app/main/ui/dashboard/inline_edition.cljs b/frontend/src/app/main/ui/dashboard/inline_edition.cljs index 4df5a9739..13449aece 100644 --- a/frontend/src/app/main/ui/dashboard/inline_edition.cljs +++ b/frontend/src/app/main/ui/dashboard/inline_edition.cljs @@ -9,7 +9,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.keyboard :as kbd] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc inline-edition [{:keys [content on-end] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/libraries.cljs b/frontend/src/app/main/ui/dashboard/libraries.cljs index f5433d56a..be9df1fb8 100644 --- a/frontend/src/app/main/ui/dashboard/libraries.cljs +++ b/frontend/src/app/main/ui/dashboard/libraries.cljs @@ -16,7 +16,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.webapi :as wapi] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc libraries-page [{:keys [team] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/placeholder.cljs b/frontend/src/app/main/ui/dashboard/placeholder.cljs index 4e5e9b01c..bc85b64ff 100644 --- a/frontend/src/app/main/ui/dashboard/placeholder.cljs +++ b/frontend/src/app/main/ui/dashboard/placeholder.cljs @@ -8,7 +8,7 @@ (:require [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc empty-placeholder [{:keys [dragging? on-create-clicked project limit origin] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/project_menu.cljs b/frontend/src/app/main/ui/dashboard/project_menu.cljs index d2f2661fb..8804c52cd 100644 --- a/frontend/src/app/main/ui/dashboard/project_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/project_menu.cljs @@ -19,7 +19,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::project some?) (s/def ::show? boolean?) diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index f65eceb7d..39e5d3f2f 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -27,7 +27,7 @@ [cuerdas.core :as str] [okulary.core :as l] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc header {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/dashboard/search.cljs b/frontend/src/app/main/ui/dashboard/search.cljs index 48bfa894a..865b52575 100644 --- a/frontend/src/app/main/ui/dashboard/search.cljs +++ b/frontend/src/app/main/ui/dashboard/search.cljs @@ -16,7 +16,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.webapi :as wapi] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc search-page [{:keys [team search-term] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs index 781cb8a72..eb11a8eda 100644 --- a/frontend/src/app/main/ui/dashboard/sidebar.cljs +++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs @@ -33,7 +33,7 @@ [cljs.spec.alpha :as s] [goog.functions :as f] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc sidebar-project [{:keys [item selected?] :as props}] diff --git a/frontend/src/app/main/ui/dashboard/team.cljs b/frontend/src/app/main/ui/dashboard/team.cljs index 0f376462a..592f2dec0 100644 --- a/frontend/src/app/main/ui/dashboard/team.cljs +++ b/frontend/src/app/main/ui/dashboard/team.cljs @@ -27,7 +27,7 @@ [app.util.i18n :as i18n :refer [tr]] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc header {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/dashboard/team_form.cljs b/frontend/src/app/main/ui/dashboard/team_form.cljs index 8e79c0054..673343fcf 100644 --- a/frontend/src/app/main/ui/dashboard/team_form.cljs +++ b/frontend/src/app/main/ui/dashboard/team_form.cljs @@ -17,7 +17,7 @@ [app.util.router :as rt] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::name ::us/not-empty-string) (s/def ::team-form diff --git a/frontend/src/app/main/ui/delete_shared.cljs b/frontend/src/app/main/ui/delete_shared.cljs index 191427c32..c1bfb139b 100644 --- a/frontend/src/app/main/ui/delete_shared.cljs +++ b/frontend/src/app/main/ui/delete_shared.cljs @@ -15,7 +15,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as k] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (mf/defc delete-shared-dialog diff --git a/frontend/src/app/main/ui/export.cljs b/frontend/src/app/main/ui/export.cljs index 1b74b9383..9837a05ff 100644 --- a/frontend/src/app/main/ui/export.cljs +++ b/frontend/src/app/main/ui/export.cljs @@ -20,7 +20,7 @@ [app.util.i18n :as i18n :refer [tr c]] [app.util.strings :as ust] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc export-multiple-dialog [{:keys [exports title cmd no-selection]}] diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index 1b9c06105..c8e61a442 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -20,7 +20,7 @@ [app.util.timers :as ts] [beicon.core :as rx] [goog.functions :as f] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn use-id "Get a stable id value across rerenders." diff --git a/frontend/src/app/main/ui/hooks/mutable_observer.cljs b/frontend/src/app/main/ui/hooks/mutable_observer.cljs index 329efd24c..b5b9be423 100644 --- a/frontend/src/app/main/ui/hooks/mutable_observer.cljs +++ b/frontend/src/app/main/ui/hooks/mutable_observer.cljs @@ -8,7 +8,7 @@ (:require [app.common.data :as d] [app.common.logging :as log] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :warn) diff --git a/frontend/src/app/main/ui/hooks/resize.cljs b/frontend/src/app/main/ui/hooks/resize.cljs index eff930b8b..a14ce5d8e 100644 --- a/frontend/src/app/main/ui/hooks/resize.cljs +++ b/frontend/src/app/main/ui/hooks/resize.cljs @@ -13,7 +13,7 @@ [app.main.ui.hooks :as hooks] [app.util.dom :as dom] [app.util.storage :refer [storage]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :warn) diff --git a/frontend/src/app/main/ui/icons.clj b/frontend/src/app/main/ui/icons.clj index 603f663b2..668ac50b7 100644 --- a/frontend/src/app/main/ui/icons.clj +++ b/frontend/src/app/main/ui/icons.clj @@ -5,13 +5,13 @@ ;; Copyright (c) KALEIDOS INC (ns app.main.ui.icons - (:require [rumext.alpha])) + (:require [rumext.v2])) (defmacro icon-xref [id] (let [href (str "#icon-" (name id)) class (str "icon-" (name id))] - `(rumext.alpha/html + `(rumext.v2/html [:svg {:width 500 :height 500 :class ~class} [:use {:href ~href}]]))) diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index a3f6fccaf..2500a60d3 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.icons (:refer-clojure :exclude [import mask]) (:require-macros [app.main.ui.icons :refer [icon-xref]]) - (:require [rumext.alpha :as mf])) + (:require [rumext.v2 :as mf])) ;; Keep the list of icons sorted diff --git a/frontend/src/app/main/ui/loader.cljs b/frontend/src/app/main/ui/loader.cljs index 84933b5b5..393de79d6 100644 --- a/frontend/src/app/main/ui/loader.cljs +++ b/frontend/src/app/main/ui/loader.cljs @@ -8,7 +8,7 @@ (:require [app.main.store :as st] [app.main.ui.icons :as i] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Component diff --git a/frontend/src/app/main/ui/measurements.cljs b/frontend/src/app/main/ui/measurements.cljs index f08cf6d20..3cd60d6de 100644 --- a/frontend/src/app/main/ui/measurements.cljs +++ b/frontend/src/app/main/ui/measurements.cljs @@ -13,7 +13,7 @@ [app.common.math :as mth] [app.common.uuid :as uuid] [app.main.ui.formats :as fmt] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; ------------------------------------------------ ;; CONSTANTS diff --git a/frontend/src/app/main/ui/messages.cljs b/frontend/src/app/main/ui/messages.cljs index 229f0efa3..49be805dd 100644 --- a/frontend/src/app/main/ui/messages.cljs +++ b/frontend/src/app/main/ui/messages.cljs @@ -12,7 +12,7 @@ [app.main.store :as st] [app.main.ui.icons :as i] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc banner [{:keys [type position status controls content actions on-close data-test] :as props}] diff --git a/frontend/src/app/main/ui/modal.cljs b/frontend/src/app/main/ui/modal.cljs index aff7e81e9..47cca1645 100644 --- a/frontend/src/app/main/ui/modal.cljs +++ b/frontend/src/app/main/ui/modal.cljs @@ -12,7 +12,7 @@ [app.util.keyboard :as k] [goog.events :as events] [okulary.core :as l] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn- on-esc-clicked diff --git a/frontend/src/app/main/ui/onboarding.cljs b/frontend/src/app/main/ui/onboarding.cljs index abaa962f6..26255f140 100644 --- a/frontend/src/app/main/ui/onboarding.cljs +++ b/frontend/src/app/main/ui/onboarding.cljs @@ -18,7 +18,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as tm] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- ONBOARDING LIGHTBOX diff --git a/frontend/src/app/main/ui/onboarding/newsletter.cljs b/frontend/src/app/main/ui/onboarding/newsletter.cljs index 5cbba48cf..05c4fa8e8 100644 --- a/frontend/src/app/main/ui/onboarding/newsletter.cljs +++ b/frontend/src/app/main/ui/onboarding/newsletter.cljs @@ -11,7 +11,7 @@ [app.main.data.users :as du] [app.main.store :as st] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc onboarding-newsletter-modal {::mf/register modal/components diff --git a/frontend/src/app/main/ui/onboarding/questions.cljs b/frontend/src/app/main/ui/onboarding/questions.cljs index 0ffa76599..93c84f3d3 100644 --- a/frontend/src/app/main/ui/onboarding/questions.cljs +++ b/frontend/src/app/main/ui/onboarding/questions.cljs @@ -14,7 +14,7 @@ [goog.events :as gev] [potok.core :as ptk] [promesa.core :as p] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn load-arengu-sdk [container-ref email form-id] diff --git a/frontend/src/app/main/ui/onboarding/team_choice.cljs b/frontend/src/app/main/ui/onboarding/team_choice.cljs index 8bc8a8967..b1a1e5342 100644 --- a/frontend/src/app/main/ui/onboarding/team_choice.cljs +++ b/frontend/src/app/main/ui/onboarding/team_choice.cljs @@ -21,7 +21,7 @@ [app.util.timers :as tm] [cljs.spec.alpha :as s] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::name ::us/not-empty-string) (s/def ::team-form diff --git a/frontend/src/app/main/ui/onboarding/templates.cljs b/frontend/src/app/main/ui/onboarding/templates.cljs index 1d2ef9017..e5f80821d 100644 --- a/frontend/src/app/main/ui/onboarding/templates.cljs +++ b/frontend/src/app/main/ui/onboarding/templates.cljs @@ -16,7 +16,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.webapi :as wapi] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc template-item [{:keys [name path image project-id]}] diff --git a/frontend/src/app/main/ui/releases.cljs b/frontend/src/app/main/ui/releases.cljs index e2f31698a..1db2254d1 100644 --- a/frontend/src/app/main/ui/releases.cljs +++ b/frontend/src/app/main/ui/releases.cljs @@ -24,7 +24,7 @@ [app.main.ui.releases.v1-9] [app.util.object :as obj] [app.util.timers :as tm] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;;; --- RELEASE NOTES MODAL diff --git a/frontend/src/app/main/ui/releases/common.cljs b/frontend/src/app/main/ui/releases/common.cljs index d5f644164..a20f2e56d 100644 --- a/frontend/src/app/main/ui/releases/common.cljs +++ b/frontend/src/app/main/ui/releases/common.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.common (:require [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmulti render-release-notes :version) diff --git a/frontend/src/app/main/ui/releases/v1_10.cljs b/frontend/src/app/main/ui/releases/v1_10.cljs index cbad572c4..b2e0c7cf3 100644 --- a/frontend/src/app/main/ui/releases/v1_10.cljs +++ b/frontend/src/app/main/ui/releases/v1_10.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-10 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.10" [{:keys [klass finish version]}] diff --git a/frontend/src/app/main/ui/releases/v1_11.cljs b/frontend/src/app/main/ui/releases/v1_11.cljs index 6ff3176dd..017337bff 100644 --- a/frontend/src/app/main/ui/releases/v1_11.cljs +++ b/frontend/src/app/main/ui/releases/v1_11.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-11 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.11" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_12.cljs b/frontend/src/app/main/ui/releases/v1_12.cljs index baf8f53c7..77edc383d 100644 --- a/frontend/src/app/main/ui/releases/v1_12.cljs +++ b/frontend/src/app/main/ui/releases/v1_12.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-12 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.12" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_13.cljs b/frontend/src/app/main/ui/releases/v1_13.cljs index b177307b7..48b8c7908 100644 --- a/frontend/src/app/main/ui/releases/v1_13.cljs +++ b/frontend/src/app/main/ui/releases/v1_13.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-13 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.13" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_14.cljs b/frontend/src/app/main/ui/releases/v1_14.cljs index 383998db2..f63568d04 100644 --- a/frontend/src/app/main/ui/releases/v1_14.cljs +++ b/frontend/src/app/main/ui/releases/v1_14.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-14 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.14" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_15.cljs b/frontend/src/app/main/ui/releases/v1_15.cljs index 4b9a3d3dc..b5bffc601 100644 --- a/frontend/src/app/main/ui/releases/v1_15.cljs +++ b/frontend/src/app/main/ui/releases/v1_15.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-15 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.15" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_4.cljs b/frontend/src/app/main/ui/releases/v1_4.cljs index 701e356b2..50a180177 100644 --- a/frontend/src/app/main/ui/releases/v1_4.cljs +++ b/frontend/src/app/main/ui/releases/v1_4.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-4 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.4" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_5.cljs b/frontend/src/app/main/ui/releases/v1_5.cljs index 4240e2012..e5382ab43 100644 --- a/frontend/src/app/main/ui/releases/v1_5.cljs +++ b/frontend/src/app/main/ui/releases/v1_5.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-5 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.5" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_6.cljs b/frontend/src/app/main/ui/releases/v1_6.cljs index 8209c1b09..3eaf51443 100644 --- a/frontend/src/app/main/ui/releases/v1_6.cljs +++ b/frontend/src/app/main/ui/releases/v1_6.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-6 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.6" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_7.cljs b/frontend/src/app/main/ui/releases/v1_7.cljs index 0f1d74d2f..a0f774dfd 100644 --- a/frontend/src/app/main/ui/releases/v1_7.cljs +++ b/frontend/src/app/main/ui/releases/v1_7.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-7 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.7" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_8.cljs b/frontend/src/app/main/ui/releases/v1_8.cljs index 07cb80772..3abfebb91 100644 --- a/frontend/src/app/main/ui/releases/v1_8.cljs +++ b/frontend/src/app/main/ui/releases/v1_8.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-8 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.8" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/releases/v1_9.cljs b/frontend/src/app/main/ui/releases/v1_9.cljs index 427bb9181..2c617db95 100644 --- a/frontend/src/app/main/ui/releases/v1_9.cljs +++ b/frontend/src/app/main/ui/releases/v1_9.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.releases.v1-9 (:require [app.main.ui.releases.common :as c] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defmethod c/render-release-notes "1.9" [{:keys [slide klass next finish navigate version]}] diff --git a/frontend/src/app/main/ui/settings.cljs b/frontend/src/app/main/ui/settings.cljs index 47fd585a9..4b221c96f 100644 --- a/frontend/src/app/main/ui/settings.cljs +++ b/frontend/src/app/main/ui/settings.cljs @@ -17,7 +17,7 @@ [app.main.ui.settings.sidebar :refer [sidebar]] [app.util.i18n :as i18n :refer [tr]] [app.util.router :as rt] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc header {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs index f8dd14e05..14d69e1e5 100644 --- a/frontend/src/app/main/ui/settings/change_email.cljs +++ b/frontend/src/app/main/ui/settings/change_email.cljs @@ -18,7 +18,7 @@ [app.util.i18n :as i18n :refer [tr]] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::email-1 ::us/email) (s/def ::email-2 ::us/email) diff --git a/frontend/src/app/main/ui/settings/delete_account.cljs b/frontend/src/app/main/ui/settings/delete_account.cljs index 12f536a4e..766f3d01d 100644 --- a/frontend/src/app/main/ui/settings/delete_account.cljs +++ b/frontend/src/app/main/ui/settings/delete_account.cljs @@ -14,7 +14,7 @@ [app.main.ui.messages :as msgs] [app.util.i18n :as i18n :refer [tr]] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn on-error [{:keys [code] :as error}] diff --git a/frontend/src/app/main/ui/settings/feedback.cljs b/frontend/src/app/main/ui/settings/feedback.cljs index 8fb14f560..5ad63a1f3 100644 --- a/frontend/src/app/main/ui/settings/feedback.cljs +++ b/frontend/src/app/main/ui/settings/feedback.cljs @@ -17,7 +17,7 @@ [app.util.i18n :as i18n :refer [tr]] [beicon.core :as rx] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::content ::us/not-empty-string) (s/def ::subject ::us/not-empty-string) diff --git a/frontend/src/app/main/ui/settings/options.cljs b/frontend/src/app/main/ui/settings/options.cljs index e51090e25..f74de00f1 100644 --- a/frontend/src/app/main/ui/settings/options.cljs +++ b/frontend/src/app/main/ui/settings/options.cljs @@ -15,7 +15,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::lang (s/nilable ::us/string)) (s/def ::theme (s/nilable ::us/not-empty-string)) diff --git a/frontend/src/app/main/ui/settings/password.cljs b/frontend/src/app/main/ui/settings/password.cljs index b32519b78..ce93a8af7 100644 --- a/frontend/src/app/main/ui/settings/password.cljs +++ b/frontend/src/app/main/ui/settings/password.cljs @@ -14,7 +14,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [t tr]] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- on-error [form error] diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs index 88bf9fad3..8758aa1c6 100644 --- a/frontend/src/app/main/ui/settings/profile.cljs +++ b/frontend/src/app/main/ui/settings/profile.cljs @@ -19,7 +19,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cljs.spec.alpha :as s] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (s/def ::fullname ::us/not-empty-string) (s/def ::email ::us/email) diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index a7a5d85bc..8a48644f6 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -17,7 +17,7 @@ [app.util.keyboard :as kbd] [app.util.router :as rt] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc sidebar-content [{:keys [profile section] :as props}] diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 293fc407d..334f56025 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -16,7 +16,7 @@ [app.util.object :as obj] [app.util.svg :as usvg] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- stroke-type->dasharray [width style] diff --git a/frontend/src/app/main/ui/shapes/bool.cljs b/frontend/src/app/main/ui/shapes/bool.cljs index 9c32c6423..94a76d893 100644 --- a/frontend/src/app/main/ui/shapes/bool.cljs +++ b/frontend/src/app/main/ui/shapes/bool.cljs @@ -13,7 +13,7 @@ [app.main.ui.shapes.export :as use] [app.main.ui.shapes.path :refer [path-shape]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn bool-shape [shape-wrapper] diff --git a/frontend/src/app/main/ui/shapes/circle.cljs b/frontend/src/app/main/ui/shapes/circle.cljs index 02e9129e5..4501098ba 100644 --- a/frontend/src/app/main/ui/shapes/circle.cljs +++ b/frontend/src/app/main/ui/shapes/circle.cljs @@ -10,7 +10,7 @@ [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :refer [shape-custom-strokes]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc circle-shape {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/custom_stroke.cljs b/frontend/src/app/main/ui/shapes/custom_stroke.cljs index 2dec9ea08..484a74d8e 100644 --- a/frontend/src/app/main/ui/shapes/custom_stroke.cljs +++ b/frontend/src/app/main/ui/shapes/custom_stroke.cljs @@ -16,7 +16,7 @@ [app.main.ui.shapes.gradients :as grad] [app.util.object :as obj] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn add-props [props new-props] diff --git a/frontend/src/app/main/ui/shapes/embed.cljs b/frontend/src/app/main/ui/shapes/embed.cljs index 0d5901587..2105d15d2 100644 --- a/frontend/src/app/main/ui/shapes/embed.cljs +++ b/frontend/src/app/main/ui/shapes/embed.cljs @@ -9,7 +9,7 @@ [app.main.ui.hooks :as hooks] [app.util.http :as http] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def context (mf/create-context false)) diff --git a/frontend/src/app/main/ui/shapes/export.cljs b/frontend/src/app/main/ui/shapes/export.cljs index 06d10061d..1ea742ceb 100644 --- a/frontend/src/app/main/ui/shapes/export.cljs +++ b/frontend/src/app/main/ui/shapes/export.cljs @@ -16,7 +16,7 @@ [app.util.object :as obj] [app.util.svg :as usvg] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def include-metadata-ctx (mf/create-context false)) diff --git a/frontend/src/app/main/ui/shapes/fills.cljs b/frontend/src/app/main/ui/shapes/fills.cljs index 8687c4506..556a8020d 100644 --- a/frontend/src/app/main/ui/shapes/fills.cljs +++ b/frontend/src/app/main/ui/shapes/fills.cljs @@ -14,7 +14,7 @@ [app.main.ui.shapes.embed :as embed] [app.main.ui.shapes.gradients :as grad] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc fills {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/filters.cljs b/frontend/src/app/main/ui/shapes/filters.cljs index 04ba7bdfa..5593a8b4d 100644 --- a/frontend/src/app/main/ui/shapes/filters.cljs +++ b/frontend/src/app/main/ui/shapes/filters.cljs @@ -12,7 +12,7 @@ [app.common.uuid :as uuid] [app.util.color :as color] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn get-filter-id [] (str "filter_" (uuid/next))) diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index abd7399f8..00d043f8f 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -13,7 +13,7 @@ [app.main.ui.shapes.custom-stroke :refer [shape-fills shape-strokes]] [app.util.object :as obj] [debug :refer [debug?]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn frame-clip-id [shape render-id] diff --git a/frontend/src/app/main/ui/shapes/gradients.cljs b/frontend/src/app/main/ui/shapes/gradients.cljs index 64e37749b..3f921cc3a 100644 --- a/frontend/src/app/main/ui/shapes/gradients.cljs +++ b/frontend/src/app/main/ui/shapes/gradients.cljs @@ -14,7 +14,7 @@ [app.main.ui.context :as muc] [app.main.ui.shapes.export :as ed] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn add-metadata [props gradient] (-> props diff --git a/frontend/src/app/main/ui/shapes/group.cljs b/frontend/src/app/main/ui/shapes/group.cljs index a71a17cfa..b4cab7f1a 100644 --- a/frontend/src/app/main/ui/shapes/group.cljs +++ b/frontend/src/app/main/ui/shapes/group.cljs @@ -10,7 +10,7 @@ [app.main.ui.context :as muc] [app.main.ui.shapes.mask :refer [mask-url clip-url mask-factory]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn group-shape [shape-wrapper] diff --git a/frontend/src/app/main/ui/shapes/image.cljs b/frontend/src/app/main/ui/shapes/image.cljs index 2cd967169..42b9ddc5a 100644 --- a/frontend/src/app/main/ui/shapes/image.cljs +++ b/frontend/src/app/main/ui/shapes/image.cljs @@ -10,7 +10,7 @@ [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :refer [shape-custom-strokes]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc image-shape {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/mask.cljs b/frontend/src/app/main/ui/shapes/mask.cljs index 48761cfdc..493c43691 100644 --- a/frontend/src/app/main/ui/shapes/mask.cljs +++ b/frontend/src/app/main/ui/shapes/mask.cljs @@ -10,7 +10,7 @@ [app.common.geom.shapes :as gsh] [app.main.ui.context :as muc] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn mask-id [render-id mask] (str render-id "-" (:id mask) "-mask")) diff --git a/frontend/src/app/main/ui/shapes/path.cljs b/frontend/src/app/main/ui/shapes/path.cljs index dbb6cdf06..72d177744 100644 --- a/frontend/src/app/main/ui/shapes/path.cljs +++ b/frontend/src/app/main/ui/shapes/path.cljs @@ -11,7 +11,7 @@ [app.main.ui.shapes.custom-stroke :refer [shape-custom-strokes]] [app.util.object :as obj] [app.util.path.format :as upf] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc path-shape {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/rect.cljs b/frontend/src/app/main/ui/shapes/rect.cljs index 43cfea653..722ad5573 100644 --- a/frontend/src/app/main/ui/shapes/rect.cljs +++ b/frontend/src/app/main/ui/shapes/rect.cljs @@ -10,7 +10,7 @@ [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :refer [shape-custom-strokes]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc rect-shape {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/shape.cljs b/frontend/src/app/main/ui/shapes/shape.cljs index 6489a34d2..8b4a8fc2a 100644 --- a/frontend/src/app/main/ui/shapes/shape.cljs +++ b/frontend/src/app/main/ui/shapes/shape.cljs @@ -18,7 +18,7 @@ [app.main.ui.shapes.frame :as frame] [app.main.ui.shapes.svg-defs :as defs] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn propagate-wrapper-styles-child [child wrapper-props] diff --git a/frontend/src/app/main/ui/shapes/svg_defs.cljs b/frontend/src/app/main/ui/shapes/svg_defs.cljs index 736acfd04..174e095ea 100644 --- a/frontend/src/app/main/ui/shapes/svg_defs.cljs +++ b/frontend/src/app/main/ui/shapes/svg_defs.cljs @@ -12,7 +12,7 @@ [app.common.geom.shapes :as gsh] [app.common.geom.shapes.bounds :as gsb] [app.util.svg :as usvg] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn add-matrix [attrs transform-key transform-matrix] (update attrs diff --git a/frontend/src/app/main/ui/shapes/svg_raw.cljs b/frontend/src/app/main/ui/shapes/svg_raw.cljs index a560c17ef..3c71526af 100644 --- a/frontend/src/app/main/ui/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/shapes/svg_raw.cljs @@ -11,7 +11,7 @@ [app.main.ui.shapes.attrs :as usa] [app.util.object :as obj] [app.util.svg :as usvg] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; Graphic tags (defonce graphic-element? diff --git a/frontend/src/app/main/ui/shapes/text.cljs b/frontend/src/app/main/ui/shapes/text.cljs index 58b054b45..48390ead1 100644 --- a/frontend/src/app/main/ui/shapes/text.cljs +++ b/frontend/src/app/main/ui/shapes/text.cljs @@ -11,7 +11,7 @@ [app.main.ui.shapes.text.fo-text :as fo] [app.main.ui.shapes.text.svg-text :as svg] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- load-fonts! [content] diff --git a/frontend/src/app/main/ui/shapes/text/fo_text.cljs b/frontend/src/app/main/ui/shapes/text/fo_text.cljs index fc4f6a208..994b98980 100644 --- a/frontend/src/app/main/ui/shapes/text/fo_text.cljs +++ b/frontend/src/app/main/ui/shapes/text/fo_text.cljs @@ -14,7 +14,7 @@ [app.util.color :as uc] [app.util.object :as obj] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc render-text {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/text/fontfaces.cljs b/frontend/src/app/main/ui/shapes/text/fontfaces.cljs index 563bf51d7..d3da39791 100644 --- a/frontend/src/app/main/ui/shapes/text/fontfaces.cljs +++ b/frontend/src/app/main/ui/shapes/text/fontfaces.cljs @@ -15,7 +15,7 @@ [beicon.core :as rx] [clojure.set :as set] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn replace-embeds "Replace into the font-faces of a CSS the URL's that are present in `embed-data` by its diff --git a/frontend/src/app/main/ui/shapes/text/html_text.cljs b/frontend/src/app/main/ui/shapes/text/html_text.cljs index 86665004c..d60810e16 100644 --- a/frontend/src/app/main/ui/shapes/text/html_text.cljs +++ b/frontend/src/app/main/ui/shapes/text/html_text.cljs @@ -10,7 +10,7 @@ [app.common.data.macros :as dm] [app.main.ui.shapes.text.styles :as sts] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc render-text {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/shapes/text/svg_text.cljs b/frontend/src/app/main/ui/shapes/text/svg_text.cljs index fe14a45e4..3440a1104 100644 --- a/frontend/src/app/main/ui/shapes/text/svg_text.cljs +++ b/frontend/src/app/main/ui/shapes/text/svg_text.cljs @@ -17,7 +17,7 @@ [app.main.ui.shapes.custom-stroke :refer [shape-custom-strokes]] [app.main.ui.shapes.gradients :as grad] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def fill-attrs [:fill-color :fill-color-gradient :fill-opacity]) diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs index 2447b4e38..463a4e307 100644 --- a/frontend/src/app/main/ui/static.cljs +++ b/frontend/src/app/main/ui/static.cljs @@ -12,7 +12,7 @@ [app.util.i18n :refer [tr]] [app.util.object :as obj] [app.util.router :as rt] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc static-header {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index 2c206502b..99762cf73 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -40,7 +40,7 @@ [cuerdas.core :as str] [goog.events :as events] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def current-animations-ref (l/derived :viewer-animations st/state)) diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index d6e425f97..b0fe50432 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -21,7 +21,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc comments-menu {::mf/wrap [mf/memo] diff --git a/frontend/src/app/main/ui/viewer/handoff.cljs b/frontend/src/app/main/ui/viewer/handoff.cljs index 5a6515f8d..f21473f26 100644 --- a/frontend/src/app/main/ui/viewer/handoff.cljs +++ b/frontend/src/app/main/ui/viewer/handoff.cljs @@ -14,7 +14,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn handle-select-frame diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes.cljs index 3a121540e..c175378e5 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes.cljs @@ -17,7 +17,7 @@ [app.main.ui.viewer.handoff.attributes.svg :refer [svg-panel]] [app.main.ui.viewer.handoff.attributes.text :refer [text-panel]] [app.main.ui.viewer.handoff.exports :refer [exports]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def type->options {:multiple [:fill :stroke :image :text :shadow :blur] diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/blur.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/blur.cljs index 6c32591aa..3153b0d53 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/blur.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/blur.cljs @@ -10,7 +10,7 @@ [app.util.code-gen :as cg] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn has-blur? [shape] (:blur shape)) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs index 6aa7d635c..4be59b7a6 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/common.cljs @@ -14,7 +14,7 @@ [app.util.i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def file-colors-ref diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs index 5fad7f9dd..be8e83214 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/fill.cljs @@ -11,7 +11,7 @@ [app.util.code-gen :as cg] [app.util.color :as uc] [app.util.i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def fill-attributes [:fill-color :fill-color-gradient]) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/image.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/image.cljs index fd480b4b3..e05b6c6fe 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/image.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/image.cljs @@ -13,7 +13,7 @@ [app.util.code-gen :as cg] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn has-image? [shape] (= (:type shape) :image)) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs index 85e011ace..5f178da03 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/layout.cljs @@ -12,7 +12,7 @@ [app.util.code-gen :as cg] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def properties [:width :height :x :y :radius :rx :r1]) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/shadow.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/shadow.cljs index cd2066904..65e1177c8 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/shadow.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/shadow.cljs @@ -12,7 +12,7 @@ [app.util.code-gen :as cg] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn has-shadow? [shape] (:shadow shape)) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs index 5f550c7b3..73ce49dbb 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/stroke.cljs @@ -13,7 +13,7 @@ [app.util.color :as uc] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn shape->color [shape] {:color (:stroke-color shape) diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/svg.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/svg.cljs index 46fcff522..583648da0 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/svg.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/svg.cljs @@ -10,7 +10,7 @@ [app.main.ui.components.copy-button :refer [copy-button]] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn map->css [attr] (->> attr diff --git a/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs b/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs index 11802bf7d..d52c5b26d 100644 --- a/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/attributes/text.cljs @@ -16,7 +16,7 @@ [app.util.i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn has-text? [shape] (:content shape)) diff --git a/frontend/src/app/main/ui/viewer/handoff/code.cljs b/frontend/src/app/main/ui/viewer/handoff/code.cljs index dca0e40d6..ad035dd7c 100644 --- a/frontend/src/app/main/ui/viewer/handoff/code.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/code.cljs @@ -17,7 +17,7 @@ [app.util.dom :as dom] [cuerdas.core :as str] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn generate-markup-code [_type shapes] (let [frame (dom/query js/document "#svg-frame") diff --git a/frontend/src/app/main/ui/viewer/handoff/exports.cljs b/frontend/src/app/main/ui/viewer/handoff/exports.cljs index 09844969c..ccd5af761 100644 --- a/frontend/src/app/main/ui/viewer/handoff/exports.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/exports.cljs @@ -13,7 +13,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :refer [tr c]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc exports {::mf/wrap [#(mf/memo % =)]} diff --git a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs index fbeeb5179..f9907a283 100644 --- a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs @@ -15,7 +15,7 @@ [app.util.dom :as dom] [app.util.keyboard :as kbd] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- make-collapsed-iref [id] diff --git a/frontend/src/app/main/ui/viewer/handoff/render.cljs b/frontend/src/app/main/ui/viewer/handoff/render.cljs index fbc56b144..0567bf654 100644 --- a/frontend/src/app/main/ui/viewer/handoff/render.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/render.cljs @@ -25,7 +25,7 @@ [app.main.ui.viewer.interactions :refer [prepare-objects]] [app.util.dom :as dom] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (declare shape-container-factory) diff --git a/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs index 38765446b..a6e5cb451 100644 --- a/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/right_sidebar.cljs @@ -14,7 +14,7 @@ [app.main.ui.viewer.handoff.code :refer [code]] [app.main.ui.viewer.handoff.selection-feedback :refer [resolve-shapes]] [app.util.i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc right-sidebar [{:keys [frame page file selected]}] diff --git a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs index c36719a47..0b7af463a 100644 --- a/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/selection_feedback.cljs @@ -9,7 +9,7 @@ [app.common.data :as d] [app.common.geom.shapes :as gsh] [app.main.ui.measurements :refer [size-display measurement]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; ------------------------------------------------ ;; CONSTANTS diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index 62e0e090b..ea0bb2850 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -20,7 +20,7 @@ [app.util.dom :as dom] [app.util.i18n :refer [tr]] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def fullscreen-ref (l/derived (fn [state] diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index 2ec0d7348..02a1e62cc 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -25,7 +25,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [goog.events :as events] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn prepare-objects [frame size objects] diff --git a/frontend/src/app/main/ui/viewer/login.cljs b/frontend/src/app/main/ui/viewer/login.cljs index 250b26955..7a130a7a4 100644 --- a/frontend/src/app/main/ui/viewer/login.cljs +++ b/frontend/src/app/main/ui/viewer/login.cljs @@ -17,7 +17,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.storage :refer [storage]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :warn) diff --git a/frontend/src/app/main/ui/viewer/shapes.cljs b/frontend/src/app/main/ui/viewer/shapes.cljs index 8d62020b8..5a0de8f95 100644 --- a/frontend/src/app/main/ui/viewer/shapes.cljs +++ b/frontend/src/app/main/ui/viewer/shapes.cljs @@ -28,7 +28,7 @@ [app.util.router :as rt] [app.util.timers :as tm] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def base-frame-ctx (mf/create-context nil)) (def frame-offset-ctx (mf/create-context nil)) diff --git a/frontend/src/app/main/ui/viewer/share_link.cljs b/frontend/src/app/main/ui/viewer/share_link.cljs index 735208f65..4ab098fc4 100644 --- a/frontend/src/app/main/ui/viewer/share_link.cljs +++ b/frontend/src/app/main/ui/viewer/share_link.cljs @@ -21,7 +21,7 @@ [app.util.router :as rt] [app.util.webapi :as wapi] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :warn) diff --git a/frontend/src/app/main/ui/viewer/thumbnails.cljs b/frontend/src/app/main/ui/viewer/thumbnails.cljs index 9474a89af..0563116ec 100644 --- a/frontend/src/app/main/ui/viewer/thumbnails.cljs +++ b/frontend/src/app/main/ui/viewer/thumbnails.cljs @@ -18,7 +18,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.object :as obj] [app.util.timers :as ts] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc thumbnails-content [{:keys [children expanded? total] :as props}] diff --git a/frontend/src/app/main/ui/workspace.cljs b/frontend/src/app/main/ui/workspace.cljs index a7c8c9918..da4f644b3 100644 --- a/frontend/src/app/main/ui/workspace.cljs +++ b/frontend/src/app/main/ui/workspace.cljs @@ -33,7 +33,7 @@ [app.util.object :as obj] [debug :refer [debug?]] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Workspace diff --git a/frontend/src/app/main/ui/workspace/colorpalette.cljs b/frontend/src/app/main/ui/workspace/colorpalette.cljs index 1a8b194dc..12507ef39 100644 --- a/frontend/src/app/main/ui/workspace/colorpalette.cljs +++ b/frontend/src/app/main/ui/workspace/colorpalette.cljs @@ -21,7 +21,7 @@ [app.util.object :as obj] [cuerdas.core :as str] [goog.events :as events] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Components diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 2573b464d..11eacb462 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -24,7 +24,7 @@ [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Refs diff --git a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs index 470209490..d9b409cf0 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/color_inputs.cljs @@ -9,7 +9,7 @@ [app.common.math :as mth] [app.util.color :as uc] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn parse-hex [val] diff --git a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs index e0aea501d..43a4f768b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/gradients.cljs @@ -8,7 +8,7 @@ (:require [app.common.data.macros :as dm] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- format-rgba [{:keys [r g b alpha offset]}] diff --git a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs index b9e68a851..d9c8609a5 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/harmony.cljs @@ -13,7 +13,7 @@ [app.util.dom :as dom] [app.util.object :as obj] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn create-color-wheel [canvas-node] diff --git a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs index 028b97071..0ea8b085c 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/hsva.cljs @@ -8,7 +8,7 @@ (:require [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.color :as uc] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc hsva-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] (let [{hue :h saturation :s value :v alpha :alpha} color diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index fa7455792..7a10381ca 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -15,7 +15,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc libraries [{:keys [on-select-color on-add-library-color disable-gradient disable-opacity]}] diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 19ea5e510..63c7b467c 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -11,7 +11,7 @@ [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] [app.util.color :as uc] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc value-saturation-selector [{:keys [saturation value on-change on-start-drag on-finish-drag]}] (let [dragging? (mf/use-state false) diff --git a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs index 80739060c..83c56c1b6 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/slider_selector.cljs @@ -9,7 +9,7 @@ [app.common.math :as mth] [app.util.dom :as dom] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc slider-selector [{:keys [value class min-value max-value vertical? reverse? on-change on-start-drag on-finish-drag]}] diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs index 0031174a3..3ff73b80d 100644 --- a/frontend/src/app/main/ui/workspace/comments.cljs +++ b/frontend/src/app/main/ui/workspace/comments.cljs @@ -19,7 +19,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as tm] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Sidebar diff --git a/frontend/src/app/main/ui/workspace/context_menu.cljs b/frontend/src/app/main/ui/workspace/context_menu.cljs index ee9699d15..a21ac8451 100644 --- a/frontend/src/app/main/ui/workspace/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/context_menu.cljs @@ -31,7 +31,7 @@ [app.util.i18n :refer [tr] :as i18n] [app.util.timers :as timers] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def menu-ref (l/derived :context-menu refs/workspace-local)) diff --git a/frontend/src/app/main/ui/workspace/coordinates.cljs b/frontend/src/app/main/ui/workspace/coordinates.cljs index 5973d272d..89717ef20 100644 --- a/frontend/src/app/main/ui/workspace/coordinates.cljs +++ b/frontend/src/app/main/ui/workspace/coordinates.cljs @@ -8,7 +8,7 @@ (:require [app.main.streams :as ms] [app.main.ui.hooks :as hooks] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc coordinates [{:keys [colorpalette?]}] diff --git a/frontend/src/app/main/ui/workspace/effects.cljs b/frontend/src/app/main/ui/workspace/effects.cljs index 9cdffecdb..a124dfb45 100644 --- a/frontend/src/app/main/ui/workspace/effects.cljs +++ b/frontend/src/app/main/ui/workspace/effects.cljs @@ -12,7 +12,7 @@ [app.main.store :as st] [app.util.dom :as dom] [app.util.keyboard :as kbd] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn use-pointer-enter [{:keys [id]}] diff --git a/frontend/src/app/main/ui/workspace/header.cljs b/frontend/src/app/main/ui/workspace/header.cljs index 9c827d721..7657d319b 100644 --- a/frontend/src/app/main/ui/workspace/header.cljs +++ b/frontend/src/app/main/ui/workspace/header.cljs @@ -29,7 +29,7 @@ [beicon.core :as rx] [okulary.core :as l] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def workspace-persistence-ref (l/derived :workspace-persistence st/state)) diff --git a/frontend/src/app/main/ui/workspace/left_toolbar.cljs b/frontend/src/app/main/ui/workspace/left_toolbar.cljs index 5f86477aa..95435b53e 100644 --- a/frontend/src/app/main/ui/workspace/left_toolbar.cljs +++ b/frontend/src/app/main/ui/workspace/left_toolbar.cljs @@ -21,7 +21,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.object :as obj] [app.util.timers :as ts] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc image-upload diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index d8592c93c..52f0909b7 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -17,7 +17,7 @@ [app.util.strings :refer [matches-search]] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def workspace-file (l/derived :workspace-file st/state)) diff --git a/frontend/src/app/main/ui/workspace/nudge.cljs b/frontend/src/app/main/ui/workspace/nudge.cljs index e2b65cbdd..1b466ba4b 100644 --- a/frontend/src/app/main/ui/workspace/nudge.cljs +++ b/frontend/src/app/main/ui/workspace/nudge.cljs @@ -16,7 +16,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as k] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn- on-keydown diff --git a/frontend/src/app/main/ui/workspace/presence.cljs b/frontend/src/app/main/ui/workspace/presence.cljs index 81560583f..19b1dcd22 100644 --- a/frontend/src/app/main/ui/workspace/presence.cljs +++ b/frontend/src/app/main/ui/workspace/presence.cljs @@ -8,7 +8,7 @@ (:require [app.config :as cfg] [app.main.refs :as refs] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- SESSION WIDGET diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index cc345e1aa..2e71107b3 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -26,7 +26,7 @@ [app.main.ui.workspace.shapes.svg-raw :as svg-raw] [app.main.ui.workspace.shapes.text :as text] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (declare shape-wrapper) (declare group-wrapper) diff --git a/frontend/src/app/main/ui/workspace/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/shapes/bool.cljs index 4e824fa3f..62cc6e821 100644 --- a/frontend/src/app/main/ui/workspace/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/bool.cljs @@ -13,7 +13,7 @@ [app.main.ui.shapes.bool :as bool] [app.main.ui.shapes.shape :refer [shape-container]] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn use-double-click [{:keys [id]}] (mf/use-callback diff --git a/frontend/src/app/main/ui/workspace/shapes/common.cljs b/frontend/src/app/main/ui/workspace/shapes/common.cljs index 6f35f8d2f..cccc1cb7e 100644 --- a/frontend/src/app/main/ui/workspace/shapes/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/common.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.workspace.shapes.common (:require [app.main.ui.shapes.shape :refer [shape-container]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn generic-wrapper-factory [component] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index b3b54ca18..891e49e26 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -24,7 +24,7 @@ [app.main.ui.workspace.shapes.frame.node-store :as fns] [app.main.ui.workspace.shapes.frame.thumbnail-render :as ftr] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn frame-shape-factory [shape-wrapper] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index af460601f..a6b527721 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -14,7 +14,7 @@ [app.main.store :as st] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- transform-no-resize "If we apply a scale directly to the texts it will show deformed so we need to create this diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs index 03c15ae43..d37470c43 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs @@ -8,7 +8,7 @@ (:require [app.util.dom :as dom] [app.util.globals :as globals] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn use-node-store "Hook responsible of storing the rendered DOM node in memory while not being used" diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs index c92ae74b4..409663bd2 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs @@ -21,7 +21,7 @@ [beicon.core :as rx] [cuerdas.core :as str] [debug :refer [debug?]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- draw-thumbnail-canvas! [canvas-node img-node] diff --git a/frontend/src/app/main/ui/workspace/shapes/group.cljs b/frontend/src/app/main/ui/workspace/shapes/group.cljs index 20a592de5..dd9a1a47e 100644 --- a/frontend/src/app/main/ui/workspace/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/group.cljs @@ -13,7 +13,7 @@ [app.main.ui.shapes.group :as group] [app.main.ui.shapes.shape :refer [shape-container]] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn use-double-click [{:keys [id]}] (mf/use-callback diff --git a/frontend/src/app/main/ui/workspace/shapes/path.cljs b/frontend/src/app/main/ui/workspace/shapes/path.cljs index b466865cd..9093a8940 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path.cljs @@ -12,7 +12,7 @@ [app.main.ui.shapes.path :as path] [app.main.ui.shapes.shape :refer [shape-container]] [app.main.ui.workspace.shapes.path.common :as pc] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn apply-content-modifiers [shape content-modifiers] diff --git a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs index 509085bae..c88f5e7b5 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/common.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/common.cljs @@ -8,7 +8,7 @@ (:require [app.main.refs :as refs] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def primary-color "var(--color-select)") (def secondary-color "var(--color-distance)") diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 12ba24e8e..d6f2a1dd1 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -22,7 +22,7 @@ [app.util.path.format :as upf] [clojure.set :refer [map-invert]] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (def point-radius 5) diff --git a/frontend/src/app/main/ui/workspace/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/shapes/svg_raw.cljs index db90ddd2d..27b9aed91 100644 --- a/frontend/src/app/main/ui/workspace/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/svg_raw.cljs @@ -10,7 +10,7 @@ [app.main.ui.shapes.shape :refer [shape-container]] [app.main.ui.shapes.svg-raw :as svg-raw] [app.util.svg :as usvg] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn svg-raw-wrapper-factory [shape-wrapper] diff --git a/frontend/src/app/main/ui/workspace/shapes/text.cljs b/frontend/src/app/main/ui/workspace/shapes/text.cljs index 7374fec82..53ed5d9ac 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text.cljs @@ -16,7 +16,7 @@ [app.main.ui.shapes.shape :refer [shape-container]] [app.main.ui.shapes.text :as text] [debug :refer [debug?]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Text Wrapper for workspace (mf/defc text-wrapper diff --git a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs index 259be29a8..419c8f7e5 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/editor.cljs @@ -23,7 +23,7 @@ [app.util.object :as obj] [app.util.text-editor :as ted] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) diff --git a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs index 70346e048..bacf0eea6 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs @@ -9,7 +9,7 @@ [app.common.geom.shapes :as gsh] [app.main.data.workspace.texts :as dwt] [app.main.refs :as refs] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc text-edition-outline [{:keys [shape zoom]}] diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index 6444af3d9..00cd7303f 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -25,7 +25,7 @@ [app.util.text-svg-position :as tsp] [app.util.timers :as ts] [promesa.core :as p] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn strip-position-data [shape] (-> shape diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index 0a7c6c445..e898b4e5a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -22,7 +22,7 @@ [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Left Sidebar (Component) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 5866dd96e..c0f1f9b5b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -45,7 +45,7 @@ [cuerdas.core :as str] [okulary.core :as l] [potok.core :as ptk] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; NOTE: TODO: for avoid too many arguments, I think we can use react ;; context variables for pass to the down tree all the common diff --git a/frontend/src/app/main/ui/workspace/sidebar/history.cljs b/frontend/src/app/main/ui/workspace/sidebar/history.cljs index 28ae0c829..a22274c5d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/history.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/history.cljs @@ -15,7 +15,7 @@ [app.util.i18n :refer [t] :as i18n] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def workspace-undo (l/derived :workspace-undo st/state)) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 05f6f26a7..61e45c915 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -25,7 +25,7 @@ [beicon.core :as rx] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Layer Name diff --git a/frontend/src/app/main/ui/workspace/sidebar/options.cljs b/frontend/src/app/main/ui/workspace/sidebar/options.cljs index 04826a833..50ea9fa1e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options.cljs @@ -30,7 +30,7 @@ [app.main.ui.workspace.sidebar.options.shapes.text :as text] [app.util.i18n :as i18n :refer [tr]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Options diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs index 778b560fa..00f081aee 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/common.cljs @@ -7,7 +7,7 @@ (ns app.main.ui.workspace.sidebar.options.common (:require [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc advanced-options [{:keys [visible? children]}] (let [ref (mf/use-ref nil)] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs index e4f52e4de..3ecf47267 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/align.cljs @@ -12,7 +12,7 @@ [app.main.store :as st] [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc align-options [] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs index 016bcb5c6..64a25b603 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/blur.cljs @@ -12,7 +12,7 @@ [app.main.ui.icons :as i] [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def blur-attrs [:blur]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs index 00d0da044..29f79ca7a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/bool.cljs @@ -13,7 +13,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc bool-options [] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs index 005e6e569..7a18745e8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs @@ -16,7 +16,7 @@ [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn fill->color-att [fill file-id shared-libs] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs index 6c5fdb4db..49ccd6301 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/component.cljs @@ -18,7 +18,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def component-attrs [:component-id :component-file :shape-ref :main-instance?]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs index 4ce4b5605..d7ea7c715 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/constraints.cljs @@ -16,7 +16,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def constraint-attrs [:constraints-h :constraints-v diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs index 838477a8b..e9a32edd6 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.cljs @@ -16,7 +16,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :refer [tr c]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def exports-attrs "Shape attrs that corresponds to exports. Used in other namespaces." diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs index 41200a903..4da297586 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/fill.cljs @@ -16,7 +16,7 @@ [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def fill-attrs [:fills diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs index 046b60f15..0573166a3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/frame_grid.cljs @@ -19,7 +19,7 @@ [app.util.geom.grid :as gg] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def workspace-saved-grids (l/derived :saved-grids refs/workspace-page-options)) 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 6b3c91106..3f84469fd 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 @@ -24,7 +24,7 @@ [app.util.keyboard :as kbd] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- event-type-names [] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs index f6e4b3bbc..3aaec9d4c 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layer.cljs @@ -13,7 +13,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def layer-attrs [:opacity :blend-mode :blocked :hidden]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs index 8d22186b8..3445970a7 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_container.cljs @@ -15,7 +15,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def layout-container-attrs [:layout ;; true if active, false if not diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs index f35731a5c..ce98a6761 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/layout_item.cljs @@ -14,7 +14,7 @@ [app.main.ui.icons :as i] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def layout-item-attrs [:layout-margin ;; {:m1 0 :m2 0 :m3 0 :m4 0} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs index 3b77196e0..9a531fe2e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/measures.cljs @@ -20,7 +20,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [clojure.set :refer [rename-keys union]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def measure-attrs [:proportion-lock diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs index 739a69a0e..66f0e6f81 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs @@ -18,7 +18,7 @@ [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def shadow-attrs [:shadow]) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs index e93b7ddd0..4fecb88d8 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs @@ -17,7 +17,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def stroke-attrs [:strokes diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs index 70860edc1..4db6b521b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs @@ -13,7 +13,7 @@ [app.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]] [app.util.dom :as dom] [app.util.i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc attribute-value [{:keys [attr value on-change on-delete] :as props}] (let [handle-change diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs index 299586709..24672804a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/text.cljs @@ -22,7 +22,7 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.timers :as tm] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def text-typography-attrs [:typography-ref-id diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs index ee6570d8d..4fd7e6aed 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/typography.cljs @@ -29,7 +29,7 @@ [app.util.timers :as tm] [cuerdas.core :as str] [goog.events :as events] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- attr->string [value] (if (= value :multiple) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs index 885877928..6bb27a3f2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/page.cljs @@ -14,7 +14,7 @@ [app.main.store :as st] [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs index c7d008629..4e2cc346b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs @@ -23,7 +23,7 @@ [app.util.color :as uc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn opacity->string [opacity] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs index d1183e097..44ba32735 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/input_row.cljs @@ -10,7 +10,7 @@ [app.main.ui.components.numeric-input :refer [numeric-input]] [app.main.ui.components.select :refer [select]] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc input-row [{:keys [label options value class min max on-change type placeholder default nillable]}] [:div.row-flex.input-row diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs index cd2f82f41..bc804fad9 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs @@ -14,7 +14,7 @@ [app.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- width->string [width] (if (= width :multiple) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs index 61b6994b1..1c45a1bf2 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/bool.cljs @@ -15,7 +15,7 @@ [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs index 3a9893d6a..af0878b7e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/circle.cljs @@ -16,7 +16,7 @@ [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs index 3cfced724..f75190749 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/frame.cljs @@ -18,7 +18,7 @@ [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs index 98594e4b5..b81a4a46a 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/group.cljs @@ -21,7 +21,7 @@ [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] [app.main.ui.workspace.sidebar.options.menus.text :as ot] [app.main.ui.workspace.sidebar.options.shapes.multiple :refer [get-attrs]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options {::mf/wrap [mf/memo] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs index 4eac90200..d2b1a8358 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/image.cljs @@ -15,7 +15,7 @@ [app.main.ui.workspace.sidebar.options.menus.measures :refer [measure-attrs measures-menu]] [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs index 2935c24e6..1ccb7ad7f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/multiple.cljs @@ -25,7 +25,7 @@ [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-attrs shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.text :as ot] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; Define how to read each kind of attribute depending on the shape type: ;; - shape: read the attribute directly from the shape. diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs index 7d82c57c3..22f750df4 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/path.cljs @@ -16,7 +16,7 @@ [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs index 9fd9e7208..654aad11b 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/rect.cljs @@ -16,7 +16,7 @@ [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options {::mf/wrap [mf/memo]} diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs index 91e235788..bd7a2c138 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/svg_raw.cljs @@ -19,7 +19,7 @@ [app.main.ui.workspace.sidebar.options.menus.svg-attrs :refer [svg-attrs-menu]] [app.util.color :as uc] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; This is a list of svg tags that can be grouped in shape-container ;; this allows them to have gradients, shadows and masks diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 9bd66b689..620832b1d 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -19,7 +19,7 @@ [app.main.ui.workspace.sidebar.options.menus.shadow :refer [shadow-menu]] [app.main.ui.workspace.sidebar.options.menus.stroke :refer [stroke-attrs stroke-menu]] [app.main.ui.workspace.sidebar.options.menus.text :refer [text-menu text-fill-attrs root-attrs paragraph-attrs text-attrs]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc options [{:keys [shape file-id] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs index 3cf96e029..5247f6696 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/shortcuts.cljs @@ -22,7 +22,7 @@ [clojure.set :as set] [clojure.string] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc converted-chars [{:keys [char command] :as props}] diff --git a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs index 272283b0d..0821a50ab 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/sitemap.cljs @@ -21,7 +21,7 @@ [app.util.keyboard :as kbd] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Page Item diff --git a/frontend/src/app/main/ui/workspace/textpalette.cljs b/frontend/src/app/main/ui/workspace/textpalette.cljs index 65267cbac..c7b7625cb 100644 --- a/frontend/src/app/main/ui/workspace/textpalette.cljs +++ b/frontend/src/app/main/ui/workspace/textpalette.cljs @@ -18,7 +18,7 @@ [app.util.dom :as dom] [app.util.i18n :refer [tr]] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc typography-item [{:keys [file-id selected-ids typography name-only?]}] diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index d14f73058..46ad6bdb9 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -41,7 +41,7 @@ [app.main.ui.workspace.viewport.widgets :as widgets] [beicon.core :as rx] [debug :refer [debug?]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Viewport diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index b0415819e..f0a5658cd 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -28,7 +28,7 @@ [app.util.timers :as timers] [beicon.core :as rx] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def scale-per-pixel -0.0057) diff --git a/frontend/src/app/main/ui/workspace/viewport/comments.cljs b/frontend/src/app/main/ui/workspace/viewport/comments.cljs index 8a74d53dc..a63f97ca2 100644 --- a/frontend/src/app/main/ui/workspace/viewport/comments.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/comments.cljs @@ -13,7 +13,7 @@ [app.main.ui.comments :as cmt] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc comments-layer [{:keys [vbox vport zoom file-id page-id drawing] :as props}] diff --git a/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs b/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs index b4bdb3ac1..8d31ae5ac 100644 --- a/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/drawarea.cljs @@ -12,7 +12,7 @@ [app.main.ui.shapes.path :refer [path-shape]] [app.main.ui.workspace.shapes :as shapes] [app.main.ui.workspace.shapes.path.editor :refer [path-editor]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (declare generic-draw-area) (declare path-draw-area) diff --git a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs index 4ddd66f32..a26d7c6ab 100644 --- a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs @@ -13,7 +13,7 @@ [app.common.uuid :as uuid] [app.main.refs :as refs] [app.util.geom.grid :as gg] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc square-grid [{:keys [frame zoom grid] :as props}] (let [grid-id (mf/use-memo #(uuid/next)) diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 781e82554..524791604 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -19,7 +19,7 @@ [app.util.dom :as dom] [beicon.core :as rx] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def gradient-line-stroke-width 2) (def gradient-line-stroke-color "var(--color-white)") diff --git a/frontend/src/app/main/ui/workspace/viewport/guides.cljs b/frontend/src/app/main/ui/workspace/viewport/guides.cljs index 2378efcbf..efefcaf7a 100644 --- a/frontend/src/app/main/ui/workspace/viewport/guides.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/guides.cljs @@ -21,7 +21,7 @@ [app.main.ui.formats :as fmt] [app.main.ui.workspace.viewport.rules :as rules] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def guide-width 1) (def guide-opacity 0.7) diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index 95a23ed14..4d28abb2a 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -28,7 +28,7 @@ [beicon.core :as rx] [debug :refer [debug?]] [goog.events :as events] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn setup-dom-events [viewport-ref overlays-ref zoom disable-paste in-viewport?] diff --git a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs index ccc0a7773..447974d31 100644 --- a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs @@ -19,7 +19,7 @@ [app.util.dom :as dom] [cuerdas.core :as str] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def interactions-ref (l/derived #(dm/select-keys % [:editing-interaction-index diff --git a/frontend/src/app/main/ui/workspace/viewport/outline.cljs b/frontend/src/app/main/ui/workspace/viewport/outline.cljs index 52db618bd..a8fd6c2df 100644 --- a/frontend/src/app/main/ui/workspace/viewport/outline.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/outline.cljs @@ -12,8 +12,8 @@ [app.util.object :as obj] [app.util.path.format :as upf] [clojure.set :as set] - [rumext.alpha :as mf] - [rumext.util :refer [map->obj]])) + [rumext.v2 :as mf] + [rumext.v2.util :refer [map->obj]])) (mf/defc outline {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs index fb5a468f3..0cf7db8a8 100644 --- a/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/path_actions.cljs @@ -13,7 +13,7 @@ [app.main.ui.workspace.shapes.path.common :as pc] [app.util.i18n :as i18n :refer [tr]] [app.util.path.tools :as upt] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn check-enabled [content selected-points] (let [segments (upt/get-segments content selected-points) diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index f80223258..cf0f384eb 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -23,7 +23,7 @@ [cuerdas.core :as str] [goog.events :as events] [promesa.core :as p] - [rumext.alpha :as mf]) + [rumext.v2 :as mf]) (:import goog.events.EventType)) (defn format-viewbox [vbox] diff --git a/frontend/src/app/main/ui/workspace/viewport/presence.cljs b/frontend/src/app/main/ui/workspace/viewport/presence.cljs index 2f89a3bd3..0aa64ade4 100644 --- a/frontend/src/app/main/ui/workspace/viewport/presence.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/presence.cljs @@ -11,7 +11,7 @@ [app.util.timers :as ts] [beicon.core :as rx] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def pointer-icon-path (str "M11.58,-0.47L11.47,-0.35L0.34,10.77L0.30,10.96L-0.46," diff --git a/frontend/src/app/main/ui/workspace/viewport/rules.cljs b/frontend/src/app/main/ui/workspace/viewport/rules.cljs index 75f88dda2..88eeb0da5 100644 --- a/frontend/src/app/main/ui/workspace/viewport/rules.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/rules.cljs @@ -14,7 +14,7 @@ [app.main.ui.formats :as fmt] [app.main.ui.hooks :as hooks] [app.util.object :as obj] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def rules-pos 15) (def rules-size 4) diff --git a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs index 5248d2de1..9e6a823b7 100644 --- a/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/scroll_bars.cljs @@ -13,7 +13,7 @@ [app.main.store :as st] [app.main.ui.workspace.viewport.utils :as utils] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def scroll-x 10) (def scroll-y 10) diff --git a/frontend/src/app/main/ui/workspace/viewport/selection.cljs b/frontend/src/app/main/ui/workspace/viewport/selection.cljs index 8ac31456e..65d1958e4 100644 --- a/frontend/src/app/main/ui/workspace/viewport/selection.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/selection.cljs @@ -20,8 +20,8 @@ [app.util.dom :as dom] [app.util.object :as obj] [debug :refer [debug?]] - [rumext.alpha :as mf] - [rumext.util :refer [map->obj]])) + [rumext.v2 :as mf] + [rumext.v2.util :refer [map->obj]])) (def rotation-handler-size 20) (def resize-point-radius 4) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs index 95c816364..95cc5693c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_distances.cljs @@ -16,7 +16,7 @@ [beicon.core :as rx] [clojure.set :as set] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def ^:private line-color "var(--color-snap)") (def ^:private segment-gap 2) diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index 4d0056085..1ef1bf79c 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -13,7 +13,7 @@ [app.main.snap :as snap] [app.util.geom.snap-points :as sp] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (def ^:private line-color "var(--color-snap)") (def ^:private line-opacity 0.6) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 32f7a9775..9b0447b0a 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -22,7 +22,7 @@ [app.main.ui.workspace.viewport.path-actions :refer [path-actions]] [app.main.ui.workspace.viewport.utils :as vwu] [app.util.dom :as dom] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (mf/defc pixel-grid [{:keys [vbox zoom]}] diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs index 98934101e..9d5b1e25e 100644 --- a/frontend/src/app/render.cljs +++ b/frontend/src/app/render.cljs @@ -23,7 +23,7 @@ [clojure.spec.alpha :as s] [cuerdas.core :as str] [garden.core :refer [css]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; SETUP diff --git a/frontend/src/app/util/forms.cljs b/frontend/src/app/util/forms.cljs index 6fd124da4..561eaa803 100644 --- a/frontend/src/app/util/forms.cljs +++ b/frontend/src/app/util/forms.cljs @@ -11,7 +11,7 @@ [app.util.i18n :refer [tr]] [cljs.spec.alpha :as s] [cuerdas.core :as str] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) ;; --- Handlers Helpers diff --git a/frontend/src/app/util/i18n.cljs b/frontend/src/app/util/i18n.cljs index 7ed82dd8c..c031ee9ec 100644 --- a/frontend/src/app/util/i18n.cljs +++ b/frontend/src/app/util/i18n.cljs @@ -16,7 +16,7 @@ [cuerdas.core :as str] [goog.object :as gobj] [okulary.core :as l] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (log/set-level! :info) diff --git a/frontend/src/app/util/perf.cljs b/frontend/src/app/util/perf.cljs index 4883d3cd7..d6765564e 100644 --- a/frontend/src/app/util/perf.cljs +++ b/frontend/src/app/util/perf.cljs @@ -9,7 +9,7 @@ (:require-macros [app.util.perf]) (:require [app.common.math :as mth] - [rumext.alpha :as mf] + [rumext.v2 :as mf] [goog.functions :as f] ["react" :as react] ["tdigest" :as td])) diff --git a/frontend/src/app/util/theme.cljs b/frontend/src/app/util/theme.cljs index 2ce3f727f..e962bcbf1 100644 --- a/frontend/src/app/util/theme.cljs +++ b/frontend/src/app/util/theme.cljs @@ -12,7 +12,7 @@ [app.util.dom :as dom] [app.util.storage :refer [storage]] [beicon.core :as rx] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defonce theme (get @storage ::theme cfg/default-theme)) (defonce theme-sub (rx/subject)) diff --git a/frontend/src/app/worker/thumbnails.cljs b/frontend/src/app/worker/thumbnails.cljs index 02cb42ff1..6b3c757c3 100644 --- a/frontend/src/app/worker/thumbnails.cljs +++ b/frontend/src/app/worker/thumbnails.cljs @@ -15,7 +15,7 @@ [app.worker.impl :as impl] [beicon.core :as rx] [debug :refer [debug?]] - [rumext.alpha :as mf])) + [rumext.v2 :as mf])) (defn- handle-response [{:keys [body status] :as response}] diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 6c1da5b6b..1ca534e0d 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -4711,10 +4711,10 @@ shadow-cljs-jar@1.3.2: resolved "https://registry.yarnpkg.com/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz#97273afe1747b6a2311917c1c88d9e243c81957b" integrity sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg== -shadow-cljs@2.19.9: - version "2.19.9" - resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.19.9.tgz#1e6b6115241666504c705ca8e6d6c9c1bc64add2" - integrity sha512-rLPv98HBIKf/4Kxjxpq0gXaNBVupJ/ii+OApHuqXFuwJOgU94DbNDSP4Bzjo+az2tTD11yTzXiYZsTqyAy+VBQ== +shadow-cljs@2.20.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.20.2.tgz#24a4b204f1f2288dc4ff2d0a4f3972a6e5307645" + integrity sha512-2kzWnV1QM6KBetziCAkCf8BJdnDX2CwiAr4yhvOsiQpaNJcMzwMsJTX/gTHz58yQg0dV5uwPsIyBlvyIfl30rg== dependencies: node-libs-browser "^2.2.1" readline-sync "^1.4.7" From 99a718e40780aaaf4a878cf1d46fa41f995a377d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Sep 2022 14:15:11 +0200 Subject: [PATCH 09/19] :tada: Add openjdk19 on devenv --- docker/devenv/Dockerfile | 8 ++++---- manage.sh | 12 ++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index bcdb548d9..11bc43733 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -107,12 +107,12 @@ RUN set -eux; \ ARCH="$(dpkg --print-architecture)"; \ case "${ARCH}" in \ aarch64|arm64) \ - ESUM='37ceaf232a85cce46bcccfd71839854e8b14bf3160e7ef72a676b9cae45ee8af'; \ - BINARY_URL='https://github.com/adoptium/temurin18-binaries/releases/download/jdk-18.0.1%2B10/OpenJDK18U-jdk_aarch64_linux_hotspot_18.0.1_10.tar.gz'; \ + ESUM='c640fc5e5710dba3f92099a791be50fab54f91cf2c3838cb536ded27ecc562a6'; \ + BINARY_URL='https://cdn.azul.com/zulu/bin/zulu19.28.81-ca-jdk19.0.0-linux_aarch64.tar.gz'; \ ;; \ amd64|x86_64) \ - ESUM='16b1d9d75f22c157af04a1fd9c664324c7f4b5163c022b382a2f2e8897c1b0a2'; \ - BINARY_URL='https://github.com/adoptium/temurin18-binaries/releases/download/jdk-18.0.1%2B10/OpenJDK18U-jdk_x64_linux_hotspot_18.0.1_10.tar.gz'; \ + ESUM='6813da339124261092daab369a1c60dea5f27f4ba9608a16517191d30511a087'; \ + BINARY_URL='https://cdn.azul.com/zulu/bin/zulu19.28.81-ca-jdk19.0.0-linux_x64.tar.gz'; \ ;; \ *) \ echo "Unsupported arch: ${ARCH}"; \ diff --git a/manage.sh b/manage.sh index 438da6f8f..25591bc22 100755 --- a/manage.sh +++ b/manage.sh @@ -42,8 +42,12 @@ function build-devenv { popd; } -function push-devenv { - docker push $DEVENV_IMGNAME:latest +function build-devenv-local { + echo "Building local only development image $DEVENV_IMGNAME:latest..." + + pushd docker/devenv; + docker build -t $DEVENV_IMGNAME:latest .; + popd; } function pull-devenv { @@ -208,6 +212,10 @@ case $1 in build-devenv ${@:2} ;; + build-devenv-local) + build-devenv-local ${@:2} + ;; + push-devenv) push-devenv ${@:2} ;; From b74631bf4a76234343e297b1dc4cee69b73ed956 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Sep 2022 14:15:32 +0200 Subject: [PATCH 10/19] :arrow_up: Update shadow-cljs on exporter --- exporter/yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/exporter/yarn.lock b/exporter/yarn.lock index 625173c4f..a46197b60 100644 --- a/exporter/yarn.lock +++ b/exporter/yarn.lock @@ -1098,10 +1098,10 @@ shadow-cljs-jar@1.3.2: resolved "https://registry.yarnpkg.com/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz#97273afe1747b6a2311917c1c88d9e243c81957b" integrity sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg== -shadow-cljs@^2.19.8: - version "2.19.8" - resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.19.8.tgz#1ce96cab3e4903bed8d401ffbe88b8939f5454d3" - integrity sha512-6qek3mcAP0hrnC5FxrTebBrgLGpOuhlnp06vdxp6g0M5Gl6w2Y0hzSwa1s2K8fMOkzE4/ciQor75b2y64INgaw== +shadow-cljs@^2.20.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.20.2.tgz#24a4b204f1f2288dc4ff2d0a4f3972a6e5307645" + integrity sha512-2kzWnV1QM6KBetziCAkCf8BJdnDX2CwiAr4yhvOsiQpaNJcMzwMsJTX/gTHz58yQg0dV5uwPsIyBlvyIfl30rg== dependencies: node-libs-browser "^2.2.1" readline-sync "^1.4.7" From 47363d96f12a8f6c0afef6957cec7b99b38b1fe7 Mon Sep 17 00:00:00 2001 From: Pablo Alba Date: Mon, 26 Sep 2022 23:56:58 +0200 Subject: [PATCH 11/19] :sparkles: Improve invitation token validation --- CHANGES.md | 1 + backend/src/app/db.clj | 46 ++- backend/src/app/rpc/commands/verify_token.clj | 95 +++--- backend/src/app/rpc/mutations/teams.clj | 32 +- backend/src/app/tokens.clj | 10 +- backend/test/app/services_teams_test.clj | 296 +++++++++++++----- 6 files changed, 325 insertions(+), 155 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 04630e28f..a094033dd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -37,6 +37,7 @@ - Fix inconsistent message on deleting library when a library is linked from deleted files - Fix change multiple colors with SVG [Taiga #3889](https://tree.taiga.io/project/penpot/issue/3889) - Fix ungroup does not work for typographies [Taiga #4195](https://tree.taiga.io/project/penpot/issue/4195) +- Fix inviting to non existing users can fail [Taiga #4108](https://tree.taiga.io/project/penpot/issue/4108) ### :arrow_up: Deps updates ### :heart: Community contributions by (Thank you!) diff --git a/backend/src/app/db.clj b/backend/src/app/db.clj index f547cfa9a..28d8a3c50 100644 --- a/backend/src/app/db.clj +++ b/backend/src/app/db.clj @@ -5,6 +5,7 @@ ;; Copyright (c) KALEIDOS INC (ns app.db + (:refer-clojure :exclude [get]) (:require [app.common.data :as d] [app.common.exceptions :as ex] @@ -270,28 +271,55 @@ (sql/delete table params opts) (assoc opts :return-keys true)))) -(defn- is-deleted? +(defn is-row-deleted? [{:keys [deleted-at]}] (and (dt/instant? deleted-at) (< (inst-ms deleted-at) (inst-ms (dt/now))))) -(defn get-by-params +(defn get* + "Internal function for retrieve a single row from database that + matches a simple filters." ([ds table params] - (get-by-params ds table params nil)) - ([ds table params {:keys [check-not-found] :or {check-not-found true} :as opts}] - (let [res (exec-one! ds (sql/select table params opts))] - (when (and check-not-found (or (not res) (is-deleted? res))) + (get* ds table params nil)) + ([ds table params {:keys [check-deleted?] :or {check-deleted? true} :as opts}] + (let [rows (exec! ds (sql/select table params opts)) + rows (cond->> rows + check-deleted? + (remove is-row-deleted?))] + (first rows)))) + +(defn get + ([ds table params] + (get ds table params nil)) + ([ds table params {:keys [check-deleted?] :or {check-deleted? true} :as opts}] + (let [row (get* ds table params opts)] + (when (and (not row) check-deleted?) (ex/raise :type :not-found :table table :hint "database object not found")) - res))) + row))) + +(defn get-by-params + "DEPRECATED" + ([ds table params] + (get-by-params ds table params nil)) + ([ds table params {:keys [check-not-found] :or {check-not-found true} :as opts}] + (let [row (get* ds table params (assoc opts :check-deleted? check-not-found))] + (when (and (not row) check-not-found) + (ex/raise :type :not-found + :table table + :hint "database object not found")) + row))) (defn get-by-id ([ds table id] - (get-by-params ds table {:id id} nil)) + (get ds table {:id id} nil)) ([ds table id opts] - (get-by-params ds table {:id id} opts))) + (let [opts (cond-> opts + (contains? opts :check-not-found) + (assoc :check-deleted? (:check-not-found opts)))] + (get ds table {:id id} opts)))) (defn query ([ds table params] diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj index 27f453464..03e5e1d00 100644 --- a/backend/src/app/rpc/commands/verify_token.clj +++ b/backend/src/app/rpc/commands/verify_token.clj @@ -80,16 +80,19 @@ ;; --- Team Invitation (defn- accept-invitation - [{:keys [conn] :as cfg} {:keys [member-id team-id role member-email] :as claims} invitation] - (let [member (profile/retrieve-profile conn member-id) - - ;; Update the role if there is an invitation + [{:keys [conn] :as cfg} {:keys [team-id role member-email] :as claims} invitation member] + (let [;; Update the role if there is an invitation role (or (some-> invitation :role keyword) role) params (merge {:team-id team-id - :profile-id member-id} + :profile-id (:id member)} (teams/role->params role))] + ;; Do not allow blocked users accept invitations. + (when (:is-blocked member) + (ex/raise :type :restriction + :code :profile-blocked)) + ;; Insert the invited member to the team (db/insert! conn :team-profile-rel params {:on-conflict-do-nothing true}) @@ -98,7 +101,7 @@ (when-not (:is-active member) (db/update! conn :profile {:is-active true} - {:id member-id})) + {:id (:id member)})) ;; Delete the invitation (db/delete! conn :team-invitation @@ -106,7 +109,6 @@ (assoc member :is-active true))) - (s/def ::spec.team-invitation/profile-id ::us/uuid) (s/def ::spec.team-invitation/role ::us/keyword) (s/def ::spec.team-invitation/team-id ::us/uuid) @@ -122,23 +124,28 @@ :opt-un [::spec.team-invitation/member-id])) (defmethod process-token :team-invitation - [{:keys [conn session] :as cfg} {:keys [profile-id token]} {:keys [member-id team-id member-email] :as claims}] + [{:keys [conn session] :as cfg} {:keys [profile-id token]} + {:keys [member-id team-id member-email] :as claims}] + (us/assert ::team-invitation-claims claims) - (let [invitation (db/get-by-params conn :team-invitation - {:team-id team-id :email-to member-email} - {:check-not-found false})] + (let [invitation (db/get* conn :team-invitation + {:team-id team-id :email-to member-email}) + profile (db/get* conn :profile + {:id profile-id} + {:columns [:id :email]})] (when (nil? invitation) (ex/raise :type :validation :code :invalid-token :hint "no invitation associated with the token")) - (cond - ;; This happens when token is filled with member-id and current - ;; user is already logged in with exactly invited account. - (and (uuid? profile-id) (uuid? member-id)) - (if (= member-id profile-id) - (let [profile (accept-invitation cfg claims invitation)] + (if (some? profile) + (if (or (= member-id profile-id) + (= member-email (:email profile))) + ;; if we have logged-in user and it matches the invitation we + ;; proceed with accepting the invitation and joining the + ;; current profile to the invited team. + (let [profile (accept-invitation cfg claims invitation profile)] (with-meta (assoc claims :state :created) {::audit/name "accept-team-invitation" @@ -146,40 +153,36 @@ (audit/profile->props profile) {:team-id (:team-id claims) :role (:role claims)}) - ::audit/profile-id member-id})) + ::audit/profile-id profile-id})) + (ex/raise :type :validation :code :invalid-token :hint "logged-in user does not matches the invitation")) - ;; This happens when an unlogged user, uses an invitation link. - (and (not profile-id) (uuid? member-id)) - (let [profile (accept-invitation cfg claims invitation)] - (with-meta - (assoc claims :state :created) - {:transform-response ((:create session) (:id profile)) - ::audit/name "accept-team-invitation" - ::audit/props (merge - (audit/profile->props profile) - {:team-id (:team-id claims) - :role (:role claims)}) - ::audit/profile-id member-id})) + ;; If we have not logged-in user, we try find the invited + ;; profile by member-id or member-email props of the invitation + ;; token; If profile is found, we accept the invitation and + ;; leave the user logged-in. + (if-let [member (db/get* conn :profile + (if member-id + {:id member-id} + {:email member-email}) + {:columns [:id :email]})] + (let [profile (accept-invitation cfg claims invitation member)] + (with-meta + (assoc claims :state :created) + {:transform-response ((:create session) (:id profile)) + ::audit/name "accept-team-invitation" + ::audit/props (merge + (audit/profile->props profile) + {:team-id (:team-id claims) + :role (:role claims)}) + ::audit/profile-id member-id})) - ;; This case means that invitation token does not match with - ;; registred user, so we need to indicate to frontend to redirect - ;; it to register page. - (and (not profile-id) (nil? member-id)) - {:invitation-token token - :iss :team-invitation - :redirect-to :auth-register - :state :pending} - - ;; In all other cases, just tell to fontend to redirect the user - ;; to the login page. - :else - {:invitation-token token - :iss :team-invitation - :redirect-to :auth-login - :state :pending}))) + {:invitation-token token + :iss :team-invitation + :redirect-to :auth-register + :state :pending})))) ;; --- Default diff --git a/backend/src/app/rpc/mutations/teams.clj b/backend/src/app/rpc/mutations/teams.clj index 393ebad8b..e7f6e88df 100644 --- a/backend/src/app/rpc/mutations/teams.clj +++ b/backend/src/app/rpc/mutations/teams.clj @@ -376,18 +376,17 @@ :code :profile-is-muted :hint "looks like the profile has reported repeatedly as spam or has permanent bounces")) - (doseq [email emails] - (create-team-invitation - (assoc cfg - :email email - :conn conn - :team team - :profile profile - :role role)) - ) - - (with-meta {} - {::audit/props {:invitations (count emails)}})))) + (let [invitations (->> emails + (map (fn [email] + (assoc cfg + :email email + :conn conn + :team team + :profile profile + :role role))) + (map create-team-invitation))] + (with-meta (vec invitations) + {::audit/props {:invitations (count invitations)}}))))) (def sql:upsert-team-invitation "insert into team_invitation(team_id, email_to, role, valid_until) @@ -449,10 +448,7 @@ (when-not (:is-active member) (db/update! conn :profile {:is-active true} - {:id (:id member)})) - - (assoc member :is-active true)) - + {:id (:id member)}))) (do (db/exec-one! conn [sql:upsert-team-invitation (:id team) (str/lower email) (name role) @@ -464,7 +460,9 @@ :invited-by (:fullname profile) :team (:name team) :token itoken - :extra-data ptoken}))))) + :extra-data ptoken}))) + + itoken)) ;; --- Mutation: Create Team & Invite Members diff --git a/backend/src/app/tokens.clj b/backend/src/app/tokens.clj index 8c253fe32..30ca32b3b 100644 --- a/backend/src/app/tokens.clj +++ b/backend/src/app/tokens.clj @@ -26,10 +26,14 @@ (t/encode))] (jwe/encrypt payload tokens-key {:alg :a256kw :enc :a256gcm}))) +(defn decode + [{:keys [tokens-key]} token] + (let [payload (jwe/decrypt token tokens-key {:alg :a256kw :enc :a256gcm})] + (t/decode payload))) + (defn verify - [{:keys [tokens-key]} {:keys [token] :as params}] - (let [payload (jwe/decrypt token tokens-key {:alg :a256kw :enc :a256gcm}) - claims (t/decode payload)] + [sprops {:keys [token] :as params}] + (let [claims (decode sprops token)] (when (and (dt/instant? (:exp claims)) (dt/is-before? (:exp claims) (dt/now))) (ex/raise :type :validation diff --git a/backend/test/app/services_teams_test.clj b/backend/test/app/services_teams_test.clj index 766d62aec..650fda6b6 100644 --- a/backend/test/app/services_teams_test.clj +++ b/backend/test/app/services_teams_test.clj @@ -11,6 +11,7 @@ [app.http :as http] [app.storage :as sto] [app.test-helpers :as th] + [app.tokens :as tokens] [app.util.time :as dt] [clojure.test :as t] [datoteka.core :as fs] @@ -19,7 +20,7 @@ (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) -(t/deftest test-invite-team-member +(t/deftest invite-team-member (with-mocks [mock {:target 'app.emails/send! :return nil}] (let [profile1 (th/create-profile* 1 {:is-active true}) profile2 (th/create-profile* 2 {:is-active true}) @@ -34,17 +35,16 @@ :profile-id (:id profile1)}] ;; invite external user without complaints - (let [data (assoc data :email "foo@bar.com") - out (th/mutation! data) - ;;retrieve the value from the database and check its content + (let [data (assoc data :email "foo@bar.com") + out (th/mutation! data) + ;; retrieve the value from the database and check its content invitation (db/exec-one! - th/*pool* - ["select count(*) as num from team_invitation where team_id = ? and email_to = ?" - (:team-id data) "foo@bar.com"])] + th/*pool* + ["select count(*) as num from team_invitation where team_id = ? and email_to = ?" + (:team-id data) "foo@bar.com"])] ;; (th/print-result! out) - - (t/is (= {} (:result out))) + (t/is (th/success? out)) (t/is (= 1 (:call-count (deref mock)))) (t/is (= 1 (:num invitation)))) @@ -52,7 +52,7 @@ (th/reset-mock! mock) (let [data (assoc data :email (:email profile2)) out (th/mutation! data)] - (t/is (= {} (:result out))) + (t/is (th/success? out)) (t/is (= 1 (:call-count (deref mock))))) ;; invite user with complaint @@ -60,35 +60,183 @@ (th/reset-mock! mock) (let [data (assoc data :email "foo@bar.com") out (th/mutation! data)] - (t/is (= {} (:result out))) + (t/is (th/success? out)) (t/is (= 1 (:call-count (deref mock))))) ;; invite user with bounce (th/reset-mock! mock) + (th/create-global-complaint-for pool {:type :bounce :email "foo@bar.com"}) (let [data (assoc data :email "foo@bar.com") - out (th/mutation! data) - error (:error out)] + out (th/mutation! data)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :email-has-permanent-bounces)) - (t/is (= 0 (:call-count (deref mock))))) + (t/is (not (th/success? out))) + (t/is (= 0 (:call-count @mock))) + + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :email-has-permanent-bounces (:code edata))))) ;; invite internal user that is muted (th/reset-mock! mock) - (let [data (assoc data :email (:email profile3)) - out (th/mutation! data) - error (:error out)] - (t/is (th/ex-info? error)) - (t/is (th/ex-of-type? error :validation)) - (t/is (th/ex-of-code? error :member-is-muted)) - (t/is (= 0 (:call-count (deref mock))))) + (let [data (assoc data :email (:email profile3)) + out (th/mutation! data)] + + (t/is (not (th/success? out))) + (t/is (= 0 (:call-count @mock))) + + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :member-is-muted (:code edata))))) ))) +(t/deftest invitation-tokens + (with-mocks [mock {:target 'app.emails/send! :return nil}] + (let [profile1 (th/create-profile* 1 {:is-active true}) + profile2 (th/create-profile* 2 {:is-active true}) + + team (th/create-team* 1 {:profile-id (:id profile1)}) + + sprops (:app.setup/props th/*system*) + pool (:app.db/pool th/*system*)] + + ;; Try to invite a not existing user + (let [data {::th/type :invite-team-member + :email "notexisting@example.com" + :team-id (:id team) + :role :editor + :profile-id (:id profile1)} + out (th/mutation! data)] + + ;; (th/print-result! out) + (t/is (th/success? out)) + (t/is (= 1 (:call-count @mock))) + (t/is (= 1 (-> out :result count))) + + (let [token (-> out :result first) + claims (tokens/decode sprops token)] + (t/is (= :team-invitation (:iss claims))) + (t/is (= (:id profile1) (:profile-id claims))) + (t/is (= :editor (:role claims))) + (t/is (= (:id team) (:team-id claims))) + (t/is (= (:email data) (:member-email claims))) + (t/is (nil? (:member-id claims))))) + + (th/reset-mock! mock) + + ;; Try to invite existing user + (let [data {::th/type :invite-team-member + :email (:email profile2) + :team-id (:id team) + :role :editor + :profile-id (:id profile1)} + out (th/mutation! data)] + + ;; (th/print-result! out) + (t/is (th/success? out)) + (t/is (= 1 (:call-count @mock))) + (t/is (= 1 (-> out :result count))) + + (let [token (-> out :result first) + claims (tokens/decode sprops token)] + (t/is (= :team-invitation (:iss claims))) + (t/is (= (:id profile1) (:profile-id claims))) + (t/is (= :editor (:role claims))) + (t/is (= (:id team) (:team-id claims))) + (t/is (= (:email data) (:member-email claims))) + (t/is (= (:id profile2) (:member-id claims))))) + + ))) + + +(t/deftest accept-invitation-tokens + (let [profile1 (th/create-profile* 1 {:is-active true}) + profile2 (th/create-profile* 2 {:is-active true}) + + team (th/create-team* 1 {:profile-id (:id profile1)}) + + sprops (:app.setup/props th/*system*) + pool (:app.db/pool th/*system*)] + + (let [token (tokens/generate sprops + {:iss :team-invitation + :exp (dt/in-future "1h") + :profile-id (:id profile1) + :role :editor + :team-id (:id team) + :member-email (:email profile2) + :member-id (:id profile2)})] + + ;; --- Verify token as anonymous user + + (db/insert! pool :team-invitation + {:team-id (:id team) + :email-to (:email profile2) + :role "editor" + :valid-until (dt/in-future "48h")}) + + (let [data {::th/type :verify-token :token token} + out (th/mutation! data)] + ;; (th/print-result! out) + (t/is (th/success? out)) + (let [result (:result out)] + (t/is (= :created (:state result))) + (t/is (= (:email profile2) (:member-email result))) + (t/is (= (:id profile2) (:member-id result)))) + + (let [rows (db/query pool :team-profile-rel {:team-id (:id team)})] + (t/is (= 2 (count rows))))) + + ;; Clean members + (db/delete! pool :team-profile-rel + {:team-id (:id team) + :profile-id (:id profile2)}) + + + ;; --- Verify token as logged-in user + + (db/insert! pool :team-invitation + {:team-id (:id team) + :email-to (:email profile2) + :role "editor" + :valid-until (dt/in-future "48h")}) + + (let [data {::th/type :verify-token :token token :profile-id (:id profile2)} + out (th/mutation! data)] + ;; (th/print-result! out) + (t/is (th/success? out)) + (let [result (:result out)] + (t/is (= :created (:state result))) + (t/is (= (:email profile2) (:member-email result))) + (t/is (= (:id profile2) (:member-id result)))) + + (let [rows (db/query pool :team-profile-rel {:team-id (:id team)})] + (t/is (= 2 (count rows))))) + + + ;; --- Verify token as logged-in wrong user + + (db/insert! pool :team-invitation + {:team-id (:id team) + :email-to (:email profile2) + :role "editor" + :valid-until (dt/in-future "48h")}) + + (let [data {::th/type :verify-token :token token :profile-id (:id profile1)} + out (th/mutation! data)] + ;; (th/print-result! out) + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :validation (:type edata))) + (t/is (= :invalid-token (:code edata))))) + + ))) + + + (t/deftest invite-team-member-with-email-verification-disabled (with-mocks [mock {:target 'app.emails/send! :return nil}] (let [profile1 (th/create-profile* 1 {:is-active true}) @@ -108,20 +256,17 @@ (th/reset-mock! mock) (let [data (assoc data :email (:email profile2)) out (th/mutation! data)] - (t/is (= {} (:result out))) + (t/is (th/success? out)) (t/is (= 0 (:call-count (deref mock))))) - (let [members (db/query pool :team-profile-rel {:team-id (:id team) :profile-id (:id profile2)})] (t/is (= 1 (count members))) (t/is (true? (-> members first :can-edit)))))))) - -(t/deftest test-deletion - (let [task (:app.tasks.objects-gc/handler th/*system*) - profile1 (th/create-profile* 1 {:is-active true}) +(t/deftest team-deletion + (let [profile1 (th/create-profile* 1 {:is-active true}) team (th/create-team* 1 {:profile-id (:id profile1)}) pool (:app.db/pool th/*system*) data {::th/type :delete-team @@ -130,7 +275,7 @@ ;; team is not deleted because it does not meet all ;; conditions to be deleted. - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] (t/is (= 0 (:processed result)))) ;; query the list of teams @@ -138,7 +283,7 @@ :profile-id (:id profile1)} out (th/query! data)] ;; (th/print-result! out) - (t/is (nil? (:error out))) + (t/is (th/success? out)) (let [result (:result out)] (t/is (= 2 (count result))) (t/is (= (:id team) (get-in result [1 :id]))) @@ -149,21 +294,20 @@ :id (:id team) :profile-id (:id profile1)} out (th/mutation! params)] - ;; (th/print-result! out) - (t/is (nil? (:error out)))) + (t/is (th/success? out))) ;; query the list of teams after soft deletion (let [data {::th/type :teams :profile-id (:id profile1)} out (th/query! data)] ;; (th/print-result! out) - (t/is (nil? (:error out))) + (t/is (th/success? out)) (let [result (:result out)] (t/is (= 1 (count result))) (t/is (= (:default-team-id profile1) (get-in result [0 :id]))))) ;; run permanent deletion (should be noop) - (let [result (task {:min-age (dt/duration {:minutes 1})})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration {:minutes 1})})] (t/is (= 0 (:processed result)))) ;; query the list of projects after hard deletion @@ -172,13 +316,12 @@ :profile-id (:id profile1)} out (th/query! data)] ;; (th/print-result! out) - (let [error (:error out) - error-data (ex-data error)] - (t/is (th/ex-info? error)) - (t/is (= (:type error-data) :not-found)))) + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :not-found (:type edata))))) ;; run permanent deletion - (let [result (task {:min-age (dt/duration 0)})] + (let [result (th/run-task! :objects-gc {:min-age (dt/duration 0)})] (t/is (= 1 (:processed result)))) ;; query the list of projects of a after hard deletion @@ -187,31 +330,27 @@ :profile-id (:id profile1)} out (th/query! data)] ;; (th/print-result! out) - (let [error (:error out) - error-data (ex-data error)] - (t/is (th/ex-info? error)) - (t/is (= (:type error-data) :not-found)))) + + (t/is (not (th/success? out))) + (let [edata (-> out :error ex-data)] + (t/is (= :not-found (:type edata))))) )) - - - (t/deftest query-team-invitations - (let [prof (th/create-profile* 1 {:is-active true}) - team (th/create-team* 1 {:profile-id (:id prof)}) + (let [prof (th/create-profile* 1 {:is-active true}) + team (th/create-team* 1 {:profile-id (:id prof)}) data {::th/type :team-invitations :profile-id (:id prof) :team-id (:id team)}] - ;;insert an entry on the database with an enabled invitation + ;; insert an entry on the database with an enabled invitation (db/insert! th/*pool* :team-invitation - {:team-id (:team-id data) - :email-to "test1@mail.com" - :role "editor" - :valid-until (dt/in-future "48h")}) + {:team-id (:team-id data) + :email-to "test1@mail.com" + :role "editor" + :valid-until (dt/in-future "48h")}) - - ;;insert an entry on the database with an expired invitation + ;; insert an entry on the database with an expired invitation (db/insert! th/*pool* :team-invitation {:team-id (:team-id data) :email-to "test2@mail.com" @@ -219,27 +358,26 @@ :valid-until (dt/in-past "48h")}) (let [out (th/query! data)] - (t/is (nil? (:error out))) + (t/is (th/success? out)) (let [result (:result out) - one (first result) - two (second result)] + one (first result) + two (second result)] (t/is (= 2 (count result))) (t/is (= "test1@mail.com" (:email one))) (t/is (= "test2@mail.com" (:email two))) (t/is (false? (:expired one))) (t/is (true? (:expired two))))))) - (t/deftest update-team-invitation-role - (let [prof (th/create-profile* 1 {:is-active true}) - team (th/create-team* 1 {:profile-id (:id prof)}) + (let [prof (th/create-profile* 1 {:is-active true}) + team (th/create-team* 1 {:profile-id (:id prof)}) data {::th/type :update-team-invitation-role :profile-id (:id prof) :team-id (:id team) :email "TEST1@mail.com" :role :admin}] - ;;insert an entry on the database with an invitation + ;; insert an entry on the database with an invitation (db/insert! th/*pool* :team-invitation {:team-id (:team-id data) :email-to "test1@mail.com" @@ -247,24 +385,22 @@ :valid-until (dt/in-future "48h")}) (let [out (th/mutation! data) - ;;retrieve the value from the database and check its content - result (db/get-by-params th/*pool* :team-invitation - {:team-id (:team-id data) :email-to "test1@mail.com"} - {:check-not-found false})] - (t/is (nil? (:error out))) + ;; retrieve the value from the database and check its content + res (db/get* th/*pool* :team-invitation + {:team-id (:team-id data) :email-to "test1@mail.com"})] + (t/is (th/success? out)) (t/is (nil? (:result out))) - (t/is (= "admin" (:role result)))))) - + (t/is (= "admin" (:role res)))))) (t/deftest delete-team-invitation - (let [prof (th/create-profile* 1 {:is-active true}) - team (th/create-team* 1 {:profile-id (:id prof)}) + (let [prof (th/create-profile* 1 {:is-active true}) + team (th/create-team* 1 {:profile-id (:id prof)}) data {::th/type :delete-team-invitation :profile-id (:id prof) :team-id (:id team) :email "TEST1@mail.com"}] - ;;insert an entry on the database with an invitation + ;; insert an entry on the database with an invitation (db/insert! th/*pool* :team-invitation {:team-id (:team-id data) :email-to "test1@mail.com" @@ -272,10 +408,10 @@ :valid-until (dt/in-future "48h")}) (let [out (th/mutation! data) - ;;retrieve the value from the database and check its content - result (db/get-by-params th/*pool* :team-invitation - {:team-id (:team-id data) :email-to "test1@mail.com"} - {:check-not-found false})] - (t/is (nil? (:error out))) + ;; retrieve the value from the database and check its content + res (db/get* th/*pool* :team-invitation + {:team-id (:team-id data) :email-to "test1@mail.com"})] + + (t/is (th/success? out)) (t/is (nil? (:result out))) - (t/is (nil? result))))) + (t/is (nil? res))))) From 2753a934aa123e24f68b98cd904c4a46383ecff6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Mon, 26 Sep 2022 23:59:20 +0200 Subject: [PATCH 12/19] :paperclip: Add service result wrapper Allows attach metadata to values that does not implement the IObj clojure interface. --- backend/src/app/rpc.clj | 7 ++++--- backend/src/app/util/services.clj | 14 ++++++++++++++ backend/test/app/test_helpers.clj | 7 +++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 11acedc7c..12e16db88 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -31,9 +31,10 @@ (defn- handle-response-transformation [response request mdata] - (if-let [transform-fn (:transform-response mdata)] - (p/do (transform-fn request response)) - (p/resolved response))) + (let [response (if (sv/wrapped? response) @response response)] + (if-let [transform-fn (:transform-response mdata)] + (p/do (transform-fn request response)) + (p/resolved response)))) (defn- handle-before-comple-hook [response mdata] diff --git a/backend/src/app/util/services.clj b/backend/src/app/util/services.clj index 66f9fc8db..f8f8fc004 100644 --- a/backend/src/app/util/services.clj +++ b/backend/src/app/util/services.clj @@ -11,6 +11,20 @@ [app.common.data :as d] [cuerdas.core :as str])) +(defrecord WrappedValue [obj] + clojure.lang.IDeref + (deref [_] obj)) + +(defn wrap + ([] + (WrappedValue. nil)) + ([o] + (WrappedValue. o))) + +(defn wrapped? + [o] + (instance? WrappedValue o)) + (defmacro defmethod [sname & body] (let [[docs body] (if (string? (first body)) diff --git a/backend/test/app/test_helpers.clj b/backend/test/app/test_helpers.clj index f91e22aa6..59ed7e40a 100644 --- a/backend/test/app/test_helpers.clj +++ b/backend/test/app/test_helpers.clj @@ -23,6 +23,7 @@ [app.rpc.mutations.projects :as projects] [app.rpc.mutations.teams :as teams] [app.util.blob :as blob] + [app.util.services :as sv] [app.util.time :as dt] [clojure.java.io :as io] [clojure.spec.alpha :as s] @@ -278,8 +279,10 @@ (defmacro try-on! [expr] `(try - {:error nil - :result (deref ~expr)} + (let [result# (deref ~expr) + result# (cond-> result# (sv/wrapped? result#) deref)] + {:error nil + :result result#}) (catch Exception e# {:error (handle-error e#) :result nil}))) From 1dc493c2d50af3074431762812fe087ae5a409e3 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 27 Sep 2022 00:39:23 +0200 Subject: [PATCH 13/19] :fire: Remove assets handler code for :db backend --- backend/src/app/http/assets.clj | 7 ------- 1 file changed, 7 deletions(-) diff --git a/backend/src/app/http/assets.clj b/backend/src/app/http/assets.clj index 3a0bf2144..0fd6d1510 100644 --- a/backend/src/app/http/assets.clj +++ b/backend/src/app/http/assets.clj @@ -52,13 +52,6 @@ (let [mdata (meta obj) backend (sto/resolve-backend storage (:backend obj))] (case (:type backend) - :db - (p/let [body (sto/get-object-bytes storage obj)] - (yrs/response :status 200 - :body body - :headers {"content-type" (:content-type mdata) - "cache-control" (str "max-age=" (inst-ms cache-max-age))})) - :s3 (p/let [{:keys [host port] :as url} (sto/get-object-url storage obj {:max-age signature-max-age})] (yrs/response :status 307 From 84655c0fa3055e49647d66d1e9daf4a2addf5a3d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 27 Sep 2022 13:15:59 +0200 Subject: [PATCH 14/19] :bug: Fix content-length handling on exporter --- exporter/src/app/core.cljs | 11 +++++++---- exporter/src/app/handlers/export_shapes.cljs | 2 +- exporter/src/app/http.cljs | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/exporter/src/app/core.cljs b/exporter/src/app/core.cljs index 430ab8ca9..80e7d8e62 100644 --- a/exporter/src/app/core.cljs +++ b/exporter/src/app/core.cljs @@ -9,7 +9,7 @@ ["process" :as proc] [app.browser :as bwr] [app.common.logging :as l] - [app.config] + [app.config :as cf] [app.http :as http] [app.redis :as redis] [promesa.core :as p])) @@ -19,7 +19,9 @@ (defn start [& _] - (l/info :msg "initializing") + (l/info :msg "initializing" + :public-uri (str (cf/get :public-uri)) + :version (:full @cf/version)) (p/do! (bwr/init) (redis/init) @@ -39,5 +41,6 @@ (http/stop) (done))) -(proc/on "uncaughtException" (fn [cause] - (js/console.error cause))) +(proc/on "uncaughtException" + (fn [cause] + (js/console.error cause))) diff --git a/exporter/src/app/handlers/export_shapes.cljs b/exporter/src/app/handlers/export_shapes.cljs index 3356ffc6a..4a8e53dab 100644 --- a/exporter/src/app/handlers/export_shapes.cljs +++ b/exporter/src/app/handlers/export_shapes.cljs @@ -77,7 +77,7 @@ :name (:name resource) :status "ended"})))) on-error (fn [cause] - (l/error :hint "unexpected error happened on export multiple process" + (l/error :hint "unexpected error on export multiple" :cause cause) (if wait (p/rejected cause) diff --git a/exporter/src/app/http.cljs b/exporter/src/app/http.cljs index f07aac8c4..e0d492129 100644 --- a/exporter/src/app/http.cljs +++ b/exporter/src/app/http.cljs @@ -90,12 +90,13 @@ (fn [{:keys [:response/body :response/status] :as exchange}] (cond (map? body) - (let [data (t/encode-str body {:type :json-verbose})] + (let [data (t/encode-str body {:type :json-verbose}) + size (js/Buffer.byteLength data "utf-8")] (-> exchange (assoc :response/body data) (assoc :response/status 200) (update :response/headers assoc "content-type" "application/transit+json") - (update :response/headers assoc "content-length" (count data)))) + (update :response/headers assoc "content-length" size))) (and (nil? body) (= 200 status)) From 8fec5af55e810d96159fa07d6a1a3d1d38692d2a Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 27 Sep 2022 14:04:48 +0200 Subject: [PATCH 15/19] :bug: Fix cannot take out an element from a group at layers panel by drag --- CHANGES.md | 1 + frontend/src/app/main/ui/workspace/sidebar/layers.cljs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index a094033dd..2a12948c8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -69,6 +69,7 @@ - Fix Terms and Privacy links overlapping [Taiga #4137](https://tree.taiga.io/project/penpot/issue/4137) - Fix Export bounding box mask [Taiga #950](https://tree.taiga.io/project/penpot/issue/950) - Fix delete layers in bulk [Taiga #4160](https://tree.taiga.io/project/penpot/issue/4160) +- Fix Cannot take out an element from a group at layers panel by drag [Taiga #4209](https://tree.taiga.io/project/penpot/issue/4209) ## 1.15.3-beta diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 61e45c915..52bce124f 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -282,7 +282,8 @@ :selected selected :index index :objects objects - :key (:id item)}]))])])) + :key (:id item) + :sortable? sortable?}]))])])) ;; This components is a piece for sharding equality check between top ;; level frames and try to avoid rerender frames that are does not From 748499a26fe86a19a016defe7ecd9ebdc2125f6d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 28 Sep 2022 09:40:14 +0200 Subject: [PATCH 16/19] :tada: Add lazy loading of thumbnails on dashboard --- backend/src/app/rpc/mutations/files.clj | 2 + frontend/src/app/main/ui/dashboard/grid.cljs | 153 +++++++------ .../src/app/main/ui/dashboard/projects.cljs | 210 ++++++++++-------- frontend/src/app/main/ui/hooks.cljs | 38 +++- frontend/src/app/util/perf.cljs | 12 + 5 files changed, 250 insertions(+), 165 deletions(-) diff --git a/backend/src/app/rpc/mutations/files.clj b/backend/src/app/rpc/mutations/files.clj index 839667c32..9c45d8798 100644 --- a/backend/src/app/rpc/mutations/files.clj +++ b/backend/src/app/rpc/mutations/files.clj @@ -565,6 +565,8 @@ (s/keys :req-un [::profile-id ::file-id ::revn ::data ::props])) (sv/defmethod ::upsert-file-thumbnail + "Creates or updates the file thumbnail. Mainly used for paint the + grid thumbnals." [{:keys [pool] :as cfg} {:keys [profile-id file-id revn data props]}] (db/with-atomic [conn pool] (files/check-edition-permissions! conn profile-id file-id) diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 0d4e84a91..28536cf5e 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -6,9 +6,10 @@ (ns app.main.ui.dashboard.grid (:require + [app.common.data.macros :as dm] [app.common.logging :as log] [app.main.data.dashboard :as dd] - [app.main.data.messages :as dm] + [app.main.data.messages :as msg] [app.main.features :as features] [app.main.fonts :as fonts] [app.main.refs :as refs] @@ -19,43 +20,57 @@ [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.hooks :as h] [app.main.ui.icons :as i] [app.main.worker :as wrk] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] + [app.util.perf :as perf] [app.util.time :as dt] [app.util.timers :as ts] [beicon.core :as rx] + [cuerdas.core :as str] [rumext.v2 :as mf])) -(log/set-level! :warn) +(log/set-level! :info) ;; --- Grid Item Thumbnail (defn ask-for-thumbnail "Creates some hooks to handle the files thumbnails cache" [file] - (let [components-v2 (features/active-feature? :components-v2)] - (wrk/ask! {:cmd :thumbnails/generate - :revn (:revn file) - :file-id (:id file) - :components-v2 components-v2}))) + (wrk/ask! {:cmd :thumbnails/generate + :revn (:revn file) + :file-id (:id file) + :file-name (:name file) + :components-v2 (features/active-feature? :components-v2)})) (mf/defc grid-item-thumbnail {::mf/wrap [mf/memo]} [{:keys [file] :as props}] - (let [container (mf/use-ref)] - (mf/with-effect [file] - (->> (ask-for-thumbnail file) - (rx/subs (fn [{:keys [data fonts] :as params}] - (run! fonts/ensure-loaded! fonts) - (when-let [node (mf/ref-val container)] - (dom/set-html! node data)))))) + (let [container (mf/use-ref) + bgcolor (dm/get-in file [:data :options :background]) + visible? (h/use-visible container :once? true)] - [:div.grid-item-th {:style {:background-color (get-in file [:data :options :background])} - :ref container} + (mf/with-effect [file visible?] + (when visible? + (let [tp (perf/tpoint)] + (->> (ask-for-thumbnail file) + (rx/subscribe-on :af) + (rx/subs (fn [{:keys [data fonts] :as params}] + (run! fonts/ensure-loaded! fonts) + (log/info :hint "loaded thumbnail" + :file-id (dm/str (:id file)) + :file-name (:name file) + :elapsed (str/ffmt "%ms" (tp))) + (when-let [node (mf/ref-val container)] + (dom/set-html! node data)))))))) + + [:div.grid-item-th + {:style {:background-color bgcolor} + :ref container} i/loader-pencil])) ;; --- Grid Item Library @@ -144,6 +159,7 @@ (mf/defc grid-item-metadata [{:keys [modified-at]}] + (let [locale (mf/deref i18n/locale) time (dt/timeago modified-at {:locale locale})] [:span.date @@ -159,18 +175,19 @@ (mf/defc grid-item {:wrap [mf/memo]} [{:keys [file navigate? origin library-view?] :as props}] - (let [file-id (:id file) - local (mf/use-state {:menu-open false - :menu-pos nil - :edition false}) - selected-files (mf/deref refs/dashboard-selected-files) - dashboard-local (mf/deref refs/dashboard-local) - item-ref (mf/use-ref) - menu-ref (mf/use-ref) - selected? (contains? selected-files file-id) + (let [file-id (:id file) + local (mf/use-state {:menu-open false + :menu-pos nil + :edition false}) + selected-files (mf/deref refs/dashboard-selected-files) + dashboard-local (mf/deref refs/dashboard-local) + node-ref (mf/use-ref) + menu-ref (mf/use-ref) + + selected? (contains? selected-files file-id) on-menu-close - (mf/use-callback + (mf/use-fn #(swap! local assoc :menu-open false)) on-select @@ -184,7 +201,7 @@ (st/emit! (dd/toggle-file-select file))))) on-navigate - (mf/use-callback + (mf/use-fn (mf/deps file) (fn [event] (let [menu-icon (mf/ref-val menu-ref) @@ -193,14 +210,14 @@ (st/emit! (dd/go-to-workspace file)))))) on-drag-start - (mf/use-callback + (mf/use-fn (mf/deps selected-files) (fn [event] (let [offset (dom/get-offset-position (.-nativeEvent event)) select-current? (not (contains? selected-files (:id file))) - item-el (mf/ref-val item-ref) + item-el (mf/ref-val node-ref) counter-el (create-counter-element item-el (if select-current? 1 @@ -221,7 +238,7 @@ (ts/raf #(.removeChild ^js item-el counter-el))))) on-menu-click - (mf/use-callback + (mf/use-fn (mf/deps file selected?) (fn [event] (dom/prevent-default event) @@ -236,14 +253,14 @@ :menu-pos position)))) edit - (mf/use-callback + (mf/use-fn (mf/deps file) (fn [name] (st/emit! (dd/rename-file (assoc file :name name))) (swap! local assoc :edition false))) on-edit - (mf/use-callback + (mf/use-fn (mf/deps file) (fn [event] (dom/stop-propagation event) @@ -251,16 +268,14 @@ :edition true :menu-open false)))] - (mf/use-effect - (mf/deps selected? local) - (fn [] - (when (and (not selected?) (:menu-open @local)) - (swap! local assoc :menu-open false)))) + (mf/with-effect [selected? local] + (when (and (not selected?) (:menu-open @local)) + (swap! local assoc :menu-open false))) [:div.grid-item.project-th {:class (dom/classnames :selected selected? :library library-view?) - :ref item-ref + :ref node-ref :draggable true :on-click on-select :on-double-click on-navigate @@ -296,13 +311,15 @@ :origin origin :dashboard-local dashboard-local}])]]])) + (mf/defc grid [{:keys [files project on-create-clicked origin limit library-view?] :as props}] (let [dragging? (mf/use-state false) project-id (:id project) + node-ref (mf/use-var nil) on-finish-import - (mf/use-callback + (mf/use-fn (fn [] (st/emit! (dd/fetch-files {:project-id project-id}) (dd/fetch-shared-files) @@ -311,7 +328,7 @@ import-files (use-import-file project-id on-finish-import) on-drag-enter - (mf/use-callback + (mf/use-fn (fn [e] (when (or (dnd/has-type? e "Files") (dnd/has-type? e "application/x-moz-file")) @@ -319,32 +336,34 @@ (reset! dragging? true)))) on-drag-over - (mf/use-callback + (mf/use-fn (fn [e] (when (or (dnd/has-type? e "Files") (dnd/has-type? e "application/x-moz-file")) (dom/prevent-default e)))) on-drag-leave - (mf/use-callback + (mf/use-fn (fn [e] (when-not (dnd/from-child? e) (reset! dragging? false)))) - on-drop - (mf/use-callback + (mf/use-fn (fn [e] (when (or (dnd/has-type? e "Files") (dnd/has-type? e "application/x-moz-file")) (dom/prevent-default e) (reset! dragging? false) - (import-files (.-files (.-dataTransfer e))))))] + (import-files (.-files (.-dataTransfer e)))))) + ] - [:section.dashboard-grid {:on-drag-enter on-drag-enter - :on-drag-over on-drag-over - :on-drag-leave on-drag-leave - :on-drop on-drop} + [:section.dashboard-grid + {:on-drag-enter on-drag-enter + :on-drag-over on-drag-over + :on-drag-leave on-drag-leave + :on-drop on-drop + :ref node-ref} (cond (nil? files) [:& loading-placeholder] @@ -352,8 +371,10 @@ (seq files) [:div.grid-row {:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} + (when @dragging? [:div.grid-item]) + (for [item files] [:& grid-item {:file item @@ -361,21 +382,21 @@ :navigate? true :origin origin :library-view? library-view?}])] + :else - [:& empty-placeholder {:default? (:is-default project) - :on-create-clicked on-create-clicked - :project project - :limit limit - :origin origin}])])) + [:& empty-placeholder + {:default? (:is-default project) + :on-create-clicked on-create-clicked + :project project + :limit limit + :origin origin}])])) (mf/defc line-grid-row [{:keys [files selected-files dragging? limit] :as props}] - (let [limit (if dragging? - (dec limit) - limit)] - + (let [limit (if dragging? (dec limit) limit)] [:div.grid-row.no-wrap - {:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}} + {:style {:grid-template-columns (dm/str "repeat(" limit ", 1fr)")}} + (when dragging? [:div.grid-item]) (for [item (take limit files)] @@ -396,8 +417,8 @@ selected-project (mf/deref refs/dashboard-selected-project) on-finish-import - (mf/use-callback - (mf/deps (:id team)) + (mf/use-fn + (mf/deps team-id) (fn [] (st/emit! (dd/fetch-recent-files (:id team)) (dd/clear-selected-files)))) @@ -405,7 +426,7 @@ import-files (use-import-file project-id on-finish-import) on-drag-enter - (mf/use-callback + (mf/use-fn (mf/deps selected-project) (fn [e] (when (dnd/has-type? e "penpot/files") @@ -421,7 +442,7 @@ (reset! dragging? true)))) on-drag-over - (mf/use-callback + (mf/use-fn (fn [e] (when (or (dnd/has-type? e "penpot/files") (dnd/has-type? e "Files") @@ -429,19 +450,19 @@ (dom/prevent-default e)))) on-drag-leave - (mf/use-callback + (mf/use-fn (fn [e] (when-not (dnd/from-child? e) (reset! dragging? false)))) on-drop-success (fn [] - (st/emit! (dm/success (tr "dashboard.success-move-file")) + (st/emit! (msg/success (tr "dashboard.success-move-file")) (dd/fetch-recent-files (:id team)) (dd/clear-selected-files))) on-drop - (mf/use-callback + (mf/use-fn (mf/deps files selected-files) (fn [e] (when (or (dnd/has-type? e "Files") diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 39e5d3f2f..08b507302 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -6,10 +6,11 @@ (ns app.main.ui.dashboard.projects (:require + [app.common.data :as d] [app.common.math :as mth] [app.main.data.dashboard :as dd] [app.main.data.events :as ev] - [app.main.data.messages :as dm] + [app.main.data.messages :as msg] [app.main.data.modal :as modal] [app.main.data.users :as du] [app.main.refs :as refs] @@ -43,8 +44,15 @@ (mf/defc team-hero {::mf/wrap [mf/memo]} [{:keys [team close-banner] :as props}] - (let [go-members #(st/emit! (dd/go-to-team-members)) - invite-member #(st/emit! (modal/show {:type :invite-members :team team :origin :hero}))] + (let [go-members (mf/use-fn #(st/emit! (dd/go-to-team-members))) + + invite-member + (mf/use-fn + (mf/deps team) + (fn [] + (st/emit! (modal/show {:type :invite-members + :team team + :origin :hero}))))] [:div.team-hero [:img {:src "images/deco-team-banner.png" :border "0"}] [:div.text @@ -52,7 +60,9 @@ [:div.info [:span (tr "dasboard.team-hero.text")] [:a {:on-click go-members} (tr "dasboard.team-hero.management")]]] - [:button.btn-primary.invite {:on-click invite-member} (tr "onboarding.choice.team-up.invite-members")] + [:button.btn-primary.invite + {:on-click invite-member} + (tr "onboarding.choice.team-up.invite-members")] [:button.close {:on-click close-banner} [:span i/close]]])) @@ -61,46 +71,47 @@ (mf/defc tutorial-project [{:keys [close-tutorial default-project-id] :as props}] - (let [state (mf/use-state - {:status :waiting - :file nil}) + (let [state (mf/use-state {:status :waiting + :file nil}) - template (->> (mf/deref builtin-templates) - (filter #(= (:id %) "tutorial-for-beginners")) - first) + templates (mf/deref builtin-templates) + template (d/seek #(= (:id %) "tutorial-for-beginners") templates) on-template-cloned-success - (mf/use-callback + (mf/use-fn + (mf/deps default-project-id) (fn [response] (swap! state #(assoc % :status :success :file (:first response))) (st/emit! (dd/go-to-workspace {:id (first response) :project-id default-project-id :name "tutorial"}) (du/update-profile-props {:viewed-tutorial? true})))) on-template-cloned-error - (fn [] - (swap! state #(assoc % :status :waiting)) - (st/emit! - (dm/error (tr "dashboard.libraries-and-templates.import-error")))) + (mf/use-fn + (fn [] + (swap! state #(assoc % :status :waiting)) + (st/emit! + (msg/error (tr "dashboard.libraries-and-templates.import-error"))))) download-tutorial - (fn [] - (let [mdata {:on-success on-template-cloned-success :on-error on-template-cloned-error} - params {:project-id default-project-id :template-id (:id template)}] - (swap! state #(assoc % :status :importing)) - (st/emit! (with-meta (dd/clone-template (with-meta params mdata)) - {::ev/origin "get-started-hero-block"}))))] + (mf/use-fn + (mf/deps template default-project-id) + (fn [] + (let [mdata {:on-success on-template-cloned-success :on-error on-template-cloned-error} + params {:project-id default-project-id :template-id (:id template)}] + (swap! state #(assoc % :status :importing)) + (st/emit! (with-meta (dd/clone-template (with-meta params mdata)) + {::ev/origin "get-started-hero-block"})))))] [:div.tutorial [:div.img] [:div.text [:div.title (tr "dasboard.tutorial-hero.title")] [:div.info (tr "dasboard.tutorial-hero.info")] - [:button.btn-primary.action {:on-click download-tutorial} + [:button.btn-primary.action {:on-click download-tutorial} (case (:status @state) :waiting (tr "dasboard.tutorial-hero.start") :importing [:span.loader i/loader-pencil] - :success "" - ) - ]] + :success "")]] + [:button.close {:on-click close-tutorial} [:span.icon i/close]]])) @@ -128,32 +139,32 @@ [{:keys [project first? team files] :as props}] (let [locale (mf/deref i18n/locale) file-count (or (:count project) 0) + project-id (:id project) dstate (mf/deref refs/dashboard-local) edit-id (:project-for-edit dstate) - local - (mf/use-state {:menu-open false - :menu-pos nil - :edition? (= (:id project) edit-id)}) + local (mf/use-state {:menu-open false + :menu-pos nil + :edition? (= (:id project) edit-id)}) + + width (mf/use-state nil) + rowref (mf/use-ref) + itemsize (if (>= @width 1030) + 280 + 230) + + ratio (if (some? @width) (/ @width itemsize) 0) + nitems (mth/floor ratio) + limit (min 10 nitems) + limit (max 1 limit) on-nav - (mf/use-callback + (mf/use-fn (mf/deps project) - #(st/emit! (rt/nav :dashboard-files {:team-id (:team-id project) - :project-id (:id project)}))) - - width (mf/use-state nil) - rowref (mf/use-ref) - itemsize (if (>= @width 1030) - 280 - 230) - - ratio (if (some? @width) (/ @width itemsize) 0) - nitems (mth/floor ratio) - limit (min 10 nitems) - limit (max 1 limit) - + (fn [] + (st/emit! (rt/nav :dashboard-files {:team-id (:team-id project) + :project-id project-id})))) toggle-pin (mf/use-callback (mf/deps project) @@ -209,22 +220,24 @@ (dd/fetch-recent-files (:id team)) (dd/clear-selected-files))))] - (mf/use-effect - (fn [] - (let [node (mf/ref-val rowref) - mnt? (volatile! true) - sub (->> (wapi/observe-resize node) - (rx/observe-on :af) - (rx/subs (fn [entries] - (let [row (first entries) - row-rect (.-contentRect ^js row) - row-width (.-width ^js row-rect)] - (when @mnt? - (reset! width row-width))))))] - (fn [] - (vreset! mnt? false) - (rx/dispose! sub))))) - [:div.dashboard-project-row {:class (when first? "first")} + (mf/with-effect + (let [node (mf/ref-val rowref) + mnt? (volatile! true) + sub (->> (wapi/observe-resize node) + (rx/observe-on :af) + (rx/subs (fn [entries] + (let [row (first entries) + row-rect (.-contentRect ^js row) + row-width (.-width ^js row-rect)] + (when @mnt? + (reset! width row-width))))))] + (fn [] + (vreset! mnt? false) + (rx/dispose! sub)))) + + + [:div.dashboard-project-row + {:class (when first? "first")} [:div.project {:ref rowref} [:div.project-name-wrapper (if (:edition? @local) @@ -265,6 +278,7 @@ [:a.btn-secondary.btn-small.tooltip.tooltip-bottom {:on-click on-menu-click :alt (tr "dashboard.options") :data-test "project-options"} i/actions]]] + (when (and (> limit 0) (> file-count limit)) [:div.show-more {:on-click on-nav} @@ -290,53 +304,53 @@ (reverse)) recent-map (mf/deref recent-files-ref) props (some-> profile (get :props {})) - team-hero? (:team-hero? props true) + team-hero? (and (:team-hero? props true) + (not (:is-default team))) tutorial-viewed? (:viewed-tutorial? props true) walkthrough-viewed? (:viewed-walkthrough? props true) - close-banner (fn [] - (st/emit! - (du/update-profile-props {:team-hero? false}) - (ptk/event ::ev/event {::ev/name "dont-show-team-up-hero" - ::ev/origin "dashboard"}))) + team-id (:id team) - close-tutorial (fn [] - (st/emit! - (du/update-profile-props {:viewed-tutorial? true}) - (ptk/event ::ev/event {::ev/name "dont-show" - ::ev/origin "get-started-hero-block" - :type "tutorial" - :section "dashboard"}))) + close-banner + (mf/use-fn + (fn [] + (st/emit! (du/update-profile-props {:team-hero? false}) + (ptk/event ::ev/event {::ev/name "dont-show-team-up-hero" + ::ev/origin "dashboard"})))) + close-tutorial + (mf/use-fn + (fn [] + (st/emit! (du/update-profile-props {:viewed-tutorial? true}) + (ptk/event ::ev/event {::ev/name "dont-show" + ::ev/origin "get-started-hero-block" + :type "tutorial" + :section "dashboard"})))) + close-walkthrough + (mf/use-fn + (fn [] + (st/emit! (du/update-profile-props {:viewed-walkthrough? true}) + (ptk/event ::ev/event {::ev/name "dont-show" + ::ev/origin "get-started-hero-block" + :type "walkthrough" + :section "dashboard"}))))] - close-walkthrough (fn [] - (st/emit! - (du/update-profile-props {:viewed-walkthrough? true}) - (ptk/event ::ev/event {::ev/name "dont-show" - ::ev/origin "get-started-hero-block" - :type "walkthrough" - :section "dashboard"})))] + (mf/with-effect [team] + (let [tname (if (:is-default team) + (tr "dashboard.your-penpot") + (:name team))] + (dom/set-html-title (tr "title.dashboard.projects" tname)))) - (mf/use-effect - (mf/deps team) - (fn [] - (let [tname (if (:is-default team) - (tr "dashboard.your-penpot") - (:name team))] - (dom/set-html-title (tr "title.dashboard.projects" tname))))) - - (mf/use-effect - (mf/deps (:id team)) - (fn [] - (st/emit! (dd/fetch-recent-files (:id team)) - (dd/clear-selected-files)))) + (mf/with-effect [team-id] + (st/emit! (dd/fetch-recent-files team-id) + (dd/clear-selected-files))) (when (seq projects) [:* [:& header] - (when (and team-hero? (not (:is-default team))) - [:& team-hero - {:team team - :close-banner close-banner}]) + + (when team-hero? + [:& team-hero {:team team :close-banner close-banner}]) + (when (or (not tutorial-viewed?) (not walkthrough-viewed?)) [:div.hero-projects (when (and (not tutorial-viewed?) (:is-default team)) @@ -358,5 +372,5 @@ :team team :files files :first? (= project (first projects)) - :key (:id project)}]))]]))) + :key id}]))]]))) diff --git a/frontend/src/app/main/ui/hooks.cljs b/frontend/src/app/main/ui/hooks.cljs index c8e61a442..c0afc15dd 100644 --- a/frontend/src/app/main/ui/hooks.cljs +++ b/frontend/src/app/main/ui/hooks.cljs @@ -29,7 +29,7 @@ (defn use-rxsub [ob] - (let [[state reset-state!] (mf/useState @ob)] + (let [[state reset-state!] (mf/useState #(if (satisfies? IDeref ob) @ob nil))] (mf/useEffect (fn [] (let [sub (rx/subscribe ob #(reset-state! %))] @@ -313,3 +313,39 @@ (use-stream stream (partial reset! state)) state)) + +(defonce ^:private intersection-subject (rx/subject)) +(defonce ^:private intersection-observer + (delay (js/IntersectionObserver. + (fn [entries _] + (run! (partial rx/push! intersection-subject) (seq entries))) + #js {:rootMargin "0px" + :threshold 1.0}))) + +(defn use-visible + [ref & {:keys [once?]}] + (let [[state update-state!] (mf/useState false)] + (mf/with-effect [once?] + (let [node (mf/ref-val ref) + stream (->> intersection-subject + (rx/filter (fn [entry] + (let [target (unchecked-get entry "target")] + (identical? target node)))) + (rx/map (fn [entry] + (let [ratio (unchecked-get entry "intersectionRatio") + intersecting? (unchecked-get entry "isIntersecting")] + (or intersecting? (> ratio 0.5))))) + (rx/dedupe)) + stream (if once? + (->> stream + (rx/filter identity) + (rx/take 1)) + stream) + subs (rx/subscribe stream update-state!)] + (.observe ^js @intersection-observer node) + (fn [] + (.unobserve ^js @intersection-observer node) + (rx/dispose! subs)))) + + state)) + diff --git a/frontend/src/app/util/perf.cljs b/frontend/src/app/util/perf.cljs index d6765564e..f962e993e 100644 --- a/frontend/src/app/util/perf.cljs +++ b/frontend/src/app/util/perf.cljs @@ -131,3 +131,15 @@ (js/performance.clearMeasures end-mark) #js {:duration duration :avg avg}))) + +(defn now + [] + (js/performance.now)) + +(defn tpoint + "Create a measurement checkpoint for time measurement of potentially + asynchronous flow." + [] + (let [p1 (now)] + #(js/Math.floor (- (now) p1)))) + From 89e64236b0e891cc24dfd462e46eea77187ce469 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 28 Sep 2022 09:42:39 +0200 Subject: [PATCH 17/19] :sparkles: Don't log exception on health check fail --- backend/src/app/http/debug.clj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/src/app/http/debug.clj b/backend/src/app/http/debug.clj index 1133cd2a9..c66a14bd7 100644 --- a/backend/src/app/http/debug.clj +++ b/backend/src/app/http/debug.clj @@ -8,6 +8,7 @@ (:refer-clojure :exclude [error-handler]) (:require [app.common.exceptions :as ex] + [app.common.logging :as l] [app.common.pprint :as pp] [app.common.uuid :as uuid] [app.config :as cf] @@ -341,8 +342,13 @@ "Mainly a task that performs a health check." [{:keys [pool]} _] (db/with-atomic [conn pool] - (db/exec-one! conn ["select count(*) as count from server_prop;"]) - (yrs/response 200 "OK"))) + (try + (db/exec-one! conn ["select count(*) as count from server_prop;"]) + (yrs/response 200 "OK") + (catch Throwable cause + (l/warn :hint "unable to execute query on health handler" + :cause cause) + (yrs/response 503 "KO"))))) (defn changelog-handler [_ _] From 3a4563d7557df423fc89ffe9f9c872b69be5abb8 Mon Sep 17 00:00:00 2001 From: Lazalatin Date: Fri, 16 Sep 2022 22:18:32 +0200 Subject: [PATCH 18/19] :bug: Fix doubled quotes in frontend config Docker parses environment variables literally, delivering quoted flags in the $PENPOT_FLAGS variable. This in turn leads to doubled quotes in the resulting config.js in front and after the flags, omitting them completely. This commit fixes this behaviour. --- docker/images/config.env | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/images/config.env b/docker/images/config.env index 5da4a1939..7744ded6e 100644 --- a/docker/images/config.env +++ b/docker/images/config.env @@ -8,8 +8,7 @@ PENPOT_PUBLIC_URI=http://localhost:9001 ## Feature flags. - -PENPOT_FLAGS="enable-registration enable-login disable-email-verification" +PENPOT_FLAGS=enable-registration enable-login disable-email-verification ## Temporal workaround because of bad builtin default From 53c358cfd731ba2d8728444d5419b13a62ffa0f4 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 28 Sep 2022 11:30:48 +0200 Subject: [PATCH 19/19] :bug: Fix ssl support on email sending module --- backend/src/app/config.clj | 4 +++- backend/src/app/emails.clj | 28 ++++++++++++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/backend/src/app/config.clj b/backend/src/app/config.clj index b718bdeeb..f394bd6a8 100644 --- a/backend/src/app/config.clj +++ b/backend/src/app/config.clj @@ -271,13 +271,13 @@ ::public-uri ::redis-uri ::registration-domain-whitelist + ::rpc-rlimit-config ::semaphore-process-font ::semaphore-process-image ::semaphore-update-file ::semaphore-auth - ::rpc-rlimit-config ::smtp-default-from ::smtp-default-reply-to ::smtp-host @@ -286,8 +286,10 @@ ::smtp-ssl ::smtp-tls ::smtp-username + ::srepl-host ::srepl-port + ::assets-storage-backend ::storage-assets-fs-directory ::storage-assets-s3-bucket diff --git a/backend/src/app/emails.clj b/backend/src/app/emails.clj index 6429bf75c..d072845a5 100644 --- a/backend/src/app/emails.clj +++ b/backend/src/app/emails.clj @@ -56,7 +56,6 @@ type (resolve-recipient-type type)] (.addRecipients mmsg type address) mmsg))) - (defn- assign-recipients [mmsg {:keys [to cc bcc] :as params}] (cond-> mmsg @@ -139,6 +138,7 @@ (Properties.) {"mail.user" username "mail.host" host + "mail.debug" (contains? cf/flags :smtp-debug) "mail.from" default-from "mail.smtp.auth" (boolean username) "mail.smtp.starttls.enable" tls @@ -150,17 +150,14 @@ "mail.smtp.connectiontimeout" timeout})) (defn- create-smtp-session - [{:keys [debug] :or {debug false} :as opts}] - (let [props (opts->props opts) - session (Session/getInstance props)] - (.setDebug session debug) - session)) + [opts] + (let [props (opts->props opts)] + (Session/getInstance props))) (defn- create-smtp-message ^MimeMessage - [cfg params] - (let [session (create-smtp-session cfg) - mmsg (MimeMessage. ^Session session)] + [cfg session params] + (let [mmsg (MimeMessage. ^Session session)] (assign-recipients mmsg params) (assign-from mmsg cfg params) (assign-reply-to mmsg cfg params) @@ -304,9 +301,16 @@ [_ cfg] (fn [params] (when (contains? cf/flags :smtp) - (Transport/send (create-smtp-message cfg params) - (:username cfg) - (:password cfg))) + (let [session (create-smtp-session cfg)] + (with-open [transport (.getTransport session (if (:ssl cfg) "smtps" "smtp"))] + (.connect ^Transport transport + ^String (:username cfg) + ^String (:password cfg)) + + (let [^MimeMessage message (create-smtp-message cfg session params)] + (.sendMessage ^Transport transport + ^MimeMessage message + (.getAllRecipients message)))))) (when (or (contains? cf/flags :log-emails) (not (contains? cf/flags :smtp)))