fix(ux): incorrect reaction for the order list sibling blocks (#12617)

* fix(ux): incorrect reaction for the order list sibling blocks

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: lint

* chore(test): add tests for order list type and sibling block interactions

* fix: refresh nested ordered lists

* fix: split affected query keys helper

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
This commit is contained in:
Charlie
2026-05-12 18:06:12 +08:00
committed by GitHub
parent 4c98cc6b51
commit 7194e54925
2 changed files with 168 additions and 16 deletions

View File

@@ -2,7 +2,8 @@
"Compute reactive query affected keys"
(:require [cljs.spec.alpha :as s]
[datascript.core :as d]
[logseq.common.util :as common-util]))
[logseq.common.util :as common-util]
[logseq.db.frontend.property :as db-property]))
;;; keywords specs for reactive query, used by `react/q` calls
;; ::block
@@ -41,6 +42,96 @@
(= journal-tag-id (:db/id tag)))
(:block/tags (d/entity db eid)))))
(def ^:private block-query-affecting-attrs
#{:logseq.property/order-list-type})
(def ^:private order-list-affecting-attrs
#{:block/parent :block/page :block/order :logseq.property/order-list-type})
(defn- block-attr?
[attr]
(= "block" (namespace attr)))
(defn- block-query-affecting-attr?
[attr]
(or (block-attr? attr)
(contains? block-query-affecting-attrs attr)))
(defn- block-key
[block]
[::block (:db/id block)])
(defn- order-list-type
[block]
(db-property/lookup block :logseq.property/order-list-type))
(defn- sibling-entities
[block]
(cond
(:block/parent block)
(some-> (:block/parent block) :block/_parent)
(:block/page block)
(some-> (:block/page block) :block/_page)
:else
nil))
(defn- ordered-siblings
[block]
(some->> (sibling-entities block)
(sort-by :block/order)))
(defn- right-ordered-siblings
[block]
(when-let [siblings (seq (ordered-siblings block))]
(->> siblings
(drop-while #(not= (:db/id %) (:db/id block)))
rest)))
(defn- collect-right-order-list-sibling-keys
[siblings target-order-list-type]
(when target-order-list-type
(->> siblings
(take-while #(= target-order-list-type (order-list-type %)))
(map block-key))))
(defn- affected-right-order-list-sibling-keys
[db block-id]
(when-let [block (and db (d/entity db block-id))]
(let [right-siblings (right-ordered-siblings block)
right-sibling (first right-siblings)]
(concat
(collect-right-order-list-sibling-keys right-siblings (order-list-type block))
(collect-right-order-list-sibling-keys right-siblings (order-list-type right-sibling))))))
(defn- affected-order-list-descendant-keys
[db block-id]
(when-let [block (and db (d/entity db block-id))]
(letfn [(collect [parent]
(when-let [parent-list-type (order-list-type parent)]
(mapcat
(fn [child]
(when (= parent-list-type (order-list-type child))
(cons (block-key child) (collect child))))
(:block/_parent parent))))]
(collect block))))
(defn- affected-block-keys
[block]
(let [page-id (or
(when (:block/name block) (:db/id block))
(:db/id (:block/page block)))
blocks [(when-let [parent-id (:db/id (:block/parent block))]
[::block parent-id])
[::block (:db/id block)]]
refs (->> (keep (fn [ref]
(when-not (= (:db/id ref) page-id)
[[::refs (:db/id ref)]
[::block (:db/id ref)]])) (:block/refs block))
(apply concat))]
(concat blocks refs)))
(defn get-affected-queries-keys
"Get affected queries through transaction datoms."
[{:keys [tx-data db-before db-after]}]
@@ -77,8 +168,12 @@
recycle-roots? (some (fn [datom]
(= :logseq.property/deleted-at (:a datom)))
tx-data)
other-blocks (->> (filter (fn [datom] (= "block" (namespace (:a datom)))) tx-data)
other-blocks (->> (filter (fn [datom] (block-query-affecting-attr? (:a datom))) tx-data)
(map :e))
order-list-affected-blocks (->> (filter (fn [datom]
(contains? order-list-affecting-attrs (:a datom))) tx-data)
(map :e)
(distinct))
blocks (-> (concat blocks other-blocks) distinct)
block-entities (keep (fn [block-id]
(let [block-id (if (and (string? block-id) (common-util/uuid-string? block-id))
@@ -87,20 +182,7 @@
(d/entity db-after block-id))) blocks)
affected-keys (concat
(mapcat
(fn [block]
(let [page-id (or
(when (:block/name block) (:db/id block))
(:db/id (:block/page block)))
blocks [(when-let [parent-id (:db/id (:block/parent block))]
[::block parent-id])
[::block (:db/id block)]]
block-refs (:block/refs block)
refs (->> (keep (fn [ref]
(when-not (= (:db/id ref) page-id)
[[::refs (:db/id ref)]
[::block (:db/id ref)]])) block-refs)
(apply concat))]
(concat blocks refs)))
affected-block-keys
block-entities)
(mapcat
@@ -115,6 +197,15 @@
[::block target-id]])
reaction-targets)
(mapcat
(fn [block-id]
(concat
(affected-right-order-list-sibling-keys db-before block-id)
(affected-right-order-list-sibling-keys db-after block-id)
(affected-order-list-descendant-keys db-before block-id)
(affected-order-list-descendant-keys db-after block-id)))
order-list-affected-blocks)
(keep
(fn [tag]
(when tag [::objects tag]))

View File

@@ -2,6 +2,7 @@
(:require [cljs.test :refer [deftest is testing]]
[datascript.core :as d]
[frontend.worker.react :as worker-react]
[logseq.db.common.order :as db-order]
[logseq.db.test.helper :as db-test]))
(deftest affected-keys-block-reactions
@@ -20,6 +21,66 @@
affected (worker-react/get-affected-queries-keys tx-report)]
(is (some #{[:frontend.worker.react/block-reactions target-id]} affected)))))
(deftest affected-keys-order-list-type
(testing "changing order list type affects block query key"
(let [conn (db-test/create-conn-with-blocks
[{:page {:block/title "Test"}
:blocks [{:block/title "Block"
:build/properties {:logseq.property/order-list-type "number"}}]}])
block (db-test/find-block-by-content @conn "Block")
target-id (:db/id block)
tx-report (d/transact! conn
[[:db/retract target-id :logseq.property/order-list-type
(:db/id (:logseq.property/order-list-type block))]])
affected (worker-react/get-affected-queries-keys tx-report)]
(is (some #{[:frontend.worker.react/block target-id]} affected)))))
(deftest affected-keys-order-list-right-siblings
(testing "inserting a block before ordered-list siblings affects their block query keys"
(let [conn (db-test/create-conn-with-blocks
[{:page {:block/title "Test"}
:blocks [{:block/title "Block 1"
:build/properties {:logseq.property/order-list-type "number"}}
{:block/title "Block 2"
:build/properties {:logseq.property/order-list-type "number"}}
{:block/title "Block 3"
:build/properties {:logseq.property/order-list-type "number"}}]}])
block-1 (db-test/find-block-by-content @conn "Block 1")
block-2 (db-test/find-block-by-content @conn "Block 2")
block-3 (db-test/find-block-by-content @conn "Block 3")
tx-report (d/transact! conn
[{:block/uuid (random-uuid)
:block/title "Inserted"
:block/page (:db/id (:block/page block-1))
:block/parent (:db/id (:block/parent block-1))
:block/order (db-order/gen-key (:block/order block-1)
(:block/order block-2))
:block/created-at 1
:block/updated-at 1}])
affected (worker-react/get-affected-queries-keys tx-report)]
(is (some #{[:frontend.worker.react/block (:db/id block-2)]} affected))
(is (some #{[:frontend.worker.react/block (:db/id block-3)]} affected)))))
(deftest affected-keys-order-list-descendants
(testing "changing ordered-list parent type affects nested ordered-list descendants"
(let [conn (db-test/create-conn-with-blocks
[{:page {:block/title "Test"}
:blocks [{:block/title "Parent"
:build/properties {:logseq.property/order-list-type "number"}
:build/children [{:block/title "Child"
:build/properties {:logseq.property/order-list-type "number"}
:build/children [{:block/title "Grandchild"
:build/properties {:logseq.property/order-list-type "number"}}]}]}]}])
parent (db-test/find-block-by-content @conn "Parent")
child (db-test/find-block-by-content @conn "Child")
grandchild (db-test/find-block-by-content @conn "Grandchild")
tx-report (d/transact! conn
[[:db/retract (:db/id parent) :logseq.property/order-list-type
(:db/id (:logseq.property/order-list-type parent))]])
affected (worker-react/get-affected-queries-keys tx-report)]
(is (some #{[:frontend.worker.react/block (:db/id child)]} affected))
(is (some #{[:frontend.worker.react/block (:db/id grandchild)]} affected)))))
(deftest affected-keys-journals-when-journal-recycled
(testing "recycling a journal page should refresh journals query key"
(let [conn (db-test/create-conn-with-blocks