From 8882926c639ca837b790a4f7195876211451df53 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 13 Nov 2024 16:03:22 +0800 Subject: [PATCH 01/46] wip: property default value --- deps/db/src/logseq/db/frontend/property.cljs | 8 +-- .../src/logseq/db/frontend/property/type.cljs | 8 +++ deps/db/src/logseq/db/frontend/schema.cljs | 2 +- .../frontend/components/property/config.cljs | 7 +++ .../components/property/default_value.cljs | 11 ++++ .../frontend/components/property/value.cljs | 16 ++--- src/main/frontend/worker/db/migrate.cljs | 63 ++++++++++--------- 7 files changed, 72 insertions(+), 43 deletions(-) create mode 100644 src/main/frontend/components/property/default_value.cljs diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index d36b9847d9f..c41df5003ff 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -147,10 +147,10 @@ :public? true :view-context :page} :queryable? true} - ;; :logseq.property/default-value {:title "Default value" - ;; :schema {:type :any - ;; :public? true - ;; :view-context :property}} + :logseq.property/default-value {:title "Default value" + :schema {:type :entity + :public? true + :view-context :property}} :logseq.property.class/properties {:title "Tag Properties" :schema {:type :property :cardinality :many diff --git a/deps/db/src/logseq/db/frontend/property/type.cljs b/deps/db/src/logseq/db/frontend/property/type.cljs index f65d1ade2b4..e84b80fd001 100644 --- a/deps/db/src/logseq/db/frontend/property/type.cljs +++ b/deps/db/src/logseq/db/frontend/property/type.cljs @@ -28,6 +28,14 @@ "Valid property types that can change cardinality" #{:default :number :url :date :node}) +(def default-value-ref-property-types + "Valid ref property :type for default value support" + #{:default :number}) + +(def text-ref-property-types + "Valid ref property :types that support text" + #{:default :url :entity}) + (assert (set/subset? cardinality-property-types (set user-built-in-property-types)) "All closed value types are valid property types") diff --git a/deps/db/src/logseq/db/frontend/schema.cljs b/deps/db/src/logseq/db/frontend/schema.cljs index f7a06069a54..22fc3d23893 100644 --- a/deps/db/src/logseq/db/frontend/schema.cljs +++ b/deps/db/src/logseq/db/frontend/schema.cljs @@ -2,7 +2,7 @@ "Main datascript schemas for the Logseq app" (:require [clojure.set :as set])) -(def version 47) +(def version 48) ;; A page is a special block, a page can corresponds to multiple files with the same ":block/name". (def ^:large-vars/data-var schema diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index a8dc9291d24..198ec66e85a 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -23,6 +23,7 @@ [rum.core :as rum] [frontend.db-mixins :as db-mixins] [frontend.components.property.value :as pv] + [frontend.components.property.default-value :as pdv] [frontend.components.select :as select] [frontend.db.model :as model] [frontend.handler.db-based.page :as db-page-handler] @@ -527,6 +528,12 @@ [:div.px-4 (class-select property {:default-open? false})])})) + (when (contains? db-property-type/default-value-ref-property-types property-type) + (let [default-value (:logseq.property/default-value property)] + (dropdown-editor-menuitem {:icon :settings-2 :title "Default value" + :desc (if default-value (db-property/property-value-content default-value) "Set value") + :submenu-content (fn [] (pdv/default-value-config property))}))) + (when enable-closed-values? (let [values (:property/closed-values property)] (dropdown-editor-menuitem {:icon :list :title "Available choices" diff --git a/src/main/frontend/components/property/default_value.cljs b/src/main/frontend/components/property/default_value.cljs new file mode 100644 index 00000000000..19d7a4640d8 --- /dev/null +++ b/src/main/frontend/components/property/default_value.cljs @@ -0,0 +1,11 @@ +(ns frontend.components.property.default-value + (:require [rum.core :as rum] + [frontend.components.property.value :as pv] + [frontend.db :as db])) + +(rum/defc default-value-config + [property] + (let [default-value (:logseq.property/default-value property)] + (pv/property-value property + (db/entity :logseq.property/default-value) + default-value {}))) diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 9651293ce85..594bc6139b4 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -875,20 +875,21 @@ multiple-values? (db-property/many? property) class (str (when-not row? "flex flex-1 ") (when multiple-values? "property-value-content")) - type (:type schema)] + type (:type schema) + text-ref-type? (db-property-type/text-ref-property-types type)] [:div.cursor-text {:id (or dom-id (random-uuid)) :tabIndex 0 - :class (str class " " (when-not (contains? #{:default :url} type) "jtrigger")) + :class (str class " " (when-not text-ref-type? "jtrigger")) :style {:min-height 24} :on-click (fn [] - (when (and (contains? #{:default :url} type) (nil? value)) + (when (and text-ref-type? (nil? value)) (blocks - (assoc hl-color :closed-values (get-in db-property/built-in-properties [:logseq.property.pdf/hl-color :closed-values]))))) + (d/transact! conn + (concat + [{:db/ident :logseq.property.pdf/hl-page + :block/schema {:type :raw-number}} + [:db/retract (:db/id hl-page) :db/valueType] + {:db/ident :logseq.property.pdf/hl-color + :block/schema {:type :default}}] + (db-property-build/closed-values->blocks + (assoc hl-color :closed-values (get-in db-property/built-in-properties [:logseq.property.pdf/hl-color :closed-values]))))) ;; migrate data - (concat color-update-tx page-update-tx)))) + (concat color-update-tx page-update-tx)))) (defn- store-url-value-in-block-title [conn _search-db] @@ -459,7 +459,8 @@ :block/title :block/closed-value-property :block/created-at :block/updated-at :logseq.property.attribute/property-schema-classes :logseq.property.attribute/property-value-content]}] - [47 {:fix replace-hidden-type-with-schema}]]) + [47 {:fix replace-hidden-type-with-schema}] + [48 {:properties [:logseq.property/default-value]}]]) (let [max-schema-version (apply max (map first schema-version->updates))] (assert (<= db-schema/version max-schema-version)) From dab43e1853f0cd9d8c0bddc931f7fcc2a64e1d7e Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 13 Nov 2024 16:56:30 +0800 Subject: [PATCH 02/46] Add default value for :number type --- .../frontend/components/property/config.cljs | 2 +- .../frontend/components/property/value.cljs | 32 ++++++++++++------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 198ec66e85a..07b2dc9e89b 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -528,7 +528,7 @@ [:div.px-4 (class-select property {:default-open? false})])})) - (when (contains? db-property-type/default-value-ref-property-types property-type) + (when (and (contains? db-property-type/default-value-ref-property-types property-type) (not (db-property/many? property))) (let [default-value (:logseq.property/default-value property)] (dropdown-editor-menuitem {:icon :settings-2 :title "Default value" :desc (if default-value (db-property/property-value-content default-value) "Set value") diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 594bc6139b4..f6ef36c4d73 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -103,15 +103,18 @@ :on-chosen on-chosen!})])) (defn- select-type? - [property type] + [block property type] (or (contains? #{:node :number :date :page :class :property} type) - ;; closed values - (seq (:property/closed-values property)))) + ;; closed values + (seq (:property/closed-values property)) + (and (= (:db/ident property) :logseq.property/default-value) + (= (get-in block [:block/schema :type]) :number)))) (defn Date: Wed, 13 Nov 2024 18:11:13 +0800 Subject: [PATCH 03/46] fix: edge cases for :number type default values --- .../logseq/db/frontend/property/build.cljs | 21 ++++++++++------- .../src/logseq/db/frontend/property/type.cljs | 8 +++++++ .../src/logseq/outliner/property.cljs | 23 +++++++++++-------- .../test/logseq/outliner/property_test.cljs | 2 +- .../frontend/components/property/config.cljs | 2 +- src/main/frontend/db/async.cljs | 22 ++++++++++-------- src/main/frontend/worker/db/migrate.cljs | 1 + 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/property/build.cljs b/deps/db/src/logseq/db/frontend/property/build.cljs index 4147a173c8f..4a4b260967d 100644 --- a/deps/db/src/logseq/db/frontend/property/build.cljs +++ b/deps/db/src/logseq/db/frontend/property/build.cljs @@ -6,25 +6,27 @@ [logseq.db.frontend.property.type :as db-property-type])) (defn- closed-value-new-block - [block-id value property] + [block-id block-type value property] (let [property-id (:db/ident property)] (merge {:block/type "closed value" :block/format :markdown :block/uuid block-id :block/page property-id :block/closed-value-property property-id - :logseq.property/created-from-property property-id + :logseq.property/created-from-property (if (= property-id :logseq.property/default-value) + [:block/uuid block-id] + property-id) :block/parent property-id} - (if (db-property-type/original-value-ref-property-types (get-in property [:block/schema :type])) + (if (db-property-type/property-value-content? block-type property) {:property.value/content value} {:block/title value})))) (defn build-closed-value-block "Builds a closed value block to be transacted" - [block-uuid block-value property {:keys [db-ident icon]}] + [block-uuid block-type block-value property {:keys [db-ident icon]}] (assert block-uuid (uuid? block-uuid)) (cond-> - (closed-value-new-block block-uuid block-value property) + (closed-value-new-block block-uuid block-type block-value property) (and db-ident (keyword? db-ident)) (assoc :db/ident db-ident) @@ -36,10 +38,11 @@ (defn closed-values->blocks [property] - (map (fn [{uuid' :uuid :keys [db-ident value icon]}] + (map (fn [{uuid' :uuid :keys [db-ident value icon schema]}] (cond-> (build-closed-value-block uuid' + (:type schema) value property {:db-ident db-ident :icon icon}) @@ -71,9 +74,11 @@ ;; page block (:db/id block)) :block/parent (:db/id block) - :logseq.property/created-from-property (or (:db/id property) {:db/ident (:db/ident property)}) + :logseq.property/created-from-property (if (= (:db/ident property) :logseq.property/default-value) + (:db/id block) + (or (:db/id property) {:db/ident (:db/ident property)})) :block/order (db-order/gen-key)} - (if (db-property-type/original-value-ref-property-types (get-in property [:block/schema :type])) + (if (db-property-type/property-value-content? (get-in block [:block/schema :type]) property) {:property.value/content value} {:block/title value})) sqlite-util/block-with-timestamps)) diff --git a/deps/db/src/logseq/db/frontend/property/type.cljs b/deps/db/src/logseq/db/frontend/property/type.cljs index e84b80fd001..8dc19f2982e 100644 --- a/deps/db/src/logseq/db/frontend/property/type.cljs +++ b/deps/db/src/logseq/db/frontend/property/type.cljs @@ -196,3 +196,11 @@ (url? val) :url (contains? #{true false} val) :checkbox :else :default)) + +(defn property-value-content? + "Whether property value should be stored in :property.value/content" + [block-type property] + (or + (original-value-ref-property-types (get-in property [:block/schema :type])) + (and (= (:db/ident property) :logseq.property/default-value) + (original-value-ref-property-types block-type)))) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index cf9616d4228..da7bd82b151 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -74,10 +74,14 @@ :type :error}}))))) (defn ^:api convert-property-input-string - [schema-type v-str] - (if (and (= :number schema-type) (string? v-str)) - (fail-parse-double v-str) - v-str)) + [block-type property v-str] + (let [schema-type (get-in property [:block/schema :type])] + (if (and (or (= :number schema-type) + (and (= (:db/ident property) :logseq.property/default-value) + (= :number block-type))) + (string? v-str)) + (fail-parse-double v-str) + v-str))) (defn- update-datascript-schema [property {type' :type :keys [cardinality]}] @@ -207,7 +211,8 @@ (let [property (d/entity @conn property-id) block (when block-id (d/entity @conn block-id)) _ (assert (some? property) (str "Property " property-id " doesn't exist yet")) - value' (convert-property-input-string (get-in property [:block/schema :type]) value) + value' (convert-property-input-string (get-in block [:block/schema :type]) + property value) new-value-block (cond-> (db-property-build/build-property-value-block (or block property) property value') new-block-id (assoc :block/uuid new-block-id))] @@ -284,7 +289,7 @@ (let [property (d/entity @conn property-id) _ (assert (some? property) (str "Property " property-id " doesn't exist yet")) property-type (get-in property [:block/schema :type] :default) - new-value (if (db-property-type/user-ref-property-types property-type) + new-value (if (db-property-type/all-ref-property-types property-type) (convert-ref-property-value conn property-id v property-type) v) existing-value (get block property-id)] @@ -454,13 +459,13 @@ (merge {:block/uuid id :block/closed-value-property (:db/id property)} - (if (db-property-type/original-value-ref-property-types (get-in property [:block/schema :type])) + (if (db-property-type/property-value-content? (get-in block [:block/schema :type]) property) {:property.value/content resolved-value} {:block/title resolved-value}))) icon (assoc :logseq.property/icon icon))] (let [max-order (:block/order (last (:property/closed-values property))) - new-block (-> (db-property-build/build-closed-value-block block-id resolved-value + new-block (-> (db-property-build/build-closed-value-block block-id nil resolved-value property {:icon icon}) (assoc :block/order (db-order/gen-key max-order nil)))] [new-block @@ -481,7 +486,7 @@ property-type (get property-schema :type :default)] (when (contains? db-property-type/closed-value-property-types property-type) (let [value' (if (string? value) (string/trim value) value) - resolved-value (convert-property-input-string (:type property-schema) value') + resolved-value (convert-property-input-string nil property value') validate-message (validate-property-value-aux (get-property-value-schema @conn property-type property {:new-closed-value? true}) resolved-value diff --git a/deps/outliner/test/logseq/outliner/property_test.cljs b/deps/outliner/test/logseq/outliner/property_test.cljs index e4260eeea70..0b3d82b3fc9 100644 --- a/deps/outliner/test/logseq/outliner/property_test.cljs +++ b/deps/outliner/test/logseq/outliner/property_test.cljs @@ -39,7 +39,7 @@ (let [test-uuid (random-uuid)] (are [x y] (= (let [[schema-type value] x] - (outliner-property/convert-property-input-string schema-type value)) y) + (outliner-property/convert-property-input-string nil {:block/schema {:type schema-type}} value)) y) [:number "1"] 1 [:number "1.2"] 1.2 [:url test-uuid] test-uuid diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 07b2dc9e89b..adfdcff3aa8 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -401,7 +401,7 @@ (shui/popup-show! (.-target e) (fn [{:keys [id]}] (let [opts {:toggle-fn (fn [] (shui/popup-hide! id))} - values' (->> (if (contains? db-property-type/user-ref-property-types (get-in property [:block/schema :type])) + values' (->> (if (contains? db-property-type/all-ref-property-types (get-in property [:block/schema :type])) (map #(:block/uuid (db/entity %)) values) values) (remove string/blank?) diff --git a/src/main/frontend/db/async.cljs b/src/main/frontend/db/async.cljs index ab424c2b37a..a4bc327c8a3 100644 --- a/src/main/frontend/db/async.cljs +++ b/src/main/frontend/db/async.cljs @@ -93,15 +93,19 @@ "For db graphs, returns property value ids for given property db-ident. Separate from file version because values are lazy loaded" [graph property-id] - (let [empty-id (:db/id (db/entity :logseq.property/empty-placeholder))] - ( (db-property-build/build-closed-value-block uuid' + nil "Card View" property {:db-ident :logseq.property.view/type.card}) From 828615dc5e0f9634412d9cf5dad8bff897d8d4cd Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 13 Nov 2024 18:44:31 +0800 Subject: [PATCH 04/46] Add default value for :checkbox type --- deps/db/src/logseq/db/frontend/property.cljs | 4 ++ .../src/logseq/db/frontend/property/type.cljs | 2 +- .../frontend/components/property/config.cljs | 70 ++++++++++++------- src/main/frontend/worker/db/migrate.cljs | 2 +- 4 files changed, 50 insertions(+), 28 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index c41df5003ff..0acb2251470 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -151,6 +151,10 @@ :schema {:type :entity :public? true :view-context :property}} + :logseq.property/checkbox-default-value {:title "Default value" + :schema {:type :checkbox + :public? true + :view-context :property}} :logseq.property.class/properties {:title "Tag Properties" :schema {:type :property :cardinality :many diff --git a/deps/db/src/logseq/db/frontend/property/type.cljs b/deps/db/src/logseq/db/frontend/property/type.cljs index 8dc19f2982e..e0d13f11bce 100644 --- a/deps/db/src/logseq/db/frontend/property/type.cljs +++ b/deps/db/src/logseq/db/frontend/property/type.cljs @@ -30,7 +30,7 @@ (def default-value-ref-property-types "Valid ref property :type for default value support" - #{:default :number}) + #{:default :number :checkbox}) (def text-ref-property-types "Valid ref property :types that support text" diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index adfdcff3aa8..525369eae92 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -251,7 +251,7 @@ #(some-> (gdom/getElement id) (.focus)) 32)) (rum/defc dropdown-editor-menuitem - [{:keys [id icon title desc submenu-content item-props sub-content-props disabled? toggle-checked? on-toggle-checked-change]}] + [{:keys [id icon title desc submenu-content item-props sub-content-props disabled? toggle-checked? on-toggle-checked-change checkbox?]}] (let [submenu-content (when-not disabled? submenu-content) item-props' (if (and disabled? (:on-select item-props)) (assoc item-props :on-select (fn [] nil)) @@ -290,14 +290,18 @@ (some-> icon (name) (shui/tabler-icon {:size 14 :style {:margin-top "-1"}})) [:span title]] - (if (fn? desc) (desc) - (if (boolean? toggle-checked?) - [:span.scale-90.flex.items-center - (shui/switch {:id id2 :size "sm" :checked toggle-checked? - :disabled disabled? :on-click #(util/stop-propagation %) - :on-checked-change (or on-toggle-checked-change identity)})] - [:label [:span desc] - (when disabled? (shui/tabler-icon "forbid-2" {:size 15}))]))]))) + (cond + (fn? desc) + (desc) + (boolean? toggle-checked?) + [:span.scale-90.flex.items-center + (let [f (if checkbox? shui/checkbox shui/switch)] + (f {:id id2 :size "sm" :checked toggle-checked? + :disabled disabled? :on-click #(util/stop-propagation %) + :on-checked-change (or on-toggle-checked-change identity)}))] + :else + [:label [:span desc] + (when disabled? (shui/tabler-icon "forbid-2" {:size 15}))])]))) (rum/defc choice-item-content [property block] @@ -487,6 +491,23 @@ :item-props (assoc item-props :data-value value)}] (dropdown-editor-menuitem option)))])) +(rum/defc default-value-subitem + [property] + (let [property-type (get-in property [:block/schema :type]) + option (if (= :checkbox property-type) + (let [default-value (:logseq.property/checkbox-default-value property)] + {:icon :settings-2 + :title "Default value" + :toggle-checked? (boolean default-value) + :checkbox? true + :on-toggle-checked-change (fn [] + (db-property-handler/set-block-property! (:block/uuid property) :logseq.property/checkbox-default-value (not default-value)))}) + (let [default-value (:logseq.property/default-value property)] + {:icon :settings-2 :title "Default value" + :desc (if default-value (db-property/property-value-content default-value) "Set value") + :submenu-content (fn [] (pdv/default-value-config property))}))] + (dropdown-editor-menuitem option))) + (rum/defc ^:large-vars/cleanup-todo dropdown-editor-impl "property: block entity" [property owner-block values {:keys [class-schema? debug?]}] @@ -529,10 +550,7 @@ (class-select property {:default-open? false})])})) (when (and (contains? db-property-type/default-value-ref-property-types property-type) (not (db-property/many? property))) - (let [default-value (:logseq.property/default-value property)] - (dropdown-editor-menuitem {:icon :settings-2 :title "Default value" - :desc (if default-value (db-property/property-value-content default-value) "Set value") - :submenu-content (fn [] (pdv/default-value-config property))}))) + (default-value-subitem property)) (when enable-closed-values? (let [values (:property/closed-values property)] @@ -540,20 +558,20 @@ :desc (when (seq values) (str (count values) " choices")) :submenu-content (fn [] (choices-sub-pane property {:disabled? config/publishing?}))}))) - (let [many? (db-property/many? property)] - (dropdown-editor-menuitem {:icon :checks :title "Multiple values" - :toggle-checked? many? - :disabled? (or disabled? (not (contains? db-property-type/cardinality-property-types property-type))) - :on-toggle-checked-change - (fn [] - (let [update-cardinality-fn #(db-property-handler/upsert-property! (:db/ident property) - (assoc property-schema :cardinality (if many? :one :many)) {})] + (when (and (contains? db-property-type/cardinality-property-types property-type) (not disabled?)) + (let [many? (db-property/many? property)] + (dropdown-editor-menuitem {:icon :checks :title "Multiple values" + :toggle-checked? many? + :on-toggle-checked-change + (fn [] + (let [update-cardinality-fn #(db-property-handler/upsert-property! (:db/ident property) + (assoc property-schema :cardinality (if many? :one :many)) {})] ;; Only show dialog for existing values as it can be reversed for unused properties - (if (and (seq values) (not many?)) - (-> (shui/dialog-confirm! - "This action cannot be undone. Do you want to change this property to have multiple values?") - (p/then update-cardinality-fn)) - (update-cardinality-fn))))})) + (if (and (seq values) (not many?)) + (-> (shui/dialog-confirm! + "This action cannot be undone. Do you want to change this property to have multiple values?") + (p/then update-cardinality-fn)) + (update-cardinality-fn))))}))) (let [property-type (get-in property [:block/schema :type]) group' (->> [(when (and (not (contains? #{:logseq.property/parent :logseq.property.class/properties} (:db/ident property))) diff --git a/src/main/frontend/worker/db/migrate.cljs b/src/main/frontend/worker/db/migrate.cljs index 2f1d6f8a047..e031e2a594e 100644 --- a/src/main/frontend/worker/db/migrate.cljs +++ b/src/main/frontend/worker/db/migrate.cljs @@ -461,7 +461,7 @@ :block/created-at :block/updated-at :logseq.property.attribute/property-schema-classes :logseq.property.attribute/property-value-content]}] [47 {:fix replace-hidden-type-with-schema}] - [48 {:properties [:logseq.property/default-value]}]]) + [48 {:properties [:logseq.property/default-value :logseq.property/checkbox-default-value]}]]) (let [max-schema-version (apply max (map first schema-version->updates))] (assert (<= db-schema/version max-schema-version)) From 82a476e2145ac0dfc69410eee3ba8b756f1e0814 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 14 Nov 2024 17:34:03 +0800 Subject: [PATCH 05/46] Display property default value if there's no value specified --- .../src/logseq/db/frontend/entity_plus.cljc | 71 +++++++++++-------- deps/db/src/logseq/db/frontend/property.cljs | 2 +- 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/entity_plus.cljc b/deps/db/src/logseq/db/frontend/entity_plus.cljc index e68a6a2e4d3..834a6e0b2ec 100644 --- a/deps/db/src/logseq/db/frontend/entity_plus.cljc +++ b/deps/db/src/logseq/db/frontend/entity_plus.cljc @@ -43,45 +43,54 @@ ([^Entity e k default-value] (try (when k - (case k - :block/raw-title - (let [db (.-db e)] + (let [db (.-db e)] + (case k + :block/raw-title (if (and (db-based-graph? db) (= "journal" (:block/type e))) (get-journal-title db e) - (lookup-entity e :block/title default-value))) + (lookup-entity e :block/title default-value)) - :block/properties - (let [db (.-db e)] + :block/properties (if (db-based-graph? db) (lookup-entity e :block/properties (->> (into {} e) (filter (fn [[k _]] (db-property/property? k))) (into {}))) - (lookup-entity e :block/properties nil))) - - ;; cache :block/title - :block/title - (or (:block.temp/cached-title @(.-cache e)) - (let [title (get-block-title e k default-value)] - (vreset! (.-cache e) (assoc @(.-cache e) - :block.temp/cached-title title)) - title)) - - :block/_parent - (->> (lookup-entity e k default-value) - (remove (fn [e] (or (:logseq.property/created-from-property e) - (:block/closed-value-property e)))) - seq) - - :block/_raw-parent - (lookup-entity e :block/_parent default-value) - - :property/closed-values - (->> (lookup-entity e :block/_closed-value-property default-value) - (sort-by :block/order)) - - (or (get (.-kv e) k) - (lookup-entity e k default-value)))) + (lookup-entity e :block/properties nil)) + + ;; cache :block/title + :block/title + (or (:block.temp/cached-title @(.-cache e)) + (let [title (get-block-title e k default-value)] + (vreset! (.-cache e) (assoc @(.-cache e) + :block.temp/cached-title title)) + title)) + + :block/_parent + (->> (lookup-entity e k default-value) + (remove (fn [e] (or (:logseq.property/created-from-property e) + (:block/closed-value-property e)))) + seq) + + :block/_raw-parent + (lookup-entity e :block/_parent default-value) + + :property/closed-values + (->> (lookup-entity e :block/_closed-value-property default-value) + (sort-by :block/order)) + + (or + ;; from kv + (get (.-kv e) k) + ;; from db + (lookup-entity e k default-value) + ;; property default value + (when (qualified-keyword? k) + (when-let [property (d/entity db k)] + (let [schema (lookup-entity property :block/schema nil)] + (if (= :checkbox (:type schema)) + (lookup-entity property :logseq.property/checkbox-default-value nil) + (lookup-entity property :logseq.property/default-value nil))))))))) (catch :default e (js/console.error e))))) diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 0acb2251470..cf1d81ade61 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -151,7 +151,7 @@ :schema {:type :entity :public? true :view-context :property}} - :logseq.property/checkbox-default-value {:title "Default value" + :logseq.property/checkbox-default-value {:title "Checkbox default value" :schema {:type :checkbox :public? true :view-context :property}} From 8dc95098fc521896eaf5701c9ef96c746877ae0e Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sat, 16 Nov 2024 10:59:43 +0800 Subject: [PATCH 06/46] fix: checkbox value update --- .../db/src/logseq/db/frontend/entity_plus.cljc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/entity_plus.cljc b/deps/db/src/logseq/db/frontend/entity_plus.cljc index 834a6e0b2ec..bf29a92824d 100644 --- a/deps/db/src/logseq/db/frontend/entity_plus.cljc +++ b/deps/db/src/logseq/db/frontend/entity_plus.cljc @@ -83,14 +83,16 @@ ;; from kv (get (.-kv e) k) ;; from db - (lookup-entity e k default-value) - ;; property default value - (when (qualified-keyword? k) - (when-let [property (d/entity db k)] - (let [schema (lookup-entity property :block/schema nil)] - (if (= :checkbox (:type schema)) - (lookup-entity property :logseq.property/checkbox-default-value nil) - (lookup-entity property :logseq.property/default-value nil))))))))) + (let [result (lookup-entity e k default-value)] + (if (some? result) + result + ;; property default value + (when (qualified-keyword? k) + (when-let [property (d/entity db k)] + (let [schema (lookup-entity property :block/schema nil)] + (if (= :checkbox (:type schema)) + (lookup-entity property :logseq.property/checkbox-default-value nil) + (lookup-entity property :logseq.property/default-value nil))))))))))) (catch :default e (js/console.error e))))) From d50a2069c6ea1d24f46e7f9b8a8da23e216babb7 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sat, 16 Nov 2024 11:18:08 +0800 Subject: [PATCH 07/46] fix: create a new text block when clicking the default one --- src/main/frontend/components/block.cljs | 9 ++++++--- src/main/frontend/components/property/value.cljs | 14 +++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index b653d1a202a..b975f2b6d73 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2233,8 +2233,8 @@ [:span.hl-page [:strong.forbid-edit (str "P" - (or (pu/lookup properties :logseq.property.pdf/hl-page) - "?"))]] + (or (pu/lookup properties :logseq.property.pdf/hl-page) + "?"))]] (when (and area? (or (:hl-stamp properties) @@ -2740,7 +2740,10 @@ (.preventDefault e) :else - (block-content-on-pointer-down e block block-id content edit-input-id config))))))] + (let [f (:on-block-content-pointer-down config)] + (if (fn? f) + (f e) + (block-content-on-pointer-down e block block-id content edit-input-id config))))))))] [:div.block-content.inline (cond-> {:id (str "block-content-" uuid) :key (str "block-content-" uuid)} diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index f6ef36c4d73..d004a445259 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -121,8 +121,10 @@ (if (and (contains? #{:default :url} (get-in property [:block/schema :type])) (not (db-property/many? property))) (p/let [existing-value (get block (:db/ident property)) + default-value (:logseq.property/default-value property) existing-value? (and (some? existing-value) - (not= (:db/ident existing-value) :logseq.property/empty-placeholder)) + (not= (:db/ident existing-value) :logseq.property/empty-placeholder) + (not= (:db/id existing-value) (:db/id default-value))) new-block-id (when-not existing-value? (db/new-block-id)) _ (when-not existing-value? (db-property-handler/create-property-text-block! @@ -716,7 +718,10 @@ blocks-container (state/get-component :block/blocks-container) value-block (if (and (coll? value-block) (every? de/entity? value-block)) (set (remove #(= (:db/ident %) :logseq.property/empty-placeholder) value-block)) - value-block)] + value-block) + default-value (:logseq.property/default-value property) + default-value? (and (= (:db/id value-block) (:db/id default-value)) + (not= (:db/ident property) :logseq.property/default-value))] (if (seq value-block) [:div.property-block-container.content.w-full (let [config {:id (str (if multiple-values? @@ -724,7 +729,10 @@ (:block/uuid value-block))) :container-id container-id :editor-box (state/get-component :editor/box) - :property-block? true}] + :property-block? true + :on-block-content-pointer-down (when default-value? + (fn [_e] + ( Date: Sat, 16 Nov 2024 17:48:52 +0800 Subject: [PATCH 08/46] feat: add :property-value db rule --- deps/db/src/logseq/db/frontend/rules.cljc | 45 ++++++++++++++--------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 42e35b663f1..9f66c445b5b 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -155,7 +155,15 @@ (dissoc query-dsl-rules :namespace :page-property :has-page-property :page-tags :all-page-tags) - {:tags + {:property-value + '[[(property-value ?b ?prop ?pv) + [?b ?prop ?pv]] + [(property-value ?b ?prop ?pv) + [?prop-e :db/ident ?prop] + (or + [?prop-e :logseq.property/default-value ?pv] + [?prop-e :logseq.property/checkbox-default-value ?pv])]] + :tags '[(tags ?b ?tags) [?b :block/tags ?t] [?t :block/name ?tag] @@ -164,7 +172,7 @@ :has-property '[(has-property ?b ?prop) - [?b ?prop _] + (property-value ?b ?prop ?pv) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] [?prop-e :block/schema ?prop-schema] @@ -174,7 +182,7 @@ ;; Same as has-property except it returns public and private properties like :block/title :has-private-property '[(has-private-property ?b ?prop) - [?b ?prop _] + (property-value ?b ?prop ?pv) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"]] @@ -184,25 +192,27 @@ [?prop-e :block/type "property"] [?prop-e :block/schema ?prop-schema] [(get ?prop-schema :public? true) ?public] + [(get ?prop-schema :type) ?type] [(= true ?public)] - [?b ?prop ?pv] - (or - ;; non-ref value - (and - [(missing? $ ?prop-e :db/valueType)] - [?b ?prop ?val]) - ;; ref value - (and - [?prop-e :db/valueType :db.type/ref] - (or [?pv :block/title ?val] - [?pv :property.value/content ?val])))] + (and + (property-value ?b ?prop ?pv) + (or + ;; non-ref value + (and + [(missing? $ ?prop-e :db/valueType)] + [?b ?prop ?val]) + ;; ref value + (and + [?prop-e :db/valueType :db.type/ref] + (or [?pv :block/title ?val] + [?pv :property.value/content ?val]))))] - ;; Same as property except it returns public and private properties like :block/title +;; Same as property except it returns public and private properties like :block/title :private-property '[(private-property ?b ?prop ?val) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] - [?b ?prop ?pv] + (property-value ?b ?prop ?pv) (or ;; non-ref value (and @@ -231,7 +241,8 @@ becomes long or brittle, we could do scan rules for their deps with something like find-rules-in-where" {:task #{:property} - :priority #{:property}}) + :priority #{:property} + :property #{:property-value}}) (defn extract-rules "Given a rules map and the rule names to extract, returns a vector of rules to From a48fbd9e97b3d3c0b1eec70364b9ef4edf047260 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 17 Nov 2024 18:34:00 +0800 Subject: [PATCH 09/46] wip: default-value rule --- deps/db/src/logseq/db/frontend/rules.cljc | 80 +++++++++++++---------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 9f66c445b5b..6cff5558146 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -155,14 +155,44 @@ (dissoc query-dsl-rules :namespace :page-property :has-page-property :page-tags :all-page-tags) - {:property-value - '[[(property-value ?b ?prop ?pv) - [?b ?prop ?pv]] - [(property-value ?b ?prop ?pv) + {:existing-property-value + '[;; non-ref value + [(existing-property-value ?b ?prop ?val) [?prop-e :db/ident ?prop] + [(missing? $ ?prop-e :db/valueType)] + [?b ?prop ?val]] + [(existing-property-value ?b ?prop ?val) + [?prop-e :db/ident ?prop] + [?prop-e :db/valueType :db.type/ref] + [?b ?prop ?pv] + (or [?pv :block/title ?val] + [?pv :property.value/content ?val])]] + + :property-default-value + '[(property-default-value ?prop-e ?default-p ?val) + [?t :logseq.property.class/properties ?prop-e] + [?b :block/tags ?t] + [?prop-e :db/ident ?prop] + ;; Notice: `(missing? )` doesn't work here because `de/entity` + ;; returns the default value if there's no value yet. + [(get-else $ ?b ?prop "N/A") ?prop-v] + [(= ?prop-v "N/A")] + [?prop-e ?default-p ?pv] + (or [(= ?pv ?val)] + (and [(nil? ?pv)] + (or + [?pv :block/title ?val] + [?pv :property.value/content ?val])))] + + :property-value + '[[(property-value ?b ?prop-e ?val) + [?prop-e :db/ident ?prop] + (existing-property-value ?b ?prop ?val)] + [(property-value ?b ?prop-e ?val) (or - [?prop-e :logseq.property/default-value ?pv] - [?prop-e :logseq.property/checkbox-default-value ?pv])]] + (property-default-value ?prop-e :logseq.property/checkbox-default-value ?val) + (property-default-value ?prop-e :logseq.property/default-value ?val))]] + :tags '[(tags ?b ?tags) [?b :block/tags ?t] @@ -172,9 +202,9 @@ :has-property '[(has-property ?b ?prop) - (property-value ?b ?prop ?pv) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] + (property-value ?b ?prop-e ?val) [?prop-e :block/schema ?prop-schema] [(get ?prop-schema :public? true) ?public] [(= true ?public)]] @@ -182,9 +212,9 @@ ;; Same as has-property except it returns public and private properties like :block/title :has-private-property '[(has-private-property ?b ?prop) - (property-value ?b ?prop ?pv) [?prop-e :db/ident ?prop] - [?prop-e :block/type "property"]] + [?prop-e :block/type "property"] + (property-value ?b ?prop-e ?val)] :property '[(property ?b ?prop ?val) @@ -194,35 +224,14 @@ [(get ?prop-schema :public? true) ?public] [(get ?prop-schema :type) ?type] [(= true ?public)] - (and - (property-value ?b ?prop ?pv) - (or - ;; non-ref value - (and - [(missing? $ ?prop-e :db/valueType)] - [?b ?prop ?val]) - ;; ref value - (and - [?prop-e :db/valueType :db.type/ref] - (or [?pv :block/title ?val] - [?pv :property.value/content ?val]))))] + (property-value ?b ?prop-e ?val)] ;; Same as property except it returns public and private properties like :block/title :private-property '[(private-property ?b ?prop ?val) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] - (property-value ?b ?prop ?pv) - (or - ;; non-ref value - (and - [(missing? $ ?prop-e :db/valueType)] - [?b ?prop ?val]) - ;; ref value - (and - [?prop-e :db/valueType :db.type/ref] - (or [?pv :block/title ?val] - [?pv :property.value/content ?val])))] + (property-value ?b ?prop-e ?val)] :task '[(task ?b ?statuses) @@ -240,9 +249,10 @@ "For db graphs, a map of rule names and the rules they depend on. If this map becomes long or brittle, we could do scan rules for their deps with something like find-rules-in-where" - {:task #{:property} - :priority #{:property} - :property #{:property-value}}) + {:task #{:property :property-value :existing-property-value :property-default-value} + :priority #{:property :property-value :existing-property-value :property-default-value} + :property-value #{:existing-property-value :property-default-value} + :property #{:property-value :existing-property-value :property-default-value}}) (defn extract-rules "Given a rules map and the rule names to extract, returns a vector of rules to From 78c409b44cdd217237bf5c82bd4961cd6b283e05 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 17 Nov 2024 20:38:40 +0800 Subject: [PATCH 10/46] Add full-deps test --- deps/db/src/logseq/db/frontend/rules.cljc | 49 ++++++++++++------- .../test/logseq/db/frontend/rules_test.cljs | 19 ++++++- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 6cff5558146..3ff700e4ec5 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -168,8 +168,8 @@ (or [?pv :block/title ?val] [?pv :property.value/content ?val])]] - :property-default-value - '[(property-default-value ?prop-e ?default-p ?val) + :property-missing-value + '[(property-missing-value ?b ?prop-e ?default-p ?default-v) [?t :logseq.property.class/properties ?prop-e] [?b :block/tags ?t] [?prop-e :db/ident ?prop] @@ -177,12 +177,17 @@ ;; returns the default value if there's no value yet. [(get-else $ ?b ?prop "N/A") ?prop-v] [(= ?prop-v "N/A")] - [?prop-e ?default-p ?pv] - (or [(= ?pv ?val)] - (and [(nil? ?pv)] - (or - [?pv :block/title ?val] - [?pv :property.value/content ?val])))] + [?prop-e ?default-p ?default-v]] + + :property-default-value + '[[(property-default-value ?b ?prop-e ?default-p ?val) + (property-missing-value ?b ?prop-e ?default-p ?default-v) + [(= ?default-v ?val)]] + [(property-default-value ?b ?prop-e ?default-p ?val) + (property-missing-value ?b ?prop-e ?default-p ?default-v) + (or + [?default-v :block/title ?val] + [?default-v :property.value/content ?val])]] :property-value '[[(property-value ?b ?prop-e ?val) @@ -190,8 +195,8 @@ (existing-property-value ?b ?prop ?val)] [(property-value ?b ?prop-e ?val) (or - (property-default-value ?prop-e :logseq.property/checkbox-default-value ?val) - (property-default-value ?prop-e :logseq.property/default-value ?val))]] + (property-default-value ?b ?prop-e :logseq.property/checkbox-default-value ?val) + (property-default-value ?b ?prop-e :logseq.property/default-value ?val))]] :tags '[(tags ?b ?tags) @@ -249,10 +254,20 @@ "For db graphs, a map of rule names and the rules they depend on. If this map becomes long or brittle, we could do scan rules for their deps with something like find-rules-in-where" - {:task #{:property :property-value :existing-property-value :property-default-value} - :priority #{:property :property-value :existing-property-value :property-default-value} - :property-value #{:existing-property-value :property-default-value} - :property #{:property-value :existing-property-value :property-default-value}}) + {:task #{:property} + :priority #{:property} + :property-default-value #{:existing-property-value :property-missing-value} + :property-value #{:property-default-value} + :property #{:property-value}}) + +(defn- get-full-deps + [deps rules-deps] + (loop [deps' deps + result #{}] + (if (seq deps') + (recur (mapcat rules-deps deps') + (into result deps')) + result))) (defn extract-rules "Given a rules map and the rule names to extract, returns a vector of rules to @@ -262,9 +277,9 @@ No dependencies are detected by default though we could add it later e.g. find-rules-in-where" ([rules-m] (extract-rules rules-m (keys rules-m))) ([rules-m rules' & {:keys [deps]}] - (let [rules-with-deps (concat rules' - (when (map? deps) - (mapcat deps rules')))] + (let [rules-with-deps (if (map? deps) + (get-full-deps rules' deps) + rules')] (vec (mapcat #(let [val (rules-m %)] ;; if vector?, rule has multiple clauses diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs index e38c6b2b64e..7f773e5287d 100644 --- a/deps/db/test/logseq/db/frontend/rules_test.cljs +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -1,5 +1,5 @@ (ns logseq.db.frontend.rules-test - (:require [cljs.test :refer [deftest is testing]] + (:require [cljs.test :refer [deftest is testing are]] [datascript.core :as d] [logseq.db.frontend.rules :as rules] [logseq.db.test.helper :as db-test])) @@ -10,6 +10,23 @@ db (rules/extract-rules rules/db-query-dsl-rules))) +(deftest get-full-deps + (let [default-value-deps #{:property-default-value + :property-missing-value + :existing-property-value} + property-value-deps (conj default-value-deps :property-value) + property-deps (conj property-value-deps :property) + task-deps (conj property-deps :task) + priority-deps (conj property-deps :priority) + task-priority-deps (conj property-deps :task :priority)] + (are [x y] (= (#'rules/get-full-deps x rules/rules-dependencies) y) + [:property-default-value] default-value-deps + [:property-value] property-value-deps + [:property] property-deps + [:task] task-deps + [:priority] priority-deps + [:task :priority] task-priority-deps))) + (deftest has-property-rule (let [conn (db-test/create-conn-with-blocks {:properties {:foo {:block/schema {:type :default}} From d4a30cfbc1c6dbb925bd3a09d967dfb8e9467325 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Sun, 17 Nov 2024 21:12:33 +0800 Subject: [PATCH 11/46] Add more small rules --- deps/db/src/logseq/db/frontend/rules.cljc | 29 ++++++++++++++++--- .../test/logseq/db/frontend/rules_test.cljs | 3 +- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 3ff700e4ec5..cdb963ce24f 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -161,6 +161,7 @@ [?prop-e :db/ident ?prop] [(missing? $ ?prop-e :db/valueType)] [?b ?prop ?val]] + ;; ref value [(existing-property-value ?b ?prop ?val) [?prop-e :db/ident ?prop] [?prop-e :db/valueType :db.type/ref] @@ -171,8 +172,8 @@ :property-missing-value '[(property-missing-value ?b ?prop-e ?default-p ?default-v) [?t :logseq.property.class/properties ?prop-e] - [?b :block/tags ?t] [?prop-e :db/ident ?prop] + (object-has-class-property? ?b ?prop) ;; Notice: `(missing? )` doesn't work here because `de/entity` ;; returns the default value if there's no value yet. [(get-else $ ?b ?prop "N/A") ?prop-v] @@ -205,11 +206,26 @@ [(missing? $ ?b :block/link)] [(contains? ?tags ?tag)]] + :object-has-class-property + '[(object-has-class-property? ?b ?prop) + [?prop-e :db/ident ?prop] + [?t :logseq.property.class/properties ?prop-e] + [?b :block/tags ?t]] + + :has-property-or-default-value + '[(has-property-or-default-value? ?b ?prop) + [?prop-e :db/ident ?prop] + (or + [?b ?prop _] + (and (object-has-class-property? ?b ?prop) + (or [?prop-e :logseq.property/default-value _] + [?prop-e :logseq.property/checkbox-default-value _])))] + :has-property '[(has-property ?b ?prop) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] - (property-value ?b ?prop-e ?val) + (has-property-or-default-value? ?b ?prop) [?prop-e :block/schema ?prop-schema] [(get ?prop-schema :public? true) ?public] [(= true ?public)]] @@ -219,7 +235,7 @@ '[(has-private-property ?b ?prop) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] - (property-value ?b ?prop-e ?val)] + (has-property-or-default-value? ?b ?prop)] :property '[(property ?b ?prop ?val) @@ -256,9 +272,14 @@ like find-rules-in-where" {:task #{:property} :priority #{:property} + :property-missing-value #{:object-has-class-property} + :has-property-or-default-value #{:object-has-class-property} + :has-property #{:has-property-or-default-value} + :has-private-property #{:has-property-or-default-value} :property-default-value #{:existing-property-value :property-missing-value} :property-value #{:property-default-value} - :property #{:property-value}}) + :property #{:property-value} + :has-propeorty #{}}) (defn- get-full-deps [deps rules-deps] diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs index 7f773e5287d..407f54d873f 100644 --- a/deps/db/test/logseq/db/frontend/rules_test.cljs +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -13,7 +13,8 @@ (deftest get-full-deps (let [default-value-deps #{:property-default-value :property-missing-value - :existing-property-value} + :existing-property-value + :object-has-class-property} property-value-deps (conj default-value-deps :property-value) property-deps (conj property-value-deps :property) task-deps (conj property-deps :task) From ab360c3d913d589f2d8c9091d31808772bdff2b6 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 18 Nov 2024 16:18:44 +0800 Subject: [PATCH 12/46] fix: db dep tests --- deps/db/src/logseq/db/frontend/rules.cljc | 30 ++++++++++++------- .../test/logseq/db/frontend/rules_test.cljs | 6 ++-- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index cdb963ce24f..21448ac3c1a 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -180,15 +180,18 @@ [(= ?prop-v "N/A")] [?prop-e ?default-p ?default-v]] + :property-checkbox-default-value + '[(property-checkbox-default-value ?b ?prop-e ?default-p ?val) + (property-missing-value ?b ?prop-e ?default-p ?default-v) + [(missing? $ ?prop-e :db/valueType)] + [?prop-e ?default-p ?val]] + :property-default-value - '[[(property-default-value ?b ?prop-e ?default-p ?val) - (property-missing-value ?b ?prop-e ?default-p ?default-v) - [(= ?default-v ?val)]] - [(property-default-value ?b ?prop-e ?default-p ?val) - (property-missing-value ?b ?prop-e ?default-p ?default-v) - (or - [?default-v :block/title ?val] - [?default-v :property.value/content ?val])]] + '[(property-default-value ?b ?prop-e ?default-p ?val) + (property-missing-value ?b ?prop-e ?default-p ?default-v) + (or + [?default-v :block/title ?val] + [?default-v :property.value/content ?val])] :property-value '[[(property-value ?b ?prop-e ?val) @@ -196,8 +199,12 @@ (existing-property-value ?b ?prop ?val)] [(property-value ?b ?prop-e ?val) (or - (property-default-value ?b ?prop-e :logseq.property/checkbox-default-value ?val) - (property-default-value ?b ?prop-e :logseq.property/default-value ?val))]] + (and + [(missing? $ ?prop-e :db/valueType)] + (property-checkbox-default-value ?b ?prop-e :logseq.property/checkbox-default-value ?val)) + (and + [?prop-e :db/valueType :db.type/ref] + (property-default-value ?b ?prop-e :logseq.property/default-value ?val)))]] :tags '[(tags ?b ?tags) @@ -277,7 +284,8 @@ :has-property #{:has-property-or-default-value} :has-private-property #{:has-property-or-default-value} :property-default-value #{:existing-property-value :property-missing-value} - :property-value #{:property-default-value} + :property-checkbox-default-value #{:existing-property-value :property-missing-value} + :property-value #{:property-default-value :property-checkbox-default-value} :property #{:property-value} :has-propeorty #{}}) diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs index 407f54d873f..421b939d74d 100644 --- a/deps/db/test/logseq/db/frontend/rules_test.cljs +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -15,7 +15,7 @@ :property-missing-value :existing-property-value :object-has-class-property} - property-value-deps (conj default-value-deps :property-value) + property-value-deps (conj default-value-deps :property-value :property-checkbox-default-value) property-deps (conj property-value-deps :property) task-deps (conj property-deps :task) priority-deps (conj property-deps :priority) @@ -125,8 +125,8 @@ [:user.property/number-many 5] [:user.property/foo "bar"] [:user.property/page-many "Page A"]} - (->> (q-with-rules '[:find ?p ?v - :where (property ?b ?p ?v) [?b :block/title "Page"]] + (->> (q-with-rules '[:find ?p ?val + :where (property ?b ?p ?val) [?b :block/title "Page"]] @conn) set)) "property can bind to property and property value args") From 23c4bbcf056dca194f70ab3052e0188ba1490911 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 18 Nov 2024 16:23:04 +0800 Subject: [PATCH 13/46] enhance: hide default value pages --- deps/db/src/logseq/db/frontend/property.cljs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index cf1d81ade61..2b6cc09ca95 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -149,11 +149,13 @@ :queryable? true} :logseq.property/default-value {:title "Default value" :schema {:type :entity - :public? true + :public? false + :hide? true :view-context :property}} :logseq.property/checkbox-default-value {:title "Checkbox default value" :schema {:type :checkbox - :public? true + :public? false + :hide? true :view-context :property}} :logseq.property.class/properties {:title "Tag Properties" :schema {:type :property From 15e3ce98588e08f7ea39e5920f1b64c3de084a7e Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 18 Nov 2024 16:50:18 +0800 Subject: [PATCH 14/46] fix: graph parser tests --- deps/db/.carve/config.edn | 3 ++- .../test/logseq/graph_parser/exporter_test.cljs | 10 ++++++++-- src/test/frontend/db/query_dsl_test.cljs | 14 +++++++------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/deps/db/.carve/config.edn b/deps/db/.carve/config.edn index a2922f04f0c..ffc15d10674 100644 --- a/deps/db/.carve/config.edn +++ b/deps/db/.carve/config.edn @@ -13,5 +13,6 @@ logseq.db.frontend.schema logseq.db.frontend.validate logseq.db.test.helper - logseq.db] + logseq.db + logseq.db.frontend.property.type] :report {:format :ignore}} diff --git a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs index 9d45f6f767b..86bf63cbe43 100644 --- a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs @@ -43,17 +43,23 @@ db) first))) +(defn- extract-rules + [rules] + (rules/extract-rules rules/db-query-dsl-rules + rules + {:deps rules/rules-dependencies})) + (defn- find-block-by-property [db property] (d/q '[:find [(pull ?b [*]) ...] :in $ ?prop % :where (has-property ?b ?prop)] - db property (rules/extract-rules rules/db-query-dsl-rules [:has-property]))) + db property (extract-rules [:has-property]))) (defn- find-block-by-property-value [db property property-value] (->> (d/q '[:find [(pull ?b [*]) ...] :in $ ?prop ?prop-value % :where (property ?b ?prop ?prop-value)] - db property property-value (rules/extract-rules rules/db-query-dsl-rules [:property])) + db property property-value (extract-rules [:property])) first)) (defn- find-page-by-name [db name] diff --git a/src/test/frontend/db/query_dsl_test.cljs b/src/test/frontend/db/query_dsl_test.cljs index 416cffa87dd..2563b5ce709 100644 --- a/src/test/frontend/db/query_dsl_test.cljs +++ b/src/test/frontend/db/query_dsl_test.cljs @@ -148,9 +148,9 @@ prop-d:: [[nada]]"}]) (dsl-query "(property prop-d no-space-link)"))) "Blocks have property value with no space") - (is (= ["b3" "b4"] - (map (comp first str/split-lines :block/title) - (dsl-query "(property prop-d)"))) + (is (= #{"b3" "b4"} + (set (map (comp first str/split-lines :block/title) + (dsl-query "(property prop-d)")))) "Blocks that have a property")) (deftest block-property-queries @@ -264,10 +264,10 @@ prop-d:: [[nada]]"}]) "Boolean false"))) (when-not js/process.env.DB_GRAPH - (deftest page-property-queries - (testing "page property tests with default config" - (test-helper/with-config {} - (page-property-queries-test))))) + (deftest page-property-queries + (testing "page property tests with default config" + (test-helper/with-config {} + (page-property-queries-test))))) (deftest task-queries (load-test-files [{:file/path "pages/page1.md" From 3f6704e42ff24139e0c0c5a2f2e3a2129a968f17 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 13:36:33 +0800 Subject: [PATCH 15/46] fix: db large vars lint --- .../src/logseq/db/frontend/entity_plus.cljc | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/deps/db/src/logseq/db/frontend/entity_plus.cljc b/deps/db/src/logseq/db/frontend/entity_plus.cljc index bf29a92824d..6271c366f8f 100644 --- a/deps/db/src/logseq/db/frontend/entity_plus.cljc +++ b/deps/db/src/logseq/db/frontend/entity_plus.cljc @@ -38,6 +38,23 @@ result)] (or result' default-value)))))) +(defn- lookup-kv-with-default-value + [db ^Entity e k default-value] + (or + ;; from kv + (get (.-kv e) k) + ;; from db + (let [result (lookup-entity e k default-value)] + (if (some? result) + result + ;; property default value + (when (qualified-keyword? k) + (when-let [property (d/entity db k)] + (let [schema (lookup-entity property :block/schema nil)] + (if (= :checkbox (:type schema)) + (lookup-entity property :logseq.property/checkbox-default-value nil) + (lookup-entity property :logseq.property/default-value nil))))))))) + (defn lookup-kv-then-entity ([e k] (lookup-kv-then-entity e k nil)) ([^Entity e k default-value] @@ -79,20 +96,7 @@ (->> (lookup-entity e :block/_closed-value-property default-value) (sort-by :block/order)) - (or - ;; from kv - (get (.-kv e) k) - ;; from db - (let [result (lookup-entity e k default-value)] - (if (some? result) - result - ;; property default value - (when (qualified-keyword? k) - (when-let [property (d/entity db k)] - (let [schema (lookup-entity property :block/schema nil)] - (if (= :checkbox (:type schema)) - (lookup-entity property :logseq.property/checkbox-default-value nil) - (lookup-entity property :logseq.property/default-value nil))))))))))) + (lookup-kv-with-default-value db e k default-value)))) (catch :default e (js/console.error e))))) From a97fc07be4177d8814b74c7404d1c2c7d0ce024c Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 13:42:29 +0800 Subject: [PATCH 16/46] fix: datalog lint rules --- deps/db/bb.edn | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deps/db/bb.edn b/deps/db/bb.edn index c9a9f982412..178a213582a 100644 --- a/deps/db/bb.edn +++ b/deps/db/bb.edn @@ -32,7 +32,10 @@ ;; TODO: Update linter to handle false positive on ?str-val for :property (rules/extract-rules (dissoc rules/query-dsl-rules :property)) ;; TODO: Update linter to handle false positive on :task, :priority, :property and :private-property - (rules/extract-rules (dissoc rules/db-query-dsl-rules :task :priority :property :private-property)))))}} + (rules/extract-rules (dissoc rules/db-query-dsl-rules :task :priority :property :private-property + :property-checkbox-default-value + :property-missing-value + :has-property-or-default-value)))))}} :tasks/config {:large-vars From 07a809b5c5f3f34f4c49472d37d60df95d2e7836 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 14:03:16 +0800 Subject: [PATCH 17/46] enhance: use default value for new text block --- src/main/frontend/components/property/value.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index d004a445259..ae1616c44d5 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -732,7 +732,7 @@ :property-block? true :on-block-content-pointer-down (when default-value? (fn [_e] - ( Date: Tue, 19 Nov 2024 14:12:29 +0800 Subject: [PATCH 18/46] fix: remove blank strings from existing values --- src/main/frontend/components/property/config.cljs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 525369eae92..438c67af265 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -338,7 +338,8 @@ (let [uuid-values? (every? uuid? values) values' (if uuid-values? (let [values' (map #(db/entity [:block/uuid %]) values)] - (->> (util/distinct-by db-property/closed-value-content values') + (->> values' + (util/distinct-by db-property/closed-value-content) (map :block/uuid))) values)] [:div.flex.flex-col.gap-1.w-64.p-4.overflow-y-auto @@ -406,9 +407,9 @@ (fn [{:keys [id]}] (let [opts {:toggle-fn (fn [] (shui/popup-hide! id))} values' (->> (if (contains? db-property-type/all-ref-property-types (get-in property [:block/schema :type])) - (map #(:block/uuid (db/entity %)) values) - values) - (remove string/blank?) + (->> (map #(:block/uuid (db/entity %)) values) + (remove (fn [e] (string/blank? (:block/title e))))) + (remove string/blank? values)) distinct)] (if (seq values') (add-existing-values property values' opts) From 3b311352462fbdd4538e650aa960be225e503852 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 15:48:53 +0800 Subject: [PATCH 19/46] fix: add available choices --- src/main/frontend/components/property/config.cljs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 438c67af265..13c69a88afd 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -407,8 +407,10 @@ (fn [{:keys [id]}] (let [opts {:toggle-fn (fn [] (shui/popup-hide! id))} values' (->> (if (contains? db-property-type/all-ref-property-types (get-in property [:block/schema :type])) - (->> (map #(:block/uuid (db/entity %)) values) - (remove (fn [e] (string/blank? (:block/title e))))) + (->> values + (map db/entity) + (remove (fn [e] (string/blank? (:block/title e)))) + (map :block/uuid)) (remove string/blank? values)) distinct)] (if (seq values') From 8809509fec5dd336443490d9d2c55273703ff867 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 16:14:57 +0800 Subject: [PATCH 20/46] enhance: set as default choice from choices list --- src/main/frontend/components/icon.cljs | 5 ++- src/main/frontend/components/property.css | 19 +++------ .../frontend/components/property/config.cljs | 42 ++++++++++++++----- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/main/frontend/components/icon.cljs b/src/main/frontend/components/icon.cljs index 1b3e8a44855..690ac6ec4e8 100644 --- a/src/main/frontend/components/icon.cljs +++ b/src/main/frontend/components/icon.cljs @@ -459,9 +459,10 @@ (let [has-icon? (some? icon-value)] (shui/button {:ref *trigger-ref - :variant (if has-icon? :ghost :text) + :variant :ghost :size :sm - :class (if has-icon? "px-1 leading-none" "font-normal text-sm px-[0.5px] opacity-50") + :class (if has-icon? "px-1 leading-none text-muted-foreground hover:text-foreground" + "font-normal text-sm px-[0.5px] text-muted-foreground hover:text-foreground") :on-click (fn [^js e] (when-not disabled? (shui/popup-show! (.-target e) content-fn diff --git a/src/main/frontend/components/property.css b/src/main/frontend/components/property.css index 6285438307b..5580ff5248e 100644 --- a/src/main/frontend/components/property.css +++ b/src/main/frontend/components/property.css @@ -414,29 +414,20 @@ a.control-link { @apply flex items-center gap-1 relative; .ls-icon-grip-vertical { - @apply opacity-50 cursor-move active:opacity-80; + @apply cursor-move; } > strong { @apply text-sm px-0.5 flex-grow cursor-pointer font-normal - select-none active:opacity-60; + select-none; } > .ui__button { - @apply !p-0 !w-7 !h-7 overflow-hidden flex-shrink-0; + @apply !p-0 !w-5 !h-5 overflow-hidden flex-shrink-0 text-muted-foreground hover:text-foreground; } - > a.del { - @apply items-center absolute right-0 top-0 px-1 py-[7px] scale-90 hidden - opacity-80 hover:opacity-100 active:opacity-80 text-gray-08 hover:text-red-700; - } - - &:hover a.del { - @apply flex; - } - - &:hover .ls-icon-grip-vertical { - @apply opacity-80; + > .del { + @apply hover:text-red-700; } } } diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 13c69a88afd..f1407a07614 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -317,21 +317,40 @@ value (db-property/closed-value-content block)] [:li - (shui/tabler-icon "grip-vertical" {:size 14}) - (shui/button {:size "sm" :variant :outline} - (icon-component/icon-picker icon {:on-chosen (fn [_e icon] (update-icon! icon)) - :popup-opts {:align "start"} - :del-btn? (boolean icon) - :empty-label "?"})) + (shui/button {:size :sm :variant :ghost :title "Drag && Drop to reorder"} + (shui/tabler-icon "grip-vertical" {:size 14})) + (icon-component/icon-picker icon {:on-chosen (fn [_e icon] (update-icon! icon)) + :popup-opts {:align "start"} + :del-btn? (boolean icon) + :empty-label "?"}) [:strong {:on-click (fn [^js e] (shui/popup-show! (.-target e) (fn [] (choice-base-edit-form property block)) {:id :ls-base-edit-form :align "start"}))} value] - [:a.del {:on-click delete-choice! - :title "Delete this choice"} - (shui/tabler-icon "x" {:size 16})]])) + + (let [property-type (get-in property [:block/schema :type])] + (when (contains? #{:default :number} property-type) + (shui/dropdown-menu + (shui/dropdown-menu-trigger + {:as-child true} + (shui/button + {:size :sm :variant :ghost} + (shui/tabler-icon "dots" {:size 14}))) + (shui/dropdown-menu-content + {:align :end} + (shui/dropdown-menu-item + {:on-click (fn [] + (let [property-ident :logseq.property/default-value] + (db-property-handler/set-block-property! (:db/ident property) property-ident (:db/id block))))} + "Set as default choice"))))) + + (shui/button + {:size :sm :variant :ghost :class "del" + :title "Delete this choice" + :on-click delete-choice!} + (shui/tabler-icon "x" {:size 16}))])) (rum/defc add-existing-values [property values {:keys [toggle-fn]}] @@ -552,7 +571,10 @@ [:div.px-4 (class-select property {:default-open? false})])})) - (when (and (contains? db-property-type/default-value-ref-property-types property-type) (not (db-property/many? property))) + (when (and (contains? db-property-type/default-value-ref-property-types property-type) + (not (db-property/many? property)) + (not (and enable-closed-values? + (seq (:property/closed-values property))))) (default-value-subitem property)) (when enable-closed-values? From d9d04f0244fdbd2c5416949ffabf37451165b7db Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 17:52:03 +0800 Subject: [PATCH 21/46] fix: position properties not shown with default values --- deps/outliner/src/logseq/outliner/property.cljs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index da7bd82b151..eda5f13fb49 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -419,17 +419,17 @@ :classes-properties all-properties})) (defn- property-with-position? - [db property-id block-properties position] + [db property-id block position] (let [property (d/entity db property-id) schema (:block/schema property)] (and (= (:position schema) position) (not (and (:logseq.property/hide-empty-value property) - (nil? (get block-properties property-id)))) + (nil? (get block property-id)))) (not (get-in property [:block/schema :hide?])) (not (and (= (:position schema) :block-below) - (nil? (get block-properties property-id))))))) + (nil? (get block property-id))))))) (defn property-with-other-position? [property] @@ -442,7 +442,7 @@ own-properties (keys (:block/properties block))] (->> (:classes-properties (get-block-classes-properties db eid)) (concat own-properties) - (filter (fn [id] (property-with-position? db id (:block/properties block) position))) + (filter (fn [id] (property-with-position? db id block position))) (distinct) (map #(d/entity db %)) (ldb/sort-by-order) From 96373fc03fd45411b987e93f4c71889e5941ad30 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 18:09:31 +0800 Subject: [PATCH 22/46] enhance: checkbox to set default choice --- .../frontend/components/property/config.cljs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index f1407a07614..7649103538e 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -284,7 +284,7 @@ :id id1} item-props') %))] (wrap-menuitem - [:div.inner-wrap + [:div.inner-wrap.cursor-pointer {:class (util/classnames [{:disabled disabled?}])} [:strong (some-> icon (name) (shui/tabler-icon {:size 14 @@ -303,7 +303,7 @@ [:label [:span desc] (when disabled? (shui/tabler-icon "forbid-2" {:size 15}))])]))) -(rum/defc choice-item-content +(rum/defc choice-item-content < rum/reactive db-mixins/query [property block] (let [delete-choice! (fn [] (p/do! @@ -317,6 +317,22 @@ value (db-property/closed-value-content block)] [:li + (let [property-type (get-in property [:block/schema :type]) + property (db/sub-block (:db/id property)) + default-type? (contains? #{:default :number} property-type) + default-value (when default-type? (:logseq.property/default-value property)) + default-value? (= (:db/id default-value) (:db/id block))] + (when default-type? + (shui/checkbox {:size :sm + :title "Set as default choice" + :class "opacity-50 hover:opacity-100" + :checked default-value? + :on-checked-change (fn [] + (let [property-ident :logseq.property/default-value] + (if default-value? + (db-property-handler/remove-block-property! (:db/ident property) property-ident) + (db-property-handler/set-block-property! (:db/ident property) property-ident (:db/id block)))))}))) + (shui/button {:size :sm :variant :ghost :title "Drag && Drop to reorder"} (shui/tabler-icon "grip-vertical" {:size 14})) (icon-component/icon-picker icon {:on-chosen (fn [_e icon] (update-icon! icon)) @@ -330,22 +346,6 @@ :align "start"}))} value] - (let [property-type (get-in property [:block/schema :type])] - (when (contains? #{:default :number} property-type) - (shui/dropdown-menu - (shui/dropdown-menu-trigger - {:as-child true} - (shui/button - {:size :sm :variant :ghost} - (shui/tabler-icon "dots" {:size 14}))) - (shui/dropdown-menu-content - {:align :end} - (shui/dropdown-menu-item - {:on-click (fn [] - (let [property-ident :logseq.property/default-value] - (db-property-handler/set-block-property! (:db/ident property) property-ident (:db/id block))))} - "Set as default choice"))))) - (shui/button {:size :sm :variant :ghost :class "del" :title "Delete this choice" @@ -410,6 +410,8 @@ {:db/id (:db/id property)})] {:outliner-op :save-block})))})]) + (shui/dropdown-menu-separator) + ;; add choice (when-not disabled? (dropdown-editor-menuitem From 7dff15223c0fe20b7507303b3f535ea0b50eb926 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 18:19:10 +0800 Subject: [PATCH 23/46] fix: can't add existing number values to available choices --- src/main/frontend/components/icon.cljs | 32 ++++++++++--------- .../frontend/components/property/config.cljs | 7 ++-- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/frontend/components/icon.cljs b/src/main/frontend/components/icon.cljs index 690ac6ec4e8..699d5e61ade 100644 --- a/src/main/frontend/components/icon.cljs +++ b/src/main/frontend/components/icon.cljs @@ -437,7 +437,7 @@ (shui/tabler-icon "trash" {:size 17})))]]])) (rum/defc icon-picker - [icon-value {:keys [empty-label disabled? initial-open? del-btn? on-chosen icon-props popup-opts]}] + [icon-value {:keys [empty-label disabled? initial-open? del-btn? on-chosen icon-props popup-opts button-opts]}] (let [*trigger-ref (rum/use-ref nil) content-fn (if config/publishing? @@ -458,20 +458,22 @@ ;; trigger (let [has-icon? (some? icon-value)] (shui/button - {:ref *trigger-ref - :variant :ghost - :size :sm - :class (if has-icon? "px-1 leading-none text-muted-foreground hover:text-foreground" - "font-normal text-sm px-[0.5px] text-muted-foreground hover:text-foreground") - :on-click (fn [^js e] - (when-not disabled? - (shui/popup-show! (.-target e) content-fn - (medley/deep-merge - {:align :start - :id :ls-icon-picker - :content-props {:class "ls-icon-picker" - :onEscapeKeyDown #(.preventDefault %)}} - popup-opts))))} + (merge + {:ref *trigger-ref + :variant :ghost + :size :sm + :class (if has-icon? "px-1 leading-none text-muted-foreground hover:text-foreground" + "font-normal text-sm px-[0.5px] text-muted-foreground hover:text-foreground") + :on-click (fn [^js e] + (when-not disabled? + (shui/popup-show! (.-target e) content-fn + (medley/deep-merge + {:align :start + :id :ls-icon-picker + :content-props {:class "ls-icon-picker" + :onEscapeKeyDown #(.preventDefault %)}} + popup-opts))))} + button-opts) (if has-icon? (if (vector? icon-value) ; hiccup icon-value diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 7649103538e..119a7adbedd 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -338,7 +338,8 @@ (icon-component/icon-picker icon {:on-chosen (fn [_e icon] (update-icon! icon)) :popup-opts {:align "start"} :del-btn? (boolean icon) - :empty-label "?"}) + :empty-label "?" + :button-opts {:title "Set Icon"}}) [:strong {:on-click (fn [^js e] (shui/popup-show! (.-target e) (fn [] (choice-base-edit-form property block)) @@ -430,7 +431,9 @@ values' (->> (if (contains? db-property-type/all-ref-property-types (get-in property [:block/schema :type])) (->> values (map db/entity) - (remove (fn [e] (string/blank? (:block/title e)))) + (remove (fn [e] + (let [value (db-property/property-value-content e)] + (and (string? value) (string/blank? value))))) (map :block/uuid)) (remove string/blank? values)) distinct)] From 3fd680692035d389b4c0009e8c0539cd78905283 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 18:24:52 +0800 Subject: [PATCH 24/46] fix: tag instance with positioned property shouldn't be collapsable --- .../src/logseq/outliner/property.cljs | 3 ++- .../test/logseq/outliner/property_test.cljs | 2 +- src/main/frontend/components/property.cljs | 2 +- src/main/frontend/handler/editor.cljs | 20 +++++++++---------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index eda5f13fb49..40a60c82aef 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -412,7 +412,7 @@ (filter (fn [class] (seq (:logseq.property.class/properties class))))) all-properties (-> (mapcat (fn [class] - (map :db/ident (:logseq.property.class/properties class))) all-classes) + (:logseq.property.class/properties class)) all-classes) distinct)] {:classes classes :all-classes all-classes ; block own classes + parent classes @@ -441,6 +441,7 @@ (let [block (d/entity db eid) own-properties (keys (:block/properties block))] (->> (:classes-properties (get-block-classes-properties db eid)) + (map :db/ident) (concat own-properties) (filter (fn [id] (property-with-position? db id block position))) (distinct) diff --git a/deps/outliner/test/logseq/outliner/property_test.cljs b/deps/outliner/test/logseq/outliner/property_test.cljs index 0b3d82b3fc9..172daf05419 100644 --- a/deps/outliner/test/logseq/outliner/property_test.cljs +++ b/deps/outliner/test/logseq/outliner/property_test.cljs @@ -283,4 +283,4 @@ :build/tags [:c1 :c2]}]}]}) block (db-test/find-block-by-content @conn "o1")] (is (= [:user.property/p1 :user.property/p2 :user.property/p3] - (:classes-properties (outliner-property/get-block-classes-properties @conn (:db/id block))))))) + (map :db/ident (:classes-properties (outliner-property/get-block-classes-properties @conn (:db/id block)))))))) diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index 471e94d420b..eff5563299f 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -586,7 +586,7 @@ (contains? #{:logseq.property.class/properties} (:db/ident ent)))))))) properties)) {:keys [all-classes classes-properties]} (outliner-property/get-block-classes-properties (db/get-db) (:db/id block)) - classes-properties-set (set classes-properties) + classes-properties-set (set (map :db/ident classes-properties)) block-own-properties (->> properties (remove (fn [[id _]] (classes-properties-set id)))) root-block? (= (:id opts) (str (:block/uuid block))) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 09bd251715d..31058190567 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -3443,17 +3443,15 @@ (defn- db-collapsable? [block] - (let [property-keys (->> (keys (:block/properties block)) - (remove db-property/db-attribute-properties) - (remove #(outliner-property/property-with-other-position? (db/entity %))))] - (or (ldb/class-instance? (db/entity :logseq.class/Query) block) - (and (seq property-keys) - (not (db-pu/all-hidden-properties? property-keys))) - (and (seq (:block/tags block)) - (some (fn [t] - (let [properties (map :db/ident (:logseq.property.class/properties t))] - (and (seq properties) - (not (db-pu/all-hidden-properties? properties))))) (:block/tags block)))))) + (let [class-properties (:classes-properties (outliner-property/get-block-classes-properties (db/get-db) (:db/id block))) + properties (->> (keys (:block/properties block)) + (map db/entity) + (concat class-properties) + (remove (fn [e] (db-property/db-attribute-properties (:db/ident e)))) + (remove outliner-property/property-with-other-position?) + (remove (fn [e] (:hide? (:block/schema e)))))] + (or (seq properties) + (ldb/class-instance? (db/entity :logseq.class/Query) block)))) (defn collapsable? ([block-id] From e10171842525be8d9c26a8fae73961b66c366765 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 19 Nov 2024 21:17:58 +0800 Subject: [PATCH 25/46] enhance: set table row to be at least 32px height --- src/main/frontend/components/table.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/frontend/components/table.css b/src/main/frontend/components/table.css index 6665f741594..7443c63f1b4 100644 --- a/src/main/frontend/components/table.css +++ b/src/main/frontend/components/table.css @@ -27,6 +27,10 @@ } } + .ls-table-row { + @apply min-h-[32px]; + } + .ls-table-header { @apply flex flex-row items-center w-fit absolute left-0 top-0; From a5832cc3f27d31980fe500cb7a470b6fc22874fd Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 19 Nov 2024 16:34:19 -0500 Subject: [PATCH 26/46] fix: db-import of property-classes option fails on docs graph Fixed by ensuring that tag names and namespace names don't conflict when making class idents. The specific bug was a conflict between Tool class and Whiteboard/Tool. Interestingly the bug didn't appear if the Tool's description property wasn't present. Also fixed some importer tests not parsing namespaces correctly or taking :verbose option --- .../src/logseq/graph_parser/exporter.cljs | 54 ++++++++++++------- .../logseq/graph_parser/exporter_test.cljs | 23 +++++--- .../pages/Whiteboard___Arrow_head_toggle.md | 1 + .../pages/Whiteboard___Tool.md | 4 ++ 4 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Arrow_head_toggle.md create mode 100644 deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Tool.md diff --git a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs index 4a13edc29f5..d35014dde35 100644 --- a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs @@ -62,17 +62,26 @@ {:block/uuid (get-page-uuid page-names-to-uuids (get-in block [:block/namespace :block/name]))})) block)) +(defn- build-class-ident-name + [class-name] + (string/replace class-name "/" "___")) + (defn- find-or-create-class ([db class-name all-idents] (find-or-create-class db class-name all-idents {})) ([db class-name all-idents class-block] (if-let [db-ident (get @all-idents (keyword class-name))] {:db/ident db-ident} - (let [m* (cond-> {:block/title class-name - :block/name (common-util/page-name-sanity-lc class-name)} - (:block/namespace class-block) - (build-new-namespace-page)) - m (db-class/build-new-class db m*)] + (let [m + (if (:block/namespace class-block) + ;; Give namespaced tags a unique ident so they don't conflict with other tags + (-> (db-class/build-new-class db {:block/title (build-class-ident-name class-name)}) + (merge {:block/title class-name + :block/name (common-util/page-name-sanity-lc class-name)}) + (build-new-namespace-page)) + (db-class/build-new-class db + {:block/title class-name + :block/name (common-util/page-name-sanity-lc class-name)}))] (swap! all-idents assoc (keyword class-name) (:db/ident m)) (with-meta m {:new-class? true}))))) @@ -950,7 +959,8 @@ ((fn [block'] (merge (build-new-namespace-page block') {;; save original name b/c it's still used for a few name lookups - ::original-name (:block/name block')})))))) + ::original-name (:block/name block') + ::original-title (:block/title block')})))))) (defn- build-pages-tx "Given all the pages and blocks parsed from a file, return a map containing @@ -976,18 +986,26 @@ :classes-tx (:classes-tx options)} all-pages-m (mapv #(handle-page-properties % @conn per-file-state all-pages options) all-pages) - pages-tx (keep (fn [m] - (if-let [page-uuid (if (::original-name m) - (all-existing-page-uuids (::original-name m)) - (all-existing-page-uuids (:block/name m)))] - (build-existing-page (dissoc m ::original-name) @conn page-uuid per-file-state options) - (when (or (= "class" (:block/type m)) - ;; Don't build a new page if it overwrites an existing class - (not (some-> (get @(:all-idents import-state) (keyword (:block/title m))) - db-malli-schema/class?))) - (build-new-page-or-class (dissoc m ::original-name) - @conn per-file-state (:all-idents import-state) options)))) - (map :block all-pages-m))] + pages-tx (keep (fn [{m :block _properties-tx :properties-tx}] + (let [page (if-let [page-uuid (if (::original-name m) + (all-existing-page-uuids (::original-name m)) + (all-existing-page-uuids (:block/name m)))] + (build-existing-page (dissoc m ::original-name ::original-title) @conn page-uuid per-file-state options) + (when (or (= "class" (:block/type m)) + ;; Don't build a new page if it overwrites an existing class + (not (some-> (get @(:all-idents import-state) + (some-> (or (::original-title m) (:block/title m)) + build-class-ident-name + keyword)) + db-malli-schema/class?)) + ;; TODO: Enable this when it's valid for all test graphs because + ;; pages with properties must be built or else properties-tx is invalid + #_(seq properties-tx)) + (build-new-page-or-class (dissoc m ::original-name ::original-title) + @conn per-file-state (:all-idents import-state) options)))] + ;; (when-not ret (println "Skipped page tx for" (pr-str (:block/title m)))) + page)) + all-pages-m)] {:pages-tx pages-tx :page-properties-tx (mapcat :properties-tx all-pages-m) :existing-pages (select-keys all-existing-page-uuids (map :block/name all-pages*)) diff --git a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs index 86bf63cbe43..7b8ba659a07 100644 --- a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs @@ -125,18 +125,21 @@ config-file (first (filter #(string/ends-with? (:path %) "logseq/config.edn") *files)) _ (assert config-file "No 'logseq/config.edn' found for file graph dir") options' (merge default-export-options - {:user-options (dissoc options :assets) + {:user-options (dissoc options :assets :verbose) ;; asset file options - : (p/let [doc-options (gp-exporter/build-doc-options (merge {:macros {}} (:user-config options)) + (-> (p/let [doc-options (gp-exporter/build-doc-options (merge {:macros {} :file/name-format :triple-lowbar} + (:user-config options)) (merge default-export-options - {:user-options (dissoc options :user-config)})) + {:user-options (dissoc options :user-config :verbose)} + (select-keys options [:verbose]))) files' (mapv #(hash-map :path %) files) _ (gp-exporter/export-doc-files conn files' > (d/q '[:find [(pull ?b [:block/title :block/type]) ...] :where [?b :block/title] [_ :block/page ?b] (not [?b :logseq.property/built-in?])] @conn) (filter ldb/internal-page?)))) @@ -497,6 +500,10 @@ count)) "Correct number of user classes") + (is (= :user.class/Quotes___life + (:db/ident (find-page-by-name @conn "life"))) + "Namespaced tag's ident has hierarchy to make it unique") + (is (= [{:block/type "class"}] (d/q '[:find [(pull ?b [:block/type]) ...] :where [?b :block/name "life"]] @conn)) "When a class is used and referenced on the same page, there should only be one instance of it") @@ -535,7 +542,9 @@ (deftest-async export-files-with-property-classes-option (p/let [file-graph-dir "test/resources/exporter-test-graph" - files (mapv #(node-path/join file-graph-dir %) ["journals/2024_02_23.md" "pages/url.md"]) + files (mapv #(node-path/join file-graph-dir %) + ["journals/2024_02_23.md" "pages/url.md" "pages/Whiteboard___Tool.md" + "pages/Whiteboard___Arrow_head_toggle.md"]) conn (db-test/create-conn) _ (import-files-to-db files conn {:property-classes ["type"]}) _ (@#'gp-exporter/export-class-properties conn conn)] @@ -543,7 +552,7 @@ (is (empty? (map :entity (:errors (db-validate/validate-db! @conn)))) "Created graph has no validation errors") - (is (= #{:user.class/Property :user.class/Movie} + (is (= #{:user.class/Property :user.class/Movie :user.class/Class :user.class/Tool} (->> @conn (d/q '[:find [?ident ...] :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) diff --git a/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Arrow_head_toggle.md b/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Arrow_head_toggle.md new file mode 100644 index 00000000000..02aba4a1400 --- /dev/null +++ b/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Arrow_head_toggle.md @@ -0,0 +1 @@ +type:: [[Tool]] \ No newline at end of file diff --git a/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Tool.md b/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Tool.md new file mode 100644 index 00000000000..5c727eb646d --- /dev/null +++ b/deps/graph-parser/test/resources/exporter-test-graph/pages/Whiteboard___Tool.md @@ -0,0 +1,4 @@ +alias:: Whiteboard tool, Tool, Tools +type:: [[Class]] +parent:: [[Feature]] +description:: Tools on the [[Whiteboard/Toolbar]] \ No newline at end of file From 16500ba15698805da90b6a7b7d84c797a5a78892 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 19 Nov 2024 16:44:17 -0500 Subject: [PATCH 27/46] fix: frontend lint --- src/main/frontend/handler/editor.cljs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index 31058190567..f23faa195c0 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -20,7 +20,6 @@ [frontend.handler.block :as block-handler] [frontend.handler.common :as common-handler] [frontend.handler.db-based.editor :as db-editor-handler] - [frontend.handler.db-based.property.util :as db-pu] [frontend.handler.export.html :as export-html] [frontend.handler.export.text :as export-text] [frontend.handler.file-based.editor :as file-editor-handler] From 513d3136fbc9ee2a831c37cce6e613736621bad6 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Tue, 19 Nov 2024 16:49:19 -0500 Subject: [PATCH 28/46] fix: remove unused fn --- src/main/frontend/handler/db_based/property/util.cljs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/frontend/handler/db_based/property/util.cljs b/src/main/frontend/handler/db_based/property/util.cljs index 0fad6d8750c..f94ad96320e 100644 --- a/src/main/frontend/handler/db_based/property/util.cljs +++ b/src/main/frontend/handler/db_based/property/util.cljs @@ -23,12 +23,6 @@ (let [db (conn/get-db repo)] (db-property/properties-by-name db block))) -(defn all-hidden-properties? - "Checks if the given properties are all hidden properties" - [properties] - (every? (fn [id] - (:hide? (:block/schema (db-utils/entity id)))) properties)) - (defn readable-properties "Given a DB graph's properties, returns a readable properties map with keys as property names and property values dereferenced where possible. Has some From aa29ab6473a31273bfb25479d02fae60d2b0a0b4 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 15:41:22 +0800 Subject: [PATCH 29/46] perf: render primary column then other columns --- src/main/frontend/components/table.css | 2 +- src/main/frontend/components/views.cljs | 59 ++++++++++++++++--------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/main/frontend/components/table.css b/src/main/frontend/components/table.css index 7443c63f1b4..6f0eb5cb781 100644 --- a/src/main/frontend/components/table.css +++ b/src/main/frontend/components/table.css @@ -28,7 +28,7 @@ } .ls-table-row { - @apply min-h-[32px]; + @apply min-h-[33px]; } .ls-table-header { diff --git a/src/main/frontend/components/views.cljs b/src/main/frontend/components/views.cljs index 2d52a67c469..a449a87eaa0 100644 --- a/src/main/frontend/components/views.cljs +++ b/src/main/frontend/components/views.cljs @@ -432,11 +432,23 @@ [:div.absolute.top-0.left-8 (action-bar table selected-rows option)])))) -(rum/defc table-row < rum/reactive +(rum/defc row-cell < rum/static + [table row column render cell-opts idx first-col-rendered? set-first-col-rendered!] + (let [primary-key? (or (= idx 1) (= (:id column) :block/title))] + (when primary-key? + (rum/use-effect! + (fn [] + (let [timeout (js/setTimeout #(set-first-col-rendered! true) 0)] + #(js/clearTimeout timeout))) + [])) + + (shui/table-cell cell-opts + (when (or primary-key? first-col-rendered?) + (render table row column))))) + +(rum/defc table-row-inner < rum/static [{:keys [row-selected?] :as table} row columns props {:keys [show-add-property?]}] - (let [row' (db/sub-block (:id row)) - ;; merge entity temporal attributes - row (reduce (fn [e [k v]] (assoc e k v)) row' (.-kv ^js row)) + (let [[first-col-rendered? set-first-col-rendered!] (rum/use-state false) columns (if show-add-property? (conj (vec columns) {:id :add-property @@ -448,20 +460,28 @@ props {:key (str (:id row)) :data-state (when (row-selected? row) "selected")}) - (for [column columns] - (let [id (str (:id row) "-" (:id column)) - render (get column :cell) - width (get-column-size column sized-columns) - select? (= (:id column) :select) - add-property? (= (:id column) :add-property)] - (when render - (shui/table-cell - {:key id - :select? select? - :add-property? add-property? - :style {:width width - :min-width width}} - (render table row column)))))))) + (map-indexed + (fn [idx column] + (let [id (str (:id row) "-" (:id column)) + render (get column :cell) + width (get-column-size column sized-columns) + select? (= (:id column) :select) + add-property? (= (:id column) :add-property) + cell-opts {:key id + :select? select? + :add-property? add-property? + :style {:width width + :min-width width}}] + (when render + (row-cell table row column render cell-opts idx first-col-rendered? set-first-col-rendered!)))) + columns)))) + +(rum/defc table-row < rum/reactive (mixins/perf-measure-mixin "table row") + [table row columns props option] + (let [row' (db/sub-block (:id row)) + ;; merge entity temporal attributes + row (reduce (fn [e [k v]] (assoc e k v)) row' (.-kv ^js row))] + (table-row-inner table row columns props option))) (rum/defc search [input {:keys [on-change set-input!]}] @@ -517,7 +537,7 @@ (let [label (get-property-value-content e) label' (if (and block-type? (= label "class")) "tag" label)] {:label (str label') :value e})) - values) + values) (sort-by :label)))) (defn datetime-property? @@ -1065,7 +1085,6 @@ (ui/virtualized-list {:ref #(reset! *scroller-ref %) :custom-scroll-parent (gdom/getElement "main-content-container") - :increase-viewport-by {:top 600 :bottom 600} :compute-item-key (fn [idx] (let [block (nth rows idx)] (str "table-row-" (:db/id block)))) From ba67d09877810412127fe8631194fa27cbba9e5b Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 15:46:49 +0800 Subject: [PATCH 30/46] Add increase viewport by back --- src/main/frontend/components/views.cljs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/frontend/components/views.cljs b/src/main/frontend/components/views.cljs index a449a87eaa0..f643b572422 100644 --- a/src/main/frontend/components/views.cljs +++ b/src/main/frontend/components/views.cljs @@ -1085,6 +1085,7 @@ (ui/virtualized-list {:ref #(reset! *scroller-ref %) :custom-scroll-parent (gdom/getElement "main-content-container") + :increase-viewport-by {:top 300 :bottom 300} :compute-item-key (fn [idx] (let [block (nth rows idx)] (str "table-row-" (:db/id block)))) From 10cf3e17ceb527452236f13ebd28bc2d50b12f5c Mon Sep 17 00:00:00 2001 From: charlie Date: Wed, 20 Nov 2024 16:18:24 +0800 Subject: [PATCH 31/46] fix(ui): missing drag handle for the table header columns --- src/main/frontend/components/table.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/components/table.css b/src/main/frontend/components/table.css index 6f0eb5cb781..bfc74b81327 100644 --- a/src/main/frontend/components/table.css +++ b/src/main/frontend/components/table.css @@ -51,8 +51,11 @@ } .ls-table-header-cell { - @apply overflow-hidden; position: relative; + + > .ui__button { + @apply overflow-hidden; + } } } From 20e91a76e7cb2ba3b16e388873c49e9e77007192 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Wed, 20 Nov 2024 17:33:15 +0800 Subject: [PATCH 32/46] enhance: don't show bullet when the last open block is not empty --- src/main/frontend/components/page.cljs | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 873d2613e23..3f9a479b3f0 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -180,8 +180,8 @@ (util/stop e) (state/set-state! :editor/container-id container-id) (editor-handler/api-insert-new-block! "" args)) - :on-mouse-over #(dom/add-class! (rum/deref *bullet-ref) "opacity-100") - :on-mouse-leave #(dom/remove-class! (rum/deref *bullet-ref) "opacity-100") + :on-mouse-over #(dom/add-class! (rum/deref *bullet-ref) "opacity-50") + :on-mouse-leave #(dom/remove-class! (rum/deref *bullet-ref) "opacity-50") :on-key-down (fn [e] (util/stop e) (when (= "Enter" (util/ekey e)) @@ -225,24 +225,27 @@ [:<> (let [blocks (cond (and - (not block?) - (empty? children) page-e) + (not block?) + (empty? children) page-e) (dummy-block page-e) :else (let [document-mode? (state/sub :document/mode?) hiccup-config (merge - {:id (if block? (str block-id) page-name) - :db/id (:db/id block) - :block? block? - :editor-box editor/box - :document/mode? document-mode?} - config) + {:id (if block? (str block-id) page-name) + :db/id (:db/id block) + :block? block? + :editor-box editor/box + :document/mode? document-mode?} + config) config (common-handler/config-with-document-mode hiccup-config) blocks (if block? [block] (db/sort-by-order children block))] [:div (page-blocks-inner page-e blocks config sidebar? whiteboard? block-id) - (when-not config/publishing? + (when-not (or config/publishing? + (let [last-child-id (model/get-block-deep-last-open-child-id (db/get-db) (:db/id (last blocks))) + block' (if last-child-id (db/entity last-child-id) (last blocks))] + (string/blank? (:block/title block')))) (let [args (if block-id {:block-uuid block-id} {:page page-name})] @@ -250,9 +253,9 @@ (if (and db-based? (or (ldb/class? block) (ldb/property? block))) [:div.mt-4.ml-2.-mb-1 (ui/foldable - [:div.font-medium.opacity-50 {:class "pl-0.5"} "Notes"] - [:div.ml-1.-mb-2 blocks] - {:disable-on-pointer-down? true})] + [:div.font-medium.opacity-50 {:class "pl-0.5"} "Notes"] + [:div.ml-1.-mb-2 blocks] + {:disable-on-pointer-down? true})] blocks))]))) (rum/defc today-queries < rum/reactive From b1cbc4aa351bfd2af14c799f9cba48a87ef1e8dd Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 20 Nov 2024 10:39:21 -0500 Subject: [PATCH 33/46] fix: docs graph fails to import with both property* options enabled --- .../graph-parser/src/logseq/graph_parser/exporter.cljs | 2 +- .../test/logseq/graph_parser/exporter_test.cljs | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs index d35014dde35..bf92323c4c9 100644 --- a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs @@ -715,7 +715,7 @@ ;; that aren't conrolled by :classes-tx (cond-> block (seq parent-classes-from-properties) - (merge (find-or-create-class db (:block/title block) (:all-idents import-state) block)) + (merge (find-or-create-class db ((some-fn ::original-title :block/title) block) (:all-idents import-state) block)) (seq parent-classes-from-properties) (assoc :logseq.property/parent (let [new-class (first parent-classes-from-properties) diff --git a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs index 7b8ba659a07..f425217dbcf 100644 --- a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs @@ -609,14 +609,18 @@ (deftest-async export-files-with-property-parent-classes-option (p/let [file-graph-dir "test/resources/exporter-test-graph" - files (mapv #(node-path/join file-graph-dir %) ["pages/CreativeWork.md" "pages/Movie.md" "pages/type.md"]) + files (mapv #(node-path/join file-graph-dir %) ["pages/CreativeWork.md" "pages/Movie.md" "pages/type.md" + "pages/Whiteboard___Tool.md" "pages/Whiteboard___Arrow_head_toggle.md"]) conn (db-test/create-conn) - _ (import-files-to-db files conn {:property-parent-classes ["parent"]})] + _ (import-files-to-db files conn {:property-parent-classes ["parent"] + ;; Also add this option to trigger some edge cases with namespace pages + :property-classes ["type"]})] (is (empty? (map :entity (:errors (db-validate/validate-db! @conn)))) "Created graph has no validation errors") - (is (= #{:user.class/Movie :user.class/CreativeWork :user.class/Thing} + (is (= #{:user.class/Movie :user.class/CreativeWork :user.class/Thing + :user.class/Class :user.class/Tool :user.class/Whiteboard___Tool} (->> @conn (d/q '[:find [?ident ...] :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) From 049bcd069f0bf000838ffc7debe7a6e1fb392ba8 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Wed, 20 Nov 2024 13:27:36 -0500 Subject: [PATCH 34/46] enhance: default to importing all tags Fixes LOG-3235. Still default to not importing all tags in tests and scripts to simplify their workflows --- deps/graph-parser/script/db_import.cljs | 3 +- .../src/logseq/graph_parser/exporter.cljs | 2 +- .../logseq/graph_parser/exporter_test.cljs | 116 +++++++++--------- src/main/frontend/components/imports.cljs | 4 +- 4 files changed, 64 insertions(+), 61 deletions(-) diff --git a/deps/graph-parser/script/db_import.cljs b/deps/graph-parser/script/db_import.cljs index 9877eedae08..a718de29215 100644 --- a/deps/graph-parser/script/db_import.cljs +++ b/deps/graph-parser/script/db_import.cljs @@ -138,12 +138,13 @@ file-graph' (resolve-path file-graph) conn (outliner-cli/init-conn dir db-name {:classpath (cp/get-classpath)}) directory? (.isDirectory (fs/statSync file-graph')) - user-options (cond-> (dissoc options :verbose :files :help) + user-options (cond-> (merge {:all-tags false} (dissoc options :verbose :files :help)) ;; coerce option collection into strings (:tag-classes options) (update :tag-classes (partial mapv str)) true (set/rename-keys {:all-tags :convert-all-tags? :remove-inline-tags :remove-inline-tags?})) + _ (when (:verbose options) (prn :options user-options)) options' (merge {:user-options user-options :graph-name db-name} (select-keys options [:files :verbose]))] diff --git a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs index bf92323c4c9..32416ecce56 100644 --- a/deps/graph-parser/src/logseq/graph_parser/exporter.cljs +++ b/deps/graph-parser/src/logseq/graph_parser/exporter.cljs @@ -1476,7 +1476,7 @@ :filename-format (or (:file/name-format config) :legacy) :verbose (:verbose options)} :user-config config - :user-options (merge {:remove-inline-tags? true} (:user-options options)) + :user-options (merge {:remove-inline-tags? true :convert-all-tags? true} (:user-options options)) :import-state (new-import-state) :macros (or (:macros options) (:macros config))} (merge (select-keys options [:set-ui-state :export-file :notify-user])))) diff --git a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs index f425217dbcf..79d5ecbe144 100644 --- a/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs +++ b/deps/graph-parser/test/logseq/graph_parser/exporter_test.cljs @@ -125,7 +125,7 @@ config-file (first (filter #(string/ends-with? (:path %) "logseq/config.edn") *files)) _ (assert config-file "No 'logseq/config.edn' found for file graph dir") options' (merge default-export-options - {:user-options (dissoc options :assets :verbose) + {:user-options (merge {:convert-all-tags? false} (dissoc options :assets :verbose)) ;; asset file options : (p/let [doc-options (gp-exporter/build-doc-options (merge {:macros {} :file/name-format :triple-lowbar} (:user-config options)) (merge default-export-options - {:user-options (dissoc options :user-config :verbose)} + {:user-options (merge {:convert-all-tags? false} + (dissoc options :user-config :verbose))} (select-keys options [:verbose]))) files' (mapv #(hash-map :path %) files) _ (gp-exporter/export-doc-files conn files' > @conn - (d/q '[:find [?ident ...] - :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) - count)) + (is (= 11 (->> @conn + (d/q '[:find [?ident ...] + :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) + count)) "Correct number of user classes") (is (= 4 (count (d/datoms @conn :avet :block/type "whiteboard")))) (is (= 0 (count @(:ignored-properties import-state))) ":filters should be the only ignored property") @@ -347,6 +348,20 @@ (:block/title (find-block-by-content @conn #"tasks with"))) "Advanced query has custom title migrated")) + (testing "tags convert to classes" + (is (= :user.class/Quotes___life + (:db/ident (find-page-by-name @conn "life"))) + "Namespaced tag's ident has hierarchy to make it unique") + + (is (= [{:block/type "class"}] + (d/q '[:find [(pull ?b [:block/type]) ...] :where [?b :block/name "life"]] @conn)) + "When a class is used and referenced on the same page, there should only be one instance of it") + + (is (= ["life"] + (->> (:block/tags (find-block-by-content @conn #"with namespace tag")) + (mapv #(db-property/ref->property-value-contents @conn %)))) + "Block tagged with namespace tag is only associated with leaf child tag")) + (testing "namespaces" (let [expand-children (fn expand-children [ent parent] (if-let [children (:logseq.property/_parent ent)] @@ -414,23 +429,6 @@ (is (= 3 (count (find-block-by-property @conn :user.property/people))) "Converted property has correct number of property values"))) - (testing "replacing refs in :block/title" - (is (= 2 - (->> (find-block-by-content @conn #"replace with same start string") - :block/title - (re-seq #"\[\[~\^\S+\]\]") - distinct - count)) - "A block with ref names that start with same string has 2 distinct refs") - - (is (= 1 - (->> (find-block-by-content @conn #"replace case insensitive") - :block/title - (re-seq #"\[\[~\^\S+\]\]") - distinct - count)) - "A block with different case of same ref names has 1 distinct ref")) - (testing "imported concepts can have names of new-built concepts" (is (= #{:logseq.property/description :user.property/description} (set (d/q '[:find [?ident ...] :where [?b :db/ident ?ident] [?b :block/name "description"]] @conn))) @@ -465,9 +463,41 @@ (let [block-with-props (find-block-by-content @conn #"block with props")] (is (= {:user.property/prop-num 10} (readable-properties @conn block-with-props))) - (is (= "block with props" (:block/title block-with-props))))) + (is (= "block with props" (:block/title block-with-props))))))) + +(deftest-async export-basic-graph-with-convert-all-tags-option-disabled + (p/let [file-graph-dir "test/resources/exporter-test-graph" + conn (db-test/create-conn) + {:keys [import-state]} + (import-file-graph-to-db file-graph-dir conn {:convert-all-tags? false})] + + (is (empty? (map :entity (:errors (db-validate/validate-db! @conn)))) + "Created graph has no validation errors") + (is (= 0 (count @(:ignored-properties import-state))) "No ignored properties") + (is (= 0 (->> @conn + (d/q '[:find [?ident ...] + :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) + count)) + "Correct number of user classes") - (testing "tags without tag options" + (testing "replacing refs in :block/title when :remove-inline-tags? set" + (is (= 2 + (->> (find-block-by-content @conn #"replace with same start string") + :block/title + (re-seq #"\[\[~\^\S+\]\]") + distinct + count)) + "A block with ref names that start with same string has 2 distinct refs") + + (is (= 1 + (->> (find-block-by-content @conn #"replace case insensitive") + :block/title + (re-seq #"\[\[~\^\S+\]\]") + distinct + count)) + "A block with different case of same ref names has 1 distinct ref")) + + (testing "tags convert to page, refs and page-tags" (let [block (find-block-by-content @conn #"Inception") tag-page (find-page-by-name @conn "Movie") tagged-page (find-page-by-name @conn "Interstellar")] @@ -485,34 +515,6 @@ (:logseq.property/page-tags (readable-properties @conn (find-page-by-name @conn "chat-gpt")))) "tagged page has new page and other pages marked with '#' and '[[]]` imported as tags to page-tags"))))) -(deftest-async export-basic-graph-with-convert-all-tags-option - (p/let [file-graph-dir "test/resources/exporter-test-graph" - conn (db-test/create-conn) - {:keys [import-state]} - (import-file-graph-to-db file-graph-dir conn {:convert-all-tags? true})] - - (is (empty? (map :entity (:errors (db-validate/validate-db! @conn)))) - "Created graph has no validation errors") - (is (= 0 (count @(:ignored-properties import-state))) "No ignored properties") - (is (= 11 (->> @conn - (d/q '[:find [?ident ...] - :where [?b :block/type "class"] [?b :db/ident ?ident] (not [?b :logseq.property/built-in?])]) - count)) - "Correct number of user classes") - - (is (= :user.class/Quotes___life - (:db/ident (find-page-by-name @conn "life"))) - "Namespaced tag's ident has hierarchy to make it unique") - - (is (= [{:block/type "class"}] - (d/q '[:find [(pull ?b [:block/type]) ...] :where [?b :block/name "life"]] @conn)) - "When a class is used and referenced on the same page, there should only be one instance of it") - - (is (= ["life"] - (->> (:block/tags (find-block-by-content @conn #"with namespace tag")) - (mapv #(db-property/ref->property-value-contents @conn %)))) - "Block tagged with namespace tag is only associated with leaf child tag"))) - (deftest-async export-files-with-tag-classes-option (p/let [file-graph-dir "test/resources/exporter-test-graph" files (mapv #(node-path/join file-graph-dir %) ["journals/2024_02_07.md" "pages/Interstellar.md"]) diff --git a/src/main/frontend/components/imports.cljs b/src/main/frontend/components/imports.cljs index bfb66d4e3a4..2545cf699f8 100644 --- a/src/main/frontend/components/imports.cljs +++ b/src/main/frontend/components/imports.cljs @@ -170,7 +170,7 @@ [:div.border.p-6.rounded.bg-gray-01.mt-4 (let [form-ctx (form-core/use-form {:defaultValues {:graph-name initial-name - :convert-all-tags? false + :convert-all-tags? true :tag-classes "" :remove-inline-tags? true :property-classes "" @@ -184,7 +184,7 @@ ;; (js/console.log "[form] submit: " e (js->clj e)) (on-submit-fn (js->clj e :keywordize-keys true)) (shui/dialog-close!))) - [convert-all-tags-input set-convert-all-tags-input!] (rum/use-state false)] + [convert-all-tags-input set-convert-all-tags-input!] (rum/use-state true)] (shui/form-provider form-ctx [:form From a4118905513a950002b199d095740150c3d3eee7 Mon Sep 17 00:00:00 2001 From: charlie Date: Thu, 21 Nov 2024 14:43:19 +0800 Subject: [PATCH 35/46] enhance(ux): display the page properties on the right sidebar as default --- src/main/frontend/components/block.cljs | 5 ++++- src/main/frontend/components/objects.cljs | 8 +++++--- src/main/frontend/components/page.cljs | 5 +++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index b975f2b6d73..947817bf0c1 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -3289,6 +3289,7 @@ editing? (or (state/sub-editing? [container-id (:block/uuid block)]) (state/sub-editing? [:unknown-container (:block/uuid block)])) table? (:table? config*) + sidebar? (:sidebar? config*) property? (:property? config*) custom-query? (boolean (:custom-query? config*)) ref-or-custom-query? (or ref? custom-query?) @@ -3457,7 +3458,9 @@ (when-not (:table? config) (query-property-cp block config collapsed?)) - (when (and db-based? (not collapsed?) (not (or table? property?))) + (when (and db-based? + (or sidebar? (not collapsed?)) + (not (or table? property?))) [:div (when-not (:page-title? config) {:style {:padding-left 45}}) (db-properties-cp config block {:in-block-container? true})]) diff --git a/src/main/frontend/components/objects.cljs b/src/main/frontend/components/objects.cljs index 1aa1198b267..1f21b51a56a 100644 --- a/src/main/frontend/components/objects.cljs +++ b/src/main/frontend/components/objects.cljs @@ -197,14 +197,16 @@ (set-data! (get-class-objects class)) (when-let [f (get-in table [:data-fns :set-row-selection!])] (f {})))))})] - {:disable-on-pointer-down? true})]))) + {:disable-on-pointer-down? true + :default-collapsed? (:sidebar? config)})]))) (rum/defcs class-objects < rum/reactive db-mixins/query mixins/container-id - [state class current-page?] + [state class {:keys [current-page? sidebar?]}] (when class (let [class (db/sub-block (:db/id class)) config {:container-id (:container-id state) - :current-page? current-page?} + :current-page? current-page? + :sidebar? sidebar?} properties (outliner-property/get-class-properties class) repo (state/get-current-repo) objects (->> (db-model/sub-class-objects repo (:db/id class)) diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index 3f9a479b3f0..37f4fe45fdb 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -485,6 +485,7 @@ {:page-title? true :page-title-actions-cp (when (and with-actions? (not= (:db/id (state/get-edit-block)) (:db/id page))) db-page-title-actions) :hide-title? sidebar? + :sidebar? sidebar? :hide-children? true :container-id container-id :from-journals? (contains? #{:home :all-journals} (get-in (state/get-route-match) [:data :name]))} @@ -610,7 +611,7 @@ :on-mouse-leave (fn [e] (page-mouse-leave e *control-show?))} (page-blocks-collapse-control title *control-show? *all-collapsed?)]) - (when (and (not whiteboard?) (not sidebar?) (ldb/page? page)) + (when (and (not whiteboard?) (ldb/page? page)) (if db-based? (db-page-title page whiteboard-page? sidebar? (:container-id state)) (page-title-cp page {:journal? journal? @@ -622,7 +623,7 @@ (db-page/configure-property page)) (when (and db-based? class-page?) - (objects/class-objects page (:current-page? option))) + (objects/class-objects page {:current-page? option :sidebar? sidebar?})) (when (and db-based? (ldb/property? page)) (objects/property-related-objects page (:current-page? option))) From 8864c3515fcb7b709934d65dbf0ddedea6fa78e9 Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Thu, 21 Nov 2024 16:24:34 -0500 Subject: [PATCH 36/46] enhance: add tests for default value querying Had to extend sqlite.build with :build/properties-ref-types for :logseq.property/default-value's internal ref type needs --- deps/db/bb.edn | 3 +- deps/db/src/logseq/db/sqlite/build.cljs | 21 ++++++--- src/test/frontend/db/query_dsl_test.cljs | 54 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/deps/db/bb.edn b/deps/db/bb.edn index 178a213582a..24afe54d770 100644 --- a/deps/db/bb.edn +++ b/deps/db/bb.edn @@ -39,4 +39,5 @@ :tasks/config {:large-vars - {:max-lines-count 50}}} + {:max-lines-count 50 + :metadata-exceptions #{:large-vars/doc-var}}}} diff --git a/deps/db/src/logseq/db/sqlite/build.cljs b/deps/db/src/logseq/db/sqlite/build.cljs index 98c6d1efdf5..1583737d4e4 100644 --- a/deps/db/src/logseq/db/sqlite/build.cljs +++ b/deps/db/src/logseq/db/sqlite/build.cljs @@ -83,12 +83,16 @@ (->> properties (keep (fn [[k v]] (if-let [built-in-type (get-in db-property/built-in-properties [k :schema :type])] - (when (and (db-property-type/value-ref-property-types built-in-type) - ;; closed values are referenced by their :db/ident so no need to create values - (not (get-in db-property/built-in-properties [k :closed-values]))) + (if (and (db-property-type/value-ref-property-types built-in-type) + ;; closed values are referenced by their :db/ident so no need to create values + (not (get-in db-property/built-in-properties [k :closed-values]))) (let [property-map {:db/ident k :block/schema {:type built-in-type}}] - [property-map v])) + [property-map v]) + (when-let [built-in-type' (get (:build/properties-ref-types new-block) built-in-type)] + (let [property-map {:db/ident k + :block/schema {:type built-in-type'}}] + [property-map v]))) (when (and (db-property-type/value-ref-property-types (get-in properties-config [k :block/schema :type])) ;; TODO: Support translate-property-value without this hack (not (vector? v))) @@ -159,7 +163,8 @@ {:block-uuid (:block/uuid prop-m) :title (:block/title prop-m)}) {:db/id (or (property-db-ids prop-name) - (throw (ex-info "No :db/id for property" {:property prop-name})))}) + (throw (ex-info "No :db/id for property" {:property prop-name})))} + (select-keys prop-m [:build/properties-ref-types])) pvalue-tx-m (->property-value-tx-m new-block (:build/properties prop-m) properties all-idents)] (cond-> [] (seq pvalue-tx-m) @@ -248,6 +253,8 @@ [:block/schema [:map [:type :keyword]]] [:build/properties {:optional true} User-properties] + [:build/properties-ref-types {:optional true} + [:map-of :keyword :keyword]] [:build/closed-values {:optional true} [:vector [:map @@ -543,7 +550,7 @@ classes-tx pages-and-blocks-tx)))) -(defn build-blocks-tx +(defn ^:large-vars/doc-var build-blocks-tx "Given an EDN map for defining pages, blocks and properties, this creates a map with two keys of transactable data for use with d/transact!. The :init-tx key must be transacted first and the :block-props-tx can be transacted after. @@ -572,6 +579,8 @@ * :build/properties - Define properties on a property page. * :build/closed-values - Define closed values with a vec of maps. A map contains keys :uuid, :value and :icon. * :build/schema-classes - Vec of class name keywords. Defines a property's range classes + * :build/properties-ref-types - Map of internal ref types to public ref types that are valid only for this property. + Useful when remapping value ref types e.g. for :logseq.property/default-value * :classes - This is a map to configure classes where the keys are class name keywords and the values are maps of datascript attributes e.g. `{:block/title \"Foo\"}`. Additional keys available: diff --git a/src/test/frontend/db/query_dsl_test.cljs b/src/test/frontend/db/query_dsl_test.cljs index 2563b5ce709..afb775db020 100644 --- a/src/test/frontend/db/query_dsl_test.cljs +++ b/src/test/frontend/db/query_dsl_test.cljs @@ -183,6 +183,60 @@ prop-d:: [[nada]]"}]) (map :block/title (dsl-query "(property \"zzz name!\")"))) "filter can handle property name"))) +(when js/process.env.DB_GRAPH + (deftest property-default-type-default-value-queries + (load-test-files-for-db-graph + {:properties + {:default {:block/schema {:type :default} + :build/properties + {:logseq.property/default-value "foo"} + :build/properties-ref-types {:entity :number}}} + :classes {:Class1 {:build/schema-properties [:default]}} + :pages-and-blocks + [{:page {:block/title "page1"} + :blocks [{:block/title "b1" + :build/properties {:default "foo"}} + {:block/title "b2" + :build/properties {:default "bar"}} + {:block/title "b3" + :build/tags [:Class1]}]}]}) + + (is (= ["b3" "b2" "b1"] + (map :block/title (dsl-query "(property :user.property/default)"))) + "Blocks with any :default property or tagged with a tag that has that default-value property") + (is (= ["b1" "b3"] + (map :block/title (dsl-query "(property :user.property/default \"foo\")"))) + "Blocks with :default property value or tagged with a tag that has that default-value property value") + (is (= ["b2"] + (map :block/title (dsl-query "(property :user.property/default \"bar\")"))) + "Blocks with :default property value and not tagged with a tag that has that default-value property value")) + + (deftest property-checkbox-type-default-value-queries + (load-test-files-for-db-graph + {:properties + {:checkbox {:block/schema {:type :checkbox} + :build/properties + {:logseq.property/checkbox-default-value true}}} + :classes {:Class1 {:build/schema-properties [:checkbox]}} + :pages-and-blocks + [{:page {:block/title "page1"} + :blocks [{:block/title "b1" + :build/properties {:checkbox true}} + {:block/title "b2" + :build/properties {:checkbox false}} + {:block/title "b3" + :build/tags [:Class1]}]}]}) + + (is (= ["b3" "b2" "b1"] + (map :block/title (dsl-query "(property :user.property/checkbox)"))) + "Blocks with any :checkbox property or tagged with a tag that has that default-value property") + (is (= ["b1" "b3"] + (map :block/title (dsl-query "(property :user.property/checkbox true)"))) + "Blocks with :checkbox property value or tagged with a tag that has that default-value property value") + (is (= ["b2"] + (map :block/title (dsl-query "(property :user.property/checkbox false)"))) + "Blocks with :checkbox property value and not tagged with a tag that has that default-value property value"))) + (deftest block-property-query-performance (let [pages (->> (repeat 10 {:tags ["tag1" "tag2"]}) (map-indexed (fn [idx {:keys [tags]}] From ce18010b2b67a2f0451cd896c1034888270630cf Mon Sep 17 00:00:00 2001 From: Gabriel Horner Date: Thu, 21 Nov 2024 17:56:58 -0500 Subject: [PATCH 37/46] refactor: Decouple simple queries in db graph from original *property rules by giving simple queries their own rules. This allows simple queries to grow in functionality and complexity without affecting other features. Also fixed private-property rule wasn't working because deps weren't configured --- .github/workflows/build.yml | 3 + deps/db/bb.edn | 6 +- deps/db/src/logseq/db/frontend/rules.cljc | 70 ++++++++++++++----- .../test/logseq/db/frontend/rules_test.cljs | 10 +-- src/main/frontend/db/query_dsl.cljs | 18 +++-- src/test/frontend/db/query_dsl_test.cljs | 29 ++++++-- 6 files changed, 100 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index afa10f553c5..e6a26f5207d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,9 @@ jobs: - name: Run some ClojureScript tests against DB version run: DB_GRAPH=1 node static/tests.js -r frontend.db.query-dsl-test + - name: Run ClojureScript query tests against DB version with basic query type + run: DB_GRAPH=1 DB_QUERY_TYPE=basic node static/tests.js -r frontend.db.query-dsl-test + - name: Run ClojureScript tests run: node static/tests.js -e fix-me diff --git a/deps/db/bb.edn b/deps/db/bb.edn index 24afe54d770..c52f770ca77 100644 --- a/deps/db/bb.edn +++ b/deps/db/bb.edn @@ -31,8 +31,10 @@ (concat (mapcat val rules/rules) ;; TODO: Update linter to handle false positive on ?str-val for :property (rules/extract-rules (dissoc rules/query-dsl-rules :property)) - ;; TODO: Update linter to handle false positive on :task, :priority, :property and :private-property - (rules/extract-rules (dissoc rules/db-query-dsl-rules :task :priority :property :private-property + ;; TODO: Update linter to handle false positive on :task, :priority, :*property* rules + (rules/extract-rules (dissoc rules/db-query-dsl-rules + :task :priority + :property :simple-query-property :private-property :property-checkbox-default-value :property-missing-value :has-property-or-default-value)))))}} diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index 21448ac3c1a..e7411994512 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -206,13 +206,6 @@ [?prop-e :db/valueType :db.type/ref] (property-default-value ?b ?prop-e :logseq.property/default-value ?val)))]] - :tags - '[(tags ?b ?tags) - [?b :block/tags ?t] - [?t :block/name ?tag] - [(missing? $ ?b :block/link)] - [(contains? ?tags ?tag)]] - :object-has-class-property '[(object-has-class-property? ?b ?prop) [?prop-e :db/ident ?prop] @@ -228,8 +221,9 @@ (or [?prop-e :logseq.property/default-value _] [?prop-e :logseq.property/checkbox-default-value _])))] - :has-property - '[(has-property ?b ?prop) + ;; Checks if a property exists for simple queries. Supports default values + :has-simple-query-property + '[(has-simple-query-property ?b ?prop) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] (has-property-or-default-value? ?b ?prop) @@ -237,15 +231,46 @@ [(get ?prop-schema :public? true) ?public] [(= true ?public)]] - ;; Same as has-property except it returns public and private properties like :block/title - :has-private-property - '[(has-private-property ?b ?prop) + ;; Same as has-simple-query-property except it returns public and private properties like :block/title + :has-private-simple-query-property + '[(has-private-simple-query-property ?b ?prop) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] (has-property-or-default-value? ?b ?prop)] + ;; Checks if a property exists for any features that are not simple queries + :has-property + '[(has-property ?b ?prop) + [?b ?prop _] + [?prop-e :db/ident ?prop] + [?prop-e :block/type "property"] + [?prop-e :block/schema ?prop-schema] + [(get ?prop-schema :public? true) ?public] + [(= true ?public)]] + + ;; Checks if a property has a value for any features that are not simple queries :property '[(property ?b ?prop ?val) + [?prop-e :db/ident ?prop] + [?prop-e :block/type "property"] + [?prop-e :block/schema ?prop-schema] + [(get ?prop-schema :public? true) ?public] + [(= true ?public)] + [?b ?prop ?pv] + (or + ;; non-ref value + (and + [(missing? $ ?prop-e :db/valueType)] + [?b ?prop ?val]) + ;; ref value + (and + [?prop-e :db/valueType :db.type/ref] + (or [?pv :block/title ?val] + [?pv :property.value/content ?val])))] + + ;; Checks if a property has a value for simple queries. Supports default values + :simple-query-property + '[(simple-query-property ?b ?prop ?val) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] [?prop-e :block/schema ?prop-schema] @@ -254,13 +279,20 @@ [(= true ?public)] (property-value ?b ?prop-e ?val)] -;; Same as property except it returns public and private properties like :block/title - :private-property - '[(private-property ?b ?prop ?val) + ;; Same as property except it returns public and private properties like :block/title + :private-simple-query-property + '[(private-simple-query-property ?b ?prop ?val) [?prop-e :db/ident ?prop] [?prop-e :block/type "property"] (property-value ?b ?prop-e ?val)] + :tags + '[(tags ?b ?tags) + [?b :block/tags ?t] + [?t :block/name ?tag] + [(missing? $ ?b :block/link)] + [(contains? ?tags ?tag)]] + :task '[(task ?b ?statuses) ;; and needed to avoid binding error @@ -281,13 +313,13 @@ :priority #{:property} :property-missing-value #{:object-has-class-property} :has-property-or-default-value #{:object-has-class-property} - :has-property #{:has-property-or-default-value} - :has-private-property #{:has-property-or-default-value} + :has-simple-query-property #{:has-property-or-default-value} + :has-private-simple-query-property #{:has-property-or-default-value} :property-default-value #{:existing-property-value :property-missing-value} :property-checkbox-default-value #{:existing-property-value :property-missing-value} :property-value #{:property-default-value :property-checkbox-default-value} - :property #{:property-value} - :has-propeorty #{}}) + :simple-query-property #{:property-value} + :private-simple-query-property #{:property-value}}) (defn- get-full-deps [deps rules-deps] diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs index 421b939d74d..16aecd244c6 100644 --- a/deps/db/test/logseq/db/frontend/rules_test.cljs +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -16,14 +16,14 @@ :existing-property-value :object-has-class-property} property-value-deps (conj default-value-deps :property-value :property-checkbox-default-value) - property-deps (conj property-value-deps :property) - task-deps (conj property-deps :task) - priority-deps (conj property-deps :priority) - task-priority-deps (conj property-deps :task :priority)] + property-deps (conj property-value-deps :simple-query-property) + task-deps #{:property :task} + priority-deps #{:property :priority} + task-priority-deps #{:property :task :priority}] (are [x y] (= (#'rules/get-full-deps x rules/rules-dependencies) y) [:property-default-value] default-value-deps [:property-value] property-value-deps - [:property] property-deps + [:simple-query-property] property-deps [:task] task-deps [:priority] priority-deps [:task :priority] task-priority-deps))) diff --git a/src/main/frontend/db/query_dsl.cljs b/src/main/frontend/db/query_dsl.cljs index 2d2cabeca16..4a1017919be 100644 --- a/src/main/frontend/db/query_dsl.cljs +++ b/src/main/frontend/db/query_dsl.cljs @@ -334,18 +334,24 @@ (let [k (if db-graph? (->db-keyword-property (nth e 1)) (->file-keyword-property (nth e 1))) v (nth e 2) v' (if db-graph? (->db-property-value k v) (->file-property-value v))] - (if private-property? - {:query (list 'private-property '?b k v') - :rules [:private-property]} + (if db-graph? + (if private-property? + {:query (list 'private-simple-query-property '?b k v') + :rules [:private-simple-query-property]} + {:query (list 'simple-query-property '?b k v') + :rules [:simple-query-property]}) {:query (list 'property '?b k v') :rules [:property]}))) (defn- build-property-one-arg [e {:keys [db-graph? private-property?]}] (let [k (if db-graph? (->db-keyword-property (nth e 1)) (->file-keyword-property (nth e 1)))] - (if private-property? - {:query (list 'has-private-property '?b k) - :rules [:has-private-property]} + (if db-graph? + (if private-property? + {:query (list 'has-private-simple-query-property '?b k) + :rules [:has-private-simple-query-property]} + {:query (list 'has-simple-query-property '?b k) + :rules [:has-simple-query-property]}) {:query (list 'has-property '?b k) :rules [:has-property]}))) diff --git a/src/test/frontend/db/query_dsl_test.cljs b/src/test/frontend/db/query_dsl_test.cljs index afb775db020..058c9ce0c9c 100644 --- a/src/test/frontend/db/query_dsl_test.cljs +++ b/src/test/frontend/db/query_dsl_test.cljs @@ -19,9 +19,12 @@ ;; ============ (def dsl-query* - "When $EXAMPLE set, prints query result of build query. Useful for - documenting examples and debugging" - (if (some? js/process.env.EXAMPLE) + "Overrides dsl-query/query with ENV variables. When $EXAMPLE is set, prints query + result of build query. This is useful for documenting examples and debugging. + When $DB_QUERY_TYPE is set, runs query tests against other versions of simple query e.g. + more basic property rules" + (cond + (some? js/process.env.EXAMPLE) (fn dsl-query-star [& args] (let [old-build-query query-dsl/build-query] (with-redefs [query-dsl/build-query @@ -30,6 +33,24 @@ (println "EXAMPLE:" (pr-str (:query res))) res))] (apply query-dsl/query args)))) + (some? js/process.env.DB_QUERY_TYPE) + (fn dsl-query-star [& args] + (let [old-build-property @#'query-dsl/build-property] + (with-redefs [query-dsl/build-property + (fn [& args'] + (let [m (apply old-build-property args') + m' (cond + (= (:rules m) [:simple-query-property]) + {:rules [:property] + :query (apply list 'property (rest (:query m)))} + (= (:rules m) [:has-simple-query-property]) + {:rules [:has-property] + :query (apply list 'has-property (rest (:query m)))} + :else + m)] + m'))] + (apply query-dsl/query args)))) + :else query-dsl/query)) (defn- ->smart-query @@ -183,7 +204,7 @@ prop-d:: [[nada]]"}]) (map :block/title (dsl-query "(property \"zzz name!\")"))) "filter can handle property name"))) -(when js/process.env.DB_GRAPH +(when (and js/process.env.DB_GRAPH (not js/process.env.DB_QUERY_TYPE)) (deftest property-default-type-default-value-queries (load-test-files-for-db-graph {:properties From 0f1cb55dce26d53de01ae7de460803cd25ec023c Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 12:21:50 +0800 Subject: [PATCH 38/46] fix: set value to empty after deleting default property value --- deps/outliner/src/logseq/outliner/core.cljs | 29 ++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/core.cljs b/deps/outliner/src/logseq/outliner/core.cljs index c3197ca71ee..df6c29215d9 100644 --- a/deps/outliner/src/logseq/outliner/core.cljs +++ b/deps/outliner/src/logseq/outliner/core.cljs @@ -20,7 +20,8 @@ [logseq.outliner.tree :as otree] [logseq.outliner.validate :as outliner-validate] [malli.core :as m] - [malli.util :as mu])) + [malli.util :as mu] + [logseq.db.frontend.property :as db-property])) (def ^:private block-map (mu/optional-keys @@ -729,15 +730,25 @@ txs-state (ds/new-outliner-txs-state) block-ids (map (fn [b] [:block/uuid (:block/uuid b)]) top-level-blocks) start-block (first top-level-blocks) - end-block (last top-level-blocks)] + end-block (last top-level-blocks) + delete-one-block? (or (= 1 (count top-level-blocks)) (= start-block end-block))] (when (seq top-level-blocks) - (if (or - (= 1 (count top-level-blocks)) - (= start-block end-block)) - (delete-block conn txs-state start-block) - (doseq [id block-ids] - (let [node (d/entity @conn id)] - (otree/-del node txs-state conn))))) + (let [from-property (:logseq.property/created-from-property start-block) + default-value-property? (:logseq.property/default-value from-property)] + (cond + (and delete-one-block? default-value-property?) + (let [datoms (d/datoms @conn :avet (:db/ident from-property) (:db/id start-block)) + tx-data (map (fn [d] {:db/id (:e d) + (:db/ident from-property) :logseq.property/empty-placeholder}) datoms)] + (when (seq tx-data) (swap! txs-state concat tx-data))) + + delete-one-block? + (delete-block conn txs-state start-block) + + :else + (doseq [id block-ids] + (let [node (d/entity @conn id)] + (otree/-del node txs-state conn)))))) {:tx-data @txs-state})) (defn- move-to-original-position? From 6d0bdd6af07b22ee76b4e7f8fe87fbad881314a3 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 12:43:09 +0800 Subject: [PATCH 39/46] fix: delete default value from a property result in empty placeholder --- deps/outliner/src/logseq/outliner/core.cljs | 4 +++- deps/outliner/src/logseq/outliner/property.cljs | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/core.cljs b/deps/outliner/src/logseq/outliner/core.cljs index df6c29215d9..aa3231e1434 100644 --- a/deps/outliner/src/logseq/outliner/core.cljs +++ b/deps/outliner/src/logseq/outliner/core.cljs @@ -734,7 +734,9 @@ delete-one-block? (or (= 1 (count top-level-blocks)) (= start-block end-block))] (when (seq top-level-blocks) (let [from-property (:logseq.property/created-from-property start-block) - default-value-property? (:logseq.property/default-value from-property)] + default-value-property? (and (:logseq.property/default-value from-property) + (not= (:db/id start-block) + (:db/id (:logseq.property/default-value from-property))))] (cond (and delete-one-block? default-value-property?) (let [datoms (d/datoms @conn :avet (:db/ident from-property) (:db/id start-block)) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index 40a60c82aef..32b6fc67af6 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -360,8 +360,15 @@ [conn eid property-id] (throw-error-if-read-only-property property-id) (let [eid (->eid eid) - block (d/entity @conn eid)] + block (d/entity @conn eid) + property (d/entity @conn property-id)] (cond + (= (:logseq.property/default-value property) (get block property-id)) + (ldb/transact! conn + [{:db/id (:db/id block) + property-id :logseq.property/empty-placeholder}] + {:outliner-op :save-block}) + (and (ldb/class? block) (= property-id :logseq.property/parent)) (ldb/transact! conn [[:db/add (:db/id block) :logseq.property/parent :logseq.class/Root]] From d46dc7387065a32889a0536f2344eaf92edcace4 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 13:37:28 +0800 Subject: [PATCH 40/46] fix: creating a new text block when focusing on default value --- .../src/logseq/outliner/property.cljs | 3 ++ src/main/frontend/components/block.cljs | 47 ++++++++++-------- src/main/frontend/components/container.cljs | 6 ++- src/main/frontend/components/content.cljs | 48 ++++++++++--------- .../frontend/components/property/value.cljs | 1 + 5 files changed, 60 insertions(+), 45 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/property.cljs b/deps/outliner/src/logseq/outliner/property.cljs index 32b6fc67af6..abbe0bfd984 100644 --- a/deps/outliner/src/logseq/outliner/property.cljs +++ b/deps/outliner/src/logseq/outliner/property.cljs @@ -363,6 +363,9 @@ block (d/entity @conn eid) property (d/entity @conn property-id)] (cond + (= :logseq.property/empty-placeholder (:db/ident (get block property-id))) + nil + (= (:logseq.property/default-value property) (get block property-id)) (ldb/transact! conn [{:db/id (:db/id block) diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 947817bf0c1..47ae2a9c2e7 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -791,12 +791,12 @@ {:ref *el-trigger :on-mouse-enter (fn [^js e] (when (= (some-> (.-target e) (.closest ".preview-ref-link")) - (rum/deref *el-trigger)) + (rum/deref *el-trigger)) (let [timer (rum/deref *timer) timer1 (rum/deref *timer1)] (when-not timer (rum/set-ref! *timer - (js/setTimeout #(set-visible! true) 1000))) + (js/setTimeout #(set-visible! true) 1000))) (when timer1 (js/clearTimeout timer1) (rum/set-ref! *timer1 nil))))) @@ -809,7 +809,7 @@ (rum/set-ref! *timer nil)) (when-not timer1 (rum/set-ref! *timer1 - (js/setTimeout #(set-visible! false) 300))))))} + (js/setTimeout #(set-visible! false) 300))))))} children])) (rum/defc page-preview-trigger @@ -825,8 +825,8 @@ (let [[ready? set-ready!] (rum/use-state false)] (rum/use-effect! - (fn [] - (let [el-popup (rum/deref *el-popup) + (fn [] + (let [el-popup (rum/deref *el-popup) focus! #(js/setTimeout (fn [] (.focus el-popup)))] (set-ready! true) (focus!) @@ -849,7 +849,7 @@ ;; check the top popup whether is the preview popup (when (ui/last-shui-preview-popup?) (rum/set-ref! *timer1 - (js/setTimeout #(set-visible! false) 500))))} + (js/setTimeout #(set-visible! false) 500))))} (when-let [page-cp (and ready? (state/get-page-blocks-cp))] (page-cp {:repo (state/get-current-repo) :page-name (str (:block/uuid source)) @@ -858,11 +858,11 @@ :preview? true}))])))] (rum/use-effect! - (fn [] - (if (some-> (rum/deref *el-wrap) (.closest "[data-radix-popper-content-wrapper]")) - (set-in-popup! true) - (set-in-popup! false))) - []) + (fn [] + (if (some-> (rum/deref *el-wrap) (.closest "[data-radix-popper-content-wrapper]")) + (set-in-popup! true) + (set-in-popup! false))) + []) [:span {:ref *el-wrap} (if (boolean? in-popup?) @@ -1184,15 +1184,15 @@ :on-mouse-leave (fn [] (when (ui/last-shui-preview-popup?) (rum/set-ref! *timer1 - (js/setTimeout #(set-visible! false) 500))))} + (js/setTimeout #(set-visible! false) 500))))} [(breadcrumb config repo id {:indent? true}) (blocks-container - (assoc config :id (str id) :preview? true) - [(db/entity [:block/uuid id])])]])] + (assoc config :id (str id) :preview? true) + [(db/entity [:block/uuid id])])]])] (popup-preview-impl children - {:visible? visible? :set-visible! set-visible! - :*timer *timer :*timer1 *timer1 - :render render}))) + {:visible? visible? :set-visible! set-visible! + :*timer *timer :*timer1 *timer1 + :render render}))) (rum/defc block-reference < rum/reactive db-mixins/query {:init (fn [state] @@ -3342,7 +3342,14 @@ (when order-list? " is-order-list") (when (string/blank? title) " is-blank") (when original-block " embed-block")) - :haschild (str (boolean has-child?))} + :haschild (str (boolean has-child?)) + :on-focus (fn [] + (when (:property-default-value? config) + (when-let [f (:on-block-content-pointer-down config)] + (f))))} + + (:property-default-value? config) + (assoc :data-is-property-default-value (:property-default-value? config)) original-block (assoc :originalblockid (str (:block/uuid original-block))) @@ -3459,8 +3466,8 @@ (query-property-cp block config collapsed?)) (when (and db-based? - (or sidebar? (not collapsed?)) - (not (or table? property?))) + (or sidebar? (not collapsed?)) + (not (or table? property?))) [:div (when-not (:page-title? config) {:style {:padding-left 45}}) (db-properties-cp config block {:in-block-container? true})]) diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index 16a2235db6b..b4a8cecd6de 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -836,11 +836,13 @@ ;; block bullet (and block-id (parse-uuid block-id)) - (let [block (.closest target ".ls-block")] + (let [block (.closest target ".ls-block") + property-default-value? (when block + (= "true" (d/attr block "data-is-property-default-value")))] (when block (state/clear-selection!) (state/conj-selection-block! block :down)) - (show! (cp-content/block-context-menu-content target (uuid block-id)))) + (show! (cp-content/block-context-menu-content target (uuid block-id) property-default-value?))) :else false)] diff --git a/src/main/frontend/components/content.cljs b/src/main/frontend/components/content.cljs index e1c631309e0..a337f9a1a9a 100644 --- a/src/main/frontend/components/content.cljs +++ b/src/main/frontend/components/content.cljs @@ -64,7 +64,7 @@ {:key "delete" :on-click #(do (editor-handler/delete-selection %) (state/hide-custom-context-menu!) - (shui/popup-hide!))} + (shui/popup-hide!))} (t :editor/delete-selection) (shui/dropdown-menu-shortcut (ui/keyboard-shortcut-from-config :editor/delete))) @@ -165,15 +165,15 @@ (p/let [exists? (page-handler/ [:div.px-4.py-2.text-sm {:on-click (fn [e] (util/stop e))} @@ -183,7 +183,7 @@ :on-key-down (fn [e] (util/stop-propagation e) (when (and (= "Enter" (util/ekey e)) - (not (string/blank? (util/trim-safe @input)))) + (not (string/blank? (util/trim-safe @input)))) (submit!))) :on-change (fn [e] (reset! input (util/evalue e)))}] @@ -192,7 +192,7 @@ (ui/button (t :submit) :on-click submit!)] (shui/dropdown-menu-separator)]) (shui/dropdown-menu-item - {:key "Make a Template" + {:key "Make a Template" :on-click (fn [e] (util/stop e) (reset! edit? true))} @@ -200,7 +200,7 @@ (rum/defc ^:large-vars/cleanup-todo block-context-menu-content < shortcut/disable-all-shortcuts - [_target block-id] + [_target block-id property-default-value?] (let [repo (state/get-current-repo) db? (config/db-based-graph? repo)] (when-let [block (db/entity [:block/uuid block-id])] @@ -265,18 +265,20 @@ #(export/export-blocks [block-id] {:whiteboard? false})))} (t :content/copy-export-as)) - (shui/dropdown-menu-item - {:key "Cut" - :on-click (fn [_e] - (editor-handler/cut-block! block-id))} - (t :editor/cut) - (shui/dropdown-menu-shortcut (ui/keyboard-shortcut-from-config :editor/cut))) + (when-not property-default-value? + (shui/dropdown-menu-item + {:key "Cut" + :on-click (fn [_e] + (editor-handler/cut-block! block-id))} + (t :editor/cut) + (shui/dropdown-menu-shortcut (ui/keyboard-shortcut-from-config :editor/cut)))) - (shui/dropdown-menu-item - {:key "delete" - :on-click #(editor-handler/delete-block-aux! block)} - (t :editor/delete-selection) - (shui/dropdown-menu-shortcut (ui/keyboard-shortcut-from-config :editor/delete))) + (when-not property-default-value? + (shui/dropdown-menu-item + {:key "delete" + :on-click #(editor-handler/delete-block-aux! block)} + (t :editor/delete-selection) + (shui/dropdown-menu-shortcut (ui/keyboard-shortcut-from-config :editor/delete)))) (shui/dropdown-menu-separator) diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index ae1616c44d5..a3463c92d6c 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -728,6 +728,7 @@ (:block/uuid block) (:block/uuid value-block))) :container-id container-id + :property-default-value? default-value? :editor-box (state/get-component :editor/box) :property-block? true :on-block-content-pointer-down (when default-value? From d65834104be32c95e93518c142c4a3a35d534e67 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 14:05:47 +0800 Subject: [PATCH 41/46] enhance: use default text value when adding property to non-tag node --- deps/outliner/src/logseq/outliner/core.cljs | 3 +-- src/main/frontend/components/property/value.cljs | 13 ++++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/deps/outliner/src/logseq/outliner/core.cljs b/deps/outliner/src/logseq/outliner/core.cljs index aa3231e1434..c828f0dd548 100644 --- a/deps/outliner/src/logseq/outliner/core.cljs +++ b/deps/outliner/src/logseq/outliner/core.cljs @@ -20,8 +20,7 @@ [logseq.outliner.tree :as otree] [logseq.outliner.validate :as outliner-validate] [malli.core :as m] - [malli.util :as mu] - [logseq.db.frontend.property :as db-property])) + [malli.util :as mu])) (def ^:private block-map (mu/optional-keys diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index a3463c92d6c..6ec8ec1a126 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -127,11 +127,14 @@ (not= (:db/id existing-value) (:db/id default-value))) new-block-id (when-not existing-value? (db/new-block-id)) _ (when-not existing-value? - (db-property-handler/create-property-text-block! - (:db/id block) - (:db/id property) - value - {:new-block-id new-block-id}))] + (let [value' (if (and default-value (string? value) (string/blank? value)) + (db-property/property-value-content default-value) + value)] + (db-property-handler/create-property-text-block! + (:db/id block) + (:db/id property) + value' + {:new-block-id new-block-id})))] (if existing-value? existing-value (db/entity [:block/uuid new-block-id]))) (p/let [new-block-id (db/new-block-id) _ (db-property-handler/create-property-text-block! From 525842b73161cc31076e025c885c83b3b53c79e6 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 14:21:19 +0800 Subject: [PATCH 42/46] fix: tagged nodes are not displayed on property page with default value --- src/main/frontend/components/views.cljs | 2 +- src/main/frontend/db/async.cljs | 7 +++++-- src/main/frontend/db/model.cljs | 9 ++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/components/views.cljs b/src/main/frontend/components/views.cljs index f643b572422..44f0c6b1187 100644 --- a/src/main/frontend/components/views.cljs +++ b/src/main/frontend/components/views.cljs @@ -476,7 +476,7 @@ (row-cell table row column render cell-opts idx first-col-rendered? set-first-col-rendered!)))) columns)))) -(rum/defc table-row < rum/reactive (mixins/perf-measure-mixin "table row") +(rum/defc table-row < rum/reactive [table row columns props option] (let [row' (db/sub-block (:id row)) ;; merge entity temporal attributes diff --git a/src/main/frontend/db/async.cljs b/src/main/frontend/db/async.cljs index a4bc327c8a3..d1f222c03b3 100644 --- a/src/main/frontend/db/async.cljs +++ b/src/main/frontend/db/async.cljs @@ -8,6 +8,7 @@ [frontend.db.file-based.async :as file-async] [frontend.db :as db] [frontend.db.model :as db-model] + [logseq.db.frontend.rules :as rules] [frontend.persist-db.browser :as db-browser] [datascript.core :as d] [frontend.db.react :as react] @@ -269,9 +270,11 @@ [graph property-ident] (> (d/q '[:find [?objects ...] - :in $ ?prop - :where [?objects ?prop]] + (->> (d/q '[:find [?b ...] + :in $ % ?prop + :where + (has-property-or-default-value? ?b ?prop)] (conn/get-db repo) + (rules/extract-rules rules/db-query-dsl-rules [:has-property-or-default-value] + {:deps rules/rules-dependencies}) (:db/ident property)) (map #(db-utils/entity repo %))))) From 471d413d8022a7496801cbf2db5d5d38ed0e34da Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 14:38:22 +0800 Subject: [PATCH 43/46] Rename checkbox-default-value to scalar-default-value --- deps/db/bb.edn | 2 +- deps/db/src/logseq/db/frontend/entity_plus.cljc | 2 +- deps/db/src/logseq/db/frontend/property.cljs | 10 +++++----- deps/db/src/logseq/db/frontend/rules.cljc | 12 ++++++------ deps/db/test/logseq/db/frontend/rules_test.cljs | 2 +- src/main/frontend/components/property/config.cljs | 4 ++-- src/main/frontend/components/property/value.cljs | 13 ++++++++----- src/main/frontend/worker/db/migrate.cljs | 2 +- src/test/frontend/db/query_dsl_test.cljs | 2 +- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/deps/db/bb.edn b/deps/db/bb.edn index c52f770ca77..000c6db732f 100644 --- a/deps/db/bb.edn +++ b/deps/db/bb.edn @@ -35,7 +35,7 @@ (rules/extract-rules (dissoc rules/db-query-dsl-rules :task :priority :property :simple-query-property :private-property - :property-checkbox-default-value + :property-scalar-default-value :property-missing-value :has-property-or-default-value)))))}} diff --git a/deps/db/src/logseq/db/frontend/entity_plus.cljc b/deps/db/src/logseq/db/frontend/entity_plus.cljc index 6271c366f8f..ff0fc0d5c8b 100644 --- a/deps/db/src/logseq/db/frontend/entity_plus.cljc +++ b/deps/db/src/logseq/db/frontend/entity_plus.cljc @@ -52,7 +52,7 @@ (when-let [property (d/entity db k)] (let [schema (lookup-entity property :block/schema nil)] (if (= :checkbox (:type schema)) - (lookup-entity property :logseq.property/checkbox-default-value nil) + (lookup-entity property :logseq.property/scalar-default-value nil) (lookup-entity property :logseq.property/default-value nil))))))))) (defn lookup-kv-then-entity diff --git a/deps/db/src/logseq/db/frontend/property.cljs b/deps/db/src/logseq/db/frontend/property.cljs index 2b6cc09ca95..492324be3b1 100644 --- a/deps/db/src/logseq/db/frontend/property.cljs +++ b/deps/db/src/logseq/db/frontend/property.cljs @@ -152,11 +152,11 @@ :public? false :hide? true :view-context :property}} - :logseq.property/checkbox-default-value {:title "Checkbox default value" - :schema {:type :checkbox - :public? false - :hide? true - :view-context :property}} + :logseq.property/scalar-default-value {:title "Non ref type default value" + :schema {:type :any + :public? false + :hide? true + :view-context :property}} :logseq.property.class/properties {:title "Tag Properties" :schema {:type :property :cardinality :many diff --git a/deps/db/src/logseq/db/frontend/rules.cljc b/deps/db/src/logseq/db/frontend/rules.cljc index e7411994512..006ec8ea451 100644 --- a/deps/db/src/logseq/db/frontend/rules.cljc +++ b/deps/db/src/logseq/db/frontend/rules.cljc @@ -180,8 +180,8 @@ [(= ?prop-v "N/A")] [?prop-e ?default-p ?default-v]] - :property-checkbox-default-value - '[(property-checkbox-default-value ?b ?prop-e ?default-p ?val) + :property-scalar-default-value + '[(property-scalar-default-value ?b ?prop-e ?default-p ?val) (property-missing-value ?b ?prop-e ?default-p ?default-v) [(missing? $ ?prop-e :db/valueType)] [?prop-e ?default-p ?val]] @@ -201,7 +201,7 @@ (or (and [(missing? $ ?prop-e :db/valueType)] - (property-checkbox-default-value ?b ?prop-e :logseq.property/checkbox-default-value ?val)) + (property-scalar-default-value ?b ?prop-e :logseq.property/scalar-default-value ?val)) (and [?prop-e :db/valueType :db.type/ref] (property-default-value ?b ?prop-e :logseq.property/default-value ?val)))]] @@ -219,7 +219,7 @@ [?b ?prop _] (and (object-has-class-property? ?b ?prop) (or [?prop-e :logseq.property/default-value _] - [?prop-e :logseq.property/checkbox-default-value _])))] + [?prop-e :logseq.property/scalar-default-value _])))] ;; Checks if a property exists for simple queries. Supports default values :has-simple-query-property @@ -316,8 +316,8 @@ :has-simple-query-property #{:has-property-or-default-value} :has-private-simple-query-property #{:has-property-or-default-value} :property-default-value #{:existing-property-value :property-missing-value} - :property-checkbox-default-value #{:existing-property-value :property-missing-value} - :property-value #{:property-default-value :property-checkbox-default-value} + :property-scalar-default-value #{:existing-property-value :property-missing-value} + :property-value #{:property-default-value :property-scalar-default-value} :simple-query-property #{:property-value} :private-simple-query-property #{:property-value}}) diff --git a/deps/db/test/logseq/db/frontend/rules_test.cljs b/deps/db/test/logseq/db/frontend/rules_test.cljs index 16aecd244c6..35317cb1dbc 100644 --- a/deps/db/test/logseq/db/frontend/rules_test.cljs +++ b/deps/db/test/logseq/db/frontend/rules_test.cljs @@ -15,7 +15,7 @@ :property-missing-value :existing-property-value :object-has-class-property} - property-value-deps (conj default-value-deps :property-value :property-checkbox-default-value) + property-value-deps (conj default-value-deps :property-value :property-scalar-default-value) property-deps (conj property-value-deps :simple-query-property) task-deps #{:property :task} priority-deps #{:property :priority} diff --git a/src/main/frontend/components/property/config.cljs b/src/main/frontend/components/property/config.cljs index 119a7adbedd..82fb3e2d4d5 100644 --- a/src/main/frontend/components/property/config.cljs +++ b/src/main/frontend/components/property/config.cljs @@ -522,13 +522,13 @@ [property] (let [property-type (get-in property [:block/schema :type]) option (if (= :checkbox property-type) - (let [default-value (:logseq.property/checkbox-default-value property)] + (let [default-value (:logseq.property/scalar-default-value property)] {:icon :settings-2 :title "Default value" :toggle-checked? (boolean default-value) :checkbox? true :on-toggle-checked-change (fn [] - (db-property-handler/set-block-property! (:block/uuid property) :logseq.property/checkbox-default-value (not default-value)))}) + (db-property-handler/set-block-property! (:block/uuid property) :logseq.property/scalar-default-value (not default-value)))}) (let [default-value (:logseq.property/default-value property)] {:icon :settings-2 :title "Default value" :desc (if default-value (db-property/property-value-content default-value) "Set value") diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index 6ec8ec1a126..da6f9e9118f 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -160,8 +160,8 @@ "If a class and in a class schema context, add the property to its schema. Otherwise, add a block's property and its value" ([block property-key property-value] (updates))] (assert (<= db-schema/version max-schema-version)) diff --git a/src/test/frontend/db/query_dsl_test.cljs b/src/test/frontend/db/query_dsl_test.cljs index 058c9ce0c9c..861418413ed 100644 --- a/src/test/frontend/db/query_dsl_test.cljs +++ b/src/test/frontend/db/query_dsl_test.cljs @@ -237,7 +237,7 @@ prop-d:: [[nada]]"}]) {:properties {:checkbox {:block/schema {:type :checkbox} :build/properties - {:logseq.property/checkbox-default-value true}}} + {:logseq.property/scalar-default-value true}}} :classes {:Class1 {:build/schema-properties [:checkbox]}} :pages-and-blocks [{:page {:block/title "page1"} From 460fcf69fcc2b5f90271ed36ebfc1e9cf646c732 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 14:47:53 +0800 Subject: [PATCH 44/46] enhance: put default value the first choice --- src/main/frontend/db/async.cljs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/frontend/db/async.cljs b/src/main/frontend/db/async.cljs index d1f222c03b3..b5e087381cf 100644 --- a/src/main/frontend/db/async.cljs +++ b/src/main/frontend/db/async.cljs @@ -105,7 +105,8 @@ property-id empty-id)] (if default-value-id - (conj result default-value-id) + ;; put default value the first + (concat [default-value-id] result) result)))) (comment From 90e94275886249ce828b88d7c8cab07f6c5c60ab Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 25 Nov 2024 15:11:09 +0800 Subject: [PATCH 45/46] fix: can't toggle checkbox --- src/main/frontend/components/property.cljs | 10 ++++++++-- src/main/frontend/components/property/value.cljs | 5 +---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/frontend/components/property.cljs b/src/main/frontend/components/property.cljs index eff5563299f..27889c7ac39 100644 --- a/src/main/frontend/components/property.cljs +++ b/src/main/frontend/components/property.cljs @@ -111,7 +111,10 @@ (and block (= type :checkbox)) (p/do! (ui/hide-popups-until-preview-popup!) - (pv/ Date: Tue, 26 Nov 2024 15:33:09 +0800 Subject: [PATCH 46/46] fix: recursively creating new block for :many default property --- src/main/frontend/components/property/value.cljs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/frontend/components/property/value.cljs b/src/main/frontend/components/property/value.cljs index d951998495f..87d54c591e9 100644 --- a/src/main/frontend/components/property/value.cljs +++ b/src/main/frontend/components/property/value.cljs @@ -731,7 +731,6 @@ (:block/uuid block) (:block/uuid value-block))) :container-id container-id - :property-default-value? default-value? :editor-box (state/get-component :editor/box) :property-block? true :on-block-content-pointer-down (when default-value? @@ -740,7 +739,7 @@ (if (set? value-block) (blocks-container config (ldb/sort-by-order value-block)) (rum/with-key - (block-container config value-block) + (block-container (assoc config :property-default-value? default-value?) value-block) (str (:db/id property) "-" (:block/uuid value-block)))))] [:div {:tabIndex 0