Forráskód Böngészése

fix: page auto-complete in query builder

This commit also adds `loading?` to ui/select to display a spinner
when it's loading data from the worker db.
Tienson Qin 6 hónapja
szülő
commit
f66627c280

+ 4 - 2
src/main/frontend/components/query.cljs

@@ -61,8 +61,10 @@
            (util/hiccup-keywordize result))
 
          (and db-graph? (not (:built-in-query? config)))
-         (query-view/query-result (assoc config :id (str (:block/uuid current-block)))
-                                  current-block result)
+         (when-let [query (:logseq.property/query current-block)]
+           (when-not (string/blank? (:block/title query))
+             (query-view/query-result (assoc config :id (str (:block/uuid current-block)))
+                                      current-block result)))
 
          (and (not db-graph?)
               (or page-list? table?))

+ 26 - 18
src/main/frontend/components/query/builder.cljs

@@ -224,6 +224,19 @@
               (fn [{:keys [value]}]
                 (append-tree! *tree opts loc [(if db-based? :tags :page-tags) value]))))))
 
+(rum/defc page-search
+  [on-chosen]
+  (let [[result set-result!] (hooks/use-state nil)
+        [loading? set-loading!] (hooks/use-state nil)]
+    (hooks/use-effect!
+     (fn []
+       (set-loading! true)
+       (p/let [result (state/<invoke-db-worker :thread-api/get-all-page-titles (state/get-current-repo))]
+         (set-result! result)
+         (set-loading! false)))
+     [])
+    (select result on-chosen {:loading? loading?})))
+
 (defn- db-based-query-filter-picker
   [state *find *tree loc clause opts]
   (let [*mode (::mode state)
@@ -277,18 +290,16 @@
                               (append-tree! *tree opts loc (vec (cons :priority choices)))))})
 
        "page"
-       (let [pages (sort (db-model/get-all-page-titles repo))]
-         (select pages
-                 (fn [{:keys [value]}]
-                   (append-tree! *tree opts loc [:page value]))))
+       (page-search (fn [{:keys [value]}]
+                      (append-tree! *tree opts loc [:page value]))
+                    {})
 
        ;; TODO: replace with node reference
        "page reference"
-       (let [pages (sort (db-model/get-all-page-titles repo))]
-         (select pages
-                 (fn [{:keys [value]}]
-                   (append-tree! *tree opts loc [:page-ref value]))
-                 {}))
+
+       (page-search (fn [{:keys [value]}]
+                      (append-tree! *tree opts loc [:page-ref value]))
+                    {})
 
        "full text search"
        (search (fn [v] (append-tree! *tree opts loc v))
@@ -362,17 +373,14 @@
                               (append-tree! *tree opts loc (vec (cons :priority choices)))))})
 
        "page"
-       (let [pages (sort (db-model/get-all-page-titles repo))]
-         (select pages
-                 (fn [{:keys [value]}]
-                   (append-tree! *tree opts loc [:page value]))))
+       (page-search (fn [{:keys [value]}]
+                      (append-tree! *tree opts loc [:page value]))
+                    {})
 
        "page reference"
-       (let [pages (sort (db-model/get-all-page-titles repo))]
-         (select pages
-                 (fn [{:keys [value]}]
-                   (append-tree! *tree opts loc [:page-ref value]))
-                 {}))
+       (page-search (fn [{:keys [value]}]
+                      (append-tree! *tree opts loc [:page-ref value]))
+                    {})
 
        "full text search"
        (search (fn [v] (append-tree! *tree opts loc v))

+ 69 - 50
src/main/frontend/components/select.cljs

@@ -8,6 +8,7 @@
             [frontend.context.i18n :refer [t]]
             [frontend.handler.common.developer :as dev-common-handler]
             [frontend.handler.repo :as repo-handler]
+            [frontend.hooks :as hooks]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.search :as search]
             [frontend.state :as state]
@@ -43,6 +44,27 @@
        row]
       row)))
 
+(rum/defc search-input
+  [*input {:keys [prompt-key input-default-placeholder input-opts on-input]}]
+  (let [[input set-input!] (hooks/use-state @*input)]
+    (hooks/use-effect!
+     (fn []
+       (reset! *input input)
+       (when (fn? on-input) (on-input input)))
+     [(hooks/use-debounced-value input 100)])
+    [:div.input-wrap
+     {:style {:margin-bottom "-2px"}}
+     [:input.cp__select-input.w-full
+      (merge {:type        "text"
+              :class "!p-1.5"
+              :placeholder (or input-default-placeholder (t prompt-key))
+              :auto-focus  true
+              :value       input
+              :on-change   (fn [e]
+                             (let [v (util/evalue e)]
+                               (set-input! v)))}
+             input-opts)]]))
+
 (rum/defcs ^:large-vars/cleanup-todo select
   "Provides a select dropdown powered by a fuzzy search. Takes the following options:
    * :items - Vec of things to select from. Assumes a vec of maps with :value key by default. Required option
@@ -54,6 +76,7 @@
    * :exact-match-exclude-items - A set of strings that can't be added as a new item. Default is #{}
    * :transform-fn - Optional fn to transform search results given results and current input
    * :new-case-sensitive? - Boolean to allow new values to be case sensitive
+   * :loading? - whether it's loading the items
    TODO: Describe more options"
   < rum/reactive
   shortcut/disable-all-shortcuts
@@ -76,7 +99,7 @@
                  item-cp transform-fn tap-*input-val
                  multiple-choices? on-apply new-case-sensitive?
                  dropdown? show-new-when-not-exact-match? exact-match-exclude-items
-                 input-container initial-open?]
+                 input-container initial-open? loading?]
           :or {limit 100
                prompt-key :select/default-prompt
                empty-placeholder (fn [_t] [:div])
@@ -123,54 +146,50 @@
         input-opts' (if (fn? input-opts) (input-opts (empty? search-result)) input-opts)
         input-container (or
                          input-container
-                         [:div.input-wrap
-                          {:style {:margin-bottom "-2px"}}
-                          [:input.cp__select-input.w-full
-                           (merge {:type        "text"
-                                   :class "!p-1.5"
-                                   :placeholder (or input-default-placeholder (t prompt-key))
-                                   :auto-focus  true
-                                   :value       @input
-                                   :on-change   (fn [e]
-                                                  (let [v (util/evalue e)]
-                                                    (reset! input v)
-                                                    (and (fn? on-input) (on-input v))))}
-                                  input-opts')]])
-        results-container [:div
-                           {:class (when (seq search-result) "py-1")}
-                           [:div.item-results-wrap
-                            (ui/auto-complete
-                             search-result
-                             {:grouped? grouped?
-                              :item-render       (or item-cp (fn [result chosen?]
-                                                               (render-item result chosen? multiple-choices? *selected-choices)))
-                              :class             "cp__select-results"
-                              :on-chosen         (fn [raw-chosen e]
-                                                   (reset! input "")
-                                                   (let [chosen (extract-chosen-fn raw-chosen)]
-                                                     (if multiple-choices?
-                                                       (if (selected-choices chosen)
-                                                         (do
-                                                           (swap! *selected-choices disj chosen)
-                                                           (when on-chosen (on-chosen chosen false @*selected-choices e)))
-                                                         (do
-                                                           (swap! *selected-choices conj chosen)
-                                                           (when on-chosen (on-chosen chosen true @*selected-choices e))))
-                                                       (do
-                                                         (when (and close-modal? (not multiple-choices?))
-                                                           (state/close-modal!))
-                                                         (when on-chosen
-                                                           (on-chosen chosen true @*selected-choices e))))))
-                              :empty-placeholder (empty-placeholder t)})]
+                         (search-input input
+                                       {:prompt-key prompt-key
+                                        :input-default-placeholder input-default-placeholder
+                                        :input-opts input-opts'
+                                        :on-input on-input}))
+        results-container-f (fn []
+                              (if loading?
+                                [:div.px-1.py-2
+                                 (ui/loading "Loading ...")]
+                                [:div
+                                 {:class (when (seq search-result) "py-1")}
+                                 [:div.item-results-wrap
+                                  (ui/auto-complete
+                                   search-result
+                                   {:grouped? grouped?
+                                    :item-render       (or item-cp (fn [result chosen?]
+                                                                     (render-item result chosen? multiple-choices? *selected-choices)))
+                                    :class             "cp__select-results"
+                                    :on-chosen         (fn [raw-chosen e]
+                                                         (reset! input "")
+                                                         (let [chosen (extract-chosen-fn raw-chosen)]
+                                                           (if multiple-choices?
+                                                             (if (selected-choices chosen)
+                                                               (do
+                                                                 (swap! *selected-choices disj chosen)
+                                                                 (when on-chosen (on-chosen chosen false @*selected-choices e)))
+                                                               (do
+                                                                 (swap! *selected-choices conj chosen)
+                                                                 (when on-chosen (on-chosen chosen true @*selected-choices e))))
+                                                             (do
+                                                               (when (and close-modal? (not multiple-choices?))
+                                                                 (state/close-modal!))
+                                                               (when on-chosen
+                                                                 (on-chosen chosen true @*selected-choices e))))))
+                                    :empty-placeholder (empty-placeholder t)})]
 
-                           (when (and multiple-choices? (fn? on-apply))
-                             [:div.p-4 (ui/button "Apply"
-                                                  {:small? true
-                                                   :on-pointer-down (fn [e]
-                                                                      (util/stop e)
-                                                                      (when @*toggle (@*toggle))
-                                                                      (on-apply selected-choices)
-                                                                      (when close-modal? (state/close-modal!)))})])]]
+                                 (when (and multiple-choices? (fn? on-apply))
+                                   [:div.p-4 (ui/button "Apply"
+                                                        {:small? true
+                                                         :on-pointer-down (fn [e]
+                                                                            (util/stop e)
+                                                                            (when @*toggle (@*toggle))
+                                                                            (on-apply selected-choices)
+                                                                            (when close-modal? (state/close-modal!)))})])]))]
     (when (fn? tap-*input-val)
       (tap-*input-val input))
     [:div.cp__select
@@ -180,12 +199,12 @@
      (if dropdown?
        (ui/dropdown
         (if (fn? input-container) input-container (fn [] input-container))
-        (fn [] results-container)
+        results-container-f
         {:initial-open? initial-open?
          :*toggle-fn *toggle})
        [:<>
         (if (fn? input-container) (input-container) input-container)
-        results-container])]))
+        (results-container-f)])]))
 
 (defn select-config
   "Config that supports multiple types (uses) of this component. To add a new

+ 1 - 1
src/main/frontend/extensions/handbooks/core.cljs

@@ -534,7 +534,7 @@
 
         [scrolled?, set-scrolled!] (rum/use-state false)
         on-scroll (hooks/use-memo
-                   #(util/debounce 100 (fn [^js e] (set-scrolled! (not (< (.. e -target -scrollTop) 10)))))
+                   #(util/debounce (fn [^js e] (set-scrolled! (not (< (.. e -target -scrollTop) 10)))) 100)
                    [])]
 
     ;; load handbooks

+ 20 - 0
src/main/frontend/worker/db_worker.cljs

@@ -770,6 +770,26 @@
   (let [conn (worker-state/get-datascript-conn repo)]
     (db-graph/build-graph @conn option)))
 
+(def ^:private *get-all-page-titles-cache (volatile! (cache/lru-cache-factory {})))
+(defn- get-all-page-titles
+  [db]
+  (let [pages (ldb/get-all-pages db)]
+    (sort (map :block/title pages))))
+
+(def ^:private get-all-page-titles-with-cache
+  (common.cache/cache-fn
+   *get-all-page-titles-cache
+   (fn [repo]
+     (let [db @(worker-state/get-datascript-conn repo)]
+       [[repo (:max-tx db)] ;cache-key
+        [db]             ;f-args
+        ]))
+   get-all-page-titles))
+
+(def-thread-api :thread-api/get-all-page-titles
+  [repo]
+  (get-all-page-titles-with-cache repo))
+
 (comment
   (def-thread-api :general/dangerousRemoveAllDbs
     []