mirror of
https://github.com/logseq/logseq.git
synced 2026-05-29 15:09:41 +00:00
fix: stabilize undo/redo raw tx replay order
This commit is contained in:
8
deps/db/src/logseq/db/common/normalize.cljs
vendored
8
deps/db/src/logseq/db/common/normalize.cljs
vendored
@@ -113,7 +113,7 @@
|
||||
#{e block-uuid (str block-uuid)})
|
||||
#{e}))
|
||||
|
||||
(defn- reorder-retract-entity
|
||||
(defn reorder-retract-entity
|
||||
[tx-data]
|
||||
(let [retract-ops (filter retract-entity-op? tx-data)
|
||||
{recreated-block-retract-ops true
|
||||
@@ -122,7 +122,8 @@
|
||||
(boolean
|
||||
(some (fn [x]
|
||||
(and
|
||||
(= 5 (count x))
|
||||
(vector? x)
|
||||
(>= (count x) 4)
|
||||
(= (first x) :db/add)
|
||||
(= (nth x 2) :block/uuid)
|
||||
(= (nth x 3) id))) tx-data)))))
|
||||
@@ -132,7 +133,8 @@
|
||||
set)
|
||||
datom-for-retracted-eid?
|
||||
(fn [item]
|
||||
(and (= 5 (count item))
|
||||
(and (vector? item)
|
||||
(>= (count item) 4)
|
||||
(contains? retract-keys (second item))))
|
||||
datoms-for-retracted-eids (filter datom-for-retracted-eid? tx-data)
|
||||
others (remove (fn [item]
|
||||
|
||||
@@ -104,7 +104,8 @@
|
||||
(let [reversed-datom (d/datom e a v t (not added))]
|
||||
;; trick: reverse the order of `db-before` and `db-after`
|
||||
(db-normalize/normalize-datom db-before db-after reversed-datom))))
|
||||
(db-normalize/replace-attr-retract-with-retract-entity-v2 db-after)))
|
||||
(db-normalize/replace-attr-retract-with-retract-entity-v2 db-after)
|
||||
db-normalize/reorder-retract-entity))
|
||||
|
||||
(defn normalize-rebased-pending-tx
|
||||
[{:keys [db-before db-after tx-data]}]
|
||||
@@ -190,7 +191,8 @@
|
||||
(if (and (vector? item) (= 5 (count item)))
|
||||
(let [[op e a v _t] item]
|
||||
[op e a v])
|
||||
item)))))
|
||||
item)))
|
||||
db-normalize/reorder-retract-entity))
|
||||
|
||||
(defn- inferred-outliner-ops?
|
||||
[tx-meta]
|
||||
@@ -307,7 +309,8 @@
|
||||
(contains? op-construct/semantic-outliner-ops
|
||||
(first op-entry)))))
|
||||
seq)
|
||||
tx-data (if undo? reversed-tx tx)
|
||||
tx-data (-> (if undo? reversed-tx tx)
|
||||
normalize-tx-data-for-rebase)
|
||||
ops' (if (seq ops)
|
||||
ops
|
||||
[[:transact [tx-data nil]]])
|
||||
@@ -425,7 +428,8 @@
|
||||
(defn- reverse-history-action!
|
||||
[conn local-tx]
|
||||
(if-let [tx-data (seq (:reversed-tx local-tx))]
|
||||
(ldb/transact! conn tx-data
|
||||
(ldb/transact! conn
|
||||
(normalize-tx-data-for-rebase tx-data)
|
||||
{:outliner-op (:outliner-op local-tx)
|
||||
:reverse? true})
|
||||
(invalid-rebase-op! :reverse-history-action
|
||||
|
||||
@@ -159,6 +159,43 @@
|
||||
(second %))
|
||||
redo-op)))
|
||||
|
||||
(defn- move-retract-entity-ops-to-front
|
||||
[tx-data]
|
||||
(let [retract-entity-op? (fn [item]
|
||||
(and (vector? item)
|
||||
(= 2 (count item))
|
||||
(= :db/retractEntity (first item))))
|
||||
retract-ops (filter retract-entity-op? tx-data)
|
||||
others (remove retract-entity-op? tx-data)]
|
||||
(vec (concat retract-ops others))))
|
||||
|
||||
(defn- poison-history-tx-order!
|
||||
[tx-id]
|
||||
(when-let [entry (client-op/get-local-tx-entry test-repo tx-id)]
|
||||
(client-op/upsert-local-tx-entry!
|
||||
test-repo
|
||||
{:tx-id tx-id
|
||||
:pending? true
|
||||
:failed? false
|
||||
:outliner-op (:outliner-op entry)
|
||||
:undo-redo (:db-sync/undo-redo entry)
|
||||
:forward-outliner-ops (:forward-outliner-ops entry)
|
||||
:inverse-outliner-ops (:inverse-outliner-ops entry)
|
||||
:inferred-outliner-ops? (:inferred-outliner-ops? entry)
|
||||
:normalized-tx-data (move-retract-entity-ops-to-front (:tx entry))
|
||||
:reversed-tx-data (move-retract-entity-ops-to-front (:reversed-tx entry))})))
|
||||
|
||||
(defn- property-value-titles
|
||||
[value]
|
||||
(cond
|
||||
(nil? value) []
|
||||
(string? value) [value]
|
||||
(map? value) [(:block/title value)]
|
||||
(coll? value) (->> value
|
||||
(mapcat property-value-titles)
|
||||
vec)
|
||||
:else [value]))
|
||||
|
||||
(deftest undo-missing-history-action-row-replays-from-inline-ops-test
|
||||
(testing "undo/redo should replay from inline history ops when pending row is missing"
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
@@ -953,6 +990,40 @@
|
||||
(worker-undo-redo/redo test-repo)
|
||||
(is (= "foo bar" (:block/title (d/entity @conn [:block/uuid child-uuid])))))))
|
||||
|
||||
(deftest repeated-set-block-property-text-value-undo-redo-test
|
||||
(testing "set-block-property text value survives repeated undo/redo for one and many cardinalities"
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
(let [conn (worker-state/get-datascript-conn test-repo)
|
||||
{:keys [child-uuid]} (seed-page-parent-child!)]
|
||||
(doseq [[suffix cardinality] [[:one :one] [:many :many]]]
|
||||
(let [property-id (keyword (str "user.property/p1-undo-redo-" (name suffix)))]
|
||||
(outliner-op/apply-ops! conn
|
||||
[[:upsert-property [property-id
|
||||
{:logseq.property/type :default
|
||||
:db/cardinality cardinality}
|
||||
{}]]]
|
||||
(local-tx-meta {:client-id "test-client"}))
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
(outliner-op/apply-ops! conn
|
||||
[[:set-block-property [[:block/uuid child-uuid]
|
||||
property-id
|
||||
"value-1"]]]
|
||||
(local-tx-meta {:client-id "test-client"}))
|
||||
(let [history (latest-undo-history-data)]
|
||||
(is (empty? (:db-sync/forward-outliner-ops history))))
|
||||
(dotimes [_ 3]
|
||||
(when-let [undo-tx-id (:db-sync/tx-id (latest-undo-history-data))]
|
||||
(poison-history-tx-order! undo-tx-id))
|
||||
(is (map? (worker-undo-redo/undo test-repo)))
|
||||
(is (empty? (property-value-titles
|
||||
(get (d/entity @conn [:block/uuid child-uuid]) property-id))))
|
||||
(when-let [redo-tx-id (:db-sync/tx-id (latest-redo-history-data))]
|
||||
(poison-history-tx-order! redo-tx-id))
|
||||
(is (map? (worker-undo-redo/redo test-repo)))
|
||||
(let [titles (property-value-titles
|
||||
(get (d/entity @conn [:block/uuid child-uuid]) property-id))]
|
||||
(is (contains? (set titles) "value-1")))))))))
|
||||
|
||||
(deftest save-two-blocks-undo-targets-latest-block-test
|
||||
(testing "undo after saving two blocks reverts the latest saved block first"
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
|
||||
Reference in New Issue
Block a user