Explorar el Código

Merge branch 'feat/db' into refactor/db-properties-schema

Tienson Qin hace 2 años
padre
commit
3e351a4308

+ 52 - 49
src/main/frontend/components/right_sidebar.cljs

@@ -19,7 +19,6 @@
             [logseq.shui.ui :as shui]
             [frontend.util :as util]
             [frontend.config :as config]
-            [frontend.modules.editor.undo-redo :as undo-redo]
             [medley.core :as medley]
             [reitit.frontend.easy :as rfe]
             [rum.core :as rum]
@@ -69,49 +68,52 @@
                          :sidebar-key sidebar-key} repo block-id {:indent? false})]
      (block-cp repo idx block)]))
 
-(rum/defc history-action-info
-  [[k v]]
-  (when v [:.ml-4 (ui/foldable
-                   [:div (str k)]
-                   [:.ml-4 (case k
-                             :tx-id
-                             [:.my-1 [:pre.code.pre-wrap-white-space.bg-base-4 (str v)]]
-
-                             :blocks
-                             (map (fn [block]
-                                    [:.my-1 [:pre.code.pre-wrap-white-space.bg-base-4 (str block)]]) v)
-
-                             :txs
-                             (map (fn [[_ key val]]
-                                    (when val
-                                      [:pre.code.pre-wrap-white-space.bg-base-4
-                                       [:span.font-bold (str key) " "] (str val)])) v)
-
-                             (map (fn [[key val]]
-                                    (when val
-                                      [:pre.code.pre-wrap-white-space.bg-base-4
-                                       [:span.font-bold (str key) " "] (str val)])) v))]
-                   {:default-collapsed? true})]))
-
-(rum/defc history-stack
-  [label stack]
-  [:.ml-4 (ui/foldable
-           [:div label " (" (count stack) ")"]
-           (map-indexed (fn [index item]
-                          [:.ml-4 (ui/foldable [:div (str index " " (-> item :tx-meta :outliner-op))]
-                                               (map history-action-info item)
-                                               {:default-collapsed? true})]) stack)
-           {:default-collapsed? true})])
+(comment
+  (rum/defc history-action-info
+   [[k v]]
+   (when v [:.ml-4 (ui/foldable
+                    [:div (str k)]
+                    [:.ml-4 (case k
+                              :tx-id
+                              [:.my-1 [:pre.code.pre-wrap-white-space.bg-base-4 (str v)]]
+
+                              :blocks
+                              (map (fn [block]
+                                     [:.my-1 [:pre.code.pre-wrap-white-space.bg-base-4 (str block)]]) v)
+
+                              :txs
+                              (map (fn [[_ key val]]
+                                     (when val
+                                       [:pre.code.pre-wrap-white-space.bg-base-4
+                                        [:span.font-bold (str key) " "] (str val)])) v)
+
+                              (map (fn [[key val]]
+                                     (when val
+                                       [:pre.code.pre-wrap-white-space.bg-base-4
+                                        [:span.font-bold (str key) " "] (str val)])) v))]
+                    {:default-collapsed? true})])))
+
+(comment
+  (rum/defc history-stack
+   [label stack]
+   [:.ml-4 (ui/foldable
+            [:div label " (" (count stack) ")"]
+            (map-indexed (fn [index item]
+                           [:.ml-4 (ui/foldable [:div (str index " " (-> item :tx-meta :outliner-op))]
+                                                (map history-action-info item)
+                                                {:default-collapsed? true})]) stack)
+            {:default-collapsed? true})]))
 
 (rum/defc history < rum/reactive
   []
-  (let [state (undo-redo/get-state)
-        page-only-mode? (state/sub :history/page-only-mode?)]
-    [:div.ml-4
-     [:div.ml-3.font-bold (if page-only-mode? (t :right-side-bar/history-pageonly) (t :right-side-bar/history-global))]
-     [:div.p-4 [:.ml-4.mb-2
-                (history-stack (t :right-side-bar/history-undos) (rum/react (:undo-stack state)))
-                (history-stack (t :right-side-bar/history-redos) (rum/react (:redo-stack state)))]]]))
+  ;; (let [state (undo-redo/get-state)
+  ;;       page-only-mode? (state/sub :history/page-only-mode?)]
+  ;;   [:div.ml-4
+  ;;    [:div.ml-3.font-bold (if page-only-mode? (t :right-side-bar/history-pageonly) (t :right-side-bar/history-global))]
+  ;;    [:div.p-4 [:.ml-4.mb-2
+  ;;               (history-stack (t :right-side-bar/history-undos) (rum/react (:undo-stack state)))
+  ;;               (history-stack (t :right-side-bar/history-redos) (rum/react (:redo-stack state)))]]])
+  )
 
 (defn build-sidebar-item
   [repo idx db-id block-type *db-id init-key]
@@ -127,9 +129,9 @@
     [[:.flex.items-center (ui/icon "hierarchy" {:class "text-md mr-2"}) (t :right-side-bar/page-graph)]
      (page/page-graph)]
 
-    :history
-    [[:.flex.items-center (ui/icon "history" {:class "text-md mr-2"}) (t :right-side-bar/history)]
-     (history)]
+    ;; :history
+    ;; [[:.flex.items-center (ui/icon "history" {:class "text-md mr-2"}) (t :right-side-bar/history)]
+    ;;  (history)]
 
     :block-ref
     #_:clj-kondo/ignore
@@ -460,11 +462,12 @@
                                                                        (state/sidebar-add-block! repo "rtc" :rtc))}
             "(Dev) RTC"]])
 
-        (when (and config/dev? (state/sub [:ui/developer-mode?]))
-          [:div.text-sm
-           [:button.button.cp__right-sidebar-settings-btn {:on-click (fn [_e]
-                                                                       (state/sidebar-add-block! repo "history" :history))}
-            (t :right-side-bar/history)]])]]
+        ;; (when (and config/dev? (state/sub [:ui/developer-mode?]))
+        ;;   [:div.text-sm
+        ;;    [:button.button.cp__right-sidebar-settings-btn {:on-click (fn [_e]
+        ;;                                                                (state/sidebar-add-block! repo "history" :history))}
+        ;;     (t :right-side-bar/history)]])
+        ]]
 
       [:.sidebar-item-list.flex-1.scrollbar-spacing.px-2
        (if @*anim-finished?

+ 4 - 1
src/main/frontend/handler/editor.cljs

@@ -2569,7 +2569,10 @@
   "Select first or last block in viewpoint"
   [direction]
   (let [f (case direction :up last :down first)
-        block (->> (util/get-blocks-noncollapse)
+        container (if (some-> js/document.activeElement
+                        (.querySelector ".blocks-container"))
+                    js/document.activeElement js/document.body)
+        block (->> (util/get-blocks-noncollapse container)
                    (f))]
     (when block
       (util/scroll-to-block block)

+ 13 - 22
src/main/frontend/handler/history.cljs

@@ -1,10 +1,8 @@
 (ns ^:no-doc frontend.handler.history
-  (:require [frontend.config :as config]
-            [frontend.db :as db]
+  (:require [frontend.db :as db]
             [frontend.db.transact :as db-transact]
             [frontend.handler.editor :as editor]
             [frontend.handler.route :as route-handler]
-            [frontend.modules.editor.undo-redo :as undo-redo]
             [frontend.state :as state]
             [frontend.util :as util]
             [goog.dom :as gdom]
@@ -30,15 +28,14 @@
 
 (defn restore-app-state!
   [state]
-  (when-not (:history/page-only-mode? @state/state)
-   (let [route-match (:route-match state)
-         current-route (:route-match @state/state)
-         prev-route-data (get-route-data route-match)
-         current-route-data (get-route-data current-route)]
-     (when (and (not= prev-route-data current-route-data)
-                prev-route-data)
-       (route-handler/redirect! prev-route-data))
-     (swap! state/state merge state))))
+  (let [route-match (:route-match state)
+        current-route (:route-match @state/state)
+        prev-route-data (get-route-data route-match)
+        current-route-data (get-route-data current-route)]
+    (when (and (not= prev-route-data current-route-data)
+               prev-route-data)
+      (route-handler/redirect! prev-route-data))
+    (swap! state/state merge state)))
 
 (defn undo!
   [e]
@@ -50,11 +47,8 @@
        (editor/save-current-block!)
        (state/clear-editor-action!)
        (state/set-block-op-type! nil)
-       (if (config/db-based-graph? repo)
-         (let [^js worker @state/*db-worker]
-           (.undo worker repo))
-         (let [cursor-state (undo-redo/undo)]
-           (state/set-state! :ui/restore-cursor-state (select-keys cursor-state [:editor-cursor :app-state]))))))))
+       (let [^js worker @state/*db-worker]
+         (.undo worker repo))))))
 
 (defn redo!
   [e]
@@ -62,8 +56,5 @@
     (when (db-transact/request-finished?)
       (util/stop e)
       (state/clear-editor-action!)
-      (if (config/db-based-graph? repo)
-        (let [^js worker @state/*db-worker]
-          (.redo worker repo))
-        (let [cursor-state (undo-redo/redo)]
-          (state/set-state! :ui/restore-cursor-state (select-keys cursor-state [:editor-cursor :app-state])))))))
+      (let [^js worker @state/*db-worker]
+        (.redo worker repo)))))

+ 0 - 220
src/main/frontend/modules/editor/undo_redo.cljs

@@ -1,220 +0,0 @@
-(ns frontend.modules.editor.undo-redo
-  (:require [frontend.db :as db]
-            [frontend.handler.notification :as notification]
-            [frontend.util.page :as page-util]
-            [frontend.state :as state]
-            [clojure.set :as set]
-            [medley.core :as medley]
-            [frontend.handler.route :as route-handler]
-            [promesa.core :as p]))
-
-;;;; APIs
-
-(def ^:private undo-redo-states (atom {}))
-(def *pause-listener (atom false))
-
-(defn get-state
-  []
-  (let [repo (state/get-current-repo)]
-    (assert (string? repo) "Repo should satisfy string?")
-    (if-let [state (get @undo-redo-states repo)]
-      state
-      (let [new-state {:undo-stack (atom [])
-                       :redo-stack (atom [])}]
-        (swap! undo-redo-states assoc repo new-state)
-        new-state))))
-
-(defn- get-undo-stack
-  []
-  (-> (get-state) :undo-stack))
-
-(defn- get-redo-stack
-  []
-  (-> (get-state) :redo-stack))
-
-(defn push-undo
-  [txs]
-  (let [undo-stack (get-undo-stack)]
-    (swap! undo-stack conj txs)))
-
-(defn pop-undo
-  []
-  (let [undo-stack (get-undo-stack)]
-    (when-let [stack @undo-stack]
-      (when (seq stack)
-        (let [removed-e (peek stack)
-              popped-stack (pop stack)]
-          (reset! undo-stack popped-stack)
-          removed-e)))))
-
-(defn push-redo
-  [txs]
-  (let [redo-stack (get-redo-stack)]
-    (swap! redo-stack conj txs)))
-
-(defn pop-redo
-  []
-  (let [redo-stack (get-redo-stack)]
-    (when-let [removed-e (peek @redo-stack)]
-      (swap! redo-stack pop)
-      removed-e)))
-
-(defn page-pop-redo
-  [page-id]
-  (prn "[debug] redo: " (:block/original-name (db/pull page-id)))
-  (when-let [redo-stack (get-redo-stack)]
-    (when-let [stack @redo-stack]
-      (when (seq stack)
-        (let [reversed-stack (medley/indexed (reverse stack))
-              idx (some (fn [[idx item]]
-                          (some #(when (or (= (:db/id %) page-id)
-                                           (= (:db/id (:block/page %)) page-id)) idx) (:blocks item))) reversed-stack)]
-          (when idx
-            (let [idx' (- (count stack) idx 1)
-                  before (subvec stack 0 idx')
-                  after (subvec stack (inc idx'))
-                  others (vec (concat before after))]
-              (reset! redo-stack others)
-              (prn "[debug] redo remove: " (nth stack idx'))
-              (nth stack idx'))))))))
-
-(defn- smart-pop-redo
-  []
-  (if (:history/page-only-mode? @state/state)
-    (if-let [page-id (page-util/get-editing-page-id)]
-      (page-pop-redo page-id)
-      (pop-redo))
-    (pop-redo)))
-
-(defn reset-redo
-  []
-  (let [redo-stack (get-redo-stack)]
-    (reset! redo-stack [])))
-
-(defn get-txs
-  [redo? txs]
-  (let [txs (if redo? txs (reverse txs))]
-    (mapv (fn [[id attr value tx add?]]
-            (let [op (cond
-                       (and redo? add?) :db/add
-                       (and (not redo?) add?) :db/retract
-                       (and redo? (not add?)) :db/retract
-                       (and (not redo?) (not add?)) :db/add)]
-              [op id attr value tx]))
-          txs)))
-
-;;;; Invokes
-
-(defn- transact!
-  [txs tx-meta]
-  (db/transact! (state/get-current-repo) txs tx-meta))
-
-(defn- page-pop-undo
-  [page-id]
-  (let [undo-stack (get-undo-stack)]
-    (when-let [stack @undo-stack]
-      (when (seq stack)
-        (let [reversed-stack (medley/indexed (reverse stack))
-              idx (some (fn [[idx item]]
-                          (some #(when (or (= (:db/id %) page-id)
-                                           (= (:db/id (:block/page %)) page-id)) idx) (:blocks item))) reversed-stack)]
-          (when idx
-            (let [idx' (- (count stack) idx 1)
-                  before (subvec stack 0 idx')
-                  after (subvec stack (inc idx'))
-                  others (vec (concat before after))]
-              (reset! undo-stack others)
-              (prn "[debug] undo remove: " (nth stack idx'))
-              (nth stack idx'))))))))
-
-(defn- smart-pop-undo
-  []
-  (if (:history/page-only-mode? @state/state)
-    (if-let [page-id (page-util/get-editing-page-id)]
-      (page-pop-undo page-id)
-      (pop-undo))
-    (pop-undo)))
-
-(defn pause-listener!
-  []
-  (reset! *pause-listener true))
-
-(defn resume-listener!
-  []
-  (reset! *pause-listener false))
-
-(defn undo
-  []
-  (when-let [e (smart-pop-undo)]
-    (pause-listener!)
-    (state/set-editor-op! :undo)
-    (let [{:keys [txs tx-meta tx-id]} e
-          new-txs (get-txs false txs)
-          editor-cursor (:before (get @(get @state/state :history/tx->editor-cursor) tx-id))]
-      (push-redo e)
-      (p/do!
-       (transact! new-txs (assoc tx-meta :undo? true))
-
-       (when (= :rename-page (:outliner-op tx-meta))
-         (when-let [old-page (:old-name (:data tx-meta))]
-           (route-handler/redirect-to-page! old-page))))
-      (assoc e
-             :txs-op new-txs
-             :editor-cursor editor-cursor))))
-
-(defn redo
-  []
-  (when-let [{:keys [txs tx-meta tx-id] :as e} (smart-pop-redo)]
-    (pause-listener!)
-    (state/set-editor-op! :redo)
-    (let [new-txs (get-txs true txs)
-          editor-cursor (let [s (get @(get @state/state :history/tx->editor-cursor) tx-id)]
-                          (if (= (:outliner-op tx-meta) :save-block)
-                            (:before s)
-                            (or (:after s) (:before s))))]
-      (push-undo e)
-      (p/do!
-       (transact! new-txs (assoc tx-meta :redo? true))
-
-       (when (= :rename-page (:outliner-op tx-meta))
-         (when-let [new-page (:new-name (:data tx-meta))]
-           (route-handler/redirect-to-page! new-page))))
-
-      (assoc e
-             :txs-op new-txs
-             :editor-cursor editor-cursor))))
-
-(defn toggle-undo-redo-mode!
-  []
-  (swap! state/state update :history/page-only-mode? not)
-  (let [mode (if (:history/page-only-mode? @state/state) "Page only" "Global")]
-    (notification/show!
-     [:p (str "Undo/redo mode: " mode)])))
-
-
-(defn listen-db-changes!
-  [{:keys [tx-id tx-data tx-meta blocks pages]}]
-  (when (and (seq tx-data)
-             (not (or (:undo? tx-meta)
-                      (:redo? tx-meta)))
-             (not @*pause-listener)
-             (not (set/subset?
-                   (set (map :a tx-data))
-                   #{:block/created-at :block/updated-at})))
-    (reset-redo)
-    (if (:replace? tx-meta)
-      (when-let [removed-e (pop-undo)]
-        (let [entity (update removed-e :txs concat tx-data)]
-          (push-undo entity)))
-      (let [updated-blocks (concat blocks pages)
-            entity {:blocks updated-blocks
-                    :tx-id tx-id
-                    :txs tx-data
-                    :tx-meta tx-meta
-                    :app-state (select-keys @state/state
-                                            [:route-match
-                                             :ui/sidebar-open?
-                                             :ui/sidebar-collapsed-blocks
-                                             :sidebar/blocks])}]
-        (push-undo entity))))
-  (resume-listener!))

+ 1 - 14
src/main/frontend/modules/outliner/pipeline.cljs

@@ -1,22 +1,12 @@
 (ns frontend.modules.outliner.pipeline
-  (:require [frontend.config :as config]
-            [frontend.db :as db]
+  (:require [frontend.db :as db]
             [frontend.db.react :as react]
             [frontend.state :as state]
-            [frontend.modules.editor.undo-redo :as undo-redo]
             [datascript.core :as d]
             [frontend.handler.ui :as ui-handler]
             [frontend.handler.history :as history]
             [frontend.util :as util]))
 
-(defn store-undo-data!
-  [{:keys [tx-meta] :as opts}]
-  (when-not config/test?
-    (when (or (:outliner/transact? tx-meta)
-              (:outliner-op tx-meta)
-              (:whiteboard/transact? tx-meta))
-      (undo-redo/listen-db-changes! opts))))
-
 (defn- get-tx-id
   [tx-report]
   (get-in tx-report [:tempids :db/current-tx]))
@@ -69,9 +59,6 @@
                            (concat update-blocks-fully-loaded tx-data))
                          tx-data)
               tx-report (d/transact! conn tx-data' tx-meta)]
-          (when local-tx?
-            (let [tx-id (get-tx-id tx-report)]
-              (store-undo-data! (assoc opts :tx-id tx-id))))
           (when-not (or undo? redo?)
             (update-current-tx-editor-cursor! tx-report)))
 

+ 0 - 6
src/main/frontend/modules/shortcut/config.cljs

@@ -19,7 +19,6 @@
             [frontend.handler.plugin-config :as plugin-config-handler]
             [frontend.handler.window :as window-handler]
             [frontend.handler.jump :as jump-handler]
-            [frontend.modules.editor.undo-redo :as undo-redo]
             [frontend.dicts :as dicts]
             [frontend.modules.shortcut.before :as m]
             [frontend.state :as state]
@@ -360,9 +359,6 @@
    :editor/zoom-out                         {:binding (if mac? "mod+," "alt+left")
                                              :fn      editor-handler/zoom-out!}
 
-   :editor/toggle-undo-redo-mode            {:binding []
-                                             :fn      undo-redo/toggle-undo-redo-mode!}
-
    :editor/toggle-number-list               {:binding "t n"
                                              :fn      #(state/pub-event! [:editor/toggle-own-number-list (state/get-selection-block-ids)])}
 
@@ -722,7 +718,6 @@
      (-> (build-category-map
            [:editor/insert-link
             :editor/select-all-blocks
-            :editor/toggle-undo-redo-mode
             :editor/toggle-number-list
             :editor/undo
             :editor/redo
@@ -888,7 +883,6 @@
      :shortcut.category/toggle
      [:ui/toggle-help
       :editor/toggle-open-blocks
-      :editor/toggle-undo-redo-mode
       :editor/toggle-number-list
       :ui/toggle-wide-mode
       :ui/toggle-document-mode

+ 0 - 1
src/main/frontend/state.cljs

@@ -310,7 +310,6 @@
       :whiteboard/onboarding-tour?           (or (storage/get :whiteboard-onboarding-tour?) false)
       :whiteboard/last-persisted-at          {}
       :whiteboard/pending-tx-data            {}
-      :history/page-only-mode?               false
       :history/tx-before-editor-cursor       (atom nil)
       ;; db tx-id -> editor cursor
       :history/tx->editor-cursor             (atom {})

+ 3 - 10
src/main/frontend/worker/batch_tx.clj

@@ -4,15 +4,8 @@
 (defmacro with-batch-tx-mode
   "1. start batch-tx mode
   2. run body
-  3. exit batch-tx mode
-  4. refresh-ui"
-  [conn & body]
+  3. exit batch-tx mode"
+  [& body]
   `(do (frontend.worker.batch-tx/start-batch-tx-mode)
        ~@body
-       (let [txs# (frontend.worker.batch-tx/get-batch-txs)]
-         (frontend.worker.batch-tx/exit-batch-tx-mode)
-         (when (seq txs#)
-           (when-let [affected-keys# (not-empty
-                                      (frontend.worker.react/get-affected-queries-keys
-                                       {:db-after @~conn :tx-data txs#}))]
-             (frontend.worker.util/post-message :refresh-ui {:affected-keys affected-keys#}))))))
+       (frontend.worker.batch-tx/exit-batch-tx-mode)))

+ 21 - 18
src/main/frontend/worker/pipeline.cljs

@@ -76,7 +76,7 @@
   [repo conn tx-report context]
   (when-not (:pipeline-replace? (:tx-meta tx-report))
     (let [tx-meta (:tx-meta tx-report)
-          {:keys [from-disk? new-graph? undo? redo?]} tx-meta]
+          {:keys [from-disk? new-graph?]} tx-meta]
       (if (or from-disk? new-graph?)
         {:tx-report tx-report}
         (let [{:keys [pages blocks]} (ds-report/get-blocks-and-pages tx-report)
@@ -86,24 +86,23 @@
                       (when (d/entity @conn page-id)
                         (file/sync-to-file repo page-id tx-meta)))))
               deleted-block-uuids (set (outliner-pipeline/filter-deleted-blocks (:tx-data tx-report)))
-              replace-tx (when-not (or undo? redo?)
-                           (concat
+              replace-tx (concat
                             ;; block path refs
-                            (set (compute-block-path-refs-tx tx-report blocks))
+                          (set (compute-block-path-refs-tx tx-report blocks))
 
                             ;; delete empty property parent block
-                            (when (seq deleted-block-uuids)
-                              (delete-property-parent-block-if-empty tx-report deleted-block-uuids))
+                          (when (seq deleted-block-uuids)
+                            (delete-property-parent-block-if-empty tx-report deleted-block-uuids))
 
                             ;; update block/tx-id
-                            (let [updated-blocks (remove (fn [b] (contains? (set deleted-block-uuids) (:block/uuid b))) blocks)
-                                  tx-id (get-in tx-report [:tempids :db/current-tx])]
-                              (->>
-                               (map (fn [b]
-                                      (when-let [db-id (:db/id b)]
-                                        {:db/id db-id
-                                         :block/tx-id tx-id})) updated-blocks)
-                               (remove nil?)))))
+                          (let [updated-blocks (remove (fn [b] (contains? (set deleted-block-uuids) (:block/uuid b))) blocks)
+                                tx-id (get-in tx-report [:tempids :db/current-tx])]
+                            (->>
+                             (map (fn [b]
+                                    (when-let [db-id (:db/id b)]
+                                      {:db/id db-id
+                                       :block/tx-id tx-id})) updated-blocks)
+                             (remove nil?))))
               tx-report' (or
                           (when (seq replace-tx)
                             ;; TODO: remove this since transact! is really slow
@@ -113,13 +112,17 @@
                             (d/store @conn)
                             tx-report))
               fix-tx-data (validate-and-fix-db! repo conn tx-report context)
-              full-tx-data (concat (:tx-data tx-report) fix-tx-data (:tx-data tx-report'))
+              batch-processing? (batch-tx/tx-batch-processing?)
+              batch-tx-data (batch-tx/get-batch-txs)
+              full-tx-data (concat (:tx-data tx-report)
+                                   fix-tx-data
+                                   (:tx-data tx-report')
+                                   (when (and (not batch-processing?) (seq batch-tx-data))
+                                     batch-tx-data))
               final-tx-report (assoc tx-report'
                                      :tx-data full-tx-data
                                      :db-before (:db-before tx-report))
-              batch-processing? (batch-tx/tx-batch-processing?)
-              affected-query-keys (when-not (or (:importing? context)
-                                                batch-processing?)
+              affected-query-keys (when-not (:importing? context)
                                     (worker-react/get-affected-queries-keys final-tx-report))]
           (when batch-processing?
             (batch-tx/conj-batch-txs! full-tx-data))

+ 62 - 50
src/main/frontend/worker/undo_redo.cljs

@@ -87,6 +87,10 @@ when undo this op, this original entity-map will be transacted back into db")
 
 (def ^:private undo-ops-validator (m/validator [:sequential undo-op-schema]))
 
+(def ^:dynamic *undo-redo-info-for-test*
+  "record undo-op info when running-test"
+  nil)
+
 (def ^:private entity-map-pull-pattern
   [:block/uuid
    {:block/left [:block/uuid]}
@@ -201,42 +205,44 @@ when undo this op, this original entity-map will be transacted back into db")
     (when-not block-entity ;; this block shouldn't exist now
       (when-let [left-entity (d/entity @conn [:block/uuid (:block/left block-entity-map)])]
         (let [sibling? (not= (:block/left block-entity-map) (:block/parent block-entity-map))]
-          (outliner-tx/transact!
-           {:gen-undo-op? false
-            :outliner-op :insert-blocks
-            :transact-opts {:repo repo
-                            :conn conn}}
-           (outliner-core/insert-blocks! repo conn
-                                         [(cond-> {:block/uuid block-uuid
-                                                   :block/content (:block/content block-entity-map)
-                                                   :block/format :markdown}
-                                            (:block/created-at block-entity-map)
-                                            (assoc :block/created-at (:block/created-at block-entity-map))
-
-                                            (:block/updated-at block-entity-map)
-                                            (assoc :block/updated-at (:block/updated-at block-entity-map))
-
-                                            (seq (:block/tags block-entity-map))
-                                            (assoc :block/tags (mapv (partial vector :block/uuid)
-                                                                     (:block/tags block-entity-map))))]
-                                         left-entity {:sibling? sibling? :keep-uuid? true}))
-          :push-undo-redo)))))
+          (some->>
+           (outliner-tx/transact!
+            {:gen-undo-op? false
+             :outliner-op :insert-blocks
+             :transact-opts {:repo repo
+                             :conn conn}}
+            (outliner-core/insert-blocks! repo conn
+                                          [(cond-> {:block/uuid block-uuid
+                                                    :block/content (:block/content block-entity-map)
+                                                    :block/format :markdown}
+                                             (:block/created-at block-entity-map)
+                                             (assoc :block/created-at (:block/created-at block-entity-map))
+
+                                             (:block/updated-at block-entity-map)
+                                             (assoc :block/updated-at (:block/updated-at block-entity-map))
+
+                                             (seq (:block/tags block-entity-map))
+                                             (assoc :block/tags (mapv (partial vector :block/uuid)
+                                                                      (:block/tags block-entity-map))))]
+                                          left-entity {:sibling? sibling? :keep-uuid? true}))
+           (conj [:push-undo-redo])))))))
 
 (defmethod reverse-apply-op ::insert-block
   [op conn repo]
   (let [[_ {:keys [block-uuid]}] op]
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
       (when (empty? (:block/_parent block-entity)) ;if have children, skip
-        (outliner-tx/transact!
-         {:gen-undo-op? false
-          :outliner-op :delete-blocks
-          :transact-opts {:repo repo
-                          :conn conn}}
-         (outliner-core/delete-blocks! repo conn
-                                       (common-config/get-date-formatter (worker-state/get-config repo))
-                                       [block-entity]
-                                       {:children? false}))
-        :push-undo-redo))))
+        (some->>
+         (outliner-tx/transact!
+          {:gen-undo-op? false
+           :outliner-op :delete-blocks
+           :transact-opts {:repo repo
+                           :conn conn}}
+          (outliner-core/delete-blocks! repo conn
+                                        (common-config/get-date-formatter (worker-state/get-config repo))
+                                        [block-entity]
+                                        {:children? false}))
+         (conj [:push-undo-redo]))))))
 
 (defmethod reverse-apply-op ::move-block
   [op conn repo]
@@ -244,13 +250,14 @@ when undo this op, this original entity-map will be transacted back into db")
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
       (when-let [left-entity (d/entity @conn [:block/uuid block-origin-left])]
         (let [sibling? (not= block-origin-left block-origin-parent)]
-          (outliner-tx/transact!
-           {:gen-undo-op? false
-            :outliner-op :move-blocks
-            :transact-opts {:repo repo
-                            :conn conn}}
-           (outliner-core/move-blocks! repo conn [block-entity] left-entity sibling?))
-          :push-undo-redo)))))
+          (some->>
+           (outliner-tx/transact!
+            {:gen-undo-op? false
+             :outliner-op :move-blocks
+             :transact-opts {:repo repo
+                             :conn conn}}
+            (outliner-core/move-blocks! repo conn [block-entity] left-entity sibling?))
+           (conj [:push-undo-redo])))))))
 
 (defmethod reverse-apply-op ::update-block
   [op conn repo]
@@ -258,15 +265,16 @@ when undo this op, this original entity-map will be transacted back into db")
     (when-let [block-entity (d/entity @conn [:block/uuid block-uuid])]
       (when (normal-block? block-entity)
         (let [new-block (assoc block-entity :block/content block-origin-content)]
-          (outliner-tx/transact!
-           {:gen-undo-op? false
-            :outliner-op :save-block
-            :transact-opts {:repo repo
-                            :conn conn}}
-           (outliner-core/save-block! repo conn
-                                      (common-config/get-date-formatter (worker-state/get-config repo))
-                                      new-block))
-          :push-undo-redo)))))
+          (some->>
+           (outliner-tx/transact!
+            {:gen-undo-op? false
+             :outliner-op :save-block
+             :transact-opts {:repo repo
+                             :conn conn}}
+            (outliner-core/save-block! repo conn
+                                       (common-config/get-date-formatter (worker-state/get-config repo))
+                                       new-block))
+           (conj [:push-undo-redo])))))))
 
 (defn undo
   [repo conn]
@@ -274,8 +282,10 @@ when undo this op, this original entity-map will be transacted back into db")
     (let [redo-ops-to-push (transient [])]
       (batch-tx/with-batch-tx-mode conn
         (doseq [op ops]
-          (let [rev-op (reverse-op @conn op)]
-            (when (= :push-undo-redo (reverse-apply-op op conn repo))
+          (let [rev-op (reverse-op @conn op)
+                r (reverse-apply-op op conn repo)]
+            (when (= :push-undo-redo (first r))
+              (some-> *undo-redo-info-for-test* (reset! {:op op :tx (second r)}))
               (conj! redo-ops-to-push rev-op)))))
       (when-let [rev-ops (not-empty (persistent! redo-ops-to-push))]
         (push-redo-ops repo (cons boundary rev-ops)))
@@ -291,8 +301,10 @@ when undo this op, this original entity-map will be transacted back into db")
     (let [undo-ops-to-push (transient [])]
       (batch-tx/with-batch-tx-mode conn
         (doseq [op ops]
-          (let [rev-op (reverse-op @conn op)]
-            (when (= :push-undo-redo (reverse-apply-op op conn repo))
+          (let [rev-op (reverse-op @conn op)
+                r (reverse-apply-op op conn repo)]
+            (when (= :push-undo-redo (first r))
+              (some-> *undo-redo-info-for-test* (reset! {:op op :tx (second r)}))
               (conj! undo-ops-to-push rev-op)))))
       (when-let [rev-ops (not-empty (persistent! undo-ops-to-push))]
         (push-undo-ops repo (cons boundary rev-ops)))

+ 0 - 1
src/resources/dicts/en.edn

@@ -727,7 +727,6 @@
   :editor/select-parent           "Select parent block"
   :editor/zoom-in                 "Zoom in editing block / Forwards otherwise"
   :editor/zoom-out                "Zoom out editing block / Backwards otherwise"
-  :editor/toggle-undo-redo-mode   "Toggle undo redo mode (global or page only)"
   :editor/toggle-number-list      "Toggle number list"
   :editor/add-property            "Add property"
   :editor/jump                    "Jump to a property key or value"

+ 64 - 33
src/test/frontend/worker/undo_redo_test.cljs

@@ -7,8 +7,8 @@
             [frontend.test.helper :as test-helper]
             [frontend.worker.undo-redo :as undo-redo]))
 
-(def init-data (test-helper/initial-test-page-and-blocks))
-(defn start-and-destroy-db
+(def ^:private init-data (test-helper/initial-test-page-and-blocks))
+(defn- start-and-destroy-db
   [f]
   (test-helper/db-based-start-and-destroy-db
    f
@@ -16,7 +16,7 @@
 
 (use-fixtures :each start-and-destroy-db)
 
-(def gen-non-exist-block-uuid gen/uuid)
+(def ^:private gen-non-exist-block-uuid gen/uuid)
 
 (defn- gen-block-uuid
   [db & {:keys [non-exist-frequency] :or {non-exist-frequency 1}}]
@@ -45,7 +45,7 @@
   [db]
   (gen/let [block-uuid (gen-block-uuid db {:non-exist-frequency 80})
             [parent left] (gen-parent-left-pair db)
-            content gen/string-ascii]
+            content gen/string-alphanumeric]
     [:frontend.worker.undo-redo/remove-block
      {:block-uuid block-uuid
       :block-entity-map
@@ -57,12 +57,12 @@
 (defn- gen-update-block-op
   [db]
   (gen/let [block-uuid (gen-block-uuid db)
-            content gen/string-ascii]
+            content gen/string-alphanumeric]
     [:frontend.worker.undo-redo/update-block
      {:block-uuid block-uuid
       :block-origin-content content}]))
 
-(def gen-boundary (gen/return [:frontend.worker.undo-redo/boundary]))
+(def ^:private gen-boundary (gen/return [:frontend.worker.undo-redo/boundary]))
 
 (defn- gen-op
   [db & {:keys [insert-block-op move-block-op remove-block-op update-block-op boundary-op]
@@ -79,41 +79,71 @@
 
 (defn- get-db-block-set
   [db]
-  (set (d/q '[:find ?uuid ?parent-uuid ?left-uuid
-              :where
-              [?b :block/uuid ?uuid]
-              [?b :block/parent ?parent]
-              [?b :block/left ?left]
-              [?parent :block/uuid ?parent-uuid]
-              [?left :block/uuid ?left-uuid]]
-            db)))
+  (set
+   (apply concat
+          (d/q '[:find ?uuid
+                 :where
+                 [?b :block/uuid ?uuid]
+                 [?b :block/parent ?parent]
+                 [?b :block/left ?left]
+                 [?parent :block/uuid ?parent-uuid]
+                 [?left :block/uuid ?left-uuid]]
+               db))))
+
+
+(defn- check-block-count
+  [{:keys [op tx]} current-db]
+  (case (first op)
+    :frontend.worker.undo-redo/move-block
+    (assert (= (:block-origin-left (second op))
+               (:block/uuid (:block/left (d/entity current-db [:block/uuid (:block-uuid (second op))]))))
+            {:op op :tx-data (:tx-data tx) :x (keys tx)})
+
+    :frontend.worker.undo-redo/update-block
+    (assert (some? (d/entity current-db [:block/uuid (:block-uuid (second op))]))
+            {:op op :tx-data (:tx-data tx)})
+
+    :frontend.worker.undo-redo/insert-block
+    (assert (nil? (d/entity current-db [:block/uuid (:block-uuid (second op))]))
+            {:op op :tx-data (:tx-data tx) :x (keys tx)})
+    :frontend.worker.undo-redo/remove-block
+    (assert (some? (d/entity current-db [:block/uuid (:block-uuid (second op))]))
+            {:op op :tx-data (:tx-data tx) :x (keys tx)})
+    ;; else
+    nil))
 
 (defn- undo-all-then-redo-all
   [conn]
-  (loop [i 0]
-    (if (not= :frontend.worker.undo-redo/empty-undo-stack
-              (undo-redo/undo test-helper/test-db-name-db-version conn))
-      (recur (inc i))
-      (prn :undo-count i)))
-
-  (loop []
-    (when (not= :frontend.worker.undo-redo/empty-redo-stack
-                (undo-redo/redo test-helper/test-db-name-db-version conn))
-      (recur))))
-
-(deftest undo-test
+  (binding [undo-redo/*undo-redo-info-for-test* (atom nil)]
+    (loop [i 0]
+      (let [r (undo-redo/undo test-helper/test-db-name-db-version conn)
+            current-db @conn]
+        (check-block-count @undo-redo/*undo-redo-info-for-test* current-db)
+        (if (not= :frontend.worker.undo-redo/empty-undo-stack r)
+          (recur (inc i))
+          (prn :undo-count i))))
+
+    (loop []
+      (let [r (undo-redo/redo test-helper/test-db-name-db-version conn)
+            current-db @conn]
+        (check-block-count @undo-redo/*undo-redo-info-for-test* current-db)
+        (when (not= :frontend.worker.undo-redo/empty-redo-stack r)
+          (recur))))))
+
+(deftest undo-redo-gen-test
   (let [conn (db/get-db false)
-        all-remove-ops (gen/generate (gen/vector (gen-op @conn {:remove-block-op 1000}) 100))]
+        all-remove-ops (gen/generate (gen/vector (gen-op @conn {:remove-block-op 1000}) 20))]
     (#'undo-redo/push-undo-ops test-helper/test-db-name-db-version all-remove-ops)
+    (prn :block-count-before-init (count (get-db-block-set @conn)))
     (loop [i 0]
-      (if (not= :frontend.worker.undo-redo/empty-undo-stack
-                (undo-redo/undo test-helper/test-db-name-db-version conn))
-        (recur (inc i))
-        (prn :undo-count i)))
+      (when (not= :frontend.worker.undo-redo/empty-undo-stack
+                  (undo-redo/undo test-helper/test-db-name-db-version conn))
+        (recur (inc i))))
+    (prn :block-count (count (get-db-block-set @conn)))
     (undo-redo/clear-undo-redo-stack)
     (testing "move blocks"
       (let [origin-graph-block-set (get-db-block-set @conn)
-            ops (gen/generate (gen/vector (gen-op @conn {:move-block-op 1000 :boundary-op 500}) 1000))]
+            ops (gen/generate (gen/vector (gen-op @conn {:move-block-op 1000 :boundary-op 500}) 300))]
         (prn :ops (count ops))
         (#'undo-redo/push-undo-ops test-helper/test-db-name-db-version ops)
 
@@ -133,4 +163,5 @@
         (undo-all-then-redo-all conn)
         (undo-all-then-redo-all conn)
 
-        (is (= origin-graph-block-set (get-db-block-set @conn)))))))
+        (is (= origin-graph-block-set (get-db-block-set @conn)))))
+    ))