mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
enhance(recycle): permanently delete recycled roots with sync-safe replay
This commit is contained in:
@@ -4,9 +4,12 @@
|
||||
[datascript.core :as d]
|
||||
[frontend.components.block :as component-block]
|
||||
[frontend.db :as db]
|
||||
[frontend.db-mixins :as db-mixins]
|
||||
[frontend.db.react :as react]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.state :as state]
|
||||
[frontend.util :as util]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.shui.ui :as shui]
|
||||
[rum.core :as rum]))
|
||||
@@ -36,6 +39,20 @@
|
||||
(map #(d/entity db %))
|
||||
(sort-by :logseq.property/deleted-at #(compare %2 %1))))
|
||||
|
||||
(defn- sub-deleted-root-ids
|
||||
[]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(some-> (react/q repo
|
||||
[:frontend.worker.react/recycle-roots]
|
||||
{:query-fn (fn [db _]
|
||||
(->> (d/q '[:find [?e ...]
|
||||
:where
|
||||
[?e :logseq.property/deleted-at]]
|
||||
db)
|
||||
vec))}
|
||||
nil)
|
||||
util/react)))
|
||||
|
||||
(defn- group-title
|
||||
[db root]
|
||||
(if (ldb/page? root)
|
||||
@@ -59,7 +76,11 @@
|
||||
(defn- deleted-root-header
|
||||
[db root]
|
||||
(let [user (deleted-by db root)
|
||||
deleted-at (:logseq.property/deleted-at root)]
|
||||
deleted-at (:logseq.property/deleted-at root)
|
||||
root-uuid (:block/uuid root)
|
||||
delete-message (str "Permanently delete this "
|
||||
(if (ldb/page? root) "page" "block")
|
||||
" from Recycle? This cannot be undone.")]
|
||||
[:div.flex.items-center.justify-between.gap-4.text-xs.text-muted-foreground
|
||||
[:div.flex.items-center.gap-1.min-w-0.flex-1
|
||||
(deleted-by-avatar user)
|
||||
@@ -68,12 +89,20 @@
|
||||
(str (if (ldb/page? root) "Page" "Block")
|
||||
" deleted "
|
||||
(.toLocaleString (js/Date. deleted-at)))]]]
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:size :xs
|
||||
:class "!py-0 !px-1 h-4"
|
||||
:on-click #(page-handler/restore-recycled! (:block/uuid root))}
|
||||
"Restore")]))
|
||||
[:div.flex.items-center.gap-1
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:size :xs
|
||||
:class "!py-0 !px-1 h-4"
|
||||
:on-click #(page-handler/restore-recycled! root-uuid)}
|
||||
"Restore")
|
||||
(shui/button
|
||||
{:variant :ghost
|
||||
:size :xs
|
||||
:class "!py-0 !px-1 h-4 hover:text-destructive"
|
||||
:on-click #(when (js/confirm delete-message)
|
||||
(page-handler/delete-recycled-permanently! root-uuid))}
|
||||
"Delete permanently")]]))
|
||||
|
||||
(defn- deleted-root-outliner
|
||||
[root]
|
||||
@@ -88,10 +117,17 @@
|
||||
:id (str (:block/uuid root))}
|
||||
root))
|
||||
|
||||
(rum/defc recycle-page
|
||||
(rum/defc recycle-page < rum/reactive db-mixins/query
|
||||
[_page]
|
||||
(let [db* (db/get-db)
|
||||
groups (->> (deleted-roots db*)
|
||||
root-ids (or (sub-deleted-root-ids)
|
||||
[])
|
||||
roots (if (seq root-ids)
|
||||
(->> root-ids
|
||||
(keep #(d/entity db* %))
|
||||
(sort-by :logseq.property/deleted-at #(compare %2 %1)))
|
||||
(deleted-roots db*))
|
||||
groups (->> roots
|
||||
(group-by #(group-title db* %))
|
||||
(sort-by (fn [[_ roots]]
|
||||
(:logseq.property/deleted-at (first roots)))
|
||||
|
||||
@@ -57,6 +57,16 @@
|
||||
(outliner-op/transact! tx-data nil))
|
||||
true))))
|
||||
|
||||
(defn delete-recycled-permanently!
|
||||
[root-uuid]
|
||||
(when-let [root (db/entity [:block/uuid root-uuid])]
|
||||
(when-let [tx-data (seq (outliner-recycle/permanently-delete-tx-data (db/get-db) root))]
|
||||
(p/do!
|
||||
(ui-outliner-tx/transact!
|
||||
{:outliner-op :recycle-delete-permanently}
|
||||
(outliner-op/recycle-delete-permanently! root-uuid))
|
||||
true))))
|
||||
|
||||
(defn <unfavorite-page!
|
||||
[page-name]
|
||||
(p/do!
|
||||
|
||||
@@ -163,3 +163,8 @@
|
||||
([page-uuid opts]
|
||||
(op-transact!
|
||||
[:delete-page [page-uuid (current-user-delete-opts opts)]])))
|
||||
|
||||
(defn recycle-delete-permanently!
|
||||
[root-uuid]
|
||||
(op-transact!
|
||||
[:recycle-delete-permanently [root-uuid]]))
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
(s/def ::objects (s/tuple #(= ::objects %) int?))
|
||||
;; get block reactions
|
||||
(s/def ::block-reactions (s/tuple #(= ::block-reactions %) int?))
|
||||
;; recycle roots list
|
||||
(s/def ::recycle-roots (s/tuple #(= ::recycle-roots %)))
|
||||
;; custom react-query
|
||||
(s/def ::custom any?)
|
||||
|
||||
@@ -27,6 +29,7 @@
|
||||
:refs ::refs
|
||||
:objects ::objects
|
||||
:block-reactions ::block-reactions
|
||||
:recycle-roots ::recycle-roots
|
||||
:custom ::custom))
|
||||
|
||||
(s/def ::affected-keys (s/coll-of ::react-query-keys))
|
||||
@@ -71,6 +74,9 @@
|
||||
(= :logseq.property.reaction/target (:a datom))) tx-data)
|
||||
(map :v)
|
||||
(distinct))
|
||||
recycle-roots? (some (fn [datom]
|
||||
(= :logseq.property/deleted-at (:a datom)))
|
||||
tx-data)
|
||||
other-blocks (->> (filter (fn [datom] (= "block" (namespace (:a datom)))) tx-data)
|
||||
(map :e))
|
||||
blocks (-> (concat blocks other-blocks) distinct)
|
||||
@@ -114,6 +120,9 @@
|
||||
(when tag [::objects tag]))
|
||||
tags)
|
||||
|
||||
(when recycle-roots?
|
||||
[[::recycle-roots]])
|
||||
|
||||
(when journals?
|
||||
[[::journals]]))]
|
||||
(->>
|
||||
|
||||
@@ -800,6 +800,27 @@
|
||||
(ldb/transact! conn tx-data
|
||||
{:outliner-op :restore-recycled}))
|
||||
|
||||
:recycle-delete-permanently
|
||||
(let [[root-id] args
|
||||
root-ref (cond
|
||||
(and (vector? root-id)
|
||||
(= :block/uuid (first root-id)))
|
||||
root-id
|
||||
|
||||
(uuid? root-id)
|
||||
[:block/uuid root-id]
|
||||
|
||||
:else
|
||||
root-id)
|
||||
root (d/entity @conn root-ref)
|
||||
tx-data (when root
|
||||
(seq (outliner-recycle/permanently-delete-tx-data @conn root)))]
|
||||
;; Keep replay idempotent under concurrent edits where the recycled root may
|
||||
;; already be permanently removed by a preceding remote tx.
|
||||
(when (seq tx-data)
|
||||
(ldb/transact! conn tx-data
|
||||
{:outliner-op :recycle-delete-permanently})))
|
||||
|
||||
:set-block-property
|
||||
(let [[block-eid property-id v] args
|
||||
block-eid' (or (replay-entity-id-value @conn block-eid)
|
||||
|
||||
Reference in New Issue
Block a user