diff --git a/frontend/src/app/main/data/changes.cljs b/frontend/src/app/main/data/changes.cljs index 7cae1add0f..042f943e2c 100644 --- a/frontend/src/app/main/data/changes.cljs +++ b/frontend/src/app/main/data/changes.cljs @@ -122,7 +122,8 @@ (defn commit "Create a commit event instance" [{:keys [commit-id redo-changes undo-changes origin save-undo? features - file-id file-revn file-vern undo-group tags stack-undo? source ignore-wasm?]}] + file-id file-revn file-vern undo-group tags stack-undo? source ignore-wasm? + selected-before]}] (assert (cpc/check-changes redo-changes) "expect valid vector of changes for redo-changes") @@ -148,7 +149,8 @@ :undo-group undo-group :tags tags :stack-undo? stack-undo? - :ignore-wasm? ignore-wasm?}] + :ignore-wasm? ignore-wasm? + :selected-before selected-before}] (ptk/reify ::commit cljs.core/IDeref @@ -205,15 +207,17 @@ ;; Prevent commit changes by a viewer team member (it really should never happen) (when (:can-edit permissions) - (rx/of (-> params - (assoc :undo-group undo-group) - (assoc :features features) - (assoc :tags tags) - (assoc :stack-undo? stack-undo?) - (assoc :save-undo? save-undo?) - (assoc :file-id file-id) - (assoc :file-revn (resolve-file-revn state file-id)) - (assoc :file-vern (resolve-file-vern state file-id)) - (assoc :undo-changes uchg) - (assoc :redo-changes rchg) - (commit)))))))) + (let [selected (dm/get-in state [:workspace-local :selected])] + (rx/of (-> params + (assoc :undo-group undo-group) + (assoc :features features) + (assoc :tags tags) + (assoc :stack-undo? stack-undo?) + (assoc :save-undo? save-undo?) + (assoc :file-id file-id) + (assoc :file-revn (resolve-file-revn state file-id)) + (assoc :file-vern (resolve-file-vern state file-id)) + (assoc :undo-changes uchg) + (assoc :redo-changes rchg) + (assoc :selected-before selected) + (commit))))))))) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index dd03d7601e..35677f3785 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -484,12 +484,13 @@ (rx/filter dch/commit?) (rx/map deref) (rx/mapcat - (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo?]}] + (fn [{:keys [save-undo? undo-changes redo-changes undo-group tags stack-undo? selected-before]}] (if (and save-undo? (seq undo-changes)) (let [entry {:undo-changes undo-changes :redo-changes redo-changes :undo-group undo-group - :tags tags}] + :tags tags + :selected-before selected-before}] (rx/of (dwu/append-undo entry stack-undo?))) (rx/empty)))))) (rx/take-until stoper-s)))) diff --git a/frontend/src/app/main/data/workspace/undo.cljs b/frontend/src/app/main/data/workspace/undo.cljs index 2b2c6f048b..2296aed447 100644 --- a/frontend/src/app/main/data/workspace/undo.cljs +++ b/frontend/src/app/main/data/workspace/undo.cljs @@ -60,7 +60,9 @@ [:undo-changes [:vector cpc/schema:change]] [:redo-changes [:vector cpc/schema:change]] [:undo-group ::sm/uuid] - [:tags [:set :keyword]]]) + [:tags [:set :keyword]] + [:selected-before {:optional true} [:maybe [:set ::sm/uuid]]] + [:selected-after {:optional true} [:maybe [:set ::sm/uuid]]]]) (def check-undo-entry (sm/check-fn schema:undo-entry)) @@ -103,24 +105,28 @@ (defn- stack-undo-entry "Extends the current undo entry in the workspace with new changes if it exists, or creates a new entry if it doesn't." - [state {:keys [undo-changes redo-changes] :as entry}] + [state {:keys [undo-changes redo-changes selected-after] :as entry}] (let [index (get-in state [:workspace-undo :index] -1)] (if (>= index 0) (update-in state [:workspace-undo :items index] (fn [item] (-> item (update :undo-changes #(into undo-changes %)) - (update :redo-changes #(into % redo-changes))))) + (update :redo-changes #(into % redo-changes)) + (assoc :selected-after selected-after)))) (add-undo-entry state entry)))) (defn- accumulate-undo-entry "Extends the current undo transaction with new changes." - [state {:keys [undo-changes redo-changes undo-group tags]}] + [state {:keys [undo-changes redo-changes undo-group tags selected-before selected-after]}] (-> state (update-in [:workspace-undo :transaction :undo-changes] #(into undo-changes %)) (update-in [:workspace-undo :transaction :redo-changes] #(into % redo-changes)) (cond-> (nil? (get-in state [:workspace-undo :transaction :undo-group])) (assoc-in [:workspace-undo :transaction :undo-group] undo-group)) + (cond-> (nil? (get-in state [:workspace-undo :transaction :selected-before])) + (assoc-in [:workspace-undo :transaction :selected-before] selected-before)) + (assoc-in [:workspace-undo :transaction :selected-after] selected-after) (assoc-in [:workspace-undo :transaction :tags] tags))) (defn append-undo @@ -137,18 +143,20 @@ (ptk/reify ::append-undo ptk/UpdateEvent (update [_ state] - (cond - (and (get-in state [:workspace-undo :transaction]) - (or (not stack?) - (d/not-empty? (get-in state [:workspace-undo :transaction :undo-changes])) - (d/not-empty? (get-in state [:workspace-undo :transaction :redo-changes])))) - (accumulate-undo-entry state entry) + (let [selected-after (dm/get-in state [:workspace-local :selected]) + entry (assoc entry :selected-after selected-after)] + (cond + (and (get-in state [:workspace-undo :transaction]) + (or (not stack?) + (d/not-empty? (get-in state [:workspace-undo :transaction :undo-changes])) + (d/not-empty? (get-in state [:workspace-undo :transaction :redo-changes])))) + (accumulate-undo-entry state entry) - stack? - (stack-undo-entry state entry) + stack? + (stack-undo-entry state entry) - :else - (add-undo-entry state entry))))) + :else + (add-undo-entry state entry)))))) (def empty-tx {:undo-changes [] :redo-changes []}) @@ -234,6 +242,16 @@ (rx/map first) (rx/map commit-undo-transaction)))))) +(defn- restore-selection + "Restores the selection state from an undo entry." + [selected-ids] + (ptk/reify ::restore-selection + ptk/UpdateEvent + (update [_ state] + (if (some? selected-ids) + (assoc-in state [:workspace-local :selected] selected-ids) + state)))) + (defn undo-to-index "Repeat undoing or redoing until dest-index is reached." [dest-index] @@ -302,12 +320,15 @@ (find-first-group-idx index))] (if undo-group - (rx/of (undo-to-index (dec undo-group-index))) + (let [first-item (get items undo-group-index)] + (rx/of (undo-to-index (dec undo-group-index)) + (restore-selection (:selected-before first-item)))) (rx/of (materialize-undo changes (dec index)) (dch/commit-changes {:redo-changes changes :undo-changes [] :save-undo? false :origin it}) + (restore-selection (:selected-before item)) (assure-valid-current-page))))))))))) (def redo @@ -337,12 +358,15 @@ redo-group-index (when undo-group (find-last-group-idx (inc index)))] (if undo-group - (rx/of (undo-to-index redo-group-index)) + (let [last-item (get items redo-group-index)] + (rx/of (undo-to-index redo-group-index) + (restore-selection (:selected-after last-item)))) (rx/of (materialize-undo changes (inc index)) (dch/commit-changes {:redo-changes changes :undo-changes [] :origin it - :save-undo? false}))))))))))) + :save-undo? false}) + (restore-selection (:selected-after item)))))))))))) (defn- assure-valid-current-page []