mirror of
https://github.com/logseq/logseq.git
synced 2026-05-25 05:04:24 +00:00
fix(outliner): stabilize history op refs
This commit is contained in:
@@ -44,7 +44,7 @@
|
||||
|
||||
(assert (empty? (last (data/diff immutable-db-ident-entities nil-db-ident-entities))))
|
||||
|
||||
(def ^:private lookup-entity @#'entity/lookup-entity)
|
||||
(def lookup-entity @#'entity/lookup-entity)
|
||||
|
||||
(def ^:private *seen-immutable-entities (volatile! {}))
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.content :as db-content]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
[logseq.db.frontend.property.type :as db-property-type]))
|
||||
[logseq.db.frontend.property.type :as db-property-type]
|
||||
[logseq.db.common.entity-plus :as entity-plus]))
|
||||
|
||||
(def ^:private semantic-outliner-ops
|
||||
#{:save-block
|
||||
@@ -62,6 +63,8 @@
|
||||
(when-let [id (:block/uuid x)]
|
||||
(:db/id (d/entity db [:block/uuid id]))))]
|
||||
(stable-entity-ref db eid))
|
||||
(uuid? x)
|
||||
[:block/uuid x]
|
||||
(and (integer? x) (not (neg? x)))
|
||||
(if-let [ent (d/entity db x)]
|
||||
(cond
|
||||
@@ -71,6 +74,19 @@
|
||||
x)
|
||||
:else x))
|
||||
|
||||
(defn- stable-block-ref-with-tx-data
|
||||
[db tx-data x]
|
||||
(let [ref (stable-entity-ref db x)]
|
||||
(if (and (integer? ref) (not (neg? ref)))
|
||||
(or (some (fn [item]
|
||||
(when (and (= ref (:e item))
|
||||
(= :block/uuid (:a item))
|
||||
(uuid? (:v item)))
|
||||
[:block/uuid (:v item)]))
|
||||
tx-data)
|
||||
ref)
|
||||
ref)))
|
||||
|
||||
(defn- sanitize-ref-value
|
||||
[db v]
|
||||
(cond
|
||||
@@ -464,7 +480,7 @@
|
||||
:move-blocks
|
||||
(let [[ids target-id opts] args]
|
||||
[:move-blocks [(stable-id-coll db ids)
|
||||
(stable-entity-ref db target-id)
|
||||
(stable-block-ref-with-tx-data db tx-data target-id)
|
||||
opts]])
|
||||
|
||||
:delete-blocks
|
||||
@@ -569,7 +585,7 @@
|
||||
:delete-closed-value
|
||||
(let [[property-id value-block-id] args]
|
||||
[:delete-closed-value [(stable-entity-ref db property-id)
|
||||
(stable-entity-ref db value-block-id)]])
|
||||
(stable-block-ref-with-tx-data db tx-data value-block-id)]])
|
||||
|
||||
[op args]))
|
||||
|
||||
@@ -598,6 +614,9 @@
|
||||
(integer? block)
|
||||
(d/entity db block)
|
||||
|
||||
(uuid? block)
|
||||
(d/entity db [:block/uuid block])
|
||||
|
||||
(vector? block)
|
||||
(d/entity db block)
|
||||
|
||||
@@ -645,8 +664,8 @@
|
||||
|
||||
(defn- block-property-value
|
||||
[db block-id property-id]
|
||||
(when-let [value (some-> (d/entity db block-id)
|
||||
(get property-id))]
|
||||
;; `get` lookup may include derived defaults.
|
||||
(when-let [value (entity-plus/lookup-entity (d/entity db block-id) property-id)]
|
||||
(property-ref-value db property-id value)))
|
||||
|
||||
(defn- property-history-refs-from-tx-data
|
||||
|
||||
@@ -157,6 +157,40 @@
|
||||
(is (= [[:delete-blocks [[[:block/uuid child-uuid]] {}]]]
|
||||
forward-outliner-ops)))))
|
||||
|
||||
(deftest derive-history-outliner-ops-move-blocks-resolves-target-id-from-tx-data-test
|
||||
(testing "move-blocks should resolve stale numeric target id using tx-data block uuid"
|
||||
(let [conn (db-test/create-conn-with-blocks
|
||||
{:pages-and-blocks
|
||||
[{:page {:block/title "page"}
|
||||
:blocks [{:block/title "child"}]}]})
|
||||
child (db-test/find-block-by-content @conn "child")
|
||||
stale-target-id 9999999
|
||||
target-uuid (random-uuid)
|
||||
tx-data [{:e stale-target-id :a :block/uuid :v target-uuid :added false}]
|
||||
tx-meta {:outliner-op :move-blocks
|
||||
:outliner-ops [[:move-blocks [[(:db/id child)] stale-target-id {:sibling? true}]]]}
|
||||
{:keys [forward-outliner-ops]}
|
||||
(op-construct/derive-history-outliner-ops @conn @conn tx-data tx-meta)]
|
||||
(is (= [:block/uuid target-uuid]
|
||||
(get-in forward-outliner-ops [0 1 1]))))))
|
||||
|
||||
(deftest derive-history-outliner-ops-delete-closed-value-resolves-value-id-from-tx-data-test
|
||||
(testing "delete-closed-value should resolve stale numeric value block id using tx-data block uuid"
|
||||
(let [conn (db-test/create-conn-with-blocks
|
||||
{:properties {:status {:logseq.property/type :default}}
|
||||
:pages-and-blocks []})
|
||||
property-page (d/entity @conn :user.property/status)
|
||||
property-id (:db/id property-page)
|
||||
stale-value-id 8888888
|
||||
value-uuid (random-uuid)
|
||||
tx-data [{:e stale-value-id :a :block/uuid :v value-uuid :added false}]
|
||||
tx-meta {:outliner-op :delete-closed-value
|
||||
:outliner-ops [[:delete-closed-value [property-id stale-value-id]]]}
|
||||
{:keys [forward-outliner-ops]}
|
||||
(op-construct/derive-history-outliner-ops @conn @conn tx-data tx-meta)]
|
||||
(is (= [:block/uuid value-uuid]
|
||||
(get-in forward-outliner-ops [0 1 1]))))))
|
||||
|
||||
(deftest derive-history-outliner-ops-builds-delete-page-inverse-for-class-property-and-today-page-test
|
||||
(testing "delete-page inverse restores hard-retracted class/property/today pages with stable db/ident"
|
||||
(let [today (date-time-util/ms->journal-day (js/Date.))
|
||||
|
||||
@@ -375,6 +375,30 @@
|
||||
(is (map? redo-result))
|
||||
(is (= "local-1" (:block/title (d/entity @conn [:block/uuid child-uuid]))))))))
|
||||
|
||||
(deftest undo-cycle-todo-removes-task-class-test
|
||||
(testing "undoing first status set should remove task class and status"
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
(let [conn (worker-state/get-datascript-conn test-repo)
|
||||
block-uuid (:block/uuid (db-test/find-block-by-content @conn "task"))]
|
||||
(outliner-op/apply-ops! conn
|
||||
[[:set-block-property [[:block/uuid block-uuid]
|
||||
:logseq.property/status
|
||||
:logseq.property/status.todo]]]
|
||||
(local-tx-meta {:client-id "test-client"}))
|
||||
|
||||
(let [block-after-set (d/entity @conn [:block/uuid block-uuid])]
|
||||
(is (= :logseq.property/status.todo
|
||||
(some-> (:logseq.property/status block-after-set) :db/ident)))
|
||||
(is (contains? (set (map :db/ident (:block/tags block-after-set)))
|
||||
:logseq.class/Task)))
|
||||
|
||||
(is (map? (worker-undo-redo/undo test-repo)))
|
||||
(let [block-after-undo (d/entity @conn [:block/uuid block-uuid])]
|
||||
(is (not (contains? (d/pull @conn [:logseq.property/status] [:block/uuid block-uuid])
|
||||
:logseq.property/status)))
|
||||
(is (not (contains? (set (map :db/ident (:block/tags block-after-undo)))
|
||||
:logseq.class/Task)))))))
|
||||
|
||||
(deftest undo-delete-page-restores-page-out-of-recycle-test
|
||||
(testing "undoing delete-page should restore page and clear recycle marker"
|
||||
(worker-undo-redo/clear-history! test-repo)
|
||||
|
||||
Reference in New Issue
Block a user