Browse Source

fix: undo && redo

Tienson Qin 1 year ago
parent
commit
07c8b7ed74

+ 3 - 19
deps/outliner/src/logseq/outliner/batch_tx.cljc

@@ -1,8 +1,7 @@
 (ns logseq.outliner.batch-tx
   "Batch process multiple transactions.
   When batch-processing, don't refresh ui."
-  #?(:cljs (:require-macros [logseq.outliner.batch-tx]))
-  #?(:cljs (:require [logseq.common.util :as common-util])))
+  #?(:cljs (:require-macros [logseq.outliner.batch-tx])))
 
 (defmacro with-batch-tx-mode
   "1. start batch-tx mode
@@ -28,20 +27,10 @@
 #?(:cljs
    (do
      (defonce ^:private state
-       (atom {;; store all tx-data when batch-processing
-              :batch/txs []
-              ;; store db before batch-tx
+       (atom {;; store db before batch-tx
               :batch/db-before nil
               ;; Opts for with-batch-tx-mode
               :batch/opts nil}))
-
-     (defn get-batch-txs
-       []
-       (->> (:batch/txs @state)
-            (sort-by :tx)
-            ;; We need all the values for :many properties
-            (common-util/distinct-by-last-wins (fn [[e a v _tx added]] [e a v added]))))
-
      (defn ^:api set-batch-db-before!
        [db]
        (swap! state assoc :batch/db-before db))
@@ -58,12 +47,7 @@
        []
        (:batch/opts @state))
 
-     (defn conj-batch-txs!
-       [tx-data]
-       (swap! state update :batch/txs (fn [data] ((fnil into []) data tx-data))))
-
      (defn ^:api exit-batch-txs-mode!
        []
-       (swap! state assoc :batch/txs [])
        (swap! state assoc :batch/db-before nil)
-       (swap! state assoc :batch/opts nil))))
+       (swap! state assoc :batch/opts nil))))

+ 17 - 23
src/main/frontend/worker/db_listener.cljs

@@ -31,7 +31,7 @@ generate asset-change events.")
 
 (defn- sync-db-to-main-thread
   "Return tx-report"
-  [{:keys [tx-meta repo conn] :as tx-report}]
+  [repo conn {:keys [tx-meta] :as tx-report}]
   (let [{:keys [from-disk?]} tx-meta
         result (worker-pipeline/invoke-hooks repo conn tx-report (worker-state/get-context))
         tx-report' (:tx-report result)]
@@ -57,7 +57,7 @@ generate asset-change events.")
 
 (comment
   (defmethod listen-db-changes :debug-listen-db-changes
-    [_ {:keys [tx-data tx-meta]}]
+    [_ {} {:keys [tx-data tx-meta]}]
     (prn :debug-listen-db-changes)
     (prn :tx-data tx-data)
     (prn :tx-meta tx-meta)))
@@ -95,11 +95,11 @@ generate asset-change events.")
                        (cond
                          (and in-batch-tx-mode?
                               (not (:batch-tx/exit? tx-meta)))
-                         ;; in-batch-mode & not end
+                         ;; still in batch mode
                          (vswap! *batch-all-txs into tx-data)
 
                          in-batch-tx-mode?
-                         ;; in-batch-mode & end
+                         ;; exit batch mode
                          (when-let [tx-data (not-empty (get-batch-txs))]
                            (vreset! *batch-all-txs [])
                            (let [db-before (batch-tx/get-batch-db-before)
@@ -108,26 +108,20 @@ generate asset-change events.")
                                                   :tx-data tx-data
                                                   :db-before db-before
                                                   :tx-meta tx-meta)
-                                 args* (assoc tx-report
-                                              :repo repo
-                                              :conn conn)
-                                 tx-report' (when sync-db-to-main-thread?
-                                              (sync-db-to-main-thread args*))
-                                 args** (if tx-report'
-                                          (assoc tx-report' :repo repo)
-                                          args*)
-                                 args*** (into args** (additional-args (:tx-data args**)))]
+                                 tx-report' (if sync-db-to-main-thread?
+                                              (sync-db-to-main-thread repo conn tx-report)
+                                              tx-report)
+                                 opt (into {:repo repo}
+                                           (additional-args (:tx-data tx-report')))]
                              (doseq [[k handler-fn] handlers]
-                               (handler-fn k args***))))
+                               (handler-fn k opt tx-report'))))
 
-                         (and (not in-batch-tx-mode?) (seq tx-data))
+                         (seq tx-data)
                          ;; raw transact
-                         (let [args* (assoc tx-report :repo repo :conn conn)
-                               tx-report' (when sync-db-to-main-thread?
-                                            (sync-db-to-main-thread args*))
-                               args** (if tx-report'
-                                        (assoc tx-report' :repo repo)
-                                        args*)
-                               args*** (into args** (additional-args (:tx-data args**)))]
+                         (let [tx-report' (if sync-db-to-main-thread?
+                                            (sync-db-to-main-thread repo conn tx-report)
+                                            tx-report)
+                               opt (into {:repo repo}
+                                         (additional-args (:tx-data tx-report')))]
                            (doseq [[k handler-fn] handlers]
-                             (handler-fn k args***)))))))))))
+                             (handler-fn k opt tx-report')))))))))))

+ 1 - 1
src/main/frontend/worker/pipeline.cljs

@@ -189,7 +189,7 @@ default = false")
                 full-tx-data (concat (:tx-data tx-report)
                                      (:tx-data refs-tx-report)
                                      (:tx-data tx-report'))
-                final-tx-report (assoc tx-report' :tx-data full-tx-data)
+                final-tx-report (assoc tx-report' :tx-data full-tx-data :tx-meta tx-meta)
                 affected-query-keys (when-not (:importing? context)
                                       (worker-react/get-affected-queries-keys final-tx-report))]
             {:tx-report final-tx-report

+ 3 - 1
src/main/frontend/worker/rtc/asset_db_listener.cljs

@@ -33,7 +33,9 @@
     (client-op/add-asset-ops repo ops)))
 
 (defmethod db-listener/listen-db-changes :gen-asset-change-events
-  [_ {:keys [_tx-data tx-meta db-before db-after repo same-entity-datoms-coll]}]
+  [_
+   {:keys [repo same-entity-datoms-coll]}
+   {:keys [_tx-data tx-meta db-before db-after]}]
   (when (and (client-op/rtc-db-graph? repo)
              (:persist-op? tx-meta true))
     (generate-asset-ops repo db-before db-after same-entity-datoms-coll)))

+ 3 - 2
src/main/frontend/worker/rtc/db_listener.cljs

@@ -132,8 +132,9 @@
    {} entity-datoms))
 
 (defmethod db-listener/listen-db-changes :gen-rtc-ops
-  [_ {:keys [_tx-data tx-meta db-before db-after repo
-             same-entity-datoms-coll id->same-entity-datoms]}]
+  [_
+   {:keys [repo same-entity-datoms-coll id->same-entity-datoms]}
+   {:keys [_tx-data tx-meta db-before db-after]}]
   (when (and (client-op/rtc-db-graph? repo)
              (:persist-op? tx-meta true))
     (let [e->a->add?->v->t (update-vals

+ 4 - 8
src/main/frontend/worker/undo_redo.cljs

@@ -129,7 +129,6 @@ when undo this op, this original entity-map will be transacted back into db")
       (seq (:block/tags m)) (update :block/tags (partial mapv :block/uuid))
       (:block/link m)       (update :block/link :block/uuid))))
 
-
 (defn- reverse-op
   "return ops"
   [db op]
@@ -252,7 +251,6 @@ when undo this op, this original entity-map will be transacted back into db")
        (:block/parent entity)
        (:block/left entity)))
 
-
 (defmulti ^:private reverse-apply-op (fn [op _conn _repo] (first op)))
 (defmethod reverse-apply-op :default
   [_ _ _]
@@ -302,7 +300,6 @@ when undo this op, this original entity-map will be transacted back into db")
           block-uuid-set)))
       block-entities))))
 
-
 (defmethod reverse-apply-op ::insert-blocks
   [op conn repo]
   (let [[_ {:keys [block-uuids]}] op]
@@ -402,7 +399,6 @@ when undo this op, this original entity-map will be transacted back into db")
       (seq other-ops)         (conj-vec other-ops)
       (seq sorted-remove-ops) (conj-vec sorted-remove-ops))))
 
-
 (defn undo
   [repo page-block-uuid conn]
   (if-let [ops (not-empty (pop-undo-ops repo page-block-uuid))]
@@ -547,8 +543,9 @@ when undo this op, this original entity-map will be transacted back into db")
         (push-undo-ops repo page-block-uuid (if gen-boundary-op? (vec (cons boundary ops')) ops'))))))
 
 (defmethod db-listener/listen-db-changes :gen-undo-ops
-  [_ {:keys [_tx-data tx-meta db-before db-after
-             repo id->attr->datom same-entity-datoms-coll]}]
+  [_
+   {:keys [repo id->attr->datom same-entity-datoms-coll]}
+   {:keys [_tx-data tx-meta db-before db-after]}]
   (when (:gen-undo-ops? tx-meta true)
     (generate-undo-ops repo db-before db-after same-entity-datoms-coll id->attr->datom
                        (:gen-undo-boundary-op? tx-meta true)
@@ -588,5 +585,4 @@ when undo this op, this original entity-map will be transacted back into db")
                                     :n n})))
 
   (remove-watch (:undo/repo->page-block-uuid->undo-ops @worker-state/*state) :xxx)
-  (remove-watch (:undo/repo->page-block-uuid->redo-ops @worker-state/*state) :xxx)
-  )
+  (remove-watch (:undo/repo->page-block-uuid->redo-ops @worker-state/*state) :xxx))

+ 28 - 44
src/main/frontend/worker/undo_redo2.cljs

@@ -80,45 +80,37 @@
   ;; to the current state.
   ;; The downside is that it'll undo the changes made by others.
   (defn- pop-undo-op
-   [repo conn]
-   (let [undo-stack (get @*undo-ops repo)
-         [op undo-stack*] (pop-stack undo-stack)]
-     (swap! *undo-ops assoc repo undo-stack*)
-     (mapv (fn [item]
-             (if (= (first item) ::db-transact)
-               (let [m (second item)
-                     tx-data' (mapv
-                               (fn [{:keys [e a v tx add] :as datom}]
-                                 (let [one-value? (= :db.cardinality/one (:db/cardinality (d/entity @conn a)))
-                                       new-value (when (and one-value? add) (get (d/entity @conn e) a))
-                                       value-not-matched? (and (some? new-value) (not= v new-value))]
-                                   (if value-not-matched?
+    [repo conn]
+    (let [undo-stack (get @*undo-ops repo)
+          [op undo-stack*] (pop-stack undo-stack)]
+      (swap! *undo-ops assoc repo undo-stack*)
+      (mapv (fn [item]
+              (if (= (first item) ::db-transact)
+                (let [m (second item)
+                      tx-data' (mapv
+                                (fn [{:keys [e a v tx add] :as datom}]
+                                  (let [one-value? (= :db.cardinality/one (:db/cardinality (d/entity @conn a)))
+                                        new-value (when (and one-value? add) (get (d/entity @conn e) a))
+                                        value-not-matched? (and (some? new-value) (not= v new-value))]
+                                    (if value-not-matched?
                                     ;; another client might updated `new-value`, the datom below will be used
                                     ;; to restore the the current state when redo this undo.
-                                     (d/datom e a new-value tx add)
-                                     datom)))
-                               (:tx-data m))]
-                 [::db-transact (assoc m :tx-data tx-data')])
-               item))
-           op))))
+                                      (d/datom e a new-value tx add)
+                                      datom)))
+                                (:tx-data m))]
+                  [::db-transact (assoc m :tx-data tx-data')])
+                item))
+            op))))
 
 (defn- pop-undo-op
-  [repo conn]
+  [repo]
   (let [undo-stack (get @*undo-ops repo)
         [op undo-stack*] (pop-stack undo-stack)]
     (swap! *undo-ops assoc repo undo-stack*)
     (let [op' (mapv (fn [item]
                       (if (= (first item) ::db-transact)
                         (let [m (second item)
-                              tx-data' (vec
-                                        (keep
-                                         (fn [{:keys [e a v _tx add] :as datom}]
-                                           (let [one-value? (= :db.cardinality/one (:db/cardinality (d/entity @conn a)))
-                                                 new-value (when (and one-value? add) (get (d/entity @conn e) a))
-                                                 value-not-matched? (and (some? new-value) (not= v new-value))]
-                                             (when-not value-not-matched?
-                                               datom)))
-                                         (:tx-data m)))]
+                              tx-data' (vec (:tx-data m))]
                           (if (seq tx-data')
                             [::db-transact (assoc m :tx-data tx-data')]
                             ::db-transact-no-tx-data))
@@ -128,22 +120,14 @@
         op'))))
 
 (defn- pop-redo-op
-  [repo conn]
+  [repo]
   (let [redo-stack (get @*redo-ops repo)
         [op redo-stack*] (pop-stack redo-stack)]
     (swap! *redo-ops assoc repo redo-stack*)
     (let [op' (mapv (fn [item]
                       (if (= (first item) ::db-transact)
                         (let [m (second item)
-                              tx-data' (vec
-                                        (keep
-                                         (fn [{:keys [e a v _tx add] :as datom}]
-                                           (let [one-value? (= :db.cardinality/one (:db/cardinality (d/entity @conn a)))
-                                                 new-value (when (and one-value? (not add)) (get (d/entity @conn e) a))
-                                                 value-not-matched? (and (some? new-value) (not= v new-value))]
-                                             (when-not value-not-matched?
-                                               datom)))
-                                         (:tx-data m)))]
+                              tx-data' (vec (:tx-data m))]
                           (if (seq tx-data')
                             [::db-transact (assoc m :tx-data tx-data')]
                             ::db-transact-no-tx-data))
@@ -269,7 +253,7 @@
 
 (defn- undo-redo-aux
   [repo conn undo?]
-  (if-let [op (not-empty ((if undo? pop-undo-op pop-redo-op) repo conn))]
+  (if-let [op (not-empty ((if undo? pop-undo-op pop-redo-op) repo))]
     (cond
       (= ::ui-state (ffirst op))
       (do
@@ -295,9 +279,9 @@
               (let [editor-cursors (->> (filter #(= ::record-editor-info (first %)) op)
                                         (map second))
                     block-content (:block/title (d/entity @conn [:block/uuid (:block-uuid
-                                                                                (if undo?
-                                                                                  (first editor-cursors)
-                                                                                  (last editor-cursors)))]))]
+                                                                              (if undo?
+                                                                                (first editor-cursors)
+                                                                                (last editor-cursors)))]))]
                 {:undo? undo?
                  :editor-cursors editor-cursors
                  :block-content block-content}))))))
@@ -331,7 +315,7 @@
     (push-undo-op repo [[::ui-state ui-state-str]])))
 
 (defmethod db-listener/listen-db-changes :gen-undo-ops
-  [_ {:keys [repo tx-data tx-meta db-after db-before]}]
+  [_ {:keys [repo]} {:keys [tx-data tx-meta db-after db-before]}]
   (let [{:keys [outliner-op]} tx-meta]
     (when (and outliner-op (not (false? (:gen-undo-ops? tx-meta)))
                (not (:create-today-journal? tx-meta)))