0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-01 01:21:21 -05:00

Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Andrey Antukh 2024-07-25 11:23:42 +02:00
commit 025034cb71
21 changed files with 190 additions and 155 deletions

View file

@ -12,9 +12,16 @@
## 2.1.1 ## 2.1.1
### :sparkles: New features
- Consolidate templates new order and naming [Taiga #8392](https://tree.taiga.io/project/penpot/task/8392)
### :bug: Bugs fixed ### :bug: Bugs fixed
- Fix the “search” label in translations [Taiga #8402](https://tree.taiga.io/project/penpot/issue/8402)
- Fix pencil loader [Taiga #8348](https://tree.taiga.io/project/penpot/issue/8348) - Fix pencil loader [Taiga #8348](https://tree.taiga.io/project/penpot/issue/8348)
- Fix several issues on the OIDC.
- Fix regression on the `email-verification` flag [Taiga #8398](https://tree.taiga.io/project/penpot/issue/8398)
## 2.1.0 - Things can only get better! ## 2.1.0 - Things can only get better!

View file

@ -1,4 +1,16 @@
[{:id "tutorial-for-beginners" [{:id "wireframing-kit"
:name "Wireframe library"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"}
{:id "prototype-examples"
:name "Prototipe template"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/prototype-examples.penpot"}
{:id "plants-app"
:name "UI mockup example"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Plants-app.penpot"}
{:id "penpot-design-system"
:name "Design system example"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}
{:id "tutorial-for-beginners"
:name "Tutorial for beginners" :name "Tutorial for beginners"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"} :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"}
{:id "lucide-icons" {:id "lucide-icons"
@ -7,12 +19,6 @@
{:id "font-awesome" {:id "font-awesome"
:name "Font Awesome" :name "Font Awesome"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Font-Awesome.penpot"} :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Font-Awesome.penpot"}
{:id "plants-app"
:name "Plants app"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Plants-app.penpot"}
{:id "wireframing-kit"
:name "Wireframing Kit"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/wireframing-kit.penpot"}
{:id "black-white-mobile-templates" {:id "black-white-mobile-templates"
:name "Black & White Mobile Templates" :name "Black & White Mobile Templates"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Black-White-Mobile-Templates.penpot"} :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Black-White-Mobile-Templates.penpot"}
@ -30,10 +36,4 @@
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Open-Color-Scheme.penpot"} :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Open-Color-Scheme.penpot"}
{:id "flex-layout-playground" {:id "flex-layout-playground"
:name "Flex Layout Playground" :name "Flex Layout Playground"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Flex-Layout-Playground.penpot"} :file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Flex-Layout-Playground.penpot"}]
{:id "prototype-examples"
:name "Prototipe template"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/prototype-examples.penpot"}
{:id "penpot-design-system"
:name "Design system example"
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}]

View file

@ -26,6 +26,7 @@
[app.rpc.commands.profile :as profile] [app.rpc.commands.profile :as profile]
[app.setup :as-alias setup] [app.setup :as-alias setup]
[app.tokens :as tokens] [app.tokens :as tokens]
[app.util.inet :as inet]
[app.util.json :as json] [app.util.json :as json]
[app.util.time :as dt] [app.util.time :as dt]
[buddy.sign.jwk :as jwk] [buddy.sign.jwk :as jwk]
@ -571,10 +572,10 @@
props (audit/profile->props profile) props (audit/profile->props profile)
context (d/without-nils {:external-session-id (:external-session-id info)})] context (d/without-nils {:external-session-id (:external-session-id info)})]
(audit/submit! cfg {::audit/type "command" (audit/submit! cfg {::audit/type "action"
::audit/name "login-with-oidc" ::audit/name "login-with-oidc"
::audit/profile-id (:id profile) ::audit/profile-id (:id profile)
::audit/ip-addr (audit/parse-client-ip request) ::audit/ip-addr (inet/parse-request request)
::audit/props props ::audit/props props
::audit/context context}) ::audit/context context})

View file

@ -21,28 +21,18 @@
[app.rpc :as-alias rpc] [app.rpc :as-alias rpc]
[app.rpc.retry :as rtry] [app.rpc.retry :as rtry]
[app.setup :as-alias setup] [app.setup :as-alias setup]
[app.util.inet :as inet]
[app.util.services :as-alias sv] [app.util.services :as-alias sv]
[app.util.time :as dt] [app.util.time :as dt]
[app.worker :as wrk] [app.worker :as wrk]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
[cuerdas.core :as str] [cuerdas.core :as str]
[integrant.core :as ig] [integrant.core :as ig]))
[ring.request :as rreq]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; HELPERS ;; HELPERS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn parse-client-ip
[request]
(let [ip-addr (or (some-> (rreq/get-header request "x-forwarded-for") (str/split ",") first)
(rreq/get-header request "x-real-ip")
(some-> (rreq/remote-addr request) str))
ip-addr (-> ip-addr
(str/split ":" 2)
(first))]
ip-addr))
(defn extract-utm-params (defn extract-utm-params
"Extracts additional data from params and namespace them under "Extracts additional data from params and namespace them under
`penpot` ns." `penpot` ns."
@ -90,17 +80,20 @@
(remove #(contains? reserved-props (key %)))) (remove #(contains? reserved-props (key %))))
props)) props))
(defn params->context (defn event-from-rpc-params
"Extract default context properties from RPC params object" "Create a base event skeleton with pre-filled some important
data that can be extracted from RPC params object"
[params] [params]
(d/without-nils (let [context {:external-session-id (::rpc/external-session-id params)
{:external-session-id (::rpc/external-session-id params) :external-event-origin (::rpc/external-event-origin params)
:event-origin (::rpc/external-event-origin params) :triggered-by (::rpc/handler-name params)}]
:triggered-by (::rpc/handler-name params)})) {::type "action"
::profile-id (::rpc/profile-id params)
::ip-addr (::rpc/ip-addr params)
::context (d/without-nils context)}))
;; --- SPECS ;; --- SPECS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; COLLECTOR ;; COLLECTOR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -167,14 +160,16 @@
(assoc :external-session-id session-id) (assoc :external-session-id session-id)
(assoc :external-event-origin event-origin) (assoc :external-event-origin event-origin)
(assoc :access-token-id (some-> token-id str)) (assoc :access-token-id (some-> token-id str))
(d/without-nils))] (d/without-nils))
ip-addr (inet/parse-request request)]
{::type (or (::type resultm) {::type (or (::type resultm)
(::rpc/type cfg)) (::rpc/type cfg))
::name (or (::name resultm) ::name (or (::name resultm)
(::sv/name mdata)) (::sv/name mdata))
::profile-id profile-id ::profile-id profile-id
::ip-addr (some-> request parse-client-ip) ::ip-addr ip-addr
::props props ::props props
::context context ::context context
@ -202,7 +197,7 @@
:name (::name event) :name (::name event)
:type (::type event) :type (::type event)
:profile-id (::profile-id event) :profile-id (::profile-id event)
:ip-addr (::ip-addr event "0.0.0.0") :ip-addr (::ip-addr event)
:context (::context event {}) :context (::context event {})
:props (::props event {}) :props (::props event {})
:source "backend"} :source "backend"}
@ -246,8 +241,7 @@
(assoc :created-at tnow) (assoc :created-at tnow)
(update :tracked-at #(or % tnow)) (update :tracked-at #(or % tnow))
(assoc :props {}) (assoc :props {})
(assoc :context {}) (assoc :context {}))]
(assoc :ip-addr "0.0.0.0"))]
(append-audit-entry! cfg params))) (append-audit-entry! cfg params)))
(when (and (contains? cf/flags :webhooks) (when (and (contains? cf/flags :webhooks)

View file

@ -29,6 +29,7 @@
[app.rpc.rlimit :as rlimit] [app.rpc.rlimit :as rlimit]
[app.setup :as-alias setup] [app.setup :as-alias setup]
[app.storage :as-alias sto] [app.storage :as-alias sto]
[app.util.inet :as inet]
[app.util.services :as sv] [app.util.services :as sv]
[app.util.time :as dt] [app.util.time :as dt]
[clojure.spec.alpha :as s] [clojure.spec.alpha :as s]
@ -81,7 +82,9 @@
(defn- get-external-event-origin (defn- get-external-event-origin
[request] [request]
(when-let [origin (rreq/get-header request "x-event-origin")] (when-let [origin (rreq/get-header request "x-event-origin")]
(when-not (> (count origin) 256) (when-not (or (> (count origin) 256)
(= origin "null")
(str/blank? origin))
origin))) origin)))
(defn- rpc-handler (defn- rpc-handler
@ -93,11 +96,13 @@
profile-id (or (::session/profile-id request) profile-id (or (::session/profile-id request)
(::actoken/profile-id request)) (::actoken/profile-id request))
ip-addr (inet/parse-request request)
session-id (get-external-session-id request) session-id (get-external-session-id request)
event-origin (get-external-event-origin request) event-origin (get-external-event-origin request)
data (-> params data (-> params
(assoc ::handler-name handler-name) (assoc ::handler-name handler-name)
(assoc ::ip-addr ip-addr)
(assoc ::request-at (dt/now)) (assoc ::request-at (dt/now))
(assoc ::external-session-id session-id) (assoc ::external-session-id session-id)
(assoc ::external-event-origin event-origin) (assoc ::external-event-origin event-origin)

View file

@ -14,11 +14,12 @@
[app.config :as cf] [app.config :as cf]
[app.db :as db] [app.db :as db]
[app.http :as-alias http] [app.http :as-alias http]
[app.loggers.audit :as audit] [app.loggers.audit :as-alias audit]
[app.rpc :as-alias rpc] [app.rpc :as-alias rpc]
[app.rpc.climit :as-alias climit] [app.rpc.climit :as-alias climit]
[app.rpc.doc :as-alias doc] [app.rpc.doc :as-alias doc]
[app.rpc.helpers :as rph] [app.rpc.helpers :as rph]
[app.util.inet :as inet]
[app.util.services :as sv] [app.util.services :as sv]
[app.util.time :as dt])) [app.util.time :as dt]))
@ -61,7 +62,7 @@
(defn- handle-events (defn- handle-events
[{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}] [{:keys [::db/pool]} {:keys [::rpc/profile-id events] :as params}]
(let [request (-> params meta ::http/request) (let [request (-> params meta ::http/request)
ip-addr (audit/parse-client-ip request) ip-addr (inet/parse-request request)
tnow (dt/now) tnow (dt/now)
xform (comp xform (comp
(map (fn [event] (map (fn [event]

View file

@ -340,7 +340,7 @@
profile (if-let [profile-id (:profile-id claims)] profile (if-let [profile-id (:profile-id claims)]
(profile/get-profile conn profile-id) (profile/get-profile conn profile-id)
(let [is-active (or (boolean (:is-active params)) (let [is-active (or (boolean (:is-active claims))
(not (contains? cf/flags :email-verification))) (not (contains? cf/flags :email-verification)))
params (-> params params (-> params
(assoc :is-active is-active) (assoc :is-active is-active)
@ -348,6 +348,9 @@
(->> (create-profile! conn params) (->> (create-profile! conn params)
(create-profile-rels! conn)))) (create-profile-rels! conn))))
;; When no profile-id comes on claims means a new register
created? (not (:profile-id claims))
invitation (when-let [token (:invitation-token params)] invitation (when-let [token (:invitation-token params)]
(tokens/verify (::setup/props cfg) {:token token :iss :team-invitation})) (tokens/verify (::setup/props cfg) {:token token :iss :team-invitation}))
@ -385,8 +388,8 @@
;; When a new user is created and it is already activated by ;; When a new user is created and it is already activated by
;; configuration or specified by OIDC, we just mark the profile ;; configuration or specified by OIDC, we just mark the profile
;; as logged-in ;; as logged-in
(not (:profile-id claims)) created?
(if (:is-active claims) (if (:is-active profile)
(-> (profile/strip-private-attrs profile) (-> (profile/strip-private-attrs profile)
(rph/with-transform (session/create-fn cfg (:id profile))) (rph/with-transform (session/create-fn cfg (:id profile)))
(rph/with-meta (rph/with-meta

View file

@ -413,15 +413,13 @@
{:modified-at (dt/now)} {:modified-at (dt/now)}
{:id project-id}) {:id project-id})
(let [props (audit/clean-props params) (let [props (audit/clean-props params)]
context (audit/params->context params)]
(doseq [file-id result] (doseq [file-id result]
(audit/submit! cfg (let [props (assoc props :id file-id)
{::audit/type "action" event (-> (audit/event-from-rpc-params params)
::audit/name "create-file" (assoc ::audit/name "create-file")
::audit/profile-id profile-id (assoc ::audit/props props))]
::audit/props (assoc props :id file-id) (audit/submit! cfg event))))
::audit/context context})))
result)))) result))))

View file

@ -787,18 +787,15 @@
(l/info :hint "invitation token" :token itoken)) (l/info :hint "invitation token" :token itoken))
(let [props (-> (dissoc tprops :profile-id) (let [props (-> (dissoc tprops :profile-id)
(audit/clean-props)) (audit/clean-props))
context (audit/params->context params)] evname (if updated?
"update-team-invitation"
(audit/submit! cfg "create-team-invitation")
{::audit/type "action" event (-> (audit/event-from-rpc-params params)
::audit/name (if updated? (assoc ::audit/name evname)
"update-team-invitation" (assoc ::audit/props props))]
"create-team-invitation") (audit/submit! cfg event))
::audit/profile-id (:id profile)
::audit/props props
::audit/context context}))
(eml/send! {::eml/conn conn (eml/send! {::eml/conn conn
::eml/factory eml/invite-to-team ::eml/factory eml/invite-to-team
@ -882,62 +879,51 @@
(sv/defmethod ::create-team-with-invitations (sv/defmethod ::create-team-with-invitations
{::doc/added "1.17" {::doc/added "1.17"
::sm/params schema:create-team-with-invitations} ::sm/params schema:create-team-with-invitations}
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id emails role name] :as params}] [cfg {:keys [::rpc/profile-id emails role name] :as params}]
(db/with-atomic [conn pool]
(let [features (-> (cfeat/get-enabled-features cf/flags) (db/tx-run! cfg
(cfeat/check-client-features! (:features params))) (fn [{:keys [::db/conn] :as cfg}]
(let [features (-> (cfeat/get-enabled-features cf/flags)
(cfeat/check-client-features! (:features params)))
params (-> params params (-> params
(assoc :profile-id profile-id) (assoc :profile-id profile-id)
(assoc :features features)) (assoc :features features))
cfg (assoc cfg ::db/conn conn) cfg (assoc cfg ::db/conn conn)
team (create-team cfg params) team (create-team cfg params)
profile (db/get-by-id conn :profile profile-id) profile (db/get-by-id conn :profile profile-id)
emails (into #{} (map profile/clean-email) emails) emails (into #{} (map profile/clean-email) emails)]
context (audit/params->context params)]
;; Create invitations for all provided emails. (let [props {:name name :features features}
(->> emails event (-> (audit/event-from-rpc-params params)
(map (fn [email] (assoc ::audit/name "create-team")
(-> params (assoc ::audit/props props))]
(assoc :team team) (audit/submit! cfg event))
(assoc :profile profile)
(assoc :email email)
(assoc :role role))))
(run! (partial create-invitation cfg)))
(run! (partial quotes/check-quote! conn) ;; Create invitations for all provided emails.
(list {::quotes/id ::quotes/teams-per-profile (->> emails
::quotes/profile-id profile-id} (map (fn [email]
{::quotes/id ::quotes/invitations-per-team (-> params
::quotes/profile-id profile-id (assoc :team team)
::quotes/team-id (:id team) (assoc :profile profile)
::quotes/incr (count emails)} (assoc :email email)
{::quotes/id ::quotes/profiles-per-team (assoc :role role))))
::quotes/profile-id profile-id (run! (partial create-invitation cfg)))
::quotes/team-id (:id team)
::quotes/incr (count emails)}))
(audit/submit! cfg (run! (partial quotes/check-quote! conn)
{::audit/type "action" (list {::quotes/id ::quotes/teams-per-profile
::audit/name "create-team" ::quotes/profile-id profile-id}
::audit/profile-id profile-id {::quotes/id ::quotes/invitations-per-team
::audit/props {:name name ::quotes/profile-id profile-id
:features features} ::quotes/team-id (:id team)
::audit/context context}) ::quotes/incr (count emails)}
{::quotes/id ::quotes/profiles-per-team
::quotes/profile-id profile-id
::quotes/team-id (:id team)
::quotes/incr (count emails)}))
(audit/submit! cfg (vary-meta team assoc ::audit/props {:invitations (count emails)})))))
{::audit/type "command"
::audit/name "create-team-invitations"
::audit/profile-id profile-id
::audit/props {:emails emails
:role role
:profile-id profile-id
:invitations (count emails)}})
(vary-meta team assoc ::audit/props {:invitations (count emails)}))))
;; --- Query: get-team-invitation-token ;; --- Query: get-team-invitation-token

View file

@ -169,19 +169,15 @@
;; if we have logged-in user and it matches the invitation we proceed ;; if we have logged-in user and it matches the invitation we proceed
;; with accepting the invitation and joining the current profile to the ;; with accepting the invitation and joining the current profile to the
;; invited team. ;; invited team.
(let [context (audit/params->context params) (let [props {:team-id (:team-id claims)
props {:team-id (:team-id claims) :role (:role claims)
:role (:role claims) :invitation-id (:id invitation)}
:invitation-id (:id invitation)}] event (-> (audit/event-from-rpc-params params)
(assoc ::audit/name "accept-team-invitation")
(assoc ::audit/props props))]
(accept-invitation cfg claims invitation profile) (accept-invitation cfg claims invitation profile)
(audit/submit! cfg (audit/submit! cfg event)
{::audit/type "action"
::audit/name "accept-team-invitation"
::audit/profile-id profile-id
::audit/props props
::audit/context context})
(assoc claims :state :created)) (assoc claims :state :created))
(ex/raise :type :validation (ex/raise :type :validation

View file

@ -51,12 +51,12 @@
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.config :as cf] [app.config :as cf]
[app.http :as-alias http] [app.http :as-alias http]
[app.loggers.audit :refer [parse-client-ip]]
[app.redis :as rds] [app.redis :as rds]
[app.redis.script :as-alias rscript] [app.redis.script :as-alias rscript]
[app.rpc :as-alias rpc] [app.rpc :as-alias rpc]
[app.rpc.helpers :as rph] [app.rpc.helpers :as rph]
[app.rpc.rlimit.result :as-alias lresult] [app.rpc.rlimit.result :as-alias lresult]
[app.util.inet :as inet]
[app.util.services :as-alias sv] [app.util.services :as-alias sv]
[app.util.time :as dt] [app.util.time :as dt]
[app.worker :as wrk] [app.worker :as wrk]
@ -215,7 +215,7 @@
[{:keys [::rpc/profile-id] :as params}] [{:keys [::rpc/profile-id] :as params}]
(let [request (-> params meta ::http/request)] (let [request (-> params meta ::http/request)]
(or profile-id (or profile-id
(some-> request parse-client-ip) (some-> request inet/parse-request)
uuid/zero))) uuid/zero)))
(defn process-request! (defn process-request!

View file

@ -0,0 +1,37 @@
;; 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.util.inet
"INET addr parsing and validation helpers"
(:require
[cuerdas.core :as str]
[ring.request :as rreq])
(:import
com.google.common.net.InetAddresses
java.net.InetAddress))
(defn valid?
[s]
(InetAddresses/isInetAddress s))
(defn normalize
[s]
(try
(let [addr (InetAddresses/forString s)]
(.getHostAddress ^InetAddress addr))
(catch Throwable _cause
nil)))
(defn parse-request
[request]
(or (some-> (rreq/get-header request "x-real-ip")
(normalize))
(some-> (rreq/get-header request "x-forwarded-for")
(str/split #"\s*,\s*")
(first)
(normalize))
(some-> (rreq/remote-addr request)
(normalize))))

View file

@ -11,7 +11,7 @@
[app.common.logging :as l] [app.common.logging :as l]
[app.common.transit :as t] [app.common.transit :as t]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
[app.loggers.audit :refer [parse-client-ip]] [app.util.inet :as inet]
[app.util.time :as dt] [app.util.time :as dt]
[promesa.exec :as px] [promesa.exec :as px]
[promesa.exec.csp :as sp] [promesa.exec.csp :as sp]
@ -84,7 +84,7 @@
output-ch (sp/chan :buf output-buff-size) output-ch (sp/chan :buf output-buff-size)
hbeat-ch (sp/chan :buf (sp/sliding-buffer 6)) hbeat-ch (sp/chan :buf (sp/sliding-buffer 6))
close-ch (sp/chan) close-ch (sp/chan)
ip-addr (parse-client-ip request) ip-addr (inet/parse-request request)
uagent (rreq/get-header request "user-agent") uagent (rreq/get-header request "user-agent")
id (uuid/next) id (uuid/next)
state (atom {}) state (atom {})

View file

@ -28,7 +28,8 @@
ring.request/Request ring.request/Request
(get-header [_ name] (get-header [_ name]
(case name (case name
"x-forwarded-for" "127.0.0.44")))) "x-forwarded-for" "127.0.0.44"
"x-real-ip" "127.0.0.43"))))
(t/deftest push-events-1 (t/deftest push-events-1
(with-redefs [app.config/flags #{:audit-log}] (with-redefs [app.config/flags #{:audit-log}]
@ -46,6 +47,7 @@
:profile-id (:id prof) :profile-id (:id prof)
:timestamp (dt/now) :timestamp (dt/now)
:type "action"}]} :type "action"}]}
params (with-meta params params (with-meta params
{:app.http/request http-request}) {:app.http/request http-request})

View file

@ -6,4 +6,4 @@
(ns app.common.files.defaults) (ns app.common.files.defaults)
(def version 50) (def version 51)

View file

@ -22,6 +22,7 @@
[app.common.schema :as sm] [app.common.schema :as sm]
[app.common.svg :as csvg] [app.common.svg :as csvg]
[app.common.text :as txt] [app.common.text :as txt]
[app.common.types.color :as ctc]
[app.common.types.component :as ctk] [app.common.types.component :as ctk]
[app.common.types.file :as ctf] [app.common.types.file :as ctf]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
@ -1004,6 +1005,17 @@
(update :pages-index update-vals update-container) (update :pages-index update-vals update-container)
(update :components update-vals update-container)))) (update :components update-vals update-container))))
(def ^:private valid-color?
(sm/lazy-validator ::ctc/color))
(defn migrate-up-51
"This migration fixes library invalid colors"
[data]
(let [update-colors
(fn [colors]
(into {} (filter #(-> % val valid-color?) colors)))]
(update data :colors update-colors)))
(def migrations (def migrations
"A vector of all applicable migrations" "A vector of all applicable migrations"
@ -1046,4 +1058,5 @@
{:id 47 :migrate-up migrate-up-47} {:id 47 :migrate-up migrate-up-47}
{:id 48 :migrate-up migrate-up-48} {:id 48 :migrate-up migrate-up-48}
{:id 49 :migrate-up migrate-up-49} {:id 49 :migrate-up migrate-up-49}
{:id 50 :migrate-up migrate-up-50}]) {:id 50 :migrate-up migrate-up-50}
{:id 51 :migrate-up migrate-up-51}])

View file

@ -299,19 +299,7 @@
(ptk/reify ::libraries-fetched (ptk/reify ::libraries-fetched
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [templates-a-b-test? (cf/external-feature-flag "dashboard-01" "test") (assoc state :builtin-templates libraries))))
remove-ids (if templates-a-b-test?
#{"wireframing-kit" "prototype-examples" "plants-app" "penpot-design-system"}
#{"prototype-examples" "penpot-design-system"})
libraries (cond->> libraries
:always
(remove #(contains? remove-ids (:id %)))
templates-a-b-test?
(concat [{:id "wireframing-kit", :name "Wireframe library"}
{:id "prototype-examples", :name "Prototype template"}
{:id "plants-app", :name "UI mockup example"}
{:id "penpot-design-system", :name "Design system example"}]))]
(assoc state :builtin-templates libraries)))))
(defn fetch-builtin-templates (defn fetch-builtin-templates
[] []

View file

@ -403,9 +403,9 @@
(mf/with-memo [] (mf/with-memo []
(-> (shuffle [{:label (tr "labels.youtube") :value "youtube"} (-> (shuffle [{:label (tr "labels.youtube") :value "youtube"}
{:label (tr "labels.event") :value "event"} {:label (tr "labels.event") :value "event"}
{:label (tr "labels.search") :value "search"} {:label (tr "onboarding.questions.referer.search") :value "search"}
{:label (tr "labels.social") :value "social"} {:label (tr "onboarding.questions.referer.social") :value "social"}
{:label (tr "labels.article") :value "article"}]) {:label (tr "onboarding.questions.referer.article") :value "article"}])
(conj {:label (tr "labels.other-short") :value "other"}))) (conj {:label (tr "labels.other-short") :value "other"})))
current-referer current-referer

View file

@ -264,8 +264,10 @@
multi-colors? multi-assets? on-asset-click on-assets-delete multi-colors? multi-assets? on-asset-click on-assets-delete
on-clear-selection on-group on-rename-group on-ungroup colors on-clear-selection on-group on-rename-group on-ungroup colors
selected-full]}] selected-full]}]
(let [group-open? (or ^boolean force-open? (let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
^boolean (get open-groups prefix (if (= prefix "") true false))) false
(or ^boolean force-open?
^boolean (get open-groups prefix (if (= prefix "") true false))))
dragging* (mf/use-state false) dragging* (mf/use-state false)
dragging? (deref dragging*) dragging? (deref dragging*)

View file

@ -128,7 +128,9 @@
[{:keys [file-id prefix groups open-groups force-open? file local? selected local-data [{:keys [file-id prefix groups open-groups force-open? file local? selected local-data
editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group editing-id renaming-id on-asset-click handle-change apply-typography on-rename-group
on-ungroup on-context-menu selected-full]}] on-ungroup on-context-menu selected-full]}]
(let [group-open? (get open-groups prefix true) (let [group-open? (if (false? (get open-groups prefix)) ;; if the user has closed it specifically, respect that
false
(get open-groups prefix true))
dragging* (mf/use-state false) dragging* (mf/use-state false)
dragging? (deref dragging*) dragging? (deref dragging*)
selected-paths (mf/with-memo [selected-full] selected-paths (mf/with-memo [selected-full]

View file

@ -2581,15 +2581,15 @@ msgid "labels.event"
msgstr "Event" msgstr "Event"
#: src/app/main/ui/onboarding/questions.cljs #: src/app/main/ui/onboarding/questions.cljs
msgid "labels.search" msgid "onboarding.questions.referer.search"
msgstr "Search Engine (Google, Yahoo, Bing)" msgstr "Search Engine (Google, Yahoo, Bing)"
#: src/app/main/ui/onboarding/questions.cljs #: src/app/main/ui/onboarding/questions.cljs
msgid "labels.social" msgid "onboarding.questions.referer.social"
msgstr "Social Media (X, Linkedin, FB, etc)" msgstr "Social Media (X, Linkedin, FB, etc)"
#: src/app/main/ui/onboarding/questions.cljs #: src/app/main/ui/onboarding/questions.cljs
msgid "labels.article" msgid "onboarding.questions.referer.article"
msgstr "Article (Blog, Post, Newsletter)" msgstr "Article (Blog, Post, Newsletter)"
#: src/app/main/ui/onboarding/questions.cljs #: src/app/main/ui/onboarding/questions.cljs