enhance: add a table for property pages

that display all nodes for the current property.
Property pages now behave like classes and display a table instead of blocks.
Also update linter to include objects ns
pull/11451/head
Gabriel Horner 2024-07-31 15:23:37 -04:00
parent 43bfeddd49
commit 2e13c9758b
7 changed files with 124 additions and 19 deletions

View File

@ -79,7 +79,7 @@
validate-fn varies by property type" validate-fn varies by property type"
[db validate-fn [{:block/keys [schema] :as property} property-val] & {:keys [new-closed-value?]}] [db validate-fn [{:block/keys [schema] :as property} property-val] & {:keys [new-closed-value?]}]
;; For debugging ;; For debugging
;; (when (not= "logseq.property" (namespace (:db/ident property))) (prn :validate-val (dissoc property :property/closed-values) property-val)) ;; (when (not (string/starts-with? (namespace (:db/ident property)) "logseq.")) (prn :validate-val (dissoc property :property/closed-values) property-val))
(let [validate-fn' (if (db-property-type/property-types-with-db (:type schema)) (let [validate-fn' (if (db-property-type/property-types-with-db (:type schema))
(fn [value] (fn [value]
(validate-fn db value {:new-closed-value? new-closed-value?})) (validate-fn db value {:new-closed-value? new-closed-value?}))

View File

@ -221,8 +221,10 @@
[conn property-id v property-type] [conn property-id v property-type]
(if (and (integer? v) (if (and (integer? v)
(or (not= property-type :number) (or (not= property-type :number)
;; Allows :number property to use number as a ref (for closed value) or value. Number value maybe only used in tests ;; Allows :number property to use number as a ref (for closed value) or value
(and (= property-type :number) (= property-id (:db/ident (:logseq.property/created-from-property (d/entity @conn v))))))) (and (= property-type :number)
(or (= property-id (:db/ident (:logseq.property/created-from-property (d/entity @conn v))))
(= :logseq.property/empty-placeholder (:db/ident (d/entity @conn v)))))))
v v
;; only value-ref-property types should call this ;; only value-ref-property types should call this
(find-or-create-property-value conn property-id v))) (find-or-create-property-value conn property-id v)))

View File

@ -16,7 +16,8 @@
"electron.db" "electron.db"
"frontend.handler.db-based." "frontend.handler.db-based."
"frontend.worker.handler.page.db-based" "frontend.worker.handler.page.db-based"
"frontend.components.property" "frontend.components.class" "frontend.components.db-based"])) "frontend.components.property" "frontend.components.class" "frontend.components.db-based"
"frontend.components.objects"]))
(def file-graph-ns (def file-graph-ns
"Namespaces or parent namespaces _only_ for file graphs" "Namespaces or parent namespaces _only_ for file graphs"
@ -38,6 +39,7 @@
"src/main/frontend/components/class.cljs" "src/main/frontend/components/class.cljs"
"src/main/frontend/components/property.cljs" "src/main/frontend/components/property.cljs"
"src/main/frontend/components/property" "src/main/frontend/components/property"
"src/main/frontend/components/objects.cljs"
"src/main/frontend/components/db_based" "src/main/frontend/components/db_based"
"src/electron/electron/db.cljs"]) "src/electron/electron/db.cljs"])

View File

@ -1,5 +1,5 @@
(ns frontend.components.objects (ns frontend.components.objects
"Tagged objects" "Provides table views for class objects and property related objects"
(:require [frontend.components.views :as views] (:require [frontend.components.views :as views]
[frontend.db :as db] [frontend.db :as db]
[logseq.db :as ldb] [logseq.db :as ldb]
@ -15,29 +15,29 @@
[frontend.modules.outliner.ui :as ui-outliner-tx] [frontend.modules.outliner.ui :as ui-outliner-tx]
[frontend.modules.outliner.op :as outliner-op])) [frontend.modules.outliner.op :as outliner-op]))
(defn- get-all-objects (defn- get-class-objects
[class] [class]
(->> (db-model/get-class-objects (state/get-current-repo) (:db/id class)) (->> (db-model/get-class-objects (state/get-current-repo) (:db/id class))
(map (fn [row] (assoc row :id (:db/id row)))))) (map (fn [row] (assoc row :id (:db/id row))))))
(defn- add-new-object! (defn- add-new-class-object!
[class set-data!] [class set-data!]
(p/let [block (editor-handler/api-insert-new-block! "" (p/let [block (editor-handler/api-insert-new-block! ""
{:page (:block/uuid class) {:page (:block/uuid class)
:properties {:block/tags (:db/id class)} :properties {:block/tags (:db/id class)}
:edit-block? false}) :edit-block? false})
_ (set-data! (get-all-objects class))] _ (set-data! (get-class-objects class))]
(editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 :unknown-container))) (editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 :unknown-container)))
(defn- get-views (defn- get-views
[class] [ent]
(let [class (db/entity (:db/id class))] (let [class (db/entity (:db/id ent))]
(-> (filter (fn [b] (-> (filter (fn [b]
(= (:db/ident class) (:logseq.property/view-for b))) (= (:db/ident class) (:logseq.property/view-for b)))
(:block/_parent class)) (:block/_parent class))
(ldb/sort-by-order)))) (ldb/sort-by-order))))
(rum/defc objects-inner < rum/static (rum/defc class-objects-inner < rum/static
[config class objects properties] [config class objects properties]
(let [[loading? set-loading?] (rum/use-state nil) (let [[loading? set-loading?] (rum/use-state nil)
[view-entity set-view-entity!] (rum/use-state nil) [view-entity set-view-entity!] (rum/use-state nil)
@ -57,7 +57,7 @@
(when-let [view (first views)] (when-let [view (first views)]
(set-view-entity! view)) (set-view-entity! view))
(p/let [_result (db-async/<get-tag-objects (state/get-current-repo) (:db/id class))] (p/let [_result (db-async/<get-tag-objects (state/get-current-repo) (:db/id class))]
(set-data! (get-all-objects class)) (set-data! (get-class-objects class))
(set-loading? false)))) (set-loading? false))))
[]) [])
@ -65,7 +65,7 @@
(views/view view-entity {:data data (views/view view-entity {:data data
:set-data! set-data! :set-data! set-data!
:columns columns :columns columns
:add-new-object! #(add-new-object! class set-data!) :add-new-object! #(add-new-class-object! class set-data!)
:create-view! (fn [] :create-view! (fn []
(p/let [result (editor-handler/api-insert-new-block! "" {:page (:block/uuid class) (p/let [result (editor-handler/api-insert-new-block! "" {:page (:block/uuid class)
:properties {:logseq.property/view-for (:db/ident class)}})] :properties {:logseq.property/view-for (:db/ident class)}})]
@ -89,11 +89,11 @@
tx-data (map (fn [pid] [:db/retract pid :block/tags (:db/id class)]) page-ids)] tx-data (map (fn [pid] [:db/retract pid :block/tags (:db/id class)]) page-ids)]
(when (seq tx-data) (when (seq tx-data)
(outliner-op/transact! tx-data {:outliner-op :save-block})))) (outliner-op/transact! tx-data {:outliner-op :save-block}))))
(set-data! (get-all-objects class)) (set-data! (get-class-objects class))
(when-let [f (get-in table [:data-fns :set-row-selection!])] (when-let [f (get-in table [:data-fns :set-row-selection!])]
(f {})))))})))) (f {})))))}))))
(rum/defcs objects < rum/reactive db-mixins/query mixins/container-id (rum/defcs class-objects < rum/reactive db-mixins/query mixins/container-id
[state class] [state class]
(when class (when class
(let [class (db/sub-block (:db/id class)) (let [class (db/sub-block (:db/id class))
@ -105,4 +105,83 @@
objects (->> (db-model/sub-class-objects repo (:db/id class)) objects (->> (db-model/sub-class-objects repo (:db/id class))
(map (fn [row] (assoc row :id (:db/id row)))))] (map (fn [row] (assoc row :id (:db/id row)))))]
[:div.ml-2 [:div.ml-2
(objects-inner config class objects properties)]))) (class-objects-inner config class objects properties)])))
(defn- get-property-related-objects [repo property]
(->> (db-model/get-property-related-objects repo (:db/id property))
(map (fn [row] (assoc row :id (:db/id row))))))
(defn- add-new-property-object!
[property set-data!]
(p/let [block (editor-handler/api-insert-new-block! ""
{:page (:block/uuid property)
:properties {(:db/ident property) (:db/id (db/entity :logseq.property/empty-placeholder))}
:edit-block? false})
_ (set-data! (get-property-related-objects (state/get-current-repo) property))]
(editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 :unknown-container)))
(rum/defc property-related-objects-inner < rum/static
[config property objects properties]
(let [[loading? set-loading?] (rum/use-state nil)
[view-entity set-view-entity!] (rum/use-state nil)
[data set-data!] (rum/use-state objects)
columns (views/build-columns config properties)]
(rum/use-effect!
(fn []
(set-data! objects))
[objects])
(rum/use-effect!
(fn []
(set-loading? true)
(p/let [_result (db-async/<get-views (state/get-current-repo) (:db/id property))
views (get-views property)]
(when-let [view (first views)]
(set-view-entity! view))
(p/let [result (db-async/<get-property-objects (state/get-current-repo) (:db/ident property))]
(set-data! (mapv #(assoc % :id (:db/id %)) result))
(set-loading? false))))
[])
(when (false? loading?)
(views/view view-entity {:data data
:set-data! set-data!
:columns columns
:add-new-object! #(add-new-property-object! property set-data!)
:create-view! (fn []
(p/let [result (editor-handler/api-insert-new-block! "" {:page (:block/uuid property)
:properties {:logseq.property/view-for (:db/ident property)}})]
(let [view (db/entity [:block/uuid (:block/uuid result)])]
(set-view-entity! view)
view)))
;; TODO: Add support for adding column
:show-add-property? false
:on-delete-rows (fn [table selected-rows]
(let [pages (filter ldb/page? selected-rows)
blocks (remove ldb/page? selected-rows)]
(p/do!
(ui-outliner-tx/transact!
{:outliner-op :delete-blocks}
(when (seq blocks)
(outliner-op/delete-blocks! blocks nil))
(let [page-ids (map :db/id pages)
tx-data (map (fn [pid] [:db/retract pid (:db/ident property)]) page-ids)]
(when (seq tx-data)
(outliner-op/transact! tx-data {:outliner-op :save-block}))))
(set-data! (get-property-related-objects (state/get-current-repo) property))
(when-let [f (get-in table [:data-fns :set-row-selection!])]
(f {})))))}))))
;; Show all nodes containing the given property
(rum/defcs property-related-objects < rum/reactive db-mixins/query mixins/container-id
[state property]
(when property
(let [property' (db/sub-block (:db/id property))
config {:container-id (:container-id state)}
;; Show tags to help differentiate property rows
properties [property' (db/entity :block/tags)]
repo (state/get-current-repo)
objects (get-property-related-objects repo property)]
[:div.ml-2
(property-related-objects-inner config property' objects properties)])))

View File

@ -561,9 +561,13 @@
(when (and db-based? (ldb/class? page)) (when (and db-based? (ldb/class? page))
[:div.mt-8 [:div.mt-8
(objects/objects page)]) (objects/class-objects page)])
(when-not (and db-based? (ldb/class? page)) (when (and db-based? (ldb/property? page))
[:div.mt-8
(objects/property-related-objects page)])
(when-not (and db-based? (or (ldb/class? page) (ldb/property? page)))
[:div [:div
(when (and block? (not sidebar?) (not whiteboard?)) (when (and block? (not sidebar?) (not whiteboard?))
(let [config (merge config {:id "block-parent" (let [config (merge config {:id "block-parent"

View File

@ -253,6 +253,15 @@
[?page :block/name]] [?page :block/name]]
tag-id)) tag-id))
(defn <get-property-objects
[graph property-ident]
(<q graph {:transact-db? true}
'[:find [(pull ?b [*]) ...]
:in $ ?property-ident
:where
[?b ?property-ident]]
property-ident))
(defn <get-tag-objects (defn <get-tag-objects
[graph class-id] [graph class-id]
(let [class-children (db-model/get-class-children graph class-id) (let [class-children (db-model/get-class-children graph class-id)

View File

@ -797,6 +797,15 @@ independent of format as format specific heading characters are stripped"
nil) nil)
react))) react)))
(defn get-property-related-objects
[repo property-id]
(when-let [property (db-utils/entity repo property-id)]
(->> (d/q '[:find [?objects ...]
:in $ ?prop
:where [?objects ?prop]]
(conn/get-db repo)
(:db/ident property))
(map #(db-utils/entity repo %)))))
(defn get-all-namespace-relation (defn get-all-namespace-relation
[repo] [repo]