diff --git a/.circleci/config.yml b/.circleci/config.yml index 93ef6837e0..dbba251c1b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -11,6 +11,7 @@ jobs: - image: cimg/redis:6.2.6 working_directory: ~/repo + resource_class: large environment: # Customize the JVM maximum heap limit diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn index c82ed8b107..5aec7c30fd 100644 --- a/.clj-kondo/config.edn +++ b/.clj-kondo/config.edn @@ -38,6 +38,9 @@ :single-key-in {:level :warning} + :non-arg-vec-return-type-hint + {:level :off} + :redundant-do {:level :off} diff --git a/CHANGES.md b/CHANGES.md index 5021c2159f..8935ed9811 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,8 @@ ### :bug: Bugs fixed +- Fix shortcut access in main menu [Taiga #3672](https://tree.taiga.io/project/penpot/issue/3672) +- Fix modify colors in a row in selected colors [Taiga #3653](https://tree.taiga.io/project/penpot/issue/3653) - Fix crash when double click on viewer assets [Taiga #3625](https://tree.taiga.io/project/penpot/issue/3625) - Fix right click on typographies assets [Taiga #3638](https://tree.taiga.io/project/penpot/issue/3638) diff --git a/backend/src/app/loggers/audit.clj b/backend/src/app/loggers/audit.clj index 8fb9ce6b99..89ffb1611a 100644 --- a/backend/src/app/loggers/audit.clj +++ b/backend/src/app/loggers/audit.clj @@ -51,7 +51,7 @@ (defn profile->props [profile] (-> profile - (select-keys [:is-active :is-muted :auth-backend :email :default-team-id :default-project-id :fullname :lang]) + (select-keys [:id :is-active :is-muted :auth-backend :email :default-team-id :default-project-id :fullname :lang]) (merge (:props profile)) (d/without-nils))) diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 9e53af92eb..a737028cea 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -6,7 +6,6 @@ (ns app.rpc (:require - [app.common.data :as d] [app.common.exceptions :as ex] [app.common.logging :as l] [app.common.spec :as us] @@ -132,10 +131,13 @@ (fn [result _] (when result (let [resultm (meta result) - profile-id (or (:profile-id params) + profile-id (or (::audit/profile-id resultm) (:profile-id result) - (::audit/profile-id resultm)) - props (d/merge params (::audit/props resultm))] + (:profile-id params)) + props (or (::audit/replace-props resultm) + (-> params + (merge (::audit/props resultm)) + (dissoc :type)))] (audit :cmd :submit :type (or (::audit/type resultm) (::type cfg)) diff --git a/backend/src/app/rpc/mutations/profile.clj b/backend/src/app/rpc/mutations/profile.clj index bd4179edbb..e82e59a8c1 100644 --- a/backend/src/app/rpc/mutations/profile.clj +++ b/backend/src/app/rpc/mutations/profile.clj @@ -137,7 +137,8 @@ :exp (dt/in-future "48h")} token (tokens :generate params)] - {:token token})) + (with-meta {:token token} + {::audit/profile-id uuid/zero}))) ;; --- MUTATION: Register Profile @@ -175,7 +176,7 @@ resp {:invitation-token token}] (with-meta resp {:transform-response ((:create session) (:id profile)) - ::audit/props (audit/profile->props profile) + ::audit/replace-props (audit/profile->props profile) ::audit/profile-id (:id profile)})) ;; If auth backend is different from "penpot" means user is @@ -184,7 +185,7 @@ (not= "penpot" (:auth-backend profile)) (with-meta (profile/strip-private-attrs profile) {:transform-response ((:create session) (:id profile)) - ::audit/props (audit/profile->props profile) + ::audit/replace-props (audit/profile->props profile) ::audit/profile-id (:id profile)}) ;; If the `:enable-insecure-register` flag is set, we proceed @@ -192,7 +193,7 @@ (true? is-active) (with-meta (profile/strip-private-attrs profile) {:transform-response ((:create session) (:id profile)) - ::audit/props (audit/profile->props profile) + ::audit/replace-props (audit/profile->props profile) ::audit/profile-id (:id profile)}) ;; In all other cases, send a verification email. @@ -214,7 +215,7 @@ :extra-data ptoken}) (with-meta profile - {::audit/props (audit/profile->props profile) + {::audit/replace-props (audit/profile->props profile) ::audit/profile-id (:id profile)})))))) (defn create-profile diff --git a/backend/src/app/tasks/telemetry.clj b/backend/src/app/tasks/telemetry.clj index cf45eeeba0..db6149b77b 100644 --- a/backend/src/app/tasks/telemetry.clj +++ b/backend/src/app/tasks/telemetry.clj @@ -199,6 +199,7 @@ "taiga" (cf/get :telemetry-referer))] (-> {:referer referer + :public-uri (cf/get :public-uri) :total-teams (retrieve-num-teams conn) :total-projects (retrieve-num-projects conn) :total-files (retrieve-num-files conn) diff --git a/docker/images/config.env b/docker/images/config.env index ad1ee70ad2..eccfbe0bfa 100644 --- a/docker/images/config.env +++ b/docker/images/config.env @@ -1,34 +1,48 @@ -# Should be set to the public domain where penpot is going to be served. +## Should be set to the public domain where penpot is going to be served. +## +## NOTE: If you are going to serve it under different domain than +## 'localhost' without HTTPS, consider setting the +## `disable-secure-session-cookies' flag on the 'PENPOT_FLAGS' +## setting. + PENPOT_PUBLIC_URI=http://localhost:9001 PENPOT_TENANT=pro -# Temporal workaround because of bad builtin default +## Feature flags. + +PENPOT_FLAGS="enable-registration enable-login" + +## Temporal workaround because of bad builtin default + PENPOT_HTTP_SERVER_HOST=0.0.0.0 -# Standard database connection parameters (only postgresql is supported): +## Standard database connection parameters (only postgresql is supported): + PENPOT_DATABASE_URI=postgresql://penpot-postgres/penpot PENPOT_DATABASE_USERNAME=penpot PENPOT_DATABASE_PASSWORD=penpot -# Redis is used for the websockets notifications. +## Redis is used for the websockets notifications. + PENPOT_REDIS_URI=redis://penpot-redis/0 -# By default, files uploaded by users are stored in local filesystem. But it -# can be configured to store in AWS S3 or completely in de the database. -# Storing in the database makes the backups more easy but will make access to -# media less performant. +## By default, files uploaded by users are stored in local +## filesystem. But it can be configured to store in AWS S3. + PENPOT_ASSETS_STORAGE_BACKEND=assets-fs PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets -# Telemetry. When enabled, a periodical process will send anonymous data about -# this instance. Telemetry data will enable us to learn on how the application -# is used, based on real scenarios. If you want to help us, please leave it -# enabled. +## Telemetry. When enabled, a periodical process will send anonymous +## data about this instance. Telemetry data will enable us to learn on +## how the application is used, based on real scenarios. If you want +## to help us, please leave it enabled. + PENPOT_TELEMETRY_ENABLED=true -# Email sending configuration. By default, emails are printed in the console, -# but for production usage is recommended to setup a real SMTP provider. Emails -# are used to confirm user registrations. +## Email sending configuration. By default, emails are printed in the +## console, but for production usage is recommended to setup a real +## SMTP provider. Emails are used to confirm user registrations. + PENPOT_SMTP_ENABLED=false PENPOT_SMTP_DEFAULT_FROM=no-reply@example.com PENPOT_SMTP_DEFAULT_REPLY_TO=no-reply@example.com @@ -39,34 +53,40 @@ PENPOT_SMTP_DEFAULT_REPLY_TO=no-reply@example.com # PENPOT_SMTP_TLS=true # PENPOT_SMTP_SSL=false -# Feature flags. Right now they are only affect frontend, but in -# future release they will affect to both backend and frontend. -PENPOT_FLAGS="enable-registration" +## Comma separated list of allowed domains to register. Empty to allow +## all. -# Comma separated list of allowed domains to register. Empty to allow all. # PENPOT_REGISTRATION_DOMAIN_WHITELIST="" ## Authentication providers -# Google +## Google + # PENPOT_GOOGLE_CLIENT_ID= # PENPOT_GOOGLE_CLIENT_SECRET= -# GitHub +## GitHub + # PENPOT_GITHUB_CLIENT_ID= # PENPOT_GITHUB_CLIENT_SECRET= -# GitLab +## GitLab + # PENPOT_GITLAB_BASE_URI=https://gitlab.com # PENPOT_GITLAB_CLIENT_ID= # PENPOT_GITLAB_CLIENT_SECRET= -# OpenID Connect (since 1.5.0) +## OpenID Connect (since 1.5.0) + # PENPOT_OIDC_BASE_URI= # PENPOT_OIDC_CLIENT_ID= # PENPOT_OIDC_CLIENT_SECRET= -# LDAP +## LDAP +## +## NOTE: to enable ldap, you will need to put 'enable-login-with-ldap' +## on the 'PENPOT_FLAGS' environment variable. + # PENPOT_LDAP_HOST=ldap # PENPOT_LDAP_PORT=10389 # PENPOT_LDAP_SSL=false @@ -78,7 +98,3 @@ PENPOT_FLAGS="enable-registration" # PENPOT_LDAP_ATTRS_EMAIL=mail # PENPOT_LDAP_ATTRS_FULLNAME=cn # PENPOT_LDAP_ATTRS_PHOTO=jpegPhoto -# PENPOT_LOGIN_WITH_LDAP=true - -# Exporter -PENPOT_DOMAIN_WHITE_LIST=localhost:9001 diff --git a/exporter/src/app/config.cljs b/exporter/src/app/config.cljs index 47b835c60f..6a312ab687 100644 --- a/exporter/src/app/config.cljs +++ b/exporter/src/app/config.cljs @@ -25,15 +25,13 @@ :host "devenv" :http-server-port 6061 :http-server-host "localhost" - :redis-uri "redis://redis/0" - :domain-white-list #{"localhost:3449"}}) + :redis-uri "redis://redis/0"}) (s/def ::http-server-port ::us/integer) (s/def ::http-server-host ::us/string) (s/def ::public-uri ::us/uri) (s/def ::tenant ::us/string) (s/def ::host ::us/string) -(s/def ::domain-white-list ::us/set-of-str) (s/def ::browser-pool-max ::us/integer) (s/def ::browser-pool-min ::us/integer) @@ -44,8 +42,7 @@ ::http-server-port ::http-server-host ::browser-pool-max - ::browser-pool-min - ::domain-white-list])) + ::browser-pool-min])) (defn- read-env [prefix] diff --git a/exporter/src/app/handlers.cljs b/exporter/src/app/handlers.cljs index 0d0cab3a31..a1a8496992 100644 --- a/exporter/src/app/handlers.cljs +++ b/exporter/src/app/handlers.cljs @@ -70,7 +70,6 @@ (defmulti command-spec :cmd) (s/def ::id ::us/string) -(s/def ::uri ::us/uri) (s/def ::wait ::us/boolean) (s/def ::cmd ::us/keyword) @@ -80,24 +79,13 @@ (s/def ::params (s/and (s/keys :req-un [::cmd] - :opt-un [::wait ::uri]) + :opt-un [::wait]) (s/multi-spec command-spec :cmd))) -(defn validate-uri! - [uri] - (let [white-list (cf/get :domain-white-list #{}) - default (cf/get :public-uri)] - (when-not (or (contains? white-list (u/get-domain uri)) - (= (u/get-domain default) (u/get-domain uri))) - (ex/raise :type :validation - :code :domain-not-allowed - :hint "looks like the uri provided is not part of the white list")))) - (defn handler [{:keys [:request/params] :as exchange}] - (let [{:keys [cmd uri] :as params} (us/conform ::params params)] + (let [{:keys [cmd] :as params} (us/conform ::params params)] (l/debug :hint "process-request" :cmd cmd) - (some-> uri validate-uri!) (case cmd :get-resource (resources/handler exchange) :export-shapes (export-shapes/handler exchange params) diff --git a/exporter/src/app/handlers/export_frames.cljs b/exporter/src/app/handlers/export_frames.cljs index 74ac5ab832..a8a4a0c85b 100644 --- a/exporter/src/app/handlers/export_frames.cljs +++ b/exporter/src/app/handlers/export_frames.cljs @@ -29,7 +29,6 @@ (s/def ::file-id ::us/uuid) (s/def ::page-id ::us/uuid) (s/def ::object-id ::us/uuid) -(s/def ::uri ::us/uri) (s/def ::export (s/keys :req-un [::file-id ::page-id ::object-id ::name])) @@ -39,18 +38,18 @@ (s/def ::params (s/keys :req-un [::exports] - :opt-un [::uri ::name])) + :opt-un [::name])) (defn handler - [{:keys [:request/auth-token] :as exchange} {:keys [exports uri profile-id] :as params}] + [{:keys [:request/auth-token] :as exchange} {:keys [exports profile-id] :as params}] ;; NOTE: we need to have the `:type` prop because the exports ;; datastructure preparation uses it for creating the groups. (let [exports (-> (map #(assoc % :type :pdf :scale 1 :suffix "") exports) - (prepare-exports auth-token uri))] + (prepare-exports auth-token))] (handle-export exchange (assoc params :exports exports)))) (defn handle-export - [exchange {:keys [exports wait uri name profile-id] :as params}] + [exchange {:keys [exports wait name profile-id] :as params}] (let [total (count exports) topic (str profile-id) resource (rsc/create :pdf (or name (-> exports first :name))) diff --git a/exporter/src/app/handlers/export_shapes.cljs b/exporter/src/app/handlers/export_shapes.cljs index b70e63cf21..c6ac2f05de 100644 --- a/exporter/src/app/handlers/export_shapes.cljs +++ b/exporter/src/app/handlers/export_shapes.cljs @@ -34,7 +34,6 @@ (s/def ::scale ::us/number) (s/def ::suffix ::us/string) (s/def ::type ::us/keyword) -(s/def ::uri ::us/uri) (s/def ::wait ::us/boolean) (s/def ::export @@ -45,11 +44,11 @@ (s/def ::params (s/keys :req-un [::exports ::profile-id] - :opt-un [::uri ::wait ::name])) + :opt-un [::wait ::name])) (defn handler - [{:keys [:request/auth-token] :as exchange} {:keys [exports uri] :as params}] - (let [exports (prepare-exports exports auth-token uri)] + [{:keys [:request/auth-token] :as exchange} {:keys [exports] :as params}] + (let [exports (prepare-exports exports auth-token)] (if (and (= 1 (count exports)) (= 1 (count (-> exports first :objects)))) (handle-single-export exchange (-> params @@ -58,7 +57,7 @@ (handle-multiple-export exchange (assoc params :exports exports))))) (defn- handle-single-export - [exchange {:keys [export wait uri profile-id name] :as params}] + [exchange {:keys [export wait profile-id name] :as params}] (let [topic (str profile-id) resource (rsc/create (:type export) (or name (:name export))) @@ -98,7 +97,7 @@ (assoc exchange :response/body (dissoc resource :path))))) (defn- handle-multiple-export - [exchange {:keys [exports wait uri profile-id name] :as params}] + [exchange {:keys [exports wait profile-id name] :as params}] (let [resource (rsc/create :zip (or name (-> exports first :name))) total (count exports) topic (str profile-id) @@ -185,7 +184,7 @@ default-partition-size 50) (defn prepare-exports - [exports token uri] + [exports token] (letfn [(process-group [group] (sequence (comp (partition-all default-partition-size) (map process-partition)) @@ -196,7 +195,6 @@ :page-id (:page-id part1) :name (:name part1) :token token - :uri uri :type (:type part1) :scale (:scale part1) :objects (mapv part-entry->object part)}) diff --git a/exporter/src/app/renderer.cljs b/exporter/src/app/renderer.cljs index 90e03ec68d..42ab6c6ad5 100644 --- a/exporter/src/app/renderer.cljs +++ b/exporter/src/app/renderer.cljs @@ -20,7 +20,6 @@ (s/def ::file-id ::us/uuid) (s/def ::scale ::us/number) (s/def ::token ::us/string) -(s/def ::uri ::us/uri) (s/def ::filename ::us/string) (s/def ::object @@ -30,8 +29,7 @@ (s/coll-of ::object :min-count 1)) (s/def ::render-params - (s/keys :req-un [::file-id ::page-id ::scale ::token ::type ::objects] - :opt-un [::uri])) + (s/keys :req-un [::file-id ::page-id ::scale ::token ::type ::objects])) (defn- render [{:keys [type] :as params} on-object] diff --git a/frontend/src/app/main/repo.cljs b/frontend/src/app/main/repo.cljs index cc2c8828fd..ee068f205a 100644 --- a/frontend/src/app/main/repo.cljs +++ b/frontend/src/app/main/repo.cljs @@ -130,9 +130,7 @@ (defmethod query :exporter [_ params] - (let [default {:wait false - :blob? false - :uri (str base-uri)}] + (let [default {:wait false :blob? false}] (send-export (merge default params)))) (derive :upload-file-media-object ::multipart-upload) diff --git a/frontend/src/app/main/ui/workspace/header.cljs b/frontend/src/app/main/ui/workspace/header.cljs index a475c9c30b..dfca387af2 100644 --- a/frontend/src/app/main/ui/workspace/header.cljs +++ b/frontend/src/app/main/ui/workspace/header.cljs @@ -398,7 +398,9 @@ [:span (tr "labels.github-repo")]] [:li {:on-click #(dom/open-new-window "https://penpot.app/terms.html")} [:span (tr "auth.terms-of-service")]] - [:li.separator {:on-click #(st/emit! (rt/nav-new-window* {:rname :settings-feedback}))} + [:li.separator {:on-click #(st/emit! (when (contains? layout :collapse-left-sidebar) (dw/toggle-layout-flag :collapse-left-sidebar)) + (-> (dw/toggle-layout-flag :shortcuts) + (vary-meta assoc ::ev/origin "workspace-header")))} [:span (tr "label.shortcuts")] [:span.shortcut (sc/get-tooltip :show-shortcuts)]] 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 6008959fc6..234c7cc06a 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 @@ -125,12 +125,11 @@ on-change (mf/use-fn (fn [new-color old-color] - (let [old-color (-> (or @prev-color* old-color) + (let [old-color (-> old-color (dissoc :name) (dissoc :path) (d/without-nils)) shapes-by-color (get @grouped-colors* old-color)] - (reset! prev-color* new-color) (st/emit! (dc/change-color-in-selected new-color shapes-by-color old-color))))) on-open (mf/use-fn 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 5f8e0d0af7..fd608efd18 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 @@ -69,6 +69,8 @@ shared-libs (mf/deref refs/workspace-libraries) hover-detach (mf/use-state false) + on-change-var (h/use-update-var {:fn on-change}) + src-colors (if (= (:file-id color) current-file-id) file-colors (get-in shared-libs [(:file-id color) :data :colors])) @@ -83,18 +85,18 @@ (when on-detach (on-detach color))) change-value (fn [new-value] - (when on-change (on-change (-> color - (assoc :color new-value) - (dissoc :gradient))))) + (when (:fn @on-change-var) ((:fn @on-change-var) (-> color + (assoc :color new-value) + (dissoc :gradient))))) change-opacity (fn [new-opacity] - (when on-change (on-change (assoc color + (when (:fn @on-change-var) ((:fn @on-change-var) (assoc color :opacity new-opacity :id nil :file-id nil)))) handle-pick-color (fn [color] - (when on-change (on-change (merge uc/empty-color color)))) + (when (:fn @on-change-var) ((:fn @on-change-var) (merge uc/empty-color color)))) handle-select (fn [] (select-only color)) diff --git a/frontend/src/app/util/object.cljs b/frontend/src/app/util/object.cljs index 325cfe3449..7831647976 100644 --- a/frontend/src/app/util/object.cljs +++ b/frontend/src/app/util/object.cljs @@ -43,6 +43,7 @@ (rest keys) (unchecked-get res key)))))) +#_:clj-kondo/ignore (defn without [obj keys] (let [keys (cond