fix(outliner): remap pasted property value uuids

This commit is contained in:
Tienson Qin
2026-04-28 12:19:47 +08:00
parent 540e410320
commit cea40a2cd6
2 changed files with 65 additions and 10 deletions

View File

@@ -612,7 +612,8 @@
(throw (js/Error. (str "[insert-blocks] illegal lookup: " lookup ", block: " block)))))
blocks-tx (build-insert-blocks-tx db target-block blocks uuids get-new-id opts)]
{:blocks-tx blocks-tx
:id->new-uuid id->new-uuid}))
:id->new-uuid id->new-uuid
:uuid->new-uuid uuids}))
(defn- get-target-block
[db blocks target-block {:keys [outliner-op bottom? top? indent? sibling? up? replace-empty-target?]}]
@@ -763,11 +764,11 @@
:keep-block-order? keep-block-order?
:outliner-op outliner-op
:insert-template? insert-template?}
{:keys [id->new-uuid blocks-tx]} (insert-blocks-aux db blocks' target-block insert-opts)]
(if (some (fn [b] (or (nil? (:block/parent b)) (nil? (:block/order b)))) blocks-tx)
(throw (ex-info "Invalid outliner data"
{:opts insert-opts
:tx (vec blocks-tx)
{:keys [id->new-uuid uuid->new-uuid blocks-tx]} (insert-blocks-aux db blocks' target-block insert-opts)]
(if (some (fn [b] (or (nil? (:block/parent b)) (nil? (:block/order b)))) blocks-tx)
(throw (ex-info "Invalid outliner data"
{:opts insert-opts
:tx (vec blocks-tx)
:blocks (vec blocks)
:target-block target-block}))
(let [tx (assign-temp-id blocks-tx target-block replace-empty-target?)
@@ -778,12 +779,14 @@
(remove old-db-id-blocks)
(remove nil?)
(map (fn [uuid'] {:block/uuid uuid'})))
from-property (:logseq.property/created-from-property target-block)
many? (= :db.cardinality/many (:db/cardinality from-property))
property-values-tx (when (and sibling? from-property many?)
from-property (:logseq.property/created-from-property target-block)
many? (= :db.cardinality/many (:db/cardinality from-property))
property-values-tx (when (and sibling? from-property many?)
(let [top-level-blocks (filter #(= 1 (:block/level %)) blocks')]
(mapcat (fn [block]
(when-let [new-id (or (id->new-uuid (:db/id block)) (:block/uuid block))]
(when-let [new-id (or (id->new-uuid (:db/id block))
(uuid->new-uuid (:block/uuid block))
(:block/uuid block))]
[{:block/uuid new-id
:logseq.property/created-from-property (:db/id from-property)}
[:db/add

View File

@@ -514,6 +514,58 @@
(is (= 1 (count children)))
(is (= "child" (:block/title (get-block (first children)))))))))
(deftest test-paste-property-values-into-empty-property-value-block
(testing "replace-empty-target remaps pasted property value uuids before adding many-property refs"
(transact-tree! [[25]])
(db/transact! test-db [{:block/uuid 25
:block/title ""}])
(let [conn (db/get-db test-db false)
_ (db/transact! test-db [{:db/ident :logseq.property/created-from-property
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/index true}])
property-ident :user.property/reproduciblesteps
_ (db/transact! test-db [{:db/ident property-ident
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/many
:logseq.property/type :default}])
property (d/entity @conn property-ident)
property-ident (:db/ident property)
target-block (get-block 25)
_ (db/transact! test-db [{:db/id (:db/id target-block)
:logseq.property/created-from-property (:db/id property)}
[:db/add (:db/id (:block/parent target-block))
property-ident
(:db/id target-block)]])
target-block (get-block 25)
_ (is (some? (:logseq.property/created-from-property target-block)))
copied-blocks [{:block/uuid 101
:block/title "1"
:block/parent 1}
{:block/uuid 102
:block/title "2"
:block/parent [:block/uuid 101]}
{:block/uuid 103
:block/title "3"
:block/parent 1}]]
(outliner-tx/transact!
(transact-opts)
(outliner-core/insert-blocks! conn
copied-blocks
target-block
{:sibling? true
:keep-uuid? true
:outliner-op :paste
:replace-empty-target? true}))
(let [parent (d/entity @conn (:db/id (:block/parent target-block)))
values (get parent property-ident)
titles (set (map :block/title values))]
;; Old copied uuid should not survive as a dangling property value ref.
(is (nil? (get-block 101)))
;; Pasted values should be the replaced target and the new sibling top-level block.
(is (= #{"1" "3"} titles))
(is (contains? (set (map :db/id values)) (:db/id (get-block 25))))))))
(deftest test-batch-transact
(testing "add 4, 5 after 2 and delete 3"
(let [tree' [[10 [[2] [3]]]]]