fix(selection): atomic batch icon writes via single outliner transact!

The per-block doseq path (avatar/text/clear) used to issue N independent
transactions through the worker — partial mid-loop failures left the
selection in a mixed state, no shared undo step, and N reactive re-renders.

Wrap the doseq in one ui-outliner-tx/transact! with op-tag
:set-block-properties. The inner handler calls each open their own
transact! but short-circuit when an outer binding is active (per the
macro at frontend/modules/outliner/ui.cljc), so all N ops collapse into a
single atomic DB transaction, one undo step, and one re-render cascade.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
scheinriese
2026-05-19 22:26:21 +02:00
parent 6f1afa4cca
commit 0334d162ef

View File

@@ -6,6 +6,7 @@
[frontend.handler.db-based.property :as db-property-handler]
[frontend.handler.editor :as editor-handler]
[frontend.handler.property :as property-handler]
[frontend.modules.outliner.ui :as ui-outliner-tx]
[frontend.state :as state]
[frontend.ui :as ui]
[frontend.util :as util]
@@ -40,14 +41,21 @@
(defn- batch-write-icon!
[blocks icon]
(if (or (nil? icon) (contains? #{:avatar :text} (:type icon)))
;; Per-block writes (avatar/text need per-row initials; clear/nil applies uniformly)
(doseq [block blocks]
(if (nil? icon)
(property-handler/remove-block-property! (:db/id block) :logseq.property/icon)
(db-property-handler/set-block-property!
(:db/id block)
:logseq.property/icon
(icon-data-for-block icon block))))
;; Per-block writes (avatar/text need per-row initials; clear/nil applies
;; uniformly). Wrap the doseq in one outliner transact! so all N writes
;; commit atomically — partial-failure used to leave the selection in a
;; mixed state. The inner handler calls each open their own transact!,
;; but the macro short-circuits when an outer binding is active, so this
;; produces a single DB tx, undo step, and reactive re-render.
(ui-outliner-tx/transact!
{:outliner-op :set-block-properties}
(doseq [block blocks]
(if (nil? icon)
(property-handler/remove-block-property! (:db/id block) :logseq.property/icon)
(db-property-handler/set-block-property!
(:db/id block)
:logseq.property/icon
(icon-data-for-block icon block)))))
;; Uniform value across blocks (icon, emoji, image): single batch transaction
(property-handler/batch-set-block-property!
(map :db/id blocks)