Files
logseq/src/main/frontend/components/objects.cljs
2026-04-09 16:22:42 +08:00

165 lines
8.2 KiB
Clojure

(ns frontend.components.objects
"Provides table views for class objects and property related objects"
(:require [frontend.components.filepicker :as filepicker]
[frontend.components.views :as views]
[frontend.context.i18n :refer [t]]
[frontend.db :as db]
[frontend.db-mixins :as db-mixins]
[frontend.db.react :as react]
[frontend.handler.editor :as editor-handler]
[frontend.mixins :as mixins]
[frontend.state :as state]
[logseq.db :as ldb]
[logseq.db.frontend.property :as db-property]
[logseq.outliner.property :as outliner-property]
[logseq.shui.hooks :as hooks]
[logseq.shui.ui :as shui]
[promesa.core :as p]
[rum.core :as rum]))
(defn- add-new-class-object!
[class properties]
(p/let [block (editor-handler/api-insert-new-block! ""
{:page (:block/uuid class)
:properties (merge properties {:block/tags (:db/id class)})
:edit-block? false})]
(editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 {:container-id :unknown-container})
block))
(defn- build-asset-file-column
[config]
{:id :file
:name (t :file/label)
:type :string
:header views/header-cp
:cell (fn [_table row _column]
(when-let [asset-cp (state/get-component :block/asset-cp)]
[:div.block-content.overflow-hidden
{:style {:max-height 30}}
(asset-cp (assoc config :disable-resize? true) row)]))
:disable-hide? true})
(comment
(defn- edit-new-object
[ref id]
(js/setTimeout
(fn []
(when-let [title-node (d/sel1 ref (util/format ".ls-table-row[data-id='%d'] .table-block-title" id))]
(.click title-node)))
100)))
(defn- refresh-view-data!
[view-parent view table ids]
(let [list-view? (= :logseq.property.view/type.list (:db/ident (:logseq.property.view/type view)))]
(when-let [repo (state/get-current-repo)]
(if list-view?
(when-let [result (:result (get @react/*query-state [repo :frontend.worker.react/objects (:db/id view-parent)]))]
(swap! result inc))
(let [set-data! (get-in table [:data-fns :set-data!])
full-data (:full-data table)]
(set-data! (vec (concat full-data ids))))))))
(rum/defc class-objects-inner < rum/static
[config class properties]
(let [*ref (hooks/use-ref nil)
;; Properties can be nil for published private graphs
properties' (remove nil? properties)
columns* (views/build-columns config properties' {:add-tags-column? true})
columns (cond
(= (:db/ident class) :logseq.class/Pdf-annotation)
(remove #(contains? #{:logseq.property/ls-type} (:id %)) columns*)
(= (:db/ident class) :logseq.class/Asset)
(remove #(contains? #{:logseq.property.asset/checksum} (:id %)) columns*)
:else
columns*)
db-ident (:db/ident class)
asset? (= db-ident :logseq.class/Asset)
columns (if asset?
;; Insert in front of tag's properties
(let [[before-cols after-cols] (split-with #(not (db-property/logseq-property? (:id %))) columns)]
(concat before-cols [(build-asset-file-column config)] after-cols))
columns)
add-new-object! (when (or asset? (not (ldb/private-tags (:db/ident class))))
(fn [view table {:keys [properties]}]
(if (= :logseq.class/Asset (:db/ident class))
(shui/dialog-open!
(fn []
[:div.flex.flex-col.gap-2
[:div.font-medium (t :asset/add-assets)]
(filepicker/picker
{:on-change (fn [_e files]
(p/let [entities (editor-handler/upload-asset! nil files :markdown editor-handler/*asset-uploading? true)]
(shui/dialog-close!)
(when (seq entities)
(refresh-view-data! class view table (map :db/id entities)))))})]))
(p/let [block (add-new-class-object! class properties)]
(when (:db/id block)
(refresh-view-data! class view table [(:db/id block)])
(state/sidebar-add-block! (state/get-current-repo) (:db/id block) :block))))))]
[:div {:ref *ref}
(views/view {:config config
:view-parent class
:view-feature-type :class-objects
:columns columns
:add-new-object! add-new-object!
:show-add-property? true
:show-items-count? true
:add-property! (fn [e]
(state/pub-event! [:editor/new-property {:block class
:class-schema? true
:target (.-target e)}]))})]))
(rum/defcs class-objects < rum/reactive db-mixins/query mixins/container-id
[state class config]
(when class
(let [class (db/sub-block (:db/id class))
config (assoc config :container-id (:container-id state))
properties (outliner-property/get-class-properties class)]
[:div.ml-1
(class-objects-inner config class properties)])))
(defn- add-new-property-object!
[property properties]
(p/let [default-value (if (= :checkbox (:logseq.property/type property))
false
(:db/id (db/entity :logseq.property/empty-placeholder)))
block (editor-handler/api-insert-new-block! ""
{:page (:block/uuid property)
:properties (merge
{(:db/ident property) default-value}
properties)
:edit-block? false})]
(editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 {:container-id :unknown-container})
block))
(rum/defc property-related-objects-inner < rum/static
[config property properties]
(let [tags? (= :block/tags (:db/ident property))
columns (views/build-columns config properties
(when tags? {:add-tags-column? false}))]
(views/view {:config config
:view-parent property
:view-feature-type :property-objects
:columns columns
:add-new-object! (fn [view table {:keys [properties]}]
(p/let [block (add-new-property-object! property properties)]
(when (:db/id block)
(state/sidebar-add-block! (state/get-current-repo) (:db/id block) :block)
(refresh-view-data! property view table [(:db/id block)]))))
;; TODO: Add support for adding column
:show-add-property? false})))
;; Show all nodes containing the given property
(rum/defcs property-related-objects < rum/reactive db-mixins/query mixins/container-id
[state property config]
(when property
(let [property' (db/sub-block (:db/id property))
config (assoc config :container-id (:container-id state))
;; Show tags to help differentiate property rows
properties (if (= (:db/ident property) :block/tags)
[property']
[property' (db/entity :block/tags)])]
[:div.ml-1
(property-related-objects-inner config property' properties)])))