From e3b3fa3342bdbab21d513c2d0a1322965177a5c6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Thu, 13 Mar 2025 09:32:19 +0100 Subject: [PATCH 1/3] :paperclip: Update changelog --- CHANGES.md | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a8a0feace1..fd01e4c3b1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,27 +2,14 @@ ## 2.5.3 -### :rocket: Epics and highlights - -### :boom: Breaking changes & Deprecations - -### :heart: Community contributions (Thank you!) - -### :sparkles: New features - ### :bug: Bugs fixed - Component sync issues with multiple tabs [Taiga #10471](https://tree.taiga.io/project/penpot/issue/10471) ## 2.5.2 -### :rocket: Epics and highlights - -### :boom: Breaking changes & Deprecations - -### :heart: Community contributions (Thank you!) - ### :sparkles: New features + - When the workspace is empty, set default the board creation tool [Taiga #9425](https://tree.taiga.io/project/penpot/us/9425) ### :bug: Bugs fixed @@ -34,22 +21,12 @@ ## 2.5.1 -### :rocket: Epics and highlights - -### :boom: Breaking changes & Deprecations - -### :heart: Community contributions (Thank you!) - ### :sparkles: New features - Improve Nginx entryponit to get the resolvers dinamically by default -### :bug: Bugs fixed - ## 2.5.0 -### :rocket: Epics and highlights - ### :boom: Breaking changes & Deprecations Although this is not a breaking change, we believe it’s important to highlight it in this @@ -78,9 +55,6 @@ If you have a big database and many cores available, you can reduce the time of all files by increasing paralelizacion changing the `max-jobs` value from 1 to N (where N is a number of cores) - -### :heart: Community contributions (Thank you!) - ### :sparkles: New features - [GRADIENTS] New gradients UI with multi-stop support. [Taiga #3418](https://tree.taiga.io/project/penpot/epic/3418) From f450c9dbe337a357691e23163f7f72e41b60e89b Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Thu, 13 Mar 2025 15:15:30 +0000 Subject: [PATCH 2/3] :tada: Add support for WEBP format on shape export It is very convenient to be able to export WEBP right from penpot. Otherwise users have to first download to PNG then convert it locally. --- Playwright only supports JPEG and PNG. So in order to support WEBP I had to first generate a PNG and then convert it afterwards. Signed-off-by: Dalai Felinto --- CHANGES.md | 6 ++++++ common/src/app/common/types/shape/export.cljc | 2 +- docs/user-guide/exporting/index.njk | 2 +- exporter/src/app/renderer.cljs | 3 ++- exporter/src/app/renderer/bitmap.cljs | 6 +++++- exporter/src/app/util/mime.cljs | 4 +++- frontend/src/app/main/data/exports/assets.cljs | 4 ++-- frontend/src/app/main/ui/inspect/exports.cljs | 3 ++- frontend/src/app/main/ui/inspect/exports.scss | 6 +++--- .../main/ui/workspace/sidebar/options/menus/exports.cljs | 3 ++- .../main/ui/workspace/sidebar/options/menus/exports.scss | 6 +++--- frontend/src/app/plugins/format.cljs | 2 +- frontend/src/app/plugins/parser.cljs | 2 +- 13 files changed, 32 insertions(+), 17 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index fd01e4c3b1..09ea41efce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.5.4 (Unreleased) + +### :sparkles: New features + +- Add support for WEBP format on shape export [Github #6053](https://github.com/penpot/penpot/pull/6053) and [Github #6074](https://github.com/penpot/penpot/pull/6074) + ## 2.5.3 ### :bug: Bugs fixed diff --git a/common/src/app/common/types/shape/export.cljc b/common/src/app/common/types/shape/export.cljc index bd2bee0a51..feb7f8dec6 100644 --- a/common/src/app/common/types/shape/export.cljc +++ b/common/src/app/common/types/shape/export.cljc @@ -8,7 +8,7 @@ (:require [app.common.schema :as sm])) -(def types #{:png :jpeg :svg :pdf}) +(def types #{:png :jpeg :webp :svg :pdf}) (def schema:export [:map {:title "ShapeExport"} diff --git a/docs/user-guide/exporting/index.njk b/docs/user-guide/exporting/index.njk index 63f9d9fb24..d685a66834 100644 --- a/docs/user-guide/exporting/index.njk +++ b/docs/user-guide/exporting/index.njk @@ -27,7 +27,7 @@ title: 07· Exporting objects
  • Size - Options for the most common sizing scales.
  • Suffix - Especially useful if you are exporting at different scales.
  • -
  • File format - PNG, SVG, JPEG, PDF.
  • +
  • File format - PNG, JPEG, WEBP, SVG, PDF.

Exporting multiple elements

diff --git a/exporter/src/app/renderer.cljs b/exporter/src/app/renderer.cljs index b4abaca4bc..4a7cf8af73 100644 --- a/exporter/src/app/renderer.cljs +++ b/exporter/src/app/renderer.cljs @@ -15,7 +15,7 @@ (s/def ::name ::us/string) (s/def ::suffix ::us/string) -(s/def ::type #{:jpeg :png :pdf :svg}) +(s/def ::type #{:png :jpeg :webp :pdf :svg}) (s/def ::page-id ::us/uuid) (s/def ::file-id ::us/uuid) (s/def ::share-id ::us/uuid) @@ -40,6 +40,7 @@ (case type :png (rb/render params on-object) :jpeg (rb/render params on-object) + :webp (rb/render params on-object) :pdf (rp/render params on-object) :svg (rs/render params on-object))) diff --git a/exporter/src/app/renderer/bitmap.cljs b/exporter/src/app/renderer/bitmap.cljs index 38022db739..750102af79 100644 --- a/exporter/src/app/renderer/bitmap.cljs +++ b/exporter/src/app/renderer/bitmap.cljs @@ -34,7 +34,11 @@ (bw/wait-for node) (case type :png (bw/screenshot node {:omit-background? true :type type :path path}) - :jpeg (bw/screenshot node {:omit-background? false :type type :path path})) + :jpeg (bw/screenshot node {:omit-background? false :type type :path path}) + :webp (p/let [png-path (sh/tempfile :prefix "penpot.tmp.render.bitmap." :suffix ".png")] + ;; playwright only supports jpg and png, we need to convert it afterwards + (bw/screenshot node {:omit-background? true :type :png :path png-path}) + (sh/run-cmd! (str "convert " png-path " -quality 100 WEBP:" path)))) (on-object (assoc object :path path)))) (render [uri page] diff --git a/exporter/src/app/util/mime.cljs b/exporter/src/app/util/mime.cljs index 18601cbd07..7bb0ce77c7 100644 --- a/exporter/src/app/util/mime.cljs +++ b/exporter/src/app/util/mime.cljs @@ -15,6 +15,7 @@ (case type :png ".png" :jpeg ".jpg" + :webp ".webp" :svg ".svg" :pdf ".pdf" :zip ".zip")) @@ -26,6 +27,7 @@ :pdf "application/pdf" :svg "image/svg+xml" :jpeg "image/jpeg" - :png "image/png")) + :png "image/png" + :webp "image/webp")) diff --git a/frontend/src/app/main/data/exports/assets.cljs b/frontend/src/app/main/data/exports/assets.cljs index 1e800aee6d..b1f0293993 100644 --- a/frontend/src/app/main/data/exports/assets.cljs +++ b/frontend/src/app/main/data/exports/assets.cljs @@ -266,10 +266,10 @@ (defn export-shapes-event [exports origin] (let [types (reduce (fn [counts {:keys [type]}] - (if (#{:png :pdf :svg :jpeg} type) + (if (#{:png :jpeg :webp :svg :pdf} type) (update counts type inc) counts)) - {:png 0, :pdf 0, :svg 0, :jpeg 0} + {:png 0, :jpeg 0, :webp 0, :pdf 0, :svg 0} exports)] (ptk/event ::ev/event (merge types diff --git a/frontend/src/app/main/ui/inspect/exports.cljs b/frontend/src/app/main/ui/inspect/exports.cljs index 8c5495ad1e..5f1aa2118e 100644 --- a/frontend/src/app/main/ui/inspect/exports.cljs +++ b/frontend/src/app/main/ui/inspect/exports.cljs @@ -37,7 +37,7 @@ scale-enabled? (mf/use-callback (fn [export] - (#{:png :jpeg} (:type export)))) + (#{:png :jpeg :webp} (:type export)))) in-progress? (:in-progress xstate) @@ -123,6 +123,7 @@ format-options [{:value "png" :label "PNG"} {:value "jpeg" :label "JPG"} + {:value "webp" :label "WEBP"} {:value "svg" :label "SVG"} {:value "pdf" :label "PDF"}]] diff --git a/frontend/src/app/main/ui/inspect/exports.scss b/frontend/src/app/main/ui/inspect/exports.scss index 8244d9e23f..f7365067c8 100644 --- a/frontend/src/app/main/ui/inspect/exports.scss +++ b/frontend/src/app/main/ui/inspect/exports.scss @@ -51,7 +51,7 @@ .element-group { display: grid; - grid-template-columns: repeat(8, 1fr); + grid-template-columns: repeat(9, 1fr); column-gap: $s-4; .action-btn { @extend .button-tertiary; @@ -64,13 +64,13 @@ } .input-wrapper { - grid-column: span 7; + grid-column: span 8; display: grid; grid-template-columns: subgrid; } .format-select { - grid-column: span 2; + grid-column: span 3; padding: 0; .dropdown-upwards { 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 dd8908d76d..415d0295a1 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 @@ -53,7 +53,7 @@ scale-enabled? (mf/use-fn (fn [export] - (#{:png :jpeg} (:type export)))) + (#{:png :jpeg :webp} (:type export)))) on-download (mf/use-fn @@ -173,6 +173,7 @@ format-options [{:value "png" :label "PNG"} {:value "jpeg" :label "JPG"} + {:value "webp" :label "WEBP"} {:value "svg" :label "SVG"} {:value "pdf" :label "PDF"}]] diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss index 6bf3152dd4..0f9aae670e 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss +++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/exports.scss @@ -32,18 +32,18 @@ .element-group { display: grid; - grid-template-columns: repeat(8, 1fr); + grid-template-columns: repeat(9, 1fr); column-gap: $s-4; } .input-wrapper { - grid-column: span 7; + grid-column: span 8; display: grid; grid-template-columns: subgrid; } .format-select { - grid-column: span 2; + grid-column: span 3; padding: 0; .dropdown-upwards { diff --git a/frontend/src/app/plugins/format.cljs b/frontend/src/app/plugins/format.cljs index 829476da0b..6555f6a367 100644 --- a/frontend/src/app/plugins/format.cljs +++ b/frontend/src/app/plugins/format.cljs @@ -261,7 +261,7 @@ :hidden hidden}))) ;; export interface Export { -;; type: 'png' | 'jpeg' | 'svg' | 'pdf'; +;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf'; ;; scale: number; ;; suffix: string; ;; } diff --git a/frontend/src/app/plugins/parser.cljs b/frontend/src/app/plugins/parser.cljs index 8d884350dd..0ce6aad418 100644 --- a/frontend/src/app/plugins/parser.cljs +++ b/frontend/src/app/plugins/parser.cljs @@ -243,7 +243,7 @@ ;; export interface Export { -;; type: 'png' | 'jpeg' | 'svg' | 'pdf'; +;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf'; ;; scale: number; ;; suffix: string; ;; } From 05d6d2fcd4ee5439f39449287eade641f22cecec Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Fri, 14 Mar 2025 09:55:41 +0100 Subject: [PATCH 3/3] :bug: Fix several corner cases that causes race conditions on workspace and dashboard loading * :bug: Fix several race conditions on workspace and dashboard code It also fixes a corner case that happens when penpot workspace is loaded in a background tab on firefox. * :bug: Add missing team-id prop to several file returning endpoints --- CHANGES.md | 8 ++ backend/src/app/rpc/commands/files.clj | 3 + frontend/src/app/main/data/dashboard.cljs | 40 ++++----- frontend/src/app/main/data/fonts.cljs | 11 ++- frontend/src/app/main/data/team.cljs | 59 +++++--------- frontend/src/app/main/data/workspace.cljs | 7 +- frontend/src/app/main/ui/dashboard.cljs | 81 ++++++++++--------- .../src/app/main/ui/dashboard/file_menu.cljs | 2 +- frontend/src/app/main/ui/dashboard/grid.cljs | 6 +- .../src/app/main/ui/dashboard/import.cljs | 6 +- .../src/app/main/ui/dashboard/projects.cljs | 17 ++-- .../src/app/main/ui/dashboard/templates.cljs | 1 + .../src/app/main/ui/workspace/libraries.cljs | 5 +- frontend/src/app/render.cljs | 17 +++- 14 files changed, 138 insertions(+), 125 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 09ea41efce..83dac41721 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,14 @@ - Add support for WEBP format on shape export [Github #6053](https://github.com/penpot/penpot/pull/6053) and [Github #6074](https://github.com/penpot/penpot/pull/6074) +### :bug: Bugs fixed + +- Fix feature loading on workspace when opening a file in a background + tab [Taiga #10377](https://tree.taiga.io/project/penpot/issue/10377) +- Fix minor inconsistencies on RPC `get-file-libraries` and `get-file` + methods (add missing team-id prop) + + ## 2.5.3 ### :bug: Bugs fixed diff --git a/backend/src/app/rpc/commands/files.clj b/backend/src/app/rpc/commands/files.clj index bc512c0b7f..e3e29ddf0a 100644 --- a/backend/src/app/rpc/commands/files.clj +++ b/backend/src/app/rpc/commands/files.clj @@ -323,6 +323,7 @@ file (-> (get-file cfg id :project-id project-id) (assoc :permissions perms) + (assoc :team-id (:id team)) (check-version!))] (-> (cfeat/get-team-enabled-features cf/flags team) @@ -613,6 +614,7 @@ SELECT l.id, l.features, l.project_id, + p.team_id, l.created_at, l.modified_at, l.deleted_at, @@ -622,6 +624,7 @@ l.synced_at, l.is_shared FROM libs AS l + INNER JOIN project AS p ON (p.id = l.project_id) WHERE l.deleted_at IS NULL OR l.deleted_at > now();") (defn get-file-libraries diff --git a/frontend/src/app/main/data/dashboard.cljs b/frontend/src/app/main/data/dashboard.cljs index b3ebe6ace8..564e97dd90 100644 --- a/frontend/src/app/main/data/dashboard.cljs +++ b/frontend/src/app/main/data/dashboard.cljs @@ -38,7 +38,9 @@ (declare process-message) (defn initialize - [] + [team-id] + (assert (uuid? team-id) "expected uuid instance for `team-id`") + (ptk/reify ::initialize ptk/WatchEvent (watch [_ state stream] @@ -46,8 +48,8 @@ profile-id (:profile-id state)] (->> (rx/merge - (rx/of (fetch-projects) - (df/fetch-fonts)) + (rx/of (fetch-projects team-id) + (df/fetch-fonts team-id)) (->> stream (rx/filter (ptk/type? ::dws/message)) (rx/map deref) @@ -60,8 +62,8 @@ (rx/take-until stopper)))))) (defn finalize - [] - (ptk/data-event ::finalize {})) + [team-id] + (ptk/data-event ::finalize {:team-id team-id})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Data Fetching (context aware: current team) @@ -69,7 +71,7 @@ ;; --- EVENT: fetch-projects -(defn projects-fetched +(defn- projects-fetched [projects] (ptk/reify ::projects-fetched ptk/UpdateEvent @@ -80,13 +82,12 @@ projects)))) (defn fetch-projects - [] + [team-id] (ptk/reify ::fetch-projects ptk/WatchEvent - (watch [_ state _] - (let [team-id (:current-team-id state)] - (->> (rp/cmd! :get-projects {:team-id team-id}) - (rx/map projects-fetched)))))) + (watch [_ _ _] + (->> (rp/cmd! :get-projects {:team-id team-id}) + (rx/map projects-fetched))))) ;; --- EVENT: search @@ -115,7 +116,7 @@ ;; --- EVENT: recent-files -(defn recent-files-fetched +(defn- recent-files-fetched [files] (ptk/reify ::recent-files-fetched ptk/UpdateEvent @@ -126,13 +127,14 @@ (update :files d/merge files)))))) (defn fetch-recent-files - [] - (ptk/reify ::fetch-recent-files - ptk/WatchEvent - (watch [_ state _] - (let [team-id (:current-team-id state)] - (->> (rp/cmd! :get-team-recent-files {:team-id team-id}) - (rx/map recent-files-fetched)))))) + ([] (fetch-recent-files nil)) + ([team-id] + (ptk/reify ::fetch-recent-files + ptk/WatchEvent + (watch [_ state _] + (when-let [team-id (or team-id (:current-team-id state))] + (->> (rp/cmd! :get-team-recent-files {:team-id team-id}) + (rx/map recent-files-fetched))))))) ;; --- EVENT: fetch-template-files diff --git a/frontend/src/app/main/data/fonts.cljs b/frontend/src/app/main/data/fonts.cljs index a1aba3d671..4706e7c5c3 100644 --- a/frontend/src/app/main/data/fonts.cljs +++ b/frontend/src/app/main/data/fonts.cljs @@ -73,13 +73,12 @@ (fonts/register! :custom fonts)))))) (defn fetch-fonts - [] - (ptk/reify ::load-team-fonts + [team-id] + (ptk/reify ::fetch-fonts ptk/WatchEvent - (watch [_ state _] - (let [team-id (:current-team-id state)] - (->> (rp/cmd! :get-font-variants {:team-id team-id}) - (rx/map fonts-fetched)))))) + (watch [_ _ _] + (->> (rp/cmd! :get-font-variants {:team-id team-id}) + (rx/map fonts-fetched))))) (defn process-upload "Given a seq of blobs and the team id, creates a ready-to-use fonts diff --git a/frontend/src/app/main/data/team.cljs b/frontend/src/app/main/data/team.cljs index 50af94a444..43e1690257 100644 --- a/frontend/src/app/main/data/team.cljs +++ b/frontend/src/app/main/data/team.cljs @@ -64,13 +64,14 @@ (update :profiles merge (d/index-by :id members)))))) (defn fetch-members - [] - (ptk/reify ::fetch-members - ptk/WatchEvent - (watch [_ state _] - (let [team-id (:current-team-id state)] - (->> (rp/cmd! :get-team-members {:team-id team-id}) - (rx/map (partial members-fetched team-id))))))) + ([] (fetch-members nil)) + ([team-id] + (ptk/reify ::fetch-members + ptk/WatchEvent + (watch [_ state _] + (when-let [team-id (or team-id (:current-team-id state))] + (->> (rp/cmd! :get-team-members {:team-id team-id}) + (rx/map (partial members-fetched team-id)))))))) (defn- invitations-fetched [team-id invitations] @@ -88,41 +89,20 @@ (->> (rp/cmd! :get-team-invitations {:team-id team-id}) (rx/map (partial invitations-fetched team-id))))))) -(defn set-current-team - [{:keys [id permissions features] :as team}] - (ptk/reify ::set-current-team - ptk/UpdateEvent - (update [_ state] - (-> state - ;; FIXME: redundant operation, only necessary on workspace - ;; until workspace initialization is refactored - (update-in [:teams id] merge team) - (assoc :permissions permissions) - ;; FIXME: this is a redundant operation that only needed by - ;; workspace; ti will not be needed after workspace - ;; bootstrap & urls refactor - (assoc :current-team-id id))) - - ptk/WatchEvent - (watch [_ _ _] - (rx/of (features/initialize (or features #{})))) - - ptk/EffectEvent - (effect [_ _ _] - (swap! storage/global assoc ::current-team-id id)))) - (defn- team-initialized - [] + [team-id] (ptk/reify ::team-initialized ptk/WatchEvent (watch [_ state _] - (let [team-id (:current-team-id state) - teams (get state :teams) - team (get teams team-id)] + (let [teams (get state :teams) + team (get teams team-id)] (if (not team) (rx/throw (ex/error :type :authentication)) - (rx/of (set-current-team team) - (fetch-members))))))) + (let [permissions (get team :permissions) + features (get team :features)] + (rx/of #(assoc % :permissions permissions) + (features/initialize (or features #{})) + (fetch-members team-id)))))))) (defn initialize-team [team-id] @@ -138,8 +118,7 @@ (rx/of (fetch-teams)) (->> stream (rx/filter (ptk/type? ::teams-fetched)) - (rx/observe-on :async) - (rx/map team-initialized))) + (rx/map (partial team-initialized team-id)))) (rx/take-until stopper)))))) (defn finalize-team @@ -169,7 +148,7 @@ params (assoc params :team-id team-id)] (->> (rp/cmd! :update-team-member-role params) (rx/mapcat (fn [_] - (rx/of (fetch-members) + (rx/of (fetch-members team-id) (fetch-teams) (ptk/data-event ::ev/event {::ev/name "update-team-member-role" @@ -187,7 +166,7 @@ params (assoc params :team-id team-id)] (->> (rp/cmd! :delete-team-member params) (rx/mapcat (fn [_] - (rx/of (fetch-members) + (rx/of (fetch-members team-id) (fetch-teams) (ptk/data-event ::ev/event {::ev/name "delete-team-member" diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 168e305c1a..fc82954333 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -291,7 +291,8 @@ (watch [_ state stream] (let [features (features/get-team-enabled-features state) render-wasm? (contains? features "render-wasm/v1") - stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)] + stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream) + team-id (:current-team-id state)] (->> (rx/concat ;; Firstly load wasm module if it is enabled and fonts @@ -305,7 +306,7 @@ (rx/filter (ptk/type? ::df/fonts-loaded)) (rx/take 1) (rx/ignore)) - (rx/of (df/fetch-fonts))) + (rx/of (df/fetch-fonts team-id))) ;; Then fetch file and thumbnails (->> (rx/zip (rp/cmd! :get-file {:id file-id :features features}) @@ -335,7 +336,7 @@ ptk/WatchEvent (watch [_ state stream] - (log/debug :hint "initialize-workspace" :file-id file-id) + (log/debug :hint "initialize-workspace" :file-id (dm/str file-id)) (let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream) rparams (rt/get-params state)] diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index d0d7bafdee..9dbe96ae0a 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -210,42 +210,45 @@ (swap! storage/session dissoc :plugin-url)))))) (defn use-templates-import - [can-edit? template-url default-project-id] - (mf/with-layout-effect - [can-edit? template-url default-project-id] - (when (and (some? template-url) (some? default-project-id)) - (if can-edit? - (let [valid-url? (and (str/ends-with? template-url ".penpot") - (str/starts-with? template-url cf/templates-uri)) - template-name (when valid-url? (subs template-url (count cf/templates-uri))) - on-import #(st/emit! (dpj/fetch-files default-project-id) - (dd/fetch-recent-files) - (dd/fetch-projects) - (dd/clear-selected-files) - (ptk/event ::ev/event {::ev/name "install-template-from-link-finished" - :name template-name - :url template-url}))] - (if valid-url? - (do - (st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})) - (->> (http/send! {:method :get - :uri template-url - :response-type :blob - :omit-default-headers true}) - (rx/subs! - (fn [result] - (if (or (< (:status result) 200) (>= (:status result) 300)) - (st/emit! (notif/error (tr "dashboard.import.error"))) - (st/emit! (modal/show - {:type :import - :project-id default-project-id - :entries [{:name template-name :uri (wapi/create-uri (:body result))}] - :on-finish-import on-import}))))))) - (st/emit! (notif/error (tr "dashboard.import.bad-url"))))) - (st/emit! (notif/error (tr "dashboard.import.no-perms")))) + [can-edit? template-url project] + (let [project-id (get project :id) + team-id (get project :team-id)] + (mf/with-layout-effect [can-edit? template-url project-id team-id] + (when (and (some? template-url) + (some? project-id) + (some? team-id)) + (if can-edit? + (let [valid-url? (and (str/ends-with? template-url ".penpot") + (str/starts-with? template-url cf/templates-uri)) + template-name (when valid-url? (subs template-url (count cf/templates-uri))) + on-import #(st/emit! (dpj/fetch-files project-id) + (dd/fetch-recent-files team-id) + (dd/fetch-projects team-id) + (dd/clear-selected-files) + (ptk/event ::ev/event {::ev/name "install-template-from-link-finished" + :name template-name + :url template-url}))] + (if valid-url? + (do + (st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url})) + (->> (http/send! {:method :get + :uri template-url + :response-type :blob + :omit-default-headers true}) + (rx/subs! + (fn [result] + (if (or (< (:status result) 200) (>= (:status result) 300)) + (st/emit! (notif/error (tr "dashboard.import.error"))) + (st/emit! (modal/show + {:type :import + :project-id project-id + :entries [{:name template-name :uri (wapi/create-uri (:body result))}] + :on-finish-import on-import}))))))) + (st/emit! (notif/error (tr "dashboard.import.bad-url"))))) + (st/emit! (notif/error (tr "dashboard.import.no-perms")))) - (binding [storage/*sync* true] - (swap! storage/session dissoc :template-url))))) + (binding [storage/*sync* true] + (swap! storage/session dissoc :template-url)))))) (mf/defc dashboard* {::mf/props :obj} @@ -270,10 +273,10 @@ (hooks/use-shortcuts ::dashboard sc/shortcuts) - (mf/with-effect [] - (st/emit! (dd/initialize)) + (mf/with-effect [team-id] + (st/emit! (dd/initialize team-id)) (fn [] - (st/emit! (dd/finalize)))) + (st/emit! (dd/finalize team-id)))) (mf/with-effect [] (let [key (events/listen goog/global "keydown" @@ -285,7 +288,7 @@ (events/unlistenByKey key)))) (use-plugin-register plugin-url team-id (:id default-project)) - (use-templates-import can-edit? template-url (:id default-project)) + (use-templates-import can-edit? template-url default-project) [:& (mf/provider ctx/current-project-id) {:value project-id} [:> modal-container*] diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index f882c2179c..6e10ede276 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -133,7 +133,7 @@ (st/emit! (dcm/go-to-dashboard-files {:project-id project-id :team-id team-id})) - (st/emit! (dd/fetch-recent-files) + (st/emit! (dd/fetch-recent-files team-id) (dd/clear-selected-files)))) on-move-accept diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 4a3112ca2c..2a2bf20f76 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -566,8 +566,9 @@ on-finish-import (mf/use-fn + (mf/deps team-id) (fn [] - (st/emit! (dd/fetch-recent-files) + (st/emit! (dd/fetch-recent-files team-id) (dd/clear-selected-files)))) import-files (use-import-file project-id on-finish-import) @@ -608,9 +609,10 @@ on-drop-success (mf/use-fn + (mf/deps team-id) (fn [] (st/emit! (ntf/success (tr "dashboard.success-move-file")) - (dd/fetch-recent-files) + (dd/fetch-recent-files team-id) (dd/clear-selected-files)))) on-drop diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index c9fb7df2b0..ce6b83afb4 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -344,11 +344,13 @@ continue-template (mf/use-fn + (mf/deps on-finish-import) (fn [template] (let [on-success (fn [_event] (reset! status* :import-success) - (st/emit! (dd/fetch-recent-files))) + (when (fn? on-finish-import) + (on-finish-import))) on-error (fn [cause] @@ -479,8 +481,6 @@ [:> import-entry* {:entry (assoc template :status status) :can-be-deleted false}])] - ;; (prn "import-dialog" status) - [:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :action-buttons)} (when (= :analyze status) diff --git a/frontend/src/app/main/ui/dashboard/projects.cljs b/frontend/src/app/main/ui/dashboard/projects.cljs index 12f22309b7..3aaa590f81 100644 --- a/frontend/src/app/main/ui/dashboard/projects.cljs +++ b/frontend/src/app/main/ui/dashboard/projects.cljs @@ -105,7 +105,8 @@ [{:keys [project is-first team files can-edit]}] (let [locale (mf/deref i18n/locale) - project-id (:id project) + project-id (get project :id) + team-id (get team :id) file-count (or (:count project) 0) is-draft? (:is-default project) @@ -191,11 +192,11 @@ on-import (mf/use-fn - (mf/deps project-id) + (mf/deps project-id team-id) (fn [] (st/emit! (dpj/fetch-files project-id) - (dd/fetch-recent-files) - (dd/fetch-projects) + (dd/fetch-recent-files team-id) + (dd/fetch-projects team-id) (dd/clear-selected-files)))) handle-create-click @@ -317,6 +318,8 @@ (sort-by :modified-at) (reverse))) + team-id (get team :id) + recent-map (mf/deref ref:recent-files) permisions (:permissions team) @@ -327,7 +330,7 @@ show-team-hero* (mf/use-state #(get storage/global ::show-team-hero true)) show-team-hero? (deref show-team-hero*) - is-my-penpot (= (:default-team-id profile) (:id team)) + is-my-penpot (= (:default-team-id profile) team-id) is-defalt-team? (:is-default team) on-close @@ -346,8 +349,8 @@ (:name team))] (dom/set-html-title (tr "title.dashboard.projects" tname)))) - (mf/with-effect [] - (st/emit! (dd/fetch-recent-files) + (mf/with-effect [team-id] + (st/emit! (dd/fetch-recent-files team-id) (dd/clear-selected-files))) (when (seq projects) diff --git a/frontend/src/app/main/ui/dashboard/templates.cljs b/frontend/src/app/main/ui/dashboard/templates.cljs index b336942364..cef2fcc914 100644 --- a/frontend/src/app/main/ui/dashboard/templates.cljs +++ b/frontend/src/app/main/ui/dashboard/templates.cljs @@ -37,6 +37,7 @@ [template team-id project-id default-project-id section] (letfn [(on-finish [] (st/emit! + (dd/fetch-recent-files team-id) (ptk/event ::ev/event {::ev/name "import-template-finish" ::ev/origin "dashboard" :template (:name template) diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 90d9111b25..0c6a8b8feb 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -568,7 +568,6 @@ [{:keys [starting-tab file-id] :as props :or {starting-tab :libraries}}] (let [files (mf/deref refs/files) file (get files file-id) - team-id (:team-id file) shared? (:is-shared file) linked-libraries @@ -616,8 +615,8 @@ :id "updates" :content updates-tab}]] - (mf/with-effect [team-id] - (st/emit! (dtm/fetch-shared-files team-id))) + (mf/with-effect [] + (st/emit! (dtm/fetch-shared-files))) [:div {:class (stl/css :modal-overlay) :on-click close-dialog-outside diff --git a/frontend/src/app/render.cljs b/frontend/src/app/render.cljs index d8a3d86505..258c988128 100644 --- a/frontend/src/app/render.cljs +++ b/frontend/src/app/render.cljs @@ -14,7 +14,6 @@ [app.common.types.components-list :as ctkl] [app.common.uri :as u] [app.main.data.fonts :as df] - [app.main.data.team :as dtm] [app.main.features :as features] [app.main.render :as render] [app.main.repo :as repo] @@ -30,6 +29,20 @@ (log/setup! {:app :info}) +(defn set-current-team + [{:keys [id permissions features] :as team}] + (ptk/reify ::set-current-team + ptk/UpdateEvent + (update [_ state] + (-> state + (assoc :permissions permissions) + (update :teams assoc id team) + (assoc :current-team-id id))) + + ptk/WatchEvent + (watch [_ _ _] + (rx/of (features/initialize (or features #{})))))) + (defn- fetch-team [& {:keys [file-id]}] (ptk/reify ::fetch-team @@ -37,7 +50,7 @@ (watch [_ _ _] (->> (repo/cmd! :get-team {:file-id file-id}) (rx/mapcat (fn [team] - (rx/of (dtm/set-current-team team) + (rx/of (set-current-team team) (ptk/data-event ::team-fetched team)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;