diff --git a/CHANGES.md b/CHANGES.md index 3fff60c6a..767aec2f0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,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 dcc0663b5..1e4202632 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 f4628f478..8481543e2 100644 --- a/frontend/src/app/util/import/parser.cljs +++ b/frontend/src/app/util/import/parser.cljs @@ -628,7 +628,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 fc6c8a4c1..587e03eae 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] @@ -249,12 +285,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 @@ -280,7 +316,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))))) @@ -316,6 +352,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) @@ -369,6 +407,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)) ) @@ -392,13 +431,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] @@ -439,13 +487,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 80da61909..2a92e779b 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" @@ -2975,3 +2996,4 @@ msgstr "Sorry!" msgid "viewer.breaking-change.description" msgstr "This shareable link is no longer valid. Create a new one or ask the owner for a new one. + diff --git a/frontend/translations/es.po b/frontend/translations/es.po index f2c97d48e..265eb513c 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"