diff --git a/frontend/src/app/main/data/common.cljs b/frontend/src/app/main/data/common.cljs index fe822526a..baa380b7d 100644 --- a/frontend/src/app/main/data/common.cljs +++ b/frontend/src/app/main/data/common.cljs @@ -113,3 +113,31 @@ :accept-label (tr "modals.add-shared-confirm.accept") :accept-style :primary :on-accept add-shared}))))))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Exportations +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defn export-files + [files binary?] + (ptk/reify ::request-file-export + ptk/WatchEvent + (watch [_ state _] + (let [features (features/get-team-enabled-features state) + team-id (:current-team-id state)] + (->> (rx/from files) + (rx/mapcat + (fn [file] + (->> (rp/cmd! :has-file-libraries {:file-id (:id file)}) + (rx/map #(assoc file :has-libraries? %))))) + (rx/reduce conj []) + (rx/map (fn [files] + (modal/show + {:type :export + :features features + :team-id team-id + :has-libraries? (->> files (some :has-libraries?)) + :files files + :binary? binary?})))))))) + diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index a4730c09d..ef0ab8545 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -36,7 +36,6 @@ [app.main.data.workspace.bool :as dwb] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.collapse :as dwco] - [app.main.data.workspace.common :as dwc] [app.main.data.workspace.drawing :as dwd] [app.main.data.workspace.drawing.common :as dwdc] [app.main.data.workspace.edition :as dwe] @@ -65,6 +64,7 @@ [app.main.data.workspace.viewport :as dwv] [app.main.data.workspace.zoom :as dwz] [app.main.features :as features] + [app.main.features.pointer-map :as fpmap] [app.main.repo :as rp] [app.main.streams :as ms] [app.main.worker :as uw] @@ -145,7 +145,6 @@ (watch [_ _ stream] (let [team-id (:id team) file-id (:id file) - file-data (:data file) stoper-s (rx/filter (ptk/type? ::bundle-fetched) stream)] (->> (rx/concat @@ -166,7 +165,8 @@ ;; FIXME: move to bundle fetch stages ;; Load main file - (->> (dwc/resolve-file-data file-id file-data) + (->> (fpmap/resolve-file file) + (rx/map :data) (rx/mapcat (fn [{:keys [pages-index] :as data}] (->> (rx/from (seq pages-index)) (rx/mapcat @@ -186,10 +186,7 @@ (fn [{:keys [id synced-at]}] (->> (rp/cmd! :get-file {:id id :features features}) (rx/map #(assoc % :synced-at synced-at))))) - (rx/merge-map - (fn [{:keys [id data] :as file}] - (->> (dwc/resolve-file-data id data) - (rx/map (fn [data] (assoc file :data data)))))) + (rx/merge-map fpmap/resolve-file) (rx/merge-map (fn [{:keys [id] :as file}] (->> (rp/cmd! :get-file-object-thumbnails {:file-id id :tag "component"}) diff --git a/frontend/src/app/main/data/workspace/common.cljs b/frontend/src/app/main/data/workspace/common.cljs index 9d8221640..a5791ea6d 100644 --- a/frontend/src/app/main/data/workspace/common.cljs +++ b/frontend/src/app/main/data/workspace/common.cljs @@ -8,12 +8,10 @@ (:require [app.common.data.macros :as dm] [app.common.logging :as log] - [app.common.transit :as t] [app.common.types.shape.layout :as ctl] [app.main.data.workspace.changes :as dch] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.undo :as dwu] - [app.main.repo :as rp] [app.util.router :as rt] [beicon.core :as rx] [potok.core :as ptk])) @@ -25,26 +23,6 @@ ;; HELPERS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defn resolve-file-data - [file-id {:keys [pages-index] :as data}] - (letfn [(resolve-pointer [[key val :as kv]] - (if (t/pointer? val) - (->> (rp/cmd! :get-file-fragment {:file-id file-id :fragment-id @val}) - (rx/map #(get % :content)) - (rx/map #(vector key %))) - (rx/of kv))) - - (resolve-pointers [coll] - (->> (rx/from (seq coll)) - (rx/merge-map resolve-pointer) - (rx/reduce conj {})))] - - (->> (rx/zip (resolve-pointers data) - (resolve-pointers pages-index)) - (rx/take 1) - (rx/map (fn [[data pages-index]] - (assoc data :pages-index pages-index)))))) - (defn initialized? "Check if the state is properly initialized in a workspace. This means it has the `:current-page-id` and `:current-file-id` properly set." diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index ac2237b93..5ffe3f82e 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -27,7 +27,6 @@ [app.main.data.modal :as modal] [app.main.data.workspace :as-alias dw] [app.main.data.workspace.changes :as dch] - [app.main.data.workspace.common :as dwc] [app.main.data.workspace.groups :as dwg] [app.main.data.workspace.libraries-helpers :as dwlh] [app.main.data.workspace.notifications :as-alias dwn] @@ -38,6 +37,7 @@ [app.main.data.workspace.thumbnails :as dwt] [app.main.data.workspace.undo :as dwu] [app.main.features :as features] + [app.main.features.pointer-map :as fpmap] [app.main.refs :as refs] [app.main.repo :as rp] [app.main.store :as st] @@ -1144,9 +1144,7 @@ (->> (rp/cmd! :link-file-to-library {:file-id file-id :library-id library-id}) (rx/ignore)) (->> (rp/cmd! :get-file {:id library-id :features features}) - (rx/merge-map (fn [{:keys [id data] :as file}] - (->> (dwc/resolve-file-data id data) - (rx/map (fn [data] (assoc file :data data)))))) + (rx/merge-map fpmap/resolve-file) (rx/map (fn [file] (fn [state] (assoc-in state [:workspace-libraries library-id] file))))) diff --git a/frontend/src/app/main/features/pointer_map.cljs b/frontend/src/app/main/features/pointer_map.cljs new file mode 100644 index 000000000..842ae418a --- /dev/null +++ b/frontend/src/app/main/features/pointer_map.cljs @@ -0,0 +1,33 @@ +;; 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.main.features.pointer-map + "A frontend specific helpers for work with pointer-map feature" + (:require + [app.common.transit :as t] + [app.main.repo :as rp] + [beicon.core :as rx])) + +(defn resolve-file + [{:keys [id data] :as file}] + (letfn [(resolve-pointer [[key val :as kv]] + (if (t/pointer? val) + (->> (rp/cmd! :get-file-fragment {:file-id id :fragment-id @val}) + (rx/map #(get % :content)) + (rx/map #(vector key %))) + (rx/of kv))) + + (resolve-pointers [coll] + (->> (rx/from (seq coll)) + (rx/merge-map resolve-pointer) + (rx/reduce conj {})))] + + (->> (rx/zip (resolve-pointers data) + (resolve-pointers (:pages-index data))) + (rx/take 1) + (rx/map (fn [[data pages-index]] + (let [data (assoc data :pages-index pages-index)] + (assoc file :data data))))))) diff --git a/frontend/src/app/main/ui/dashboard/export.cljs b/frontend/src/app/main/ui/dashboard/export.cljs index b8ee87519..7f6c30028 100644 --- a/frontend/src/app/main/ui/dashboard/export.cljs +++ b/frontend/src/app/main/ui/dashboard/export.cljs @@ -10,7 +10,6 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.main.data.modal :as modal] - [app.main.features :as features] [app.main.store :as st] [app.main.ui.context :as ctx] [app.main.ui.icons :as i] @@ -79,30 +78,29 @@ {::mf/register modal/components ::mf/register-as :export ::mf/wrap-props false} - [{:keys [team-id files has-libraries? binary?]}] + [{:keys [team-id files has-libraries? binary? features]}] (let [new-css-system (mf/use-ctx ctx/new-css-system) - components-v2 (features/use-feature :components-v2) - state* (mf/use-state - #(let [files (mapv (fn [file] (assoc file :loading? true)) files)] - {:status :prepare - :selected :all - :files files})) + state* (mf/use-state + #(let [files (mapv (fn [file] (assoc file :loading? true)) files)] + {:status :prepare + :selected :all + :files files})) - state (deref state*) - selected (:selected state) - status (:status state) + state (deref state*) + selected (:selected state) + status (:status state) start-export (mf/use-fn - (mf/deps team-id selected files components-v2) + (mf/deps team-id selected files features) (fn [] (swap! state* assoc :status :exporting) (->> (uw/ask-many! {:cmd (if binary? :export-binary-file :export-standard-file) :team-id team-id + :features features :export-type selected - :files files - :components-v2 components-v2}) + :files files}) (rx/delay-emit 1000) (rx/subs (fn [msg] diff --git a/frontend/src/app/main/ui/dashboard/file_menu.cljs b/frontend/src/app/main/ui/dashboard/file_menu.cljs index 30cedc7a8..cfd6b748f 100644 --- a/frontend/src/app/main/ui/dashboard/file_menu.cljs +++ b/frontend/src/app/main/ui/dashboard/file_menu.cljs @@ -6,7 +6,7 @@ (ns app.main.ui.dashboard.file-menu (:require - [app.main.data.common :refer [show-shared-dialog]] + [app.main.data.common :as dcm] [app.main.data.dashboard :as dd] [app.main.data.events :as ev] [app.main.data.messages :as dm] @@ -148,11 +148,10 @@ (fn [_] (run! #(st/emit! (dd/set-file-shared (assoc % :is-shared false))) files))) - on-add-shared (fn [event] (dom/stop-propagation event) - (st/emit! (show-shared-dialog (:id file) add-shared))) + (st/emit! (dcm/show-shared-dialog (:id file) add-shared))) on-del-shared (fn [event] @@ -166,38 +165,26 @@ :count-libraries file-count}))) on-export-files - (fn [event-name binary?] - (st/emit! (ptk/event ::ev/event {::ev/name event-name - ::ev/origin "dashboard" - :num-files (count files)})) - - (->> (rx/from files) - (rx/flat-map - (fn [file] - (->> (rp/cmd! :has-file-libraries {:file-id (:id file)}) - (rx/map #(assoc file :has-libraries? %))))) - (rx/reduce conj []) - (rx/subs - (fn [files] - (st/emit! - (modal/show - {:type :export - :team-id current-team-id - :has-libraries? (->> files (some :has-libraries?)) - :files files - :binary? binary?})))))) + (mf/use-fn + (mf/deps files) + (fn [binary?] + (let [evname (if binary? + "export-binary-files" + "export-standard-files")] + (st/emit! (ptk/event ::ev/event {::ev/name evname + ::ev/origin "dashboard" + :num-files (count files)}) + (dcm/export-files files binary?))))) on-export-binary-files - (mf/use-callback - (mf/deps files current-team-id) - (fn [_] - (on-export-files "export-binary-files" true))) + (mf/use-fn + (mf/deps on-export-files) + (partial on-export-files true)) on-export-standard-files - (mf/use-callback - (mf/deps files current-team-id) - (fn [_] - (on-export-files "export-standard-files" false))) + (mf/use-fn + (mf/deps on-export-files) + (partial on-export-files false)) ;; NOTE: this is used for detect if component is still mounted mounted-ref (mf/use-ref true)] diff --git a/frontend/src/app/main/ui/workspace/header.cljs b/frontend/src/app/main/ui/workspace/header.cljs index d04b0260c..d9e9ba124 100644 --- a/frontend/src/app/main/ui/workspace/header.cljs +++ b/frontend/src/app/main/ui/workspace/header.cljs @@ -380,6 +380,10 @@ on-export-shapes (mf/use-fn #(st/emit! (de/show-workspace-export-dialog))) + ;; WARNING: this is broken, but as it is unused code because + ;; it belongs to the pre styles/v2 feature which is enabled by + ;; default right now. THIS CODE IS PENDING TO BE DELETED + on-export-file (mf/use-fn (mf/deps file) diff --git a/frontend/src/app/main/ui/workspace/left_header.cljs b/frontend/src/app/main/ui/workspace/left_header.cljs index 6306d159d..28af7d7ec 100644 --- a/frontend/src/app/main/ui/workspace/left_header.cljs +++ b/frontend/src/app/main/ui/workspace/left_header.cljs @@ -10,7 +10,7 @@ [app.common.files.helpers :as cfh] [app.common.uuid :as uuid] [app.config :as cf] - [app.main.data.common :refer [show-shared-dialog]] + [app.main.data.common :as dcm] [app.main.data.events :as ev] [app.main.data.exports :as de] [app.main.data.modal :as modal] @@ -21,7 +21,6 @@ [app.main.data.workspace.libraries :as dwl] [app.main.data.workspace.shortcuts :as sc] [app.main.refs :as refs] - [app.main.repo :as rp] [app.main.store :as st] [app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]] [app.main.ui.context :as ctx] @@ -31,7 +30,6 @@ [app.util.i18n :as i18n :refer [tr]] [app.util.keyboard :as kbd] [app.util.router :as rt] - [beicon.core :as rx] [cuerdas.core :as str] [potok.core :as ptk] [rumext.v2 :as mf])) @@ -443,7 +441,7 @@ (mf/defc file-menu {::mf/wrap-props false} - [{:keys [on-close file team-id]}] + [{:keys [on-close file]}] (let [file-id (:id file) shared? (:is-shared file) @@ -451,96 +449,106 @@ frames (->> (cfh/get-immediate-children objects uuid/zero) (filterv cfh/frame-shape?)) - add-shared-fn + on-remove-shared (mf/use-fn (mf/deps file-id) - #(st/emit! (dwl/set-file-shared file-id true))) + (fn [event] + (dom/prevent-default event) + (dom/stop-propagation event) + (modal/show! + {:type :delete-shared-libraries + :origin :unpublish + :ids #{file-id} + :on-accept #(st/emit! (dwl/set-file-shared file-id false)) + :count-libraries 1}))) + + on-remove-shared-key-down + (mf/use-fn + (mf/deps on-remove-shared) + (fn [event] + (when (kbd/enter? event) + (on-remove-shared event)))) on-add-shared (mf/use-fn - (mf/deps file-id add-shared-fn) - #(st/emit! (show-shared-dialog file-id add-shared-fn))) + (mf/deps file-id) + (fn [_event] + (let [on-accept #(st/emit! (dwl/set-file-shared file-id true))] + (st/emit! (dcm/show-shared-dialog file-id on-accept))))) - on-remove-shared - (mf/use-fn (mf/deps file-id) - (fn [event] - (dom/prevent-default event) - (dom/stop-propagation event) - (modal/show! - {:type :delete-shared-libraries - :origin :unpublish - :ids #{file-id} - :on-accept #(st/emit! (dwl/set-file-shared file-id false)) - :count-libraries 1}))) + on-add-shared-key-down + (mf/use-fn + (mf/deps on-add-shared) + (fn [event] + (when (kbd/enter? event) + (on-add-shared event)))) on-export-shapes (mf/use-fn #(st/emit! (de/show-workspace-export-dialog))) + on-export-shapes-key-down + (mf/use-fn + (mf/deps on-export-shapes) + (fn [event] + (when (kbd/enter? event) + (on-export-shapes event)))) + on-export-file (mf/use-fn (mf/deps file) - (fn [event-name binary?] - (st/emit! (ptk/event ::ev/event {::ev/name event-name - ::ev/origin "workspace" - :num-files 1})) + (fn [event] + (let [target (dom/get-current-target event) + binary? (= (dom/get-data target "binary") "true") + evname (if binary? + "export-binary-files" + "export-standard-files")] + (st/emit! + (ptk/event ::ev/event {::ev/name evname + ::ev/origin "workspace" + :num-files 1}) + (dcm/export-files [file] binary?))))) - (->> (rx/of file) - (rx/flat-map - (fn [file] - (->> (rp/cmd! :has-file-libraries {:file-id (:id file)}) - (rx/map #(assoc file :has-libraries? %))))) - (rx/reduce conj []) - (rx/subs - (fn [files] - (modal/show! - {:type :export - :team-id team-id - :has-libraries? (->> files (some :has-libraries?)) - :files files - :binary? binary?})))))) - - on-export-binary-file + on-export-file-key-down (mf/use-fn (mf/deps on-export-file) - (partial on-export-file "export-binary-files" true)) - - on-export-standard-file - (mf/use-fn - (mf/deps on-export-file) - (partial on-export-file "export-standard-files" false)) + (fn [event] + (when (kbd/enter? event) + (on-export-file event)))) on-export-frames (mf/use-fn (mf/deps frames) (fn [_] - (st/emit! (de/show-workspace-export-frames-dialog (reverse frames)))))] + (st/emit! (de/show-workspace-export-frames-dialog (reverse frames))))) + + on-export-frames-key-down + (mf/use-fn + (mf/deps on-export-frames) + (fn [event] + (when (kbd/enter? event) + (on-export-frames event))))] [:& dropdown-menu {:show true :list-class (stl/css-case :sub-menu true :file true) :on-close on-close} + (if ^boolean shared? [:> dropdown-menu-item* {:class (stl/css :submenu-item) :on-click on-remove-shared - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-remove-shared event))) + :on-key-down on-remove-shared-key-down :id "file-menu-remove-shared"} [:span {:class (stl/css :item-name)} (tr "dashboard.unpublish-shared")]] [:> dropdown-menu-item* {:class (stl/css :submenu-item) :on-click on-add-shared - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-add-shared event))) + :on-key-down on-add-shared-key-down :id "file-menu-add-shared"} [:span {:class (stl/css :item-name)} (tr "dashboard.add-shared")]]) [:> dropdown-menu-item* {:class (stl/css :submenu-item) :on-click on-export-shapes - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-export-shapes event))) + :on-key-down on-export-shapes-key-down :id "file-menu-export-shapes"} [:span {:class (stl/css :item-name)} (tr "dashboard.export-shapes")] [:span {:class (stl/css :shortcut)} @@ -548,35 +556,32 @@ [:span {:class (stl/css :shortcut-key) :key sc} sc])]] [:> dropdown-menu-item* {:class (stl/css :submenu-item) - :on-click on-export-binary-file - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-export-binary-file event))) + :on-click on-export-file + :on-key-down on-export-file-key-down + :data-binary true :id "file-menu-binary-file"} - [:span {:class (stl/css :item-name)} (tr "dashboard.download-binary-file")]] + [:span {:class (stl/css :item-name)} + (tr "dashboard.download-binary-file")]] [:> dropdown-menu-item* {:class (stl/css :submenu-item) - :on-click on-export-standard-file - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-export-standard-file event))) + :on-click on-export-file + :on-key-down on-export-file-key-down + :data-binary false :id "file-menu-standard-file"} - [:span {:class (stl/css :item-name)} (tr "dashboard.download-standard-file")]] - + [:span {:class (stl/css :item-name)} + (tr "dashboard.download-standard-file")]] (when (seq frames) [:> dropdown-menu-item* {:class (stl/css :submenu-item) :on-click on-export-frames - :on-key-down (fn [event] - (when (kbd/enter? event) - (on-export-frames event))) + :on-key-down on-export-frames-key-down :id "file-menu-export-frames"} [:span {:class (stl/css :item-name)} (tr "dashboard.export-frames")]])])) (mf/defc menu {::mf/wrap-props false} - [{:keys [layout file team-id]}] + [{:keys [layout file]}] (let [show-menu* (mf/use-state false) show-menu? (deref show-menu*) sub-menu* (mf/use-state false) @@ -688,7 +693,6 @@ :file [:& file-menu {:file file - :team-id team-id :on-close close-sub-menu}] :edit diff --git a/frontend/src/app/worker/export.cljs b/frontend/src/app/worker/export.cljs index 9cf7aaf6d..3221216e7 100644 --- a/frontend/src/app/worker/export.cljs +++ b/frontend/src/app/worker/export.cljs @@ -12,6 +12,7 @@ [app.common.types.components-list :as ctkl] [app.common.types.file :as ctf] [app.config :as cfg] + [app.main.features.pointer-map :as fpmap] [app.main.render :as r] [app.main.repo :as rp] [app.util.http :as http] @@ -26,7 +27,7 @@ (defn create-manifest "Creates a manifest entry for the given files" - [team-id file-id export-type files components-v2] + [team-id file-id export-type files features] (letfn [(format-page [manifest page] (-> manifest (assoc (str (:id page)) @@ -39,10 +40,7 @@ (mapv str)) index (->> (get-in file [:data :pages-index]) (vals) - (reduce format-page {})) - features (cond-> [] - components-v2 - (conj "components/v2"))] + (reduce format-page {}))] (-> manifest (assoc (str (:id file)) {:name name @@ -162,14 +160,14 @@ (rx/map #(vector (str (:id file) "/deleted-components.svg") %)))) (defn fetch-file-with-libraries - [file-id components-v2] - (let [features (cond-> #{} components-v2 (conj "components/v2"))] - (->> (rx/zip (rp/cmd! :get-file {:id file-id :features features}) - (rp/cmd! :get-file-libraries {:file-id file-id})) - (rx/map - (fn [[file file-libraries]] - (let [libraries-ids (->> file-libraries (map :id) (filterv #(not= (:id file) %)))] - (assoc file :libraries libraries-ids))))))) + [file-id features] + (->> (rx/zip (->> (rp/cmd! :get-file {:id file-id :features features}) + (rx/mapcat fpmap/resolve-file)) + (rp/cmd! :get-file-libraries {:file-id file-id})) + (rx/map + (fn [[file file-libraries]] + (let [libraries-ids (->> file-libraries (map :id) (filterv #(not= (:id file) %)))] + (assoc file :libraries libraries-ids)))))) (defn make-local-external-references [file file-id] @@ -307,8 +305,7 @@ (update file-id dissoc :libraries)))) (defn collect-files - [file-id export-type components-v2] - + [file-id export-type features] (letfn [(fetch-dependencies [[files pending]] (if (empty? pending) ;; When not pending, we finish the generation @@ -321,7 +318,7 @@ ;; The file is already in the result (rx/of [files pending]) - (->> (fetch-file-with-libraries next components-v2) + (->> (fetch-file-with-libraries next features) (rx/map (fn [file] [(-> files @@ -337,14 +334,13 @@ (rx/map #(process-export file-id export-type %)))))) (defn export-file - [team-id file-id export-type components-v2] - - (let [files-stream (->> (collect-files file-id export-type components-v2) + [team-id file-id export-type features] + (let [files-stream (->> (collect-files file-id export-type features) (rx/share)) manifest-stream (->> files-stream - (rx/map #(create-manifest team-id file-id export-type % components-v2)) + (rx/map #(create-manifest team-id file-id export-type % features)) (rx/map #(vector "manifest.json" %))) render-stream @@ -434,12 +430,12 @@ :file-id (:id file)})))))))) (defmethod impl/handler :export-standard-file - [{:keys [team-id files export-type components-v2] :as message}] + [{:keys [team-id files export-type features] :as message}] (->> (rx/from files) (rx/mapcat (fn [file] - (->> (export-file team-id (:id file) export-type components-v2) + (->> (export-file team-id (:id file) export-type features) (rx/map (fn [value] (if (contains? value :type)