mirror of https://github.com/logseq/logseq
parent
1d12ac56a1
commit
61db29ceba
|
@ -77,8 +77,10 @@
|
|||
(and (validate-fn' val)
|
||||
(contains? (set (map :db/id (:property/closed-values property))) val)))
|
||||
validate-fn')]
|
||||
(if (= (:cardinality schema) :many)
|
||||
(every? validate-fn'' property-val)
|
||||
(if (db-property/many? property)
|
||||
(if (coll? property-val)
|
||||
(every? validate-fn'' property-val)
|
||||
(validate-fn'' property-val))
|
||||
(or (validate-fn'' property-val)
|
||||
(if (= :db.type/ref (:db/valueType property))
|
||||
(and (integer? property-val)
|
||||
|
@ -104,7 +106,7 @@
|
|||
(update m :block/properties (fnil conj [])
|
||||
[(assoc (select-keys property [:db/ident :db/valueType])
|
||||
:block/schema
|
||||
(select-keys (:block/schema property) [:type :cardinality])
|
||||
(select-keys (:block/schema property) [:type])
|
||||
:property/closed-values
|
||||
;; use explicit call to be nbb compatible
|
||||
(entity-plus/lookup-kv-then-entity property :property/closed-values))
|
||||
|
@ -141,7 +143,7 @@
|
|||
(map (fn [[k v]]
|
||||
(if-let [property (and (db-property/property? k)
|
||||
(entity-fn' k))]
|
||||
(if (and (= :db.cardinality/many (:db/cardinality property))
|
||||
(if (and (db-property/many? property)
|
||||
(not (set? v)))
|
||||
;; Fix :many property values that only had one value
|
||||
[k #{v}]
|
||||
|
@ -245,9 +247,7 @@
|
|||
|
||||
(def property-type-schema-attrs
|
||||
"Property :schema attributes that vary by :type"
|
||||
[;; For any types except for :checkbox :default :template
|
||||
[:cardinality {:optional true} [:enum :one :many]]
|
||||
;; For closed values
|
||||
[;; For closed values
|
||||
[:position {:optional true} :string]])
|
||||
|
||||
(def property-common-schema-attrs
|
||||
|
|
|
@ -302,3 +302,7 @@
|
|||
(:block/page block)
|
||||
;; not closed value
|
||||
(not (some? (:block/content block)))))
|
||||
|
||||
(defn many?
|
||||
[property]
|
||||
(= (:db/cardinality property) :db.cardinality/many))
|
||||
|
|
|
@ -43,8 +43,8 @@
|
|||
:number #{:cardinality}
|
||||
:date #{:cardinality}
|
||||
:url #{:cardinality}
|
||||
:page #{:cardinality}
|
||||
:template #{}
|
||||
:page #{:cardinality :classes}
|
||||
:template #{:classes}
|
||||
:checkbox #{}}))
|
||||
|
||||
(assert (= (set user-built-in-property-types) (set (keys user-built-in-allowed-schema-attributes)))
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
{:db/ident db-ident'
|
||||
:block/type "property"
|
||||
:block/format :markdown
|
||||
:block/schema (merge {:type :default} (dissoc prop-schema :classes))
|
||||
:block/schema (merge {:type :default} (dissoc prop-schema :classes :cardinality))
|
||||
:block/name (common-util/page-name-sanity-lc (name prop-name))
|
||||
:block/uuid (or block-uuid (d/squuid))
|
||||
:block/original-name (name prop-name)
|
||||
|
|
|
@ -274,7 +274,7 @@
|
|||
(when (db-property-type/property-type-allows-schema-attribute? (:type @*property-schema) :cardinality)
|
||||
[:div.grid.grid-cols-4.gap-1.items-center.leading-8
|
||||
[:label "Multiple values:"]
|
||||
(let [many? (boolean (= :many (:cardinality @*property-schema)))]
|
||||
(let [many? (db-property/many? property)]
|
||||
(shui/checkbox
|
||||
{:checked many?
|
||||
:disabled disabled?
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
([block property-key property-value] (<add-property! block property-key property-value {}))
|
||||
([block property-key property-value {:keys [exit-edit? class-schema?]
|
||||
:or {exit-edit? true}}]
|
||||
|
||||
(let [repo (state/get-current-repo)
|
||||
class? (contains? (:block/type block) "class")]
|
||||
(p/do!
|
||||
|
@ -95,18 +96,18 @@
|
|||
(exit-edit-property))))))
|
||||
|
||||
(defn- add-or-remove-property-value
|
||||
[block property value selected?]
|
||||
(let [many? (= :db/cardinality.many (:db/cardinality property))]
|
||||
[block property value selected? page?]
|
||||
(let [many? (db-property/many? property)]
|
||||
(if selected?
|
||||
(<add-property! block (:db/ident property) value
|
||||
{:exit-edit? (not many?)})
|
||||
(let [value' (if page? (:block/uuid (db/entity value)) value)]
|
||||
(<add-property! block (:db/ident property) value' {:exit-edit? (not many?)}))
|
||||
(p/do!
|
||||
(db/transact! (state/get-current-repo)
|
||||
(db/transact! (state/get-current-repo)
|
||||
[[:db/retract (:db/id block) (:db/ident property) value]]
|
||||
{:outliner-op :save-block})
|
||||
(when-not many?
|
||||
(shui/popup-hide!)
|
||||
(exit-edit-property))))))
|
||||
(when-not many?
|
||||
(shui/popup-hide!)
|
||||
(exit-edit-property))))))
|
||||
|
||||
(defn- navigate-to-date-page
|
||||
[value]
|
||||
|
@ -186,7 +187,7 @@
|
|||
|
||||
(rum/defc property-value-date-picker
|
||||
[block property value opts]
|
||||
(let [multiple-values? (= :many (:cardinality (:block/schema property)))]
|
||||
(let [multiple-values? (db-property/many? property)]
|
||||
(date-picker value
|
||||
(merge opts
|
||||
{:multiple-values? multiple-values?
|
||||
|
@ -329,7 +330,7 @@
|
|||
(when-not (string/blank? page*)
|
||||
(p/let [id (<create-page-if-not-exists! property classes' page*)]
|
||||
(when id
|
||||
(add-or-remove-property-value block property id selected?))))))}))]
|
||||
(add-or-remove-property-value block property id selected? true))))))}))]
|
||||
(select-aux block property opts')))
|
||||
|
||||
(defn property-value-select-page
|
||||
|
@ -413,7 +414,7 @@
|
|||
(remove nil?))
|
||||
on-chosen (fn [chosen selected?]
|
||||
(let [value (if (map? chosen) (:value chosen) chosen)]
|
||||
(add-or-remove-property-value block property value selected?)))
|
||||
(add-or-remove-property-value block property value selected? false)))
|
||||
selected-choices' (get block (:db/ident property))
|
||||
selected-choices (if (coll? selected-choices')
|
||||
(->> selected-choices'
|
||||
|
@ -457,7 +458,7 @@
|
|||
[block property value-block block-cp editor-box & {:keys [closed-values?]}]
|
||||
(if (and (:block/uuid value-block) (state/sub-async-query-loading (:block/uuid value-block)))
|
||||
[:div.text-sm.opacity-70 "loading"]
|
||||
(let [multiple-values? (= (:db/cardinality property) :db/cardinality.many)]
|
||||
(let [multiple-values? (db-property/many? property)]
|
||||
(if value-block
|
||||
[:div.property-block-container.content
|
||||
(block-cp [value-block] {:id (str (if multiple-values?
|
||||
|
@ -678,7 +679,7 @@
|
|||
editor-box]
|
||||
:as opts}]
|
||||
(let [schema (:block/schema property)
|
||||
multiple-values? (= :many (:cardinality schema))
|
||||
multiple-values? (db-property/many? property)
|
||||
class (str (when-not row? "flex flex-1 ")
|
||||
(when multiple-values? "property-value-content"))
|
||||
type (:type schema)
|
||||
|
@ -840,7 +841,7 @@
|
|||
editor-id (str dom-id "-editor")
|
||||
schema (:block/schema property)
|
||||
type (some-> schema (get :type :default))
|
||||
multiple-values? (= :many (:cardinality schema))
|
||||
multiple-values? (db-property/many? property)
|
||||
empty-value? (= :logseq.property/empty-placeholder v)
|
||||
editor-args {:block property
|
||||
:parent-block block
|
||||
|
|
|
@ -138,9 +138,10 @@
|
|||
(cond-> []
|
||||
(seq changed-property-attrs)
|
||||
(conj (outliner-core/block-with-updated-at
|
||||
(merge {:db/ident db-ident} changed-property-attrs)))
|
||||
(merge {:db/ident db-ident}
|
||||
(common-util/dissoc-in changed-property-attrs [:block/schema :cardinality]))))
|
||||
(or (not= (:type schema) (get-in property [:block/schema :type]))
|
||||
(not= (:cardinality schema) (get-in property [:block/schema :cardinality]))
|
||||
(and (:cardinality schema) (not= (:cardinality schema) (keyword (name (:db/cardinality property)))))
|
||||
(and (= :default (:type schema)) (not= :db.type/ref (:db/valueType property)))
|
||||
(seq (:property/closed-values property)))
|
||||
(conj (update-datascript-schema property schema)))
|
||||
|
@ -149,8 +150,7 @@
|
|||
(mapcat
|
||||
(fn [[property-id v]]
|
||||
(build-property-value-tx-data property property-id v)) properties)))
|
||||
many->one? (and (= (:db/cardinality property) :db.cardinality/many)
|
||||
(= :one (:cardinality schema)))]
|
||||
many->one? (and (db-property/many? property) (= :one (:cardinality schema)))]
|
||||
(when (seq tx-data)
|
||||
(db/transact! repo tx-data {:outliner-op :update-property
|
||||
:property-id (:db/id property)
|
||||
|
@ -169,48 +169,6 @@
|
|||
[schema value]
|
||||
(me/humanize (mu/explain-data schema value)))
|
||||
|
||||
(defn- set-block-property-multiple-values!
|
||||
"Sets values for a :many property. Most calls to this fn come from components
|
||||
that provide all existing values when updating. If this fn is called with a
|
||||
single value it's because it came from a component that doesn't have existing
|
||||
values. In this case the existing values are fetched and added to the new
|
||||
single value e.g. adding a new date"
|
||||
[repo block property one-or-many-values]
|
||||
(let [property-id (:db/ident property)
|
||||
values (if (coll? one-or-many-values)
|
||||
one-or-many-values
|
||||
(cond->> (some->> (:db/ident property) (get block))
|
||||
(= :db.type/ref (:db/valueType property))
|
||||
(mapv :db/id)
|
||||
;; single value means add to existing values
|
||||
true
|
||||
(into [one-or-many-values])
|
||||
true
|
||||
(remove nil?)))]
|
||||
(when (seq values)
|
||||
(let [property-schema (:block/schema property)
|
||||
property-type (:type property-schema)
|
||||
schema (get-property-value-schema property-type property)
|
||||
values' (try
|
||||
(set (map #(convert-property-input-string property-type %) values))
|
||||
(catch :default e
|
||||
(notification/show! (str e) :error false)
|
||||
nil))
|
||||
old-values (get block (:db/ident property))
|
||||
deleted-values (remove values' old-values)]
|
||||
(when (not= old-values values')
|
||||
(if-let [msg (validate-property-value schema values')]
|
||||
(let [msg' (str "\"" (:block/original-name property) "\"" " " (if (coll? msg) (first msg) msg))]
|
||||
(notification/show! msg' :warning))
|
||||
(do
|
||||
(upsert-property! repo property-id (assoc property-schema :type property-type) {})
|
||||
(let [tx-data (concat
|
||||
(map (fn [v]
|
||||
(let [v' (if (map? v) (:db/id v) v)]
|
||||
[:db/retract (:db/id block) property-id v'])) deleted-values)
|
||||
(build-property-value-tx-data block property-id values' false))]
|
||||
(db/transact! repo tx-data {:outliner-op :save-block})))))))))
|
||||
|
||||
(defn- resolve-tag
|
||||
"Change `v` to a tag's db id if v is a string tag, e.g. `#book`"
|
||||
[v]
|
||||
|
@ -246,7 +204,7 @@
|
|||
property (db/entity property-id)
|
||||
k-name (:block/original-name property)
|
||||
property-schema (:block/schema property)
|
||||
{:keys [type cardinality]} property-schema
|
||||
{:keys [type]} property-schema
|
||||
v' (or (resolve-tag v) v)
|
||||
db-attribute? (contains? db-property/db-attribute-properties property-id)]
|
||||
(cond
|
||||
|
@ -254,9 +212,6 @@
|
|||
(db/transact! repo [{:db/id (:db/id block) property-id v'}]
|
||||
{:outliner-op :save-block})
|
||||
|
||||
(= cardinality :many)
|
||||
(set-block-property-multiple-values! repo block property v')
|
||||
|
||||
:else
|
||||
(let [v'' (if property v' (or v' ""))]
|
||||
(when (some? v'')
|
||||
|
@ -336,13 +291,13 @@
|
|||
(let [type (:type (:block/schema property))
|
||||
infer-schema (when-not type (infer-schema-from-input-string v))
|
||||
property-type (or type infer-schema :default)
|
||||
{:keys [cardinality]} (:block/schema property)
|
||||
many? (db-property/many? property)
|
||||
status? (= :logseq.task/status (:db/ident property))
|
||||
txs (->>
|
||||
(mapcat
|
||||
(fn [eid]
|
||||
(when-let [block (db/entity eid)]
|
||||
(when (and (some? v) (not= cardinality :many))
|
||||
(when (and (some? v) (not many?))
|
||||
(when-let [v* (try
|
||||
(convert-property-input-string property-type v)
|
||||
(catch :default e
|
||||
|
@ -396,17 +351,16 @@
|
|||
(when block
|
||||
(when (not= property-id (:db/ident block))
|
||||
(when-let [property (db/entity property-id)]
|
||||
(let [schema (:block/schema property)]
|
||||
(if (= :many (:cardinality schema))
|
||||
(db/transact! repo
|
||||
[[:db/retract (:db/id block) property-id property-value]]
|
||||
{:outliner-op :save-block})
|
||||
(if (= :default (get-in property [:block/schema :type]))
|
||||
(set-block-property! repo (:db/id block)
|
||||
(:db/ident property)
|
||||
""
|
||||
{})
|
||||
(remove-block-property! repo (:db/id block) property-id))))))))
|
||||
(if (db-property/many? property)
|
||||
(db/transact! repo
|
||||
[[:db/retract (:db/id block) property-id property-value]]
|
||||
{:outliner-op :save-block})
|
||||
(if (= :default (get-in property [:block/schema :type]))
|
||||
(set-block-property! repo (:db/id block)
|
||||
(:db/ident property)
|
||||
""
|
||||
{})
|
||||
(remove-block-property! repo (:db/id block) property-id)))))))
|
||||
|
||||
(defn collapse-expand-property!
|
||||
"Notice this works only if the value itself if a block (property type should be either :default or :template)"
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
[frontend.test.helper :as test-helper]
|
||||
[datascript.core :as d]
|
||||
[frontend.state :as state]
|
||||
[frontend.handler.page :as page-handler]))
|
||||
[frontend.handler.page :as page-handler]
|
||||
[logseq.db.frontend.property :as db-property]))
|
||||
|
||||
(def repo test-helper/test-db-name-db-version)
|
||||
|
||||
|
@ -222,7 +223,7 @@
|
|||
(let [repo (state/get-current-repo)]
|
||||
(db-property-handler/upsert-property! repo nil {:type :default} {:property-name "p0"})
|
||||
(db-property-handler/upsert-property! repo :user.property/p0 {:type :default :cardinality :many} {})
|
||||
(is (= :many (get-in (db/entity repo :user.property/p0) [:block/schema :cardinality])))))
|
||||
(is (db-property/many? (db/entity repo :user.property/p0)))))
|
||||
(testing "Multiple properties that generate the same initial :db/ident"
|
||||
(let [repo (state/get-current-repo)]
|
||||
(db-property-handler/upsert-property! repo nil {:type :default} {:property-name "p1"})
|
||||
|
|
Loading…
Reference in New Issue