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

This commit is contained in:
Andrey Antukh 2025-02-20 09:15:00 +01:00
commit 60530a80d9
30 changed files with 191 additions and 182 deletions

View file

@ -67,6 +67,7 @@ is a number of cores)
### :bug: Bugs fixed ### :bug: Bugs fixed
- Fix menu shadow color [Taiga #10102](https://tree.taiga.io/project/penpot/issue/10102) - Fix menu shadow color [Taiga #10102](https://tree.taiga.io/project/penpot/issue/10102)
- Fix missing state refresh on notifications update [Taiga #10253](https://tree.taiga.io/project/penpot/issue/10253)
- Fix icon visualization on select component [Taiga #8889](https://tree.taiga.io/project/penpot/issue/8889) - Fix icon visualization on select component [Taiga #8889](https://tree.taiga.io/project/penpot/issue/8889)
- Fix typo on integration tests docs [Taiga #10112](https://tree.taiga.io/project/penpot/issue/10112) - Fix typo on integration tests docs [Taiga #10112](https://tree.taiga.io/project/penpot/issue/10112)
- Fix problem with alt key measures being stuck [Taiga #9348](https://tree.taiga.io/project/penpot/issue/9348) - Fix problem with alt key measures being stuck [Taiga #9348](https://tree.taiga.io/project/penpot/issue/9348)

View file

@ -9,7 +9,6 @@
binfile format implementations and management rpc methods." binfile format implementations and management rpc methods."
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.features :as cfeat] [app.common.features :as cfeat]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
@ -219,10 +218,8 @@
"Given a set of file-id's, return all matching relations with the libraries" "Given a set of file-id's, return all matching relations with the libraries"
[cfg ids] [cfg ids]
(dm/assert! (assert (set? ids) "expected a set of uuids")
"expected a set of uuids" (assert (every? uuid? ids) "expected a set of uuids")
(and (set? ids)
(every? uuid? ids)))
(db/run! cfg (fn [{:keys [::db/conn]}] (db/run! cfg (fn [{:keys [::db/conn]}]
(let [ids (db/create-array conn "uuid" ids) (let [ids (db/create-array conn "uuid" ids)
@ -503,9 +500,7 @@
specific, should not be used outside of binfile domain" specific, should not be used outside of binfile domain"
[{:keys [::timestamp] :as cfg} file & {:as opts}] [{:keys [::timestamp] :as cfg} file & {:as opts}]
(dm/assert! (assert (dt/instant? timestamp) "expected valid timestamp")
"expected valid timestamp"
(dt/instant? timestamp))
(let [file (-> file (let [file (-> file
(assoc :created-at timestamp) (assoc :created-at timestamp)
@ -513,12 +508,11 @@
(assoc :ignore-sync-until (dt/plus timestamp (dt/duration {:seconds 5}))) (assoc :ignore-sync-until (dt/plus timestamp (dt/duration {:seconds 5})))
(update :features (update :features
(fn [features] (fn [features]
(let [features (cfeat/check-supported-features! features)]
(-> (::features cfg #{}) (-> (::features cfg #{})
(set/union features) (set/union features)
;; We never want to store ;; We never want to store
;; frontend-only features on file ;; frontend-only features on file
(set/difference cfeat/frontend-only-features))))))] (set/difference cfeat/frontend-only-features)))))]
(when (contains? cf/flags :file-schema-validation) (when (contains? cf/flags :file-schema-validation)
(fval/validate-file-schema! file)) (fval/validate-file-schema! file))
@ -542,7 +536,6 @@
file) file)
(defn apply-pending-migrations! (defn apply-pending-migrations!
"Apply alredy registered pending migrations to files" "Apply alredy registered pending migrations to files"
[cfg] [cfg]

View file

@ -875,14 +875,17 @@
:manifest manifest)) :manifest manifest))
;; Check if all files referenced on manifest are present ;; Check if all files referenced on manifest are present
(doseq [{file-id :id} (:files manifest)] (doseq [{file-id :id features :features} (:files manifest)]
(let [path (str "files/" file-id ".json")] (let [path (str "files/" file-id ".json")]
(when-not (get-zip-entry input path) (when-not (get-zip-entry input path)
(ex/raise :type :validation (ex/raise :type :validation
:code :invalid-binfile-v3 :code :invalid-binfile-v3
:hint "some files referenced on manifest not found" :hint "some files referenced on manifest not found"
:path path :path path
:file-id file-id)))) :file-id file-id))
(cfeat/check-supported-features! features)))
(events/tap :progress {:section :manifest}) (events/tap :progress {:section :manifest})

View file

@ -12,6 +12,7 @@
[app.binfile.v3 :as bf.v3] [app.binfile.v3 :as bf.v3]
[app.common.data :as d] [app.common.data :as d]
[app.common.exceptions :as ex] [app.common.exceptions :as ex]
[app.common.features :as cfeat]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.pprint :as pp] [app.common.pprint :as pp]
[app.common.uuid :as uuid] [app.common.uuid :as uuid]
@ -21,6 +22,7 @@
[app.rpc.commands.auth :as auth] [app.rpc.commands.auth :as auth]
[app.rpc.commands.files-create :refer [create-file]] [app.rpc.commands.files-create :refer [create-file]]
[app.rpc.commands.profile :as profile] [app.rpc.commands.profile :as profile]
[app.rpc.commands.teams :as teams]
[app.setup :as-alias setup] [app.setup :as-alias setup]
[app.srepl.helpers :as srepl] [app.srepl.helpers :as srepl]
[app.storage :as-alias sto] [app.storage :as-alias sto]
@ -317,7 +319,10 @@
:hint "missing upload file")) :hint "missing upload file"))
(let [profile (profile/get-profile pool profile-id) (let [profile (profile/get-profile pool profile-id)
project-id (:default-project-id profile)] project-id (:default-project-id profile)
team (teams/get-team pool
:profile-id profile-id
:project-id project-id)]
(when-not project-id (when-not project-id
(ex/raise :type :validation (ex/raise :type :validation
@ -329,7 +334,8 @@
cfg (assoc cfg cfg (assoc cfg
::bfc/profile-id profile-id ::bfc/profile-id profile-id
::bfc/project-id project-id ::bfc/project-id project-id
::bfc/input path)] ::bfc/input path
::bfc/features (cfeat/get-team-enabled-features cf/flags team))]
(if (= format :binfile-v3) (if (= format :binfile-v3)
(bf.v3/import-files! cfg) (bf.v3/import-files! cfg)

View file

@ -10,8 +10,10 @@
[app.binfile.common :as bfc] [app.binfile.common :as bfc]
[app.binfile.v1 :as bf.v1] [app.binfile.v1 :as bf.v1]
[app.binfile.v3 :as bf.v3] [app.binfile.v3 :as bf.v3]
[app.common.features :as cfeat]
[app.common.logging :as l] [app.common.logging :as l]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.config :as cf]
[app.db :as db] [app.db :as db]
[app.http.sse :as sse] [app.http.sse :as sse]
[app.loggers.audit :as-alias audit] [app.loggers.audit :as-alias audit]
@ -20,6 +22,7 @@
[app.rpc :as-alias rpc] [app.rpc :as-alias rpc]
[app.rpc.commands.files :as files] [app.rpc.commands.files :as files]
[app.rpc.commands.projects :as projects] [app.rpc.commands.projects :as projects]
[app.rpc.commands.teams :as teams]
[app.rpc.doc :as-alias doc] [app.rpc.doc :as-alias doc]
[app.tasks.file-gc] [app.tasks.file-gc]
[app.util.services :as sv] [app.util.services :as sv]
@ -91,41 +94,30 @@
;; --- Command: import-binfile ;; --- Command: import-binfile
(defn- import-binfile-v1
[{:keys [::wrk/executor] :as cfg} {:keys [project-id profile-id name file]}]
(let [cfg (-> cfg
(assoc ::bfc/project-id project-id)
(assoc ::bfc/profile-id profile-id)
(assoc ::bfc/name name)
(assoc ::bfc/input (:path file)))]
;; NOTE: the importation process performs some operations that are
;; not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we dispatch
;; that operation to a dedicated executor.
(px/invoke! executor (partial bf.v1/import-files! cfg))))
(defn- import-binfile-v3
[{:keys [::wrk/executor] :as cfg} {:keys [project-id profile-id name file]}]
(let [cfg (-> cfg
(assoc ::bfc/project-id project-id)
(assoc ::bfc/profile-id profile-id)
(assoc ::bfc/name name)
(assoc ::bfc/input (:path file)))]
;; NOTE: the importation process performs some operations that are
;; not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we dispatch
;; that operation to a dedicated executor.
(px/invoke! executor (partial bf.v3/import-files! cfg))))
(defn- import-binfile (defn- import-binfile
[{:keys [::db/pool] :as cfg} {:keys [project-id version] :as params}] [{:keys [::db/pool ::wrk/executor] :as cfg} {:keys [profile-id project-id version name file]}]
(let [result (case (int version) (let [team (teams/get-team pool
1 (import-binfile-v1 cfg params) :profile-id profile-id
3 (import-binfile-v3 cfg params))] :project-id project-id)
cfg (-> cfg
(assoc ::bfc/features (cfeat/get-team-enabled-features cf/flags team))
(assoc ::bfc/project-id project-id)
(assoc ::bfc/profile-id profile-id)
(assoc ::bfc/name name)
(assoc ::bfc/input (:path file)))
;; NOTE: the importation process performs some operations that are
;; not very friendly with virtual threads, and for avoid
;; unexpected blocking of other concurrent operations we dispatch
;; that operation to a dedicated executor.
result (case (int version)
1 (px/invoke! executor (partial bf.v1/import-files! cfg))
3 (px/invoke! executor (partial bf.v3/import-files! cfg)))]
(db/update! pool :project (db/update! pool :project
{:modified-at (dt/now)} {:modified-at (dt/now)}
{:id project-id}) {:id project-id})
result)) result))
(def ^:private schema:import-binfile (def ^:private schema:import-binfile

View file

@ -406,12 +406,16 @@
:prefix "penpot.template." :prefix "penpot.template."
:suffix "" :suffix ""
:min-age "30m") :min-age "30m")
format (bfc/parse-file-format template)
format (bfc/parse-file-format template)
team (teams/get-team conn
:profile-id profile-id
:project-id project-id)
cfg (-> cfg cfg (-> cfg
(assoc ::bfc/project-id project-id) (assoc ::bfc/project-id project-id)
(assoc ::bfc/profile-id profile-id) (assoc ::bfc/profile-id profile-id)
(assoc ::bfc/input template)) (assoc ::bfc/input template)
(assoc ::bfc/features (cfeat/get-team-enabled-features cf/flags team)))
result (if (= format :binfile-v3) result (if (= format :binfile-v3)
(px/invoke! executor (partial bf.v3/import-files! cfg)) (px/invoke! executor (partial bf.v3/import-files! cfg))

View file

@ -14,11 +14,12 @@
[app.config :as cf] [app.config :as cf]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.media :as di] [app.main.data.media :as di]
[app.main.data.notifications :as ntf]
[app.main.data.team :as-alias dtm] [app.main.data.team :as-alias dtm]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.router :as rt] [app.main.router :as rt]
[app.plugins.register :as plugins.register] [app.plugins.register :as plugins.register]
[app.util.i18n :as i18n] [app.util.i18n :as i18n :refer [tr]]
[app.util.storage :as storage] [app.util.storage :as storage]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
@ -239,25 +240,24 @@
[:email-comments [::sm/one-of #{:all :partial :none}]] [:email-comments [::sm/one-of #{:all :partial :none}]]
[:email-invites [::sm/one-of #{:all :none}]]]) [:email-invites [::sm/one-of #{:all :none}]]])
(def ^:private check-update-notifications-params
(sm/check-fn schema:update-notifications))
(defn update-notifications (defn update-notifications
[data] [data]
(dm/assert! (assert (check-update-notifications-params data))
"expected valid parameters"
(sm/check schema:update-notifications data))
(ptk/reify ::update-notifications (ptk/reify ::update-notifications
ev/Event ev/Event
(-data [_] {}) (-data [_] {})
ptk/UpdateEvent
(update [_ state]
(update-in state [:profile :props] assoc :notifications data))
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ _] (watch [_ _ _]
(let [{:keys [on-error on-success]
:or {on-error identity
on-success identity}} (meta data)]
(->> (rp/cmd! :update-profile-notifications data) (->> (rp/cmd! :update-profile-notifications data)
(rx/tap on-success) (rx/map #(ntf/success (tr "dashboard.notifications.notifications-saved")))))))
(rx/catch #(do (on-error %) (rx/empty)))
(rx/ignore))))))
(defn update-profile-props (defn update-profile-props
[props] [props]

View file

@ -168,11 +168,13 @@
(assoc file :data (d/removem (comp t/pointer? val) data)))))))))) (assoc file :data (d/removem (comp t/pointer? val) data))))))))))
(defn- libraries-fetched (defn- libraries-fetched
[libraries] [file-id libraries]
(ptk/reify ::libraries-fetched (ptk/reify ::libraries-fetched
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [libraries (d/index-by :id libraries)] (let [libraries (->> libraries
(map (fn [l] (assoc l :library-of file-id)))
(d/index-by :id))]
(update state :files merge libraries))) (update state :files merge libraries)))
ptk/WatchEvent ptk/WatchEvent
@ -208,7 +210,7 @@
(rx/map #(assoc % :synced-at synced-at))))) (rx/map #(assoc % :synced-at synced-at)))))
(rx/merge-map resolve-file) (rx/merge-map resolve-file)
(rx/reduce conj []) (rx/reduce conj [])
(rx/map libraries-fetched)) (rx/map (partial libraries-fetched file-id)))
(->> (rx/from libraries) (->> (rx/from libraries)
(rx/map :id) (rx/map :id)
(rx/mapcat (fn [file-id] (rx/mapcat (fn [file-id]

View file

@ -1203,7 +1203,7 @@
(vals (get state :files))) (vals (get state :files)))
do-more-info do-more-info
#(modal/show! :libraries-dialog {:starting-tab "updates"}) #(modal/show! :libraries-dialog {:starting-tab "updates" :file-id file-id})
do-update do-update
#(do (apply st/emit! (map (fn [library] #(do (apply st/emit! (map (fn [library]
@ -1390,7 +1390,10 @@
(let [libraries (:workspace-shared-files state) (let [libraries (:workspace-shared-files state)
library (d/seek #(= (:id %) library-id) libraries)] library (d/seek #(= (:id %) library-id) libraries)]
(if library (if library
(update state :files assoc library-id (dissoc library :library-summary)) (update state :files assoc library-id
(-> library
(dissoc :library-summary)
(assoc :library-of file-id)))
state))) state)))
ptk/WatchEvent ptk/WatchEvent
@ -1403,6 +1406,8 @@
(->> (rp/cmd! :get-file {:id library-id :features features}) (->> (rp/cmd! :get-file {:id library-id :features features})
(rx/merge-map fpmap/resolve-file) (rx/merge-map fpmap/resolve-file)
;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event ;; FIXME: this should call the libraries-fetched event instead of ad-hoc assoc event
(rx/map (fn [file]
(assoc file :library-of file-id)))
(rx/map (fn [file] (rx/map (fn [file]
(fn [state] (fn [state]
(assoc-in state [:files library-id] file))))) (assoc-in state [:files library-id] file)))))

View file

@ -83,10 +83,32 @@
files (without the content, only summary)" files (without the content, only summary)"
(l/derived :shared-files st/state)) (l/derived :shared-files st/state))
(defn select-libraries
[files file-id]
(persistent!
(reduce-kv (fn [result id file]
(if (or (= id file-id)
(= (:library-of file) file-id))
(assoc! result id file)
result))
(transient {})
files)))
;; NOTE: for performance reasons, prefer derefing refs/files and then
;; use with-memo mechanism with `select-libraries` this will avoid
;; executing the select-libraries reduce-kv on each state change and
;; only execute it when files are changed. This ref exists for
;; backward compatibility with the code, but it is considered
;; DEPRECATED and all new code should not use it and old code should
;; be gradually migrated to more efficient approach
(def libraries (def libraries
"A derived state that contanins the currently loaded shared libraries "A derived state that contanins the currently loaded shared
with all its content; including the current file" libraries with all its content; including the current file"
(l/derived :files st/state)) (l/derived (fn [state]
(let [files (get state :files)
file-id (get state :current-file-id)]
(select-libraries files file-id)))
st/state))
(defn extract-selected-files (defn extract-selected-files
[files selected] [files selected]

View file

@ -56,10 +56,12 @@
(make-typographies-library-ref (:typography-ref-file style))) (make-typographies-library-ref (:typography-ref-file style)))
typography-library (mf/deref typography-library-ref) typography-library (mf/deref typography-library-ref)
;; FIXME: too many duplicate operations
file-typographies-viewer (mf/deref file-typographies-ref) file-typographies-viewer (mf/deref file-typographies-ref)
file-typographies-workspace (mf/deref refs/workspace-file-typography) file-typographies-workspace (mf/deref refs/workspace-file-typography)
file-library-workspace (get (mf/deref refs/libraries) (:typography-ref-file style)) file-library-workspace (get (mf/deref refs/files) (:typography-ref-file style))
typography-external-lib (get-in file-library-workspace [:data :typographies (:typography-ref-id style)]) typography-external-lib (get-in file-library-workspace [:data :typographies (:typography-ref-id style)])
color-format (mf/use-state :hex) color-format (mf/use-state :hex)

View file

@ -26,12 +26,7 @@
"Retrieve all libraries, including the local file, on workspace or viewer" "Retrieve all libraries, including the local file, on workspace or viewer"
[from] [from]
(if (= from :workspace) (if (= from :workspace)
(let [workspace-data (deref refs/workspace-data) (deref refs/libraries)
{:keys [id] :as local} workspace-data
libraries (deref refs/libraries)]
(-> libraries
(assoc id {:id id
:data local})))
(let [viewer-data (deref refs/viewer-data) (let [viewer-data (deref refs/viewer-data)
local (get-in viewer-data [:file :data]) local (get-in viewer-data [:file :data])
id (get local :id) id (get local :id)

View file

@ -17,7 +17,7 @@
[app.main.ui.settings.change-email] [app.main.ui.settings.change-email]
[app.main.ui.settings.delete-account] [app.main.ui.settings.delete-account]
[app.main.ui.settings.feedback :refer [feedback-page]] [app.main.ui.settings.feedback :refer [feedback-page]]
[app.main.ui.settings.notifications :refer [notifications-page]] [app.main.ui.settings.notifications :refer [notifications-page*]]
[app.main.ui.settings.options :refer [options-page]] [app.main.ui.settings.options :refer [options-page]]
[app.main.ui.settings.password :refer [password-page]] [app.main.ui.settings.password :refer [password-page]]
[app.main.ui.settings.profile :refer [profile-page]] [app.main.ui.settings.profile :refer [profile-page]]
@ -71,4 +71,4 @@
[:& access-tokens-page] [:& access-tokens-page]
:settings-notifications :settings-notifications
[:& notifications-page])]]]])) [:& notifications-page* {:profile profile}])]]]]))

View file

@ -9,14 +9,11 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.schema :as sm] [app.common.schema :as sm]
[app.main.data.notifications :as ntf]
[app.main.data.profile :as dp] [app.main.data.profile :as dp]
[app.main.refs :as refs]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.components.forms :as fm] [app.main.ui.components.forms :as fm]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def default-notification-settings (def default-notification-settings
@ -24,29 +21,9 @@
:email-comments :partial :email-comments :partial
:email-invites :all}) :email-invites :all})
(def notification-settings-ref
(l/derived
(fn [profile]
(-> (merge default-notification-settings
(-> profile :props :notifications))
(d/update-vals d/name)))
refs/profile))
(defn- on-error
[form _]
(reset! form nil)
(st/emit! (ntf/error (tr "generic.error"))))
(defn- on-success
[_]
(st/emit! (ntf/success (tr "dashboard.notifications.notifications-saved"))))
(defn- on-submit (defn- on-submit
[form event] [form _event]
(dom/prevent-default event) (let [params (:clean-data @form)]
(let [params (with-meta (:clean-data @form)
{:on-success (partial on-success form)
:on-error (partial on-error form)})]
(st/emit! (dp/update-notifications params)))) (st/emit! (dp/update-notifications params))))
(def ^:private schema:notifications-form (def ^:private schema:notifications-form
@ -55,11 +32,15 @@
[:email-comments [::sm/one-of #{:all :partial :none}]] [:email-comments [::sm/one-of #{:all :partial :none}]]
[:email-invites [::sm/one-of #{:all :partial :none}]]]) [:email-invites [::sm/one-of #{:all :partial :none}]]])
(mf/defc notifications-page (mf/defc notifications-page*
[] [{:keys [profile]}]
(let [settings (mf/deref notification-settings-ref) (let [settings (mf/with-memo [profile]
(-> (merge default-notification-settings
(-> profile :props :notifications))
(update-vals d/name)))
form (fm/use-form :schema schema:notifications-form form (fm/use-form :schema schema:notifications-form
:initial settings)] :initial settings)]
(mf/with-effect [] (mf/with-effect []
(dom/set-html-title (tr "title.settings.notifications"))) (dom/set-html-title (tr "title.settings.notifications")))

View file

@ -166,9 +166,9 @@
(defn- make-library-colors-ref (defn- make-library-colors-ref
[file-id] [file-id]
(l/derived (fn [libraries] (l/derived (fn [files]
(dm/get-in libraries [file-id :data :colors])) (dm/get-in files [file-id :data :colors]))
refs/libraries)) refs/files))
(mf/defc file-color-palette* (mf/defc file-color-palette*
{::mf/private true} {::mf/private true}

View file

@ -48,7 +48,7 @@
{:value "file" :label (tr "workspace.libraries.colors.file-library")}]) {:value "file" :label (tr "workspace.libraries.colors.file-library")}])
options options
(mf/with-memo [library-options file-id] (mf/with-memo [library-options libraries file-id]
(into library-options (into library-options
(comp (comp
(map val) (map val)

View file

@ -248,10 +248,12 @@
(mf/use-fn (mf/use-fn
(mf/deps file-id) (mf/deps file-id)
#(st/emit! (dwl/set-file-shared file-id false) #(st/emit! (dwl/set-file-shared file-id false)
(modal/show :libraries-dialog {}))) (modal/show :libraries-dialog {:file-id file-id})))
on-delete-cancel on-delete-cancel
(mf/use-fn #(st/emit! (modal/show :libraries-dialog {}))) (mf/use-fn
(mf/deps file-id)
#(st/emit! (modal/show :libraries-dialog {:file-id file-id})))
publish publish
(mf/use-fn (mf/use-fn
@ -259,7 +261,7 @@
(fn [event] (fn [event]
(let [input-node (dom/get-target event) (let [input-node (dom/get-target event)
publish-library #(st/emit! (dwl/set-file-shared file-id true)) publish-library #(st/emit! (dwl/set-file-shared file-id true))
cancel-publish #(st/emit! (modal/show :libraries-dialog {}))] cancel-publish #(st/emit! (modal/show :libraries-dialog {:file-id file-id}))]
(if empty-library? (if empty-library?
(st/emit! (modal/show (st/emit! (modal/show
{:type :confirm {:type :confirm
@ -563,17 +565,15 @@
(mf/defc libraries-dialog (mf/defc libraries-dialog
{::mf/register modal/components {::mf/register modal/components
::mf/register-as :libraries-dialog} ::mf/register-as :libraries-dialog}
[{:keys [starting-tab] :as props :or {starting-tab :libraries}}] [{:keys [starting-tab file-id] :as props :or {starting-tab :libraries}}]
(let [;; NOTE: we don't want to react on file changes, we just want (let [files (mf/deref refs/files)
;; a snapshot of file on the momento of open the dialog file (get files file-id)
file (deref refs/file)
file-id (:id file)
team-id (:team-id file) team-id (:team-id file)
shared? (:is-shared file) shared? (:is-shared file)
linked-libraries linked-libraries
(mf/deref refs/files) (mf/with-memo [files file-id]
(refs/select-libraries files file-id))
linked-libraries linked-libraries
(mf/with-memo [linked-libraries file-id] (mf/with-memo [linked-libraries file-id]

View file

@ -56,6 +56,7 @@
[{:keys [layout file page-id] :as props}] [{:keys [layout file page-id] :as props}]
(let [options-mode (mf/deref refs/options-mode-global) (let [options-mode (mf/deref refs/options-mode-global)
project (mf/deref refs/project) project (mf/deref refs/project)
file-id (get file :id)
design-tokens? (features/use-feature "design-tokens/v1") design-tokens? (features/use-feature "design-tokens/v1")
mode-inspect? (= options-mode :inspect) mode-inspect? (= options-mode :inspect)
@ -116,7 +117,7 @@
assets-tab assets-tab
(mf/html [:& assets-toolbox {:size (- size 58) :file-id file}]) (mf/html [:& assets-toolbox {:size (- size 58) :file-id file-id}])
tokens-tab tokens-tab
(when design-tokens? (when design-tokens?

View file

@ -33,10 +33,10 @@
::mf/private true} ::mf/private true}
[{:keys [filters]}] [{:keys [filters]}]
(let [file-id (mf/use-ctx ctx/current-file-id) (let [file-id (mf/use-ctx ctx/current-file-id)
files (mf/deref refs/files)
libraries (mf/deref refs/libraries) libraries (mf/with-memo [files file-id]
libraries (mf/with-memo [libraries file-id] (->> (refs/select-libraries files file-id)
(->> (vals libraries) (vals)
(remove :is-indirect) (remove :is-indirect)
(remove #(= file-id (:id %))) (remove #(= file-id (:id %)))
(map (fn [file] (map (fn [file]
@ -129,8 +129,9 @@
show-libraries-dialog show-libraries-dialog
(mf/use-fn (mf/use-fn
(mf/deps file-id)
(fn [] (fn []
(modal/show! :libraries-dialog {}) (modal/show! :libraries-dialog {:file-id file-id})
(modal/allow-click-outside!))) (modal/allow-click-outside!)))
on-open-menu on-open-menu

View file

@ -323,7 +323,7 @@
current-file-id (mf/use-ctx ctx/current-file-id) current-file-id (mf/use-ctx ctx/current-file-id)
current-page-id (mf/use-ctx ctx/current-page-id) current-page-id (mf/use-ctx ctx/current-page-id)
libraries (deref refs/libraries) libraries (deref refs/files)
current-file (get libraries current-file-id) current-file (get libraries current-file-id)
objects (-> (dsh/get-page (:data current-file) current-page-id) objects (-> (dsh/get-page (:data current-file) current-page-id)

View file

@ -44,7 +44,7 @@
(defn- get-component-root-and-container (defn- get-component-root-and-container
[file-id component] [file-id component]
(let [data (dm/get-in @refs/libraries [file-id :data]) (let [data (dm/get-in @refs/files [file-id :data])
root-shape (ctf/get-component-root data component) root-shape (ctf/get-component-root data component)
container (ctf/get-component-page data component)] container (ctf/get-component-page data component)]
[root-shape container])) [root-shape container]))
@ -453,7 +453,7 @@
(fn [component event] (fn [component event]
(let [file-data (let [file-data
(dm/get-in @refs/libraries [file-id :data]) (dm/get-in @refs/files [file-id :data])
shape-main shape-main
(ctf/get-component-root file-data component)] (ctf/get-component-root file-data component)]

View file

@ -44,7 +44,7 @@
(mf/defc shape-options* (mf/defc shape-options*
{::mf/wrap [#(mf/throttle % 60)]} {::mf/wrap [#(mf/throttle % 60)]}
[{:keys [shape shapes-with-children page-id file-id shared-libs] :as props}] [{:keys [shape shapes-with-children page-id file-id libraries] :as props}]
(let [shape-type (dm/get-prop shape :type) (let [shape-type (dm/get-prop shape :type)
shape-id (dm/get-prop shape :id) shape-id (dm/get-prop shape :id)
@ -56,8 +56,8 @@
[:* [:*
(case shape-type (case shape-type
:frame [:> frame/options* props] :frame [:> frame/options* props]
:group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :shared-libs shared-libs}] :group [:& group/options {:shape shape :shape-with-children shapes-with-children :file-id file-id :libraries libraries}]
:text [:& text/options {:shape shape :file-id file-id :shared-libs shared-libs}] :text [:& text/options {:shape shape :file-id file-id :libraries libraries}]
:rect [:& rect/options {:shape shape}] :rect [:& rect/options {:shape shape}]
:circle [:& circle/options {:shape shape}] :circle [:& circle/options {:shape shape}]
:path [:& path/options {:shape shape}] :path [:& path/options {:shape shape}]
@ -83,7 +83,7 @@
[{:keys [selected objects page-id file-id selected-shapes shapes-with-children]}] [{:keys [selected objects page-id file-id selected-shapes shapes-with-children]}]
(let [sp-panel (mf/deref refs/specialized-panel) (let [sp-panel (mf/deref refs/specialized-panel)
drawing (mf/deref refs/workspace-drawing) drawing (mf/deref refs/workspace-drawing)
shared-libs (mf/deref refs/libraries) libraries (mf/deref refs/libraries)
edition (mf/deref refs/selected-edition) edition (mf/deref refs/selected-edition)
edit-grid? (ctl/grid-layout? objects edition) edit-grid? (ctl/grid-layout? objects edition)
grid-edition (mf/deref refs/workspace-grid-edition) grid-edition (mf/deref refs/workspace-grid-edition)
@ -113,7 +113,7 @@
{:shape (:object drawing) {:shape (:object drawing)
:page-id page-id :page-id page-id
:file-id file-id :file-id file-id
:shared-libs shared-libs}] :libraries libraries}]
(= 0 (count selected)) (= 0 (count selected))
[:> page/options*] [:> page/options*]
@ -123,7 +123,7 @@
{:shape (first selected-shapes) {:shape (first selected-shapes)
:page-id page-id :page-id page-id
:file-id file-id :file-id file-id
:shared-libs shared-libs :libraries libraries
:shapes-with-children shapes-with-children}] :shapes-with-children shapes-with-children}]
:else :else
@ -132,7 +132,7 @@
:shapes selected-shapes :shapes selected-shapes
:page-id page-id :page-id page-id
:file-id file-id :file-id file-id
:shared-libs shared-libs}])])) :libraries libraries}])]))
(mf/defc options-content* (mf/defc options-content*
{::mf/memo true {::mf/memo true

View file

@ -19,8 +19,8 @@
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn- prepare-colors (defn- prepare-colors
[shapes file-id shared-libs] [shapes file-id libraries]
(let [data (into [] (remove nil? (ctc/extract-all-colors shapes file-id shared-libs))) (let [data (into [] (remove nil? (ctc/extract-all-colors shapes file-id libraries)))
groups (d/group-by :attrs #(dissoc % :attrs) data) groups (d/group-by :attrs #(dissoc % :attrs) data)
all-colors (distinct (mapv :attrs data)) all-colors (distinct (mapv :attrs data))

View file

@ -373,7 +373,8 @@
(let [single? (= 1 (count shapes)) (let [single? (= 1 (count shapes))
shape (first shapes) shape (first shapes)
current-file-id (mf/use-ctx ctx/current-file-id) current-file-id (mf/use-ctx ctx/current-file-id)
libraries (mf/deref refs/files)
libraries (mf/deref refs/libraries)
objects (mf/deref refs/workspace-page-objects) objects (mf/deref refs/workspace-page-objects)
^boolean ^boolean
@ -594,9 +595,9 @@
(let [current-file-id (mf/use-ctx ctx/current-file-id) (let [current-file-id (mf/use-ctx ctx/current-file-id)
current-page-id (mf/use-ctx ctx/current-page-id) current-page-id (mf/use-ctx ctx/current-page-id)
libraries (deref refs/libraries) libraries (deref refs/files)
current-file (get libraries current-file-id) current-file (get libraries current-file-id)
data (get-in libraries [current-file-id :data]) data (get current-file :data)
state* (mf/use-state state* (mf/use-state
#(do {:show-content true #(do {:show-content true

View file

@ -184,7 +184,7 @@
(let [file-id (mf/use-ctx ctx/current-file-id) (let [file-id (mf/use-ctx ctx/current-file-id)
typographies (mf/deref refs/workspace-file-typography) typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/libraries) libraries (mf/deref refs/files)
label (case type label (case type
:multiple (tr "workspace.options.text-options.title-selection") :multiple (tr "workspace.options.text-options.title-selection")
:group (tr "workspace.options.text-options.title-group") :group (tr "workspace.options.text-options.title-group")
@ -224,21 +224,19 @@
(emit-update! ids attrs))) (emit-update! ids attrs)))
typography typography
(mf/use-memo (mf/with-memo [values file-id libraries]
(mf/deps values file-id shared-libs)
(fn []
(cond (cond
(and typography-id (and typography-id
(not= typography-id :multiple) (not= typography-id :multiple)
(not= typography-file-id file-id)) (not= typography-file-id file-id))
(-> shared-libs (-> libraries
(get-in [typography-file-id :data :typographies typography-id]) (get-in [typography-file-id :data :typographies typography-id])
(assoc :file-id typography-file-id)) (assoc :file-id typography-file-id))
(and typography-id (and typography-id
(not= typography-id :multiple) (not= typography-id :multiple)
(= typography-file-id file-id)) (= typography-file-id file-id))
(get typographies typography-id)))) (get typographies typography-id)))
on-convert-to-typography on-convert-to-typography
(fn [_] (fn [_]

View file

@ -48,13 +48,13 @@
[{:keys [index color disable-gradient disable-opacity disable-image disable-picker hidden [{:keys [index color disable-gradient disable-opacity disable-image disable-picker hidden
on-change on-reorder on-detach on-open on-close on-remove on-change on-reorder on-detach on-open on-close on-remove
disable-drag on-focus on-blur select-only select-on-focus]}] disable-drag on-focus on-blur select-only select-on-focus]}]
(let [shared-libs (mf/deref refs/libraries) (let [libraries (mf/deref refs/files)
hover-detach (mf/use-state false) hover-detach (mf/use-state false)
on-change (h/use-ref-callback on-change) on-change (h/use-ref-callback on-change)
file-id (or (:ref-file color) (:file-id color)) file-id (or (:ref-file color) (:file-id color))
color-id (or (:ref-id color) (:id color)) color-id (or (:ref-id color) (:id color))
src-colors (dm/get-in shared-libs [file-id :data :colors]) src-colors (dm/get-in libraries [file-id :data :colors])
color-name (dm/get-in src-colors [color-id :name]) color-name (dm/get-in src-colors [color-id :name])
multiple-colors? (uc/multiple? color) multiple-colors? (uc/multiple? color)

View file

@ -34,7 +34,7 @@
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
shape-with-children (unchecked-get props "shape-with-children") shape-with-children (unchecked-get props "shape-with-children")
shared-libs (unchecked-get props "shared-libs") libraries (unchecked-get props "libraries")
objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v)))) objects (->> shape-with-children (group-by :id) (d/mapm (fn [_ v] (first v))))
file-id (unchecked-get props "file-id") file-id (unchecked-get props "file-id")
layout-container-values (select-keys shape layout-container-flex-attrs) layout-container-values (select-keys shape layout-container-flex-attrs)
@ -106,7 +106,7 @@
{:type type {:type type
:shapes (vals objects) :shapes (vals objects)
:file-id file-id :file-id file-id
:libraries shared-libs}] :libraries libraries}]
(when-not (empty? shadow-ids) (when-not (empty? shadow-ids)
[:> shadow-menu* {:ids ids :values (get shape :shadow) :type type}]) [:> shadow-menu* {:ids ids :values (get shape :shadow) :type type}])

View file

@ -29,7 +29,7 @@
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(mf/defc options (mf/defc options
[{:keys [shape file-id] :as props}] [{:keys [shape file-id libraries] :as props}]
(let [ids [(:id shape)] (let [ids [(:id shape)]
type (:type shape) type (:type shape)
@ -53,8 +53,6 @@
(mf/deref refs/workspace-v2-editor-state) (mf/deref refs/workspace-v2-editor-state)
(mf/deref refs/workspace-editor-state)) (mf/deref refs/workspace-editor-state))
shared-libs (mf/deref refs/libraries)
editor-state (when (not (features/active-feature? @st/state "text-editor/v2")) editor-state (when (not (features/active-feature? @st/state "text-editor/v2"))
(get state-map (:id shape))) (get state-map (:id shape)))
@ -150,7 +148,7 @@
{:type type {:type type
:shapes [shape] :shapes [shape]
:file-id file-id :file-id file-id
:libraries shared-libs}]) :libraries libraries}])
[:> shadow-menu* {:ids ids :values (get shape :shadow)}] [:> shadow-menu* {:ids ids :values (get shape :shadow)}]

View file

@ -68,7 +68,7 @@
(str (:font-size typography) "px | " (:name variant-data))]])])) (str (:font-size typography) "px | " (:name variant-data))]])]))
(mf/defc palette (mf/defc palette
[{:keys [selected selected-ids current-file-id file-typographies shared-libs size width]}] [{:keys [selected selected-ids current-file-id file-typographies libraries size width]}]
(let [file-id (let [file-id
(case selected (case selected
:recent nil :recent nil
@ -79,7 +79,7 @@
(case selected (case selected
:recent [] :recent []
:file (sort-by #(str/lower (:name %)) (vals file-typographies)) :file (sort-by #(str/lower (:name %)) (vals file-typographies))
(sort-by #(str/lower (:name %)) (vals (get-in shared-libs [selected :data :typographies])))) (sort-by #(str/lower (:name %)) (vals (get-in libraries [selected :data :typographies]))))
state (mf/use-state {:offset 0}) state (mf/use-state {:offset 0})
offset-step 144 offset-step 144
buttons-size (cond buttons-size (cond
@ -182,13 +182,17 @@
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [size width selected] :as props}] [{:keys [size width selected] :as props}]
(let [selected-ids (mf/deref refs/selected-shapes) (let [selected-ids (mf/deref refs/selected-shapes)
;; FIXME: we have duplicate operations, if we already have the
;; libraries, so we already have file-typographies so we don't
;; need two separate lens/refs for that
file-typographies (mf/deref refs/workspace-file-typography) file-typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/libraries) libraries (mf/deref refs/files)
current-file-id (mf/use-ctx ctx/current-file-id)] current-file-id (mf/use-ctx ctx/current-file-id)]
[:& palette {:current-file-id current-file-id [:& palette {:current-file-id current-file-id
:selected-ids selected-ids :selected-ids selected-ids
:file-typographies file-typographies :file-typographies file-typographies
:shared-libs shared-libs :libraries libraries
:width width :width width
:selected selected :selected selected
:size size}])) :size size}]))

View file

@ -17,11 +17,11 @@
(mf/defc text-palette-ctx-menu (mf/defc text-palette-ctx-menu
[{:keys [show-menu? close-menu on-select-palette selected]}] [{:keys [show-menu? close-menu on-select-palette selected]}]
(let [typographies (mf/deref refs/workspace-file-typography) (let [typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/libraries)] libraries (mf/deref refs/libraries)]
[:& dropdown {:show show-menu? [:& dropdown {:show show-menu?
:on-close close-menu} :on-close close-menu}
[:ul {:class (stl/css :text-context-menu)} [:ul {:class (stl/css :text-context-menu)}
(for [[idx cur-library] (map-indexed vector (vals shared-libs))] (for [[idx cur-library] (map-indexed vector (vals libraries))]
(let [typographies (-> cur-library (get-in [:data :typographies]) vals)] (let [typographies (-> cur-library (get-in [:data :typographies]) vals)]
[:li [:li
{:class (stl/css-case :palette-library true {:class (stl/css-case :palette-library true