objects.cljs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. (ns frontend.components.objects
  2. "Provides table views for class objects and property related objects"
  3. (:require [frontend.components.views :as views]
  4. [frontend.db :as db]
  5. [logseq.db :as ldb]
  6. [frontend.db-mixins :as db-mixins]
  7. [frontend.db.async :as db-async]
  8. [frontend.db.model :as db-model]
  9. [frontend.handler.editor :as editor-handler]
  10. [frontend.mixins :as mixins]
  11. [frontend.state :as state]
  12. [logseq.outliner.property :as outliner-property]
  13. [promesa.core :as p]
  14. [rum.core :as rum]
  15. [frontend.modules.outliner.ui :as ui-outliner-tx]
  16. [frontend.modules.outliner.op :as outliner-op]
  17. [frontend.db.react :as react]))
  18. (defn- get-class-objects
  19. [class]
  20. (->> (db-model/get-class-objects (state/get-current-repo) (:db/id class))
  21. (map (fn [row] (assoc row :id (:db/id row))))))
  22. (defn- add-new-class-object!
  23. [class set-data!]
  24. (p/let [block (editor-handler/api-insert-new-block! ""
  25. {:page (:block/uuid class)
  26. :properties {:block/tags (:db/id class)}
  27. :edit-block? false})
  28. _ (set-data! (get-class-objects class))]
  29. (editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 :unknown-container)))
  30. (defn- get-views
  31. [ent]
  32. (let [class (db/entity (:db/id ent))]
  33. (-> (filter (fn [b]
  34. (= (:db/ident class) (:logseq.property/view-for b)))
  35. (:block/_parent class))
  36. (ldb/sort-by-order))))
  37. (rum/defc class-objects-inner < rum/static
  38. [config class objects properties]
  39. (let [[loading? set-loading?] (rum/use-state nil)
  40. [view-entity set-view-entity!] (rum/use-state nil)
  41. [data set-data!] (rum/use-state objects)
  42. columns (views/build-columns config properties)]
  43. (rum/use-effect!
  44. (fn []
  45. (set-data! objects))
  46. [objects])
  47. (rum/use-effect!
  48. (fn []
  49. (when (nil? loading?)
  50. (set-loading? true)
  51. (p/let [_result (db-async/<get-views (state/get-current-repo) (:db/id class))
  52. views (get-views class)]
  53. (when-let [view (first views)]
  54. (set-view-entity! view))
  55. (p/let [_result (db-async/<get-tag-objects (state/get-current-repo) (:db/id class))]
  56. (react/refresh! (state/get-current-repo)
  57. [[:frontend.worker.react/objects (:db/id class)]])
  58. (set-data! (get-class-objects class))
  59. (set-loading? false)))))
  60. [])
  61. (when (false? loading?)
  62. (views/view view-entity {:data data
  63. :set-data! set-data!
  64. :title-key :views.table/tagged-nodes
  65. :columns columns
  66. :add-new-object! #(add-new-class-object! class set-data!)
  67. :create-view! (fn []
  68. (p/let [result (editor-handler/api-insert-new-block! "" {:page (:block/uuid class)
  69. :properties {:logseq.property/view-for (:db/ident class)}})]
  70. (let [view (db/entity [:block/uuid (:block/uuid result)])]
  71. (set-view-entity! view)
  72. view)))
  73. :show-add-property? true
  74. :add-property! (fn []
  75. (state/pub-event! [:editor/new-property {:block class
  76. :class-schema? true}]))
  77. :on-delete-rows (fn [table selected-rows]
  78. (let [pages (filter ldb/page? selected-rows)
  79. blocks (remove ldb/page? selected-rows)]
  80. (p/do!
  81. (ui-outliner-tx/transact!
  82. {:outliner-op :delete-blocks}
  83. (when (seq blocks)
  84. (outliner-op/delete-blocks! blocks nil))
  85. (let [page-ids (map :db/id pages)
  86. tx-data (map (fn [pid] [:db/retract pid :block/tags (:db/id class)]) page-ids)]
  87. (when (seq tx-data)
  88. (outliner-op/transact! tx-data {:outliner-op :save-block}))))
  89. (set-data! (get-class-objects class))
  90. (when-let [f (get-in table [:data-fns :set-row-selection!])]
  91. (f {})))))}))))
  92. (rum/defcs class-objects < rum/reactive db-mixins/query mixins/container-id
  93. [state class]
  94. (when class
  95. (let [class (db/sub-block (:db/id class))
  96. config {:container-id (:container-id state)}
  97. properties (cond->> (outliner-property/get-class-properties (db/get-db) class)
  98. (= :logseq.class/Root (:db/ident class))
  99. (concat [(db/entity :block/tags)]))
  100. repo (state/get-current-repo)
  101. objects (->> (db-model/sub-class-objects repo (:db/id class))
  102. (map (fn [row] (assoc row :id (:db/id row)))))]
  103. [:div.ml-2
  104. (class-objects-inner config class objects properties)])))
  105. (defn- get-property-related-objects [repo property]
  106. (->> (db-model/get-property-related-objects repo (:db/id property))
  107. (map (fn [row] (assoc row :id (:db/id row))))))
  108. (defn- add-new-property-object!
  109. [property set-data!]
  110. (p/let [block (editor-handler/api-insert-new-block! ""
  111. {:page (:block/uuid property)
  112. :properties {(:db/ident property) (:db/id (db/entity :logseq.property/empty-placeholder))}
  113. :edit-block? false})
  114. _ (set-data! (get-property-related-objects (state/get-current-repo) property))]
  115. (editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 :unknown-container)))
  116. (rum/defc property-related-objects-inner < rum/static
  117. [config property objects properties]
  118. (let [[loading? set-loading?] (rum/use-state nil)
  119. [view-entity set-view-entity!] (rum/use-state nil)
  120. [data set-data!] (rum/use-state objects)
  121. columns (views/build-columns config properties)]
  122. (rum/use-effect!
  123. (fn []
  124. (set-data! objects))
  125. [objects])
  126. (rum/use-effect!
  127. (fn []
  128. (set-loading? true)
  129. (p/let [_result (db-async/<get-views (state/get-current-repo) (:db/id property))
  130. views (get-views property)]
  131. (when-let [view (first views)]
  132. (set-view-entity! view))
  133. (p/let [result (db-async/<get-property-objects (state/get-current-repo) (:db/ident property))]
  134. (set-data! (mapv (fn [m]
  135. (let [e (db/entity (:db/id m))]
  136. (assoc e :id (:db/id m)))) result))
  137. (set-loading? false))))
  138. [])
  139. (when (false? loading?)
  140. (views/view view-entity {:data data
  141. :set-data! set-data!
  142. :title-key :views.table/property-nodes
  143. :columns columns
  144. :add-new-object! #(add-new-property-object! property set-data!)
  145. :create-view! (fn []
  146. (p/let [result (editor-handler/api-insert-new-block! "" {:page (:block/uuid property)
  147. :properties {:logseq.property/view-for (:db/ident property)}})]
  148. (let [view (db/entity [:block/uuid (:block/uuid result)])]
  149. (set-view-entity! view)
  150. view)))
  151. ;; TODO: Add support for adding column
  152. :show-add-property? false
  153. :on-delete-rows (fn [table selected-rows]
  154. (let [pages (filter ldb/page? selected-rows)
  155. blocks (remove ldb/page? selected-rows)]
  156. (p/do!
  157. (ui-outliner-tx/transact!
  158. {:outliner-op :delete-blocks}
  159. (when (seq blocks)
  160. (outliner-op/delete-blocks! blocks nil))
  161. (let [page-ids (map :db/id pages)
  162. tx-data (map (fn [pid] [:db/retract pid (:db/ident property)]) page-ids)]
  163. (when (seq tx-data)
  164. (outliner-op/transact! tx-data {:outliner-op :save-block}))))
  165. (set-data! (get-property-related-objects (state/get-current-repo) property))
  166. (when-let [f (get-in table [:data-fns :set-row-selection!])]
  167. (f {})))))}))))
  168. ;; Show all nodes containing the given property
  169. (rum/defcs property-related-objects < rum/reactive db-mixins/query mixins/container-id
  170. [state property]
  171. (when property
  172. (let [property' (db/sub-block (:db/id property))
  173. config {:container-id (:container-id state)}
  174. ;; Show tags to help differentiate property rows
  175. properties [property' (db/entity :block/tags)]
  176. repo (state/get-current-repo)
  177. objects (get-property-related-objects repo property)]
  178. [:div.ml-2
  179. (property-related-objects-inner config property' objects properties)])))