|
|
@@ -15,7 +15,7 @@
|
|
|
[frontend.modules.outliner.tree :as tree]))
|
|
|
|
|
|
;; Util fns
|
|
|
-;; ================
|
|
|
+;; ========
|
|
|
(defn- attach-clock-property
|
|
|
[result]
|
|
|
(let [ks [:block/properties :clock-time]
|
|
|
@@ -27,8 +27,8 @@
|
|
|
(map #(medley/dissoc-in % ks) result)
|
|
|
result)))
|
|
|
|
|
|
-(defn- sort-by-fn [sort-by-item item]
|
|
|
- (case sort-by-item
|
|
|
+(defn- sort-by-fn [sort-by-column item]
|
|
|
+ (case sort-by-column
|
|
|
:created-at
|
|
|
(:block/created-at item)
|
|
|
:updated-at
|
|
|
@@ -37,66 +37,48 @@
|
|
|
(:block/content item)
|
|
|
:page
|
|
|
(:block/name item)
|
|
|
- (get-in item [:block/properties sort-by-item])))
|
|
|
+ (get-in item [:block/properties sort-by-column])))
|
|
|
|
|
|
-(defn- desc?
|
|
|
- [*desc? p-desc?]
|
|
|
- (cond
|
|
|
- (some? @*desc?)
|
|
|
- @*desc?
|
|
|
- (some? p-desc?)
|
|
|
- p-desc?
|
|
|
- :else
|
|
|
- true))
|
|
|
+(defn- sort-result [result {:keys [sort-by-column sort-desc?]}]
|
|
|
+ (if (some? sort-by-column)
|
|
|
+ (let [comp (if sort-desc? > <)]
|
|
|
+ (sort-by (fn [item]
|
|
|
+ (block/normalize-block (sort-by-fn sort-by-column item)))
|
|
|
+ comp
|
|
|
+ result))
|
|
|
+ result))
|
|
|
|
|
|
(defn- get-sort-state
|
|
|
- "Return current sort direction and column (item) being sorted, respectively
|
|
|
- :sort-desc? and :sort-by-item. :sort-by-item is nil if no sorting is to be
|
|
|
+ "Return current sort direction and column being sorted, respectively
|
|
|
+ :sort-desc? and :sort-by-column. :sort-by-column is nil if no sorting is to be
|
|
|
done"
|
|
|
- [state current-block]
|
|
|
- (let [*sort-by-item (get state ::sort-by-item)
|
|
|
- *desc? (get state ::desc?)
|
|
|
- p-desc? (get-in current-block [:block/properties :query-sort-desc])
|
|
|
- desc? (desc? *desc? p-desc?)
|
|
|
+ [current-block]
|
|
|
+ (let [p-desc? (get-in current-block [:block/properties :query-sort-desc])
|
|
|
+ desc? (if (some? p-desc?) p-desc? true)
|
|
|
p-sort-by (keyword (get-in current-block [:block/properties :query-sort-by]))
|
|
|
- sort-by-item (or @*sort-by-item
|
|
|
- (some-> p-sort-by keyword)
|
|
|
+ sort-by-column (or (some-> p-sort-by keyword)
|
|
|
(if (query-dsl/query-contains-filter? (:block/content current-block) "sort-by")
|
|
|
nil
|
|
|
:updated-at))]
|
|
|
{:sort-desc? desc?
|
|
|
- :sort-by-item sort-by-item}))
|
|
|
-
|
|
|
-(defn- sort-result [result {:keys [sort-by-item sort-desc?]}]
|
|
|
- (if (some? sort-by-item)
|
|
|
- (let [comp (if sort-desc? > <)]
|
|
|
- (sort-by (fn [item]
|
|
|
- (block/normalize-block (sort-by-fn sort-by-item item)))
|
|
|
- comp
|
|
|
- result))
|
|
|
- result))
|
|
|
+ :sort-by-column sort-by-column}))
|
|
|
|
|
|
-;; Components and public fns
|
|
|
-;; =========================
|
|
|
+;; Components
|
|
|
+;; ==========
|
|
|
(rum/defc sortable-title
|
|
|
- [title key state {:keys [sort-by-item sort-desc?]} block-id]
|
|
|
- (let [*sort-by-item (get state ::sort-by-item)
|
|
|
- *desc? (get state ::desc?)]
|
|
|
- [:th.whitespace-nowrap
|
|
|
- [:a {:on-click (fn []
|
|
|
- ;; The two local state atom changes have no effect on
|
|
|
- ;; preserving state. Consider deleting?
|
|
|
- (reset! *sort-by-item key)
|
|
|
- (swap! *desc? not)
|
|
|
- (editor-handler/set-block-property! block-id :query-sort-by (name key))
|
|
|
- (editor-handler/set-block-property! block-id :query-sort-desc (not sort-desc?)))}
|
|
|
- [:div.flex.items-center
|
|
|
- [:span.mr-1 title]
|
|
|
- (when (= sort-by-item key)
|
|
|
- [:span
|
|
|
- (if sort-desc? (svg/caret-down) (svg/caret-up))])]]]))
|
|
|
+ [title column {:keys [sort-by-column sort-desc?]} block-id]
|
|
|
+ [:th.whitespace-nowrap
|
|
|
+ [:a {:on-click (fn []
|
|
|
+ (editor-handler/set-block-property! block-id :query-sort-by (name column))
|
|
|
+ (editor-handler/set-block-property! block-id :query-sort-desc (not sort-desc?)))}
|
|
|
+ [:div.flex.items-center
|
|
|
+ [:span.mr-1 title]
|
|
|
+ (when (= sort-by-column column)
|
|
|
+ [:span
|
|
|
+ (if sort-desc? (svg/caret-down) (svg/caret-up))])]]])
|
|
|
|
|
|
(defn get-keys
|
|
|
+ "Get keys for a query table result, which are the columns in a table"
|
|
|
[result page?]
|
|
|
(let [keys (->> (distinct (mapcat keys (map :block/properties result)))
|
|
|
(remove (property/built-in-properties))
|
|
|
@@ -105,54 +87,56 @@
|
|
|
keys (if page? (distinct (concat keys [:created-at :updated-at])) keys)]
|
|
|
keys))
|
|
|
|
|
|
-;; We refer to rows and columns in a table as keys and items.
|
|
|
-;; TODO: Rename key(s) naming as it conflict with core fns
|
|
|
+(defn- get-columns [current-block result {:keys [page?]}]
|
|
|
+ (let [query-properties (some-> (get-in current-block [:block/properties :query-properties] "")
|
|
|
+ (common-handler/safe-read-string "Parsing query properties failed"))
|
|
|
+ columns (if (seq query-properties)
|
|
|
+ query-properties
|
|
|
+ (get-keys result page?))
|
|
|
+ included-columns #{:created-at :updated-at}]
|
|
|
+ (distinct
|
|
|
+ (if (some included-columns columns)
|
|
|
+ (concat (remove included-columns columns)
|
|
|
+ (filter included-columns columns)
|
|
|
+ included-columns)
|
|
|
+ columns))))
|
|
|
+
|
|
|
+;; Table rows are called items
|
|
|
(rum/defcs result-table < rum/reactive
|
|
|
- (rum/local nil ::sort-by-item)
|
|
|
- (rum/local nil ::desc?)
|
|
|
(rum/local false ::select?)
|
|
|
[state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text]
|
|
|
(when current-block
|
|
|
(let [result (tree/filter-top-level-blocks result)
|
|
|
select? (get state ::select?)
|
|
|
- sort-state (get-sort-state state current-block)
|
|
|
;; remove templates
|
|
|
result (remove (fn [b] (some? (get-in b [:block/properties :template]))) result)
|
|
|
result (if page? result (attach-clock-property result))
|
|
|
clock-time-total (when-not page?
|
|
|
(->> (map #(get-in % [:block/properties :clock-time] 0) result)
|
|
|
(apply +)))
|
|
|
- query-properties (some-> (get-in current-block [:block/properties :query-properties] "")
|
|
|
- (common-handler/safe-read-string "Parsing query properties failed"))
|
|
|
- keys (if (seq query-properties)
|
|
|
- query-properties
|
|
|
- (get-keys result page?))
|
|
|
- included-keys #{:created-at :updated-at}
|
|
|
- keys (distinct
|
|
|
- (if (some included-keys keys)
|
|
|
- (concat (remove included-keys keys)
|
|
|
- (filter included-keys keys)
|
|
|
- included-keys)
|
|
|
- keys))
|
|
|
- result (sort-result result sort-state)]
|
|
|
+ columns (get-columns current-block result {:page? page?})
|
|
|
+ ;; Sort state needs to be in sync between final result and sortable title
|
|
|
+ ;; as user needs to know if there result is sorted
|
|
|
+ sort-state (get-sort-state current-block)
|
|
|
+ result' (sort-result result sort-state)]
|
|
|
[:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e))
|
|
|
:style {:width "100%"}
|
|
|
:class (when-not page? "query-table")}
|
|
|
[:table.table-auto
|
|
|
[:thead
|
|
|
[:tr.cursor
|
|
|
- (for [key keys]
|
|
|
- (let [key-name (if (and (= key :clock-time) (integer? clock-time-total))
|
|
|
+ (for [column columns]
|
|
|
+ (let [title (if (and (= column :clock-time) (integer? clock-time-total))
|
|
|
(util/format "clock-time(total: %s)" (clock/minutes->days:hours:minutes
|
|
|
clock-time-total))
|
|
|
- (name key))]
|
|
|
- (sortable-title key-name key state sort-state (:block/uuid current-block))))]]
|
|
|
+ (name column))]
|
|
|
+ (sortable-title title column sort-state (:block/uuid current-block))))]]
|
|
|
[:tbody
|
|
|
- (for [item result]
|
|
|
+ (for [item result']
|
|
|
(let [format (:block/format item)]
|
|
|
[:tr.cursor
|
|
|
- (for [key keys]
|
|
|
- (let [value (case key
|
|
|
+ (for [column columns]
|
|
|
+ (let [value (case column
|
|
|
:page
|
|
|
[:string (or (:block/original-name item)
|
|
|
(:block/name item))]
|
|
|
@@ -176,7 +160,7 @@
|
|
|
[:string (when-let [updated-at (:block/updated-at item)]
|
|
|
(date/int->local-time-2 updated-at))]
|
|
|
|
|
|
- [:string (get-in item [:block/properties key])])]
|
|
|
+ [:string (get-in item [:block/properties column])])]
|
|
|
[:td.whitespace-nowrap {:on-mouse-down (fn [] (reset! select? false))
|
|
|
:on-mouse-move (fn [] (reset! select? true))
|
|
|
:on-mouse-up (fn []
|