♻️ Extract wait-for-persistence into shared helper (#10272)

Add wait-persisted and force-persist-and-wait to app.main.data.persistence,
removing 5 inline copies and 2 private helper functions across the codebase.

Replaced in:
- assets.cljs       -> dwp/force-persist-and-wait 400
- clipboard.cljs    -> dps/force-persist-and-wait 400
- versions.cljs     -> dwp/wait-persisted (3 call sites, dropped 2 priv fns)
- shape.cljs        -> dwp/wait-persisted 5000

Co-authored-by: deepseek-v4-flash <deepseek-v4-flash@penpot.app>
This commit is contained in:
Andrey Antukh 2026-06-18 10:43:30 +02:00 committed by GitHub
parent 203817fe6a
commit 18c8769f05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 31 additions and 39 deletions

View File

@ -15,7 +15,6 @@
[app.main.data.modal :as modal]
[app.main.data.persistence :as dwp]
[app.main.features :as features]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
[app.util.dom :as dom]
@ -204,13 +203,7 @@
:wait true
:is-wasm (wasm-export-enabled? state)}]
(rx/concat
(rx/of ::dwp/force-persist)
;; Wait the persist to be succesfull
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/first)
(rx/timeout 400 (rx/empty)))
(dwp/force-persist-and-wait 400)
(->> (rp/cmd! :export params)
(rx/map (fn [{:keys [filename mtype uri]}]

View File

@ -12,6 +12,7 @@
[app.common.uuid :as uuid]
[app.main.data.changes :as dch]
[app.main.data.helpers :as dsh]
[app.main.refs :as refs]
[app.main.repo :as rp]
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
@ -26,6 +27,26 @@
(def force-persist? #(= % ::force-persist))
(defn wait-persisted
"Returns an observable that emits the first terminal persistence status
(nil | :saved) and completes. With a timeout-ms, if persistence doesn't
settle in time the observable completes silently without emitting."
([] (wait-persisted nil))
([timeout-ms]
(let [base (->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/take 1))]
(if timeout-ms
(->> base (rx/timeout timeout-ms (rx/empty)))
base))))
(defn force-persist-and-wait
"Convenience that emits the force-persist event and then waits for
persistence to settle. Returns the combined observable."
([] (force-persist-and-wait nil))
([timeout-ms]
(rx/concat (rx/of ::force-persist) (wait-persisted timeout-ms))))
(defn- update-status
[status]
(ptk/reify ::update-status

View File

@ -37,7 +37,7 @@
[app.main.data.exports.wasm :as wasm.exports]
[app.main.data.helpers :as dsh]
[app.main.data.notifications :as ntf]
[app.main.data.persistence :as-alias dps]
[app.main.data.persistence :as dps]
[app.main.data.workspace.media :as dwm]
[app.main.data.workspace.selection :as dws]
[app.main.data.workspace.shapes :as dwsh]
@ -1166,11 +1166,7 @@
(rx/concat
;; Ensure current state persisted before exporting.
(rx/of ::dps/force-persist)
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/first)
(rx/timeout 400 (rx/empty)))
(dps/force-persist-and-wait 400)
;; Exporting itself can take its time, better to notify that we are busy.
(rx/of (ntf/info (tr "workspace.clipboard.copying")))

View File

@ -19,7 +19,6 @@
[app.main.data.workspace.pages :as dwpg]
[app.main.data.workspace.thumbnails :as th]
[app.main.features :as features]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.util.i18n :refer [tr]]
[beicon.v2.core :as rx]
@ -73,9 +72,7 @@
(rx/of ::dwp/force-persist
(ev/event {::ev/name "create-version"}))
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/take 1)
(->> (dwp/wait-persisted)
(rx/mapcat #(rp/cmd! :create-file-snapshot {:file-id file-id :label label}))
(rx/mapcat
(fn [{:keys [id]}]
@ -120,13 +117,6 @@
(effect [_ _ _]
(th/clear-queue!))))
(defn- wait-for-persistence
[file-id snapshot-id]
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/take 1)
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id snapshot-id}))))
(defn delete-version
[id]
(assert (uuid? id) "expected valid uuid for `id`")
@ -223,7 +213,8 @@
(rx/of ::dwp/force-persist
(dw/remove-layout-flag :document-history))
(->> (wait-for-persistence file-id id)
(->> (dwp/wait-persisted)
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
(rx/map #(initialize-version))))))))
(defn enter-restore
@ -349,12 +340,6 @@
;; PLUGINS SPECIFIC EVENTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn- wait-persisted-status
[]
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/take 1)))
(defn create-version-from-plugins
[file-id label resolve reject]
@ -371,7 +356,7 @@
(rx/of ::dwp/force-persist))
(->> (if (= file-id current-file-id)
(wait-persisted-status)
(dwp/wait-persisted)
(rx/of :nothing))
(rx/mapcat
(fn [_]
@ -401,7 +386,8 @@
::ev/origin "plugins"})
::dwp/force-persist)
(->> (wait-for-persistence file-id id)
(->> (dwp/wait-persisted)
(rx/mapcat #(rp/cmd! :restore-file-snapshot {:file-id file-id :id id}))
(rx/map #(initialize-version)))
(->> (rx/of 1)

View File

@ -48,7 +48,6 @@
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.variants :as dwv]
[app.main.refs :as refs]
[app.main.repo :as rp]
[app.main.store :as st]
[app.plugins.fills :as fills]
@ -1304,10 +1303,7 @@
;; renders locally and does not need this.)
(st/emit! ::dwp/force-persist)
(->> (rx/concat
(->> (rx/from-atom refs/persistence-state {:emit-current-value? true})
(rx/filter #(or (nil? %) (= :saved %)))
(rx/first)
(rx/timeout 5000 (rx/empty))
(->> (dwp/wait-persisted 5000)
(rx/ignore))
(rp/cmd! :export payload))
(rx/mapcat (fn [{:keys [uri]}]