🐛 Fix several issues related to path edition (#8187)

*  Improve save-path-content event consistency

Mainly removing possible race conditions from the event
implementation.

*  Ensure path content snapshot on start-path-edit event

*  Reuse already available shape-id on split-segments
This commit is contained in:
Andrey Antukh 2026-01-26 22:48:57 +01:00
parent 1ce0b60e3d
commit 56fd66b91a
2 changed files with 37 additions and 36 deletions

View File

@ -70,20 +70,22 @@
(= (-> content last :command) :move-to)) (= (-> content last :command) :move-to))
(into [] (take (dec (count content)) content)) (into [] (take (dec (count content)) content))
content)] content)]
(-> state (st/set-content state content)))
(st/set-content content))))
ptk/WatchEvent ptk/WatchEvent
(watch [it state _] (watch [it state _]
(let [page-id (:current-page-id state) (let [page-id (:current-page-id state)
objects (dsh/lookup-page-objects state page-id) local (get state :workspace-local)
id (dm/get-in state [:workspace-local :edition]) id (get local :edition)
old-content (dm/get-in state [:workspace-local :edit-path id :old-content]) objects (dsh/lookup-page-objects state page-id)]
shape (st/get-path state)]
(if (and (some? old-content) (some? (:id shape))) ;; NOTE: we proceed only if the shape is present on the
(let [changes (generate-path-changes it objects page-id shape old-content (:content shape))] ;; objects, if shape is a ephimeral drawing shape, we should
(rx/of (dch/commit-changes changes))) ;; do nothing
(rx/empty))))))) (when-let [shape (get objects id)]
(when-let [old-content (dm/get-in local [:edit-path id :old-content])]
(let [new-content (get shape :content)
changes (generate-path-changes it objects page-id shape old-content new-content)]
(rx/of (dch/commit-changes changes))))))))))

View File

@ -8,7 +8,6 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.types.path :as path] [app.common.types.path :as path]
[app.common.types.path.helpers :as path.helpers] [app.common.types.path.helpers :as path.helpers]
@ -289,34 +288,34 @@
(declare stop-path-edit) (declare stop-path-edit)
(defn start-path-edit (defn start-path-edit
[id] [id]
(ptk/reify ::start-path-edit (ptk/reify ::start-path-edit
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [objects (dsh/lookup-page-objects state) (let [objects (dsh/lookup-page-objects state)
edit-path (dm/get-in state [:workspace-local :edit-path id]) shape (get objects id)]
content (st/get-path state :content)
state (cond-> state
(cfh/path-shape? objects id)
(st/set-content (path/close-subpaths content)))]
(cond-> state (-> state
(or (not edit-path) (st/set-content (path/close-subpaths (:content shape)))
(= :draw (:edit-mode edit-path))) (update-in [:workspace-local :edit-path id]
(assoc-in [:workspace-local :edit-path id] {:edit-mode :move (fn [state]
:selected #{} (let [state (if state
:snap-toggled false}) (if (= :move (:edit-mode state))
(and (some? edit-path) (assoc state :edit-mode :draw)
(= :move (:edit-mode edit-path))) state)
(assoc-in [:workspace-local :edit-path id :edit-mode] :draw)))) {:edit-mode :move
:selected #{}
:snap-toggled false})]
(assoc state :old-content (:content shape))))))))
ptk/WatchEvent ptk/WatchEvent
(watch [_ _ stream] (watch [_ _ stream]
(let [stopper (->> stream (let [stopper (rx/filter #(let [type (ptk/type %)]
(rx/filter #(let [type (ptk/type %)] (= type ::dwe/clear-edition-mode)
(= type ::dwe/clear-edition-mode) (= type ::start-path-edit))
(= type ::start-path-edit))))] stream)]
(rx/concat (rx/concat
(rx/of (undo/start-path-undo)) (rx/of (undo/start-path-undo))
(->> stream (->> stream
@ -325,7 +324,8 @@
(rx/map #(stop-path-edit id)) (rx/map #(stop-path-edit id))
(rx/take-until stopper))))))) (rx/take-until stopper)))))))
(defn stop-path-edit [id] (defn stop-path-edit
[id]
(ptk/reify ::stop-path-edit (ptk/reify ::stop-path-edit
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -335,13 +335,12 @@
(watch [_ _ _] (watch [_ _ _]
(rx/of (ptk/data-event :layout/update {:ids [id]}))))) (rx/of (ptk/data-event :layout/update {:ids [id]})))))
(defn split-segments (defn- split-segments
[{:keys [from-p to-p t]}] [id {:keys [from-p to-p t]}]
(ptk/reify ::split-segments (ptk/reify ::split-segments
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [id (st/get-path-id state) (let [content (st/get-path state :content)]
content (st/get-path state :content)]
(-> state (-> state
(assoc-in [:workspace-local :edit-path id :old-content] content) (assoc-in [:workspace-local :edit-path id :old-content] content)
(st/set-content (-> content (st/set-content (-> content
@ -353,10 +352,10 @@
(rx/of (changes/save-path-content {:preserve-move-to true}))))) (rx/of (changes/save-path-content {:preserve-move-to true})))))
(defn create-node-at-position (defn create-node-at-position
[event] [params]
(ptk/reify ::create-node-at-position (ptk/reify ::create-node-at-position
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [id (st/get-path-id state)] (let [id (st/get-path-id state)]
(rx/of (dwsh/update-shapes [id] path/convert-to-path) (rx/of (dwsh/update-shapes [id] path/convert-to-path)
(split-segments event)))))) (split-segments id params))))))