fix(regression): specify node tags

pull/11491/head
Tienson Qin 2024-08-28 12:06:47 +08:00
parent c6a1e6b107
commit 80737d624c
2 changed files with 132 additions and 111 deletions

View File

@ -14,10 +14,8 @@
[frontend.db :as db]
[frontend.db-mixins :as db-mixins]
[frontend.db.async :as db-async]
[frontend.db.model :as model]
[frontend.handler.db-based.property :as db-property-handler]
[frontend.handler.notification :as notification]
[frontend.handler.page :as page-handler]
[frontend.handler.route :as route-handler]
[frontend.mixins :as mixins]
[frontend.modules.shortcut.core :as shortcut]
@ -34,80 +32,6 @@
[promesa.core :as p]
[rum.core :as rum]))
(defn- <create-class-if-not-exists!
[value]
(when (string? value)
(let [page-name (string/trim value)]
(when-not (string/blank? page-name)
(p/let [page (page-handler/<create-class! page-name {:redirect? false
:create-first-block? false})]
(:block/uuid page))))))
(rum/defc class-select
[property {:keys [multiple-choices? disabled? default-open? no-class? on-hide]
:or {multiple-choices? true}}]
(let [*ref (rum/use-ref nil)]
(rum/use-effect!
(fn []
(when default-open?
(some-> (rum/deref *ref)
(.click))))
[default-open?])
(let [schema-classes (:property/schema.classes property)]
[:div.flex.flex-1.col-span-3
(let [content-fn
(fn [{:keys [id]}]
(let [toggle-fn #(do
(when (fn? on-hide) (on-hide))
(shui/popup-hide! id))
classes (model/get-all-classes (state/get-current-repo) {:except-root-class? true})
options (map (fn [class]
{:label (:block/title class)
:value (:block/uuid class)})
classes)
options (if no-class?
(cons {:label "Skip choosing tag"
:value :no-tag}
options)
options)
opts {:items options
:input-default-placeholder (if multiple-choices? "Choose tags" "Choose tag")
:dropdown? false
:close-modal? false
:multiple-choices? multiple-choices?
:selected-choices (map :block/uuid schema-classes)
:extract-fn :label
:extract-chosen-fn :value
:show-new-when-not-exact-match? true
:input-opts {:on-key-down
(fn [e]
(case (util/ekey e)
"Escape"
(do
(util/stop e)
(toggle-fn))
nil))}
:on-chosen (fn [value select?]
(if (= value :no-tag)
(toggle-fn)
(p/let [result (<create-class-if-not-exists! value)
value' (or result value)
tx-data [[(if select? :db/add :db/retract) (:db/id property) :property/schema.classes [:block/uuid value']]]
_ (db/transact! (state/get-current-repo) tx-data {:outliner-op :update-property})]
(when-not multiple-choices? (toggle-fn)))))}]
(select/select opts)))]
[:div.flex.flex-1.cursor-pointer
{:ref *ref
:on-click (if disabled?
(constantly nil)
#(shui/popup-show! (.-target %) content-fn))}
(if (seq schema-classes)
[:div.flex.flex-1.flex-row.items-center.flex-wrap.gap-2
(for [class schema-classes]
[:a.text-sm (str "#" (:block/title class))])]
(pv/property-empty-btn-value))])])))
(defn- property-type-label
[property-type]
@ -366,25 +290,25 @@
(rum/local false ::show-class-select?)
(rum/local {} ::property-schema)
(mixins/event-mixin
(fn [state]
(mixins/hide-when-esc-or-outside
state
:on-hide (fn [_state _e type]
(when (= type :esc)
(shui/popup-hide!)
(shui/dialog-close!)
(when-let [^js input (state/get-input)]
(.focus input)))))))
(fn [state]
(mixins/hide-when-esc-or-outside
state
:on-hide (fn [_state _e type]
(when (= type :esc)
(shui/popup-hide!)
(shui/dialog-close!)
(when-let [^js input (state/get-input)]
(.focus input)))))))
{:init (fn [state]
(state/set-editor-action! :property-input)
(assoc state ::property (or (:*property (last (:rum/args state)))
(atom nil))))
(atom nil))))
:will-unmount (fn [state]
(let [args (:rum/args state)
*property-key (second args)
{:keys [original-block edit-original-block]} (last args)
editing-default-property? (and original-block (state/get-edit-block)
(not= (:db/id original-block) (:db/id (state/get-edit-block))))]
(not= (:db/id original-block) (:db/id (state/get-edit-block))))]
(when *property-key (reset! *property-key nil))
(when (and original-block edit-original-block)
(edit-original-block {:editing-default-property? editing-default-property?})))
@ -398,14 +322,14 @@
*show-class-select? (::show-class-select? state)
*property-schema (::property-schema state)
existing-tag-alias (->> db-property/db-attribute-properties
(map db-property/built-in-properties)
(keep #(when (get block (:attribute %)) (:title %)))
set)
(map db-property/built-in-properties)
(keep #(when (get block (:attribute %)) (:title %)))
set)
exclude-properties (fn [m]
(or (and (not page?) (contains? existing-tag-alias (:block/title m)))
;; Filters out properties from being in wrong :view-context
(and (not page?) (= :page (get-in m [:block/schema :view-context])))
(and page? (= :block (get-in m [:block/schema :view-context])))))
(and (not page?) (= :page (get-in m [:block/schema :view-context])))
(and page? (= :block (get-in m [:block/schema :view-context])))))
property (rum/react *property)
property-key (rum/react *property-key)]
[:div.ls-property-input.flex.flex-1.flex-row.items-center.flex-wrap.gap-1
@ -422,20 +346,20 @@
(cond
@*show-new-property-config?
(property-type-select property (merge opts
{:*property *property
:*property-name *property-key
:*property-schema *property-schema
:default-open? true
:block block
:*show-new-property-config? *show-new-property-config?
:*show-class-select? *show-class-select?}))
{:*property *property
:*property-name *property-key
:*property-schema *property-schema
:default-open? true
:block block
:*show-new-property-config? *show-new-property-config?
:*show-class-select? *show-class-select?}))
(and property @*show-class-select?)
(class-select property (assoc opts
:on-hide #(reset! *show-class-select? false)
:multiple-choices? false
:default-open? true
:no-class? true))
(property-config/class-select property (assoc opts
:on-hide #(reset! *show-class-select? false)
:multiple-choices? false
:default-open? true
:no-class? true))
:else
(when (and property (not class-schema?))
@ -446,7 +370,7 @@
(fn [e]
;; `Backspace` to close property popup and back to editing the current block
(when (and (= (util/ekey e) "Backspace")
(= "" (.-value (.-target e))))
(= "" (.-value (.-target e))))
(util/stop e)
(shui/popup-hide!)))}]
(property-select exclude-properties {:on-chosen on-chosen

View File

@ -21,7 +21,13 @@
[promesa.core :as p]
[goog.dom :as gdom]
[rum.core :as rum]
[frontend.db-mixins :as db-mixins]))
[frontend.db-mixins :as db-mixins]
[frontend.components.property.value :as pv]
[frontend.components.select :as select]
[frontend.db.model :as model]
[frontend.handler.page :as page-handler]
[frontend.ui :as ui]
[frontend.components.svg :as svg]))
(defn- re-init-commands!
"Update commands after task status and priority's closed values has been changed"
@ -64,6 +70,81 @@
(:db/id property)
:logseq.property/description description))))
(defn- <create-class-if-not-exists!
[value]
(when (string? value)
(let [page-name (string/trim value)]
(when-not (string/blank? page-name)
(p/let [page (page-handler/<create-class! page-name {:redirect? false
:create-first-block? false})]
(:block/uuid page))))))
(rum/defc class-select
[property {:keys [multiple-choices? disabled? default-open? no-class? on-hide]
:or {multiple-choices? true}}]
(let [*ref (rum/use-ref nil)]
(rum/use-effect!
(fn []
(when default-open?
(some-> (rum/deref *ref)
(.click))))
[default-open?])
(let [schema-classes (:property/schema.classes property)]
[:div.flex.flex-1.col-span-3
(let [content-fn
(fn [{:keys [id]}]
(let [toggle-fn #(do
(when (fn? on-hide) (on-hide))
(shui/popup-hide! id))
classes (model/get-all-classes (state/get-current-repo) {:except-root-class? true})
options (map (fn [class]
{:label (:block/title class)
:value (:block/uuid class)})
classes)
options (if no-class?
(cons {:label "Skip choosing tag"
:value :no-tag}
options)
options)
opts {:items options
:input-default-placeholder (if multiple-choices? "Choose tags" "Choose tag")
:dropdown? false
:close-modal? false
:multiple-choices? multiple-choices?
:selected-choices (map :block/uuid schema-classes)
:extract-fn :label
:extract-chosen-fn :value
:show-new-when-not-exact-match? true
:input-opts {:on-key-down
(fn [e]
(case (util/ekey e)
"Escape"
(do
(util/stop e)
(toggle-fn))
nil))}
:on-chosen (fn [value select?]
(if (= value :no-tag)
(toggle-fn)
(p/let [result (<create-class-if-not-exists! value)
value' (or result value)
tx-data [[(if select? :db/add :db/retract) (:db/id property) :property/schema.classes [:block/uuid value']]]
_ (db/transact! (state/get-current-repo) tx-data {:outliner-op :update-property})]
(when-not multiple-choices? (toggle-fn)))))}]
(select/select opts)))]
[:div.flex.flex-1.cursor-pointer
{:ref *ref
:on-click (if disabled?
(constantly nil)
#(shui/popup-show! (.-target %) content-fn))}
(if (seq schema-classes)
[:div.flex.flex-1.flex-row.items-center.flex-wrap.gap-2
(for [class schema-classes]
[:a.text-sm (str "#" (:block/title class))])]
(pv/property-empty-btn-value))])])))
(rum/defc name-edit-pane
[property {:keys [set-sub-open! disabled?]}]
(let [*form-data (rum/use-ref {:icon (:logseq.property/icon property)
@ -201,7 +282,8 @@
[:div.inner-wrap
{:class (util/classnames [{:disabled disabled?}])}
[:strong
(some-> icon (name) (shui/tabler-icon))
(some-> icon (name) (shui/tabler-icon {:size 14
:style {:margin-top "-1"}}))
[:span title]]
(if (fn? desc) (desc)
(if (boolean? toggle-checked?)
@ -403,16 +485,31 @@
built-in? (ldb/built-in? property)
disabled? (or built-in? config/publishing?)]
[:<>
(dropdown-editor-menuitem {:icon :edit :title "Property name" :desc [:span.flex.items-center.gap-1 icon title]
(dropdown-editor-menuitem {:icon :pencil :title "Property name" :desc [:span.flex.items-center.gap-1 icon title]
:submenu-content (fn [ops] (name-edit-pane property (assoc ops :disabled? disabled?)))})
(let [disabled? (or (ldb/built-in? property) (and property-type (seq values)))]
(dropdown-editor-menuitem {:icon :hash
:title "Property type"
:desc (str property-type-label')
:desc (if disabled?
(ui/tippy {:html [:div.w-96
"The type of this property is locked once you start using it. This is to make sure all your existing information stays correct if the property type is changed later. To unlock, all uses of a property must be deleted."]
:class "tippy-hover ml-2"
:interactive true
:disabled false}
(str property-type-label'))
(str property-type-label'))
:disabled? disabled?
:submenu-content (fn [ops]
(property-type-sub-pane property ops))}))
(when (= property-type :node)
(dropdown-editor-menuitem {:icon :hash
:title "Specify node tags"
:desc ""
:submenu-content (fn [_ops]
[:div.px-4
(class-select property {:default-open? false})])}))
(when enable-closed-values? (empty? (:property/schema.classes property))
(let [values (:property/closed-values property)]
(dropdown-editor-menuitem {:icon :list :title "Available choices"
@ -448,8 +545,8 @@
(when owner-block
(dropdown-editor-menuitem
{:id :remove-property :icon :square-x :title "Delete property" :desc "" :disabled? false
:item-props {:class "opacity-60 focus:opacity-100 focus:!text-red-rx-09"
{:id :remove-property :icon :x :title "Remove property" :desc "" :disabled? false
:item-props {:class "opacity-60 focus:!text-red-rx-09 focus:opacity-100"
:on-select (fn [^js e]
(util/stop e)
(-> (p/do!