1
0
Эх сурвалжийг харах

enhance(ux): filter by empty and not empty value

Tienson Qin 2 сар өмнө
parent
commit
12e1f35cc4

+ 42 - 31
deps/db/src/logseq/db/common/view.cljs

@@ -156,6 +156,13 @@
   (or (:db/ident property-value-entity)
       (not (contains? db-property-type/closed-value-property-types (:logseq.property/type property-entity)))))
 
+(defn- empty-value?
+  [v]
+  (or (nil? v)
+      (= :logseq.property/empty-placeholder v)
+      (and (string? v) (string/blank? v))
+      (and (coll? v) (empty? v))))
+
 (defn- ^:large-vars/cleanup-todo row-matched?
   [db row filters input]
   (let [or? (:or? filters)
@@ -172,46 +179,50 @@
            (let [value (get row property-ident)
                  value' (cond
                           (set? value) value
-                          (nil? value) #{}
+                          (nil? value) nil
                           :else #{value})
                  entity? (de/entity? (first value'))
                  result
                  (case operator
                    :is
-                   (if (boolean? match)
+                   (cond
+                     (boolean? match)
                      (= (boolean (get-property-value-content db (get row property-ident))) match)
-                     (cond
-                       (empty? match)
-                       true
-                       (and (empty? match) (empty? value'))
-                       true
-                       :else
-                       (if entity?
-                         (let [property (d/entity db property-ident)]
-                           (if (match-property-value-as-entity? (first value') property)
-                             (boolean (seq (set/intersection (set (map :block/uuid value')) match)))
-                             (boolean (seq (set/intersection (set (map db-property/property-value-content value'))
-                                                             (set (map (comp db-property/property-value-content #(d/entity db [:block/uuid %]))
-                                                                       match)))))))
-                         (boolean (seq (set/intersection (set value') match))))))
+                     (= :empty match)
+                     (empty-value? value)
+                     (empty? match)
+                     true
+                     (and (empty? match) (empty? value'))
+                     true
+                     :else
+                     (if entity?
+                       (let [property (d/entity db property-ident)]
+                         (if (match-property-value-as-entity? (first value') property)
+                           (boolean (seq (set/intersection (set (map :block/uuid value')) match)))
+                           (boolean (seq (set/intersection (set (map db-property/property-value-content value'))
+                                                           (set (map (comp db-property/property-value-content #(d/entity db [:block/uuid %]))
+                                                                     match)))))))
+                       (boolean (seq (set/intersection (set value') match)))))
 
                    :is-not
-                   (if (boolean? match)
+                   (cond
+                     (boolean? match)
                      (not= (boolean (get-property-value-content db (get row property-ident))) match)
-                     (cond
-                       (and (empty? match) (seq value'))
-                       true
-                       (and (seq match) (empty? value'))
-                       true
-                       :else
-                       (if entity?
-                         (let [property (d/entity db property-ident)]
-                           (if (match-property-value-as-entity? (first value') property)
-                             (boolean (empty? (set/intersection (set (map :block/uuid value')) match)))
-                             (boolean (empty? (set/intersection (set (map db-property/property-value-content value'))
-                                                                (set (map (comp db-property/property-value-content #(d/entity db [:block/uuid %]))
-                                                                          match)))))))
-                         (boolean (empty? (set/intersection (set value') match))))))
+                     (= :empty match)
+                     (not (empty-value? value))
+                     (and (empty? match) (seq value'))
+                     true
+                     (and (seq match) (empty? value'))
+                     true
+                     :else
+                     (if entity?
+                       (let [property (d/entity db property-ident)]
+                         (if (match-property-value-as-entity? (first value') property)
+                           (boolean (empty? (set/intersection (set (map :block/uuid value')) match)))
+                           (boolean (empty? (set/intersection (set (map db-property/property-value-content value'))
+                                                              (set (map (comp db-property/property-value-content #(d/entity db [:block/uuid %]))
+                                                                        match)))))))
+                       (boolean (empty? (set/intersection (set value') match)))))
 
                    :text-contains
                    (some (fn [v]

+ 41 - 5
src/main/frontend/components/views.cljs

@@ -980,7 +980,7 @@
    {:value "Custom date"
     :label "Custom date"}])
 
-(rum/defc filter-property < rum/static
+(rum/defc ^:large-vars/cleanup-todo filter-property < rum/static
   [view-entity columns {:keys [data-fns] :as table} opts]
   (let [[property set-property!] (rum/use-state nil)
         [values set-values!] (rum/use-state nil)
@@ -1076,7 +1076,24 @@
                                                              :filters filters'})))})))
                    :else
                    option)]
-      (select/select option))))
+      (if (and property (not (contains? #{:block/created-at :block/updated-at} (:db/ident property))))
+        [:div.flex.flex-col.gap-1.text-sm
+         (select/select option)
+         (shui/button {:variant :ghost :size :sm :class "justify-start"
+                       :on-click (fn []
+                                   (let [filters' (conj (:filters filters) [(:db/ident property) :is :empty])]
+                                     (set-filters! {:or? (:or? filters)
+                                                    :filters filters'})))}
+                      [:span.opacity-75.hover:opacity-100.font-normal.text-sm
+                       "Is Empty"])
+         (shui/button {:variant :ghost :size :sm :class "justify-start"
+                       :on-click (fn []
+                                   (let [filters' (conj (:filters filters) [(:db/ident property) :is-not :empty])]
+                                     (set-filters! {:or? (:or? filters)
+                                                    :filters filters'})))}
+                      [:span.opacity-75.hover:opacity-100.font-normal.text-sm
+                       "Is Not Empty"])]
+        (select/select option)))))
 
 (rum/defc filter-properties < rum/static
   [view-entity columns table opts]
@@ -1111,11 +1128,13 @@
 
 (defn get-property-operators
   [property]
-  (if (datetime-property? property)
+  (if (contains? #{:block/created-at :block/updated-at} (:db/ident property))
     [:before :after]
     (concat
      [:is :is-not]
      (case (:logseq.property/type property)
+       (:datetime)
+       [:before :after]
        (:default :url :node)
        [:text-contains :text-not-contains]
        (:date)
@@ -1281,8 +1300,22 @@
                                         many?
                                         (assoc
                                          :multiple-choices? true
-                                         :selected-choices value))]
-                           (select/select option)))
+                                         :selected-choices (when (coll? value) value)))]
+                           (if (and (contains? #{:is :is-not} operator)
+                                    (not (contains? #{:block/created-at :block/updated-at} (:db/ident property))))
+                             [:div.flex.flex-col.gap-1
+                              (select/select option)
+                              (shui/button {:variant :ghost :size :sm :class "justify-start"
+                                            :on-click (fn []
+                                                        (let [new-filters (update filters :filters
+                                                                                  (fn [col]
+                                                                                    (update col idx
+                                                                                            (fn [[property operator _value]]
+                                                                                              [property operator :empty]))))]
+                                                          (set-filters! new-filters)))}
+                                           [:span.opacity-75.hover:opacity-100.font-normal.text-sm
+                                            "Empty"])]
+                             (select/select option))))
                        {:align :start})))}
        (let [value (cond
                      (uuid? value)
@@ -1306,6 +1339,9 @@
             (boolean? value)
             [:div (str value)]
 
+            (= value :empty)
+            [:div "Empty"]
+
             (seq value)
             (->> (map (fn [v] [:div (get-property-value-content v)]) value)
                  (interpose [:div "or"]))