diff --git a/CHANGES.md b/CHANGES.md index 4e61617ad..adfe0d38b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,12 @@ ### :boom: Breaking changes ### :heart: Community contributions by (Thank you!) +## 1.8.3-alpha + +### :sparkles: New features + +- Adds progress report to importing process + ## 1.8.2-alpha ### :bug: Bugs fixed diff --git a/frontend/resources/styles/main/partials/modal.scss b/frontend/resources/styles/main/partials/modal.scss index 0522cb6cd..fb6d3c686 100644 --- a/frontend/resources/styles/main/partials/modal.scss +++ b/frontend/resources/styles/main/partials/modal.scss @@ -399,6 +399,13 @@ font-style: italic; } + .progress-message { + margin: 0 2rem; + color: $color-info; + font-size: $fs12; + font-style: italic; + } + .linked-libraries { display: flex; flex-wrap: wrap; diff --git a/frontend/src/app/main/ui/dashboard/import.cljs b/frontend/src/app/main/ui/dashboard/import.cljs index 3c11e03c9..032d6c01f 100644 --- a/frontend/src/app/main/ui/dashboard/import.cljs +++ b/frontend/src/app/main/ui/dashboard/import.cljs @@ -98,23 +98,53 @@ (filter #(= :ready (:status %))) (mapv #(assoc % :status :importing)))) -(defn update-status [files file-id status] +(defn update-status [files file-id status progress] (->> files (mapv (fn [file] (cond-> file - (= file-id (:file-id file)) - (assoc :status status)))))) + (and (= file-id (:file-id file)) (not= status :import-progress)) + (assoc :status status) + + (and (= file-id (:file-id file)) (= status :import-progress)) + (assoc :progress progress)))))) + +(defn parse-progress-message + [message] + (case (:type message) + :upload-data + (tr "dashboard.import.progress.upload-data" (:current message) (:total message)) + + :upload-media + (tr "dashboard.import.progress.upload-media" (:file message)) + + :process-page + (tr "dashboard.import.progress.process-page" (:file message)) + + :process-colors + (tr "dashboard.import.progress.process-colors") + + :process-typographies + (tr "dashboard.import.progress.process-typographies") + + :process-media + (tr "dashboard.import.progress.process-media") + + :process-components + (tr "dashboard.import.progress.process-components") + + (str message))) (mf/defc import-entry [{:keys [state file editing?]}] - (let [loading? (or (= :analyzing (:status file)) - (= :importing (:status file))) - load-success? (= :import-success (:status file)) - analyze-error? (= :analyze-error (:status file)) - import-error? (= :import-error (:status file)) - ready? (= :ready (:status file)) - is-shared? (:shared file) + (let [loading? (or (= :analyzing (:status file)) + (= :importing (:status file))) + load-success? (= :import-success (:status file)) + analyze-error? (= :analyze-error (:status file)) + import-error? (= :import-error (:status file)) + ready? (= :ready (:status file)) + is-shared? (:shared file) + progress (:progress file) handle-edit-key-press (mf/use-callback @@ -173,13 +203,17 @@ [:button {:on-click handle-edit-entry} i/pencil] [:button {:on-click handle-remove-entry} i/trash]]] - (when analyze-error? + (cond + analyze-error? [:div.error-message - (tr "dashboard.import.analyze-error")]) + (tr "dashboard.import.analyze-error")] - (when import-error? + import-error? [:div.error-message - (tr "dashboard.import.import-error")]) + (tr "dashboard.import.import-error")] + + (and (not load-success?) (some? progress)) + [:div.progress-message (parse-progress-message progress)]) [:div.linked-libraries (for [library-id (:libraries file)] @@ -223,11 +257,10 @@ {:cmd :import-files :project-id project-id :files files}) - (rx/delay-emit emit-delay) (rx/subs - (fn [{:keys [file-id status] :as msg}] + (fn [{:keys [file-id status message] :as msg}] (log/debug :msg msg) - (swap! state update :files update-status file-id status)))))) + (swap! state update :files update-status file-id status message)))))) handle-cancel (mf/use-callback diff --git a/frontend/src/app/util/import/parser.cljs b/frontend/src/app/util/import/parser.cljs index 257fc169b..08d4a3037 100644 --- a/frontend/src/app/util/import/parser.cljs +++ b/frontend/src/app/util/import/parser.cljs @@ -640,7 +640,7 @@ (defn get-image-name [node] - (get-in node [:attrs :penpot:name])) + (get-meta node :name)) (defn get-image-data [node] diff --git a/frontend/src/app/worker/import.cljs b/frontend/src/app/worker/import.cljs index 8f899a491..cfb28bc07 100644 --- a/frontend/src/app/worker/import.cljs +++ b/frontend/src/app/worker/import.cljs @@ -68,6 +68,33 @@ no-parse? (rx/map :content))))) +(defn progress! + ([context type] + (assert (keyword? type)) + (progress! context type nil nil nil)) + + ([context type file] + (assert (keyword? type)) + (assert (string? file)) + (progress! context type file nil nil)) + + ([context type current total] + (keyword? type) + (assert (number? current)) + (assert (number? total)) + (progress! context type nil current total)) + + ([context type file current total] + (when (and context (contains? context :progress)) + (let [msg {:type type + :file file + :current current + :total total}] + (log/debug :status :import-progress :message msg) + (rx/push! (:progress context) {:file-id (:file-id context) + :status :import-progress + :message msg}))))) + (defn resolve-factory "Creates a wrapper around the atom to remap ids to new ids and keep their relationship so they ids are coherent." @@ -118,34 +145,42 @@ (defn send-changes "Creates batches of changes to be sent to the backend" - [file] + [context file] (let [revn (atom (:revn file)) file-id (:id file) session-id (uuid/next) changes-batches (->> (fb/generate-changes file) (partition change-batch-size change-batch-size nil) - (mapv vec))] + (mapv vec)) + + current (atom 0) + total (count changes-batches)] (rx/concat (->> (rx/from changes-batches) (rx/mapcat - #(rp/mutation - :update-file - {:id file-id - :session-id session-id - :revn @revn - :changes %})) + (fn [change-batch] + (->> (rp/mutation :update-file + {:id file-id + :session-id session-id + :revn @revn + :changes change-batch}) + (rx/tap #(do (swap! current inc) + (progress! context + :upload-data @current total)))))) + (rx/map first) - (rx/tap #(reset! revn (:revn %)))) + (rx/tap #(reset! revn (:revn %))) + (rx/ignore)) (rp/mutation :persist-temp-file {:id file-id})))) (defn upload-media-files "Upload a image to the backend and returns its id" - [file-id name data-uri] + [context file-id name data-uri] - (log/debug :action "uploading" :file-id file-id :name name) + (log/debug :action "Uploading" :file-id file-id :name name) (->> (http/send! {:uri data-uri @@ -158,6 +193,7 @@ :file-id file-id :content blob :is-local true})) + (rx/tap #(progress! context :upload-media name)) (rx/flat-map #(rp/mutation! :upload-file-media-object %)))) (defn resolve-text-content [node context] @@ -251,12 +287,12 @@ (-> file process-interactions))) (defn resolve-media - [file-id node] + [context file-id node] (if (and (not (cip/close? node)) (cip/has-image? node)) (let [name (cip/get-image-name node) data-uri (cip/get-image-data node)] - (->> (upload-media-files file-id name data-uri) + (->> (upload-media-files context file-id name data-uri) (rx/catch #(do (.error js/console "Error uploading media: " name) (rx/of node))) (rx/map @@ -282,7 +318,7 @@ file (-> file (fb/add-page page-data))] (->> (rx/from nodes) (rx/filter cip/shape?) - (rx/mapcat (partial resolve-media file-id)) + (rx/mapcat (partial resolve-media context file-id)) (rx/reduce (partial process-import-node context) file) (rx/map (comp fb/close-page setup-interactions))))) @@ -318,6 +354,8 @@ pages (->> (:pages context) (mapv get-page-data))] (->> (rx/from pages) + (rx/tap (fn [[_ page-name]] + (progress! context :process-page page-name))) (rx/mapcat (fn [[page-id page-name]] (->> (get-file context :page page-id) @@ -371,6 +409,7 @@ :file-id (:id file) :content content :is-local false}))) + (rx/tap #(progress! context :upload-media (:name %))) (rx/flat-map #(rp/mutation! :upload-file-media-object %)) (rx/map (constantly media)) (rx/catch #(do (.error js/console (str "Error uploading media: " (:name media)) ) @@ -394,13 +433,22 @@ (defn process-file [context file] - (->> (rx/of file) - (rx/flat-map (partial process-pages context)) - (rx/flat-map (partial process-library-colors context)) - (rx/flat-map (partial process-library-typographies context)) - (rx/flat-map (partial process-library-media context)) - (rx/flat-map (partial process-library-components context)) - (rx/flat-map send-changes))) + (let [progress-str (rx/subject) + context (assoc context :progress progress-str)] + (rx/merge + progress-str + (->> (rx/of file) + (rx/flat-map (partial process-pages context)) + (rx/tap #(progress! context :process-colors)) + (rx/flat-map (partial process-library-colors context)) + (rx/tap #(progress! context :process-typographies)) + (rx/flat-map (partial process-library-typographies context)) + (rx/tap #(progress! context :process-media)) + (rx/flat-map (partial process-library-media context)) + (rx/tap #(progress! context :process-components)) + (rx/flat-map (partial process-library-components context)) + (rx/flat-map (partial send-changes context)) + (rx/tap #(rx/end! progress-str)))))) (defn create-files [context files] @@ -441,13 +489,13 @@ (rx/catch #(.error js/console "IMPORT ERROR" %)) (rx/flat-map (fn [[file data]] - (->> (uz/load-from-url (:uri data)) - (rx/map #(-> context (assoc :zip %) (merge data))) - (rx/flat-map #(process-file % file)) - (rx/map - (fn [_] - {:status :import-success - :file-id (:file-id data)})) + (->> (rx/concat + (->> (uz/load-from-url (:uri data)) + (rx/map #(-> context (assoc :zip %) (merge data))) + (rx/flat-map #(process-file % file))) + (rx/of + {:status :import-success + :file-id (:file-id data)})) (rx/catch (fn [err] diff --git a/frontend/translations/en.po b/frontend/translations/en.po index f39b799f8..b70e40c3b 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -323,6 +323,27 @@ msgstr "There was a problem importing the file. The file wasn't imported." msgid "dashboard.import.import-message" msgstr "%s files have been imported succesfully." +msgid "dashboard.import.progress.upload-data" +msgstr "Uploading data to server (%s/%s)" + +msgid "dashboard.import.progress.upload-media" +msgstr "Uploading file: %s" + +msgid "dashboard.import.progress.process-page" +msgstr "Processing page: %s" + +msgid "dashboard.import.progress.process-colors" +msgstr "Processing colors" + +msgid "dashboard.import.progress.process-typographies" +msgstr "Processing typographies" + +msgid "dashboard.import.progress.process-media" +msgstr "Processing media" + +msgid "dashboard.import.progress.process-components" +msgstr "Processing components" + #: src/app/main/ui/dashboard/team.cljs msgid "dashboard.invite-profile" msgstr "Invite to team" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index a0139d9e2..1eb849089 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -325,6 +325,30 @@ msgstr "Hubo un problema importando el fichero. No se ha creado el fichero." msgid "dashboard.import.import-message" msgstr "%s ficheros han sido importados con éxito." +msgid "dashboard.import.import-message" +msgstr "%s files have been imported succesfully." + +msgid "dashboard.import.progress.upload-data" +msgstr "Enviando datos al servidor (%s/%s)" + +msgid "dashboard.import.progress.upload-media" +msgstr "Enviando fichero: %s" + +msgid "dashboard.import.progress.process-page" +msgstr "Procesando página: %s" + +msgid "dashboard.import.progress.process-colors" +msgstr "Procesando colores" + +msgid "dashboard.import.progress.process-typographies" +msgstr "Procesando tipografías" + +msgid "dashboard.import.progress.process-media" +msgstr "Procesando media" + +msgid "dashboard.import.progress.process-components" +msgstr "Procesando componentes" + #: src/app/main/ui/dashboard/team.cljs msgid "dashboard.invite-profile" msgstr "Invitar al equipo"