diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 3283eab3ff0..a02526fc6d1 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -2138,16 +2138,26 @@ (ui/foldable [:div.custom-query-title title - (when (and current-block (not page-list?)) + (when current-block [:div.flex.flex-row.align-items.mt-2 {:on-mouse-down (fn [e] (util/stop e))} - [:span.mr-2.ml-2.text-sm "Table view"] - [:div {:style {:margin-top 3}} - (ui/toggle table? - (fn [] - (editor-handler/set-block-property! current-block-uuid - "query-table" - (not table?))) - true)]])] + (when-not page-list? + [:div.flex.flex-row + [:div.mx-2 [:span.text-sm "Table view"]] + [:div {:style {:margin-top 5}} + (ui/toggle table? + (fn [] + (editor-handler/set-block-property! current-block-uuid + "query-table" + (not table?))) + true)]]) + + [:a.mx-2.opacity-60.hover:opacity-100.block + {:on-click (fn [] + (let [all-keys (query-table/get-keys result page-list?)] + (state/pub-event! [:modal/set-query-properties current-block all-keys])))} + [:span.table-query-properties + [:span.text-sm.mr-1 "Set properties"] + svg/settings-sm]]])] (cond (and (seq result) view-f) (let [result (try @@ -2160,10 +2170,10 @@ (util/hiccup-keywordize result)) page-list? - (query-table/result-table config result {:page? true} map-inline page-cp ->elem inline-text) + (query-table/result-table config current-block result {:page? true} map-inline page-cp ->elem inline-text) table? - (query-table/result-table config result {:page? false} map-inline page-cp ->elem inline-text) + (query-table/result-table config current-block result {:page? false} map-inline page-cp ->elem inline-text) (and (seq result) (or only-blocks? blocks-grouped-by-page?)) (->hiccup result (cond-> (assoc config diff --git a/src/main/frontend/components/block.css b/src/main/frontend/components/block.css index f9cea5d8725..44ee0103f6f 100644 --- a/src/main/frontend/components/block.css +++ b/src/main/frontend/components/block.css @@ -427,3 +427,7 @@ a:hover > .bullet-container .bullet { a.filter svg { transform: scale(0.9); } + +.table-query-properties svg { + display: inline; +} diff --git a/src/main/frontend/components/query_table.cljs b/src/main/frontend/components/query_table.cljs index 407655a72a9..a5dc57a057b 100644 --- a/src/main/frontend/components/query_table.cljs +++ b/src/main/frontend/components/query_table.cljs @@ -7,7 +7,8 @@ [frontend.date :as date] [frontend.state :as state] [clojure.string :as string] - [frontend.components.svg :as svg])) + [frontend.components.svg :as svg] + [frontend.handler.common :as common-handler])) ;; TODO: extract to table utils (defn- sort-result-by @@ -30,85 +31,95 @@ [:span (if @desc? (svg/caret-down) (svg/caret-up))])]]]) +(defn get-keys + [result page?] + (let [keys (->> (distinct (mapcat keys (map :block/properties result))) + (remove property/built-in-properties) + (remove #{:template})) + keys (if page? (cons :page keys) (cons :block keys)) + keys (concat keys [:created-at :updated-at])] + keys)) + (rum/defcs result-table < rum/reactive (rum/local :updated-at ::sort-by-item) (rum/local true ::desc?) (rum/local false ::select?) - [state config result {:keys [select-keys page?]} map-inline page-cp ->elem inline-text] - (let [select? (get state ::select?) - *sort-by-item (get state ::sort-by-item) - *desc? (get state ::desc?) - editor-box (get config :editor-box) - ;; remove templates - result (remove (fn [b] (some? (get-in b [:block/properties :template]))) result) - all-keys (->> (distinct (mapcat keys (map :block/properties result))) - (remove property/built-in-properties)) - keys (if (seq select-keys) select-keys all-keys) - keys (if page? (cons :page keys) (cons :block keys)) - keys (concat keys [:created-at :updated-at]) - sort-by-fn (fn [item] - (let [key @*sort-by-item] - (case key - :created-at - (:block/created-at item) - :updated-at - (:block/updated-at item) - :block - (:block/content item) - :page - (:block/name item) - (get-in item [:block/properties key])))) - result (sort-result-by sort-by-fn @*desc? result)] - [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e)) - :style {:width "100%"}} - [:table.table-auto - (for [key keys] - (sortable-title (name key) key *sort-by-item *desc?)) - (for [item result] - (let [format (:block/format item) - edit-input-id (str "edit-block-" (:id config) "-" (:block/uuid item)) - heading-level (:block/heading-level item)] - [:tr.cursor - (for [key keys] - (let [value (case key + [state config current-block result {:keys [page?]} map-inline page-cp ->elem inline-text] + (when current-block + (let [select? (get state ::select?) + *sort-by-item (get state ::sort-by-item) + *desc? (get state ::desc?) + editor-box (get config :editor-box) + ;; remove templates + result (remove (fn [b] (some? (get-in b [:block/properties :template]))) result) + 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?)) + sort-by-fn (fn [item] + (let [key @*sort-by-item] + (case key + :created-at + (:block/created-at item) + :updated-at + (:block/updated-at item) + :block + (:block/content item) :page - [:string (or (:block/original-name item) - (:block/name item))] + (:block/name item) + (get-in item [:block/properties key])))) + result (sort-result-by sort-by-fn @*desc? result)] + [:div.overflow-x-auto {:on-mouse-down (fn [e] (.stopPropagation e)) + :style {:width "100%"}} + [:table.table-auto + (for [key keys] + (sortable-title (name key) key *sort-by-item *desc?)) + (for [item result] + (let [format (:block/format item) + edit-input-id (str "edit-block-" (:id config) "-" (:block/uuid item)) + heading-level (:block/heading-level item)] + [:tr.cursor + (for [key keys] + (let [value (case key + :page + [:string (or (:block/original-name item) + (:block/name item))] - :block ; block title - (let [title (:block/title item)] - (if (seq title) - [:element (->elem :div (map-inline config title))] - [:string (:block/content item)])) + :block ; block title + (let [title (:block/title item)] + (if (seq title) + [:element (->elem :div (map-inline config title))] + [:string (:block/content item)])) - :created-at - [:string (when-let [created-at (:block/created-at item)] - (date/int->local-time-2 created-at))] + :created-at + [:string (when-let [created-at (:block/created-at item)] + (date/int->local-time-2 created-at))] - :updated-at - [:string (when-let [updated-at (:block/updated-at item)] - (date/int->local-time-2 updated-at))] + :updated-at + [:string (when-let [updated-at (:block/updated-at item)] + (date/int->local-time-2 updated-at))] - [:string (get-in item [:block/properties key])])] - [:td.whitespace-nowrap {:on-mouse-down (fn [] (reset! select? false)) - :on-mouse-move (fn [] (reset! select? true)) - :on-mouse-up (fn [] - (when-not @select? - (state/sidebar-add-block! - (state/get-current-repo) - (:db/id item) - :block-ref - {:block item})))} - (when value - (if (= :element (first value)) - (second value) - (let [value (second value)] - (if (coll? value) - (let [vals (for [item value] - (page-cp {} {:block/name item}))] - (interpose [:span ", "] vals)) - (if (not (string? value)) - value - (if-let [page (db/entity [:block/name (string/lower-case value)])] - (page-cp {} page) - (inline-text format value)))))))]))]))]])) + [:string (get-in item [:block/properties key])])] + [:td.whitespace-nowrap {:on-mouse-down (fn [] (reset! select? false)) + :on-mouse-move (fn [] (reset! select? true)) + :on-mouse-up (fn [] + (when-not @select? + (state/sidebar-add-block! + (state/get-current-repo) + (:db/id item) + :block-ref + {:block item})))} + (when value + (if (= :element (first value)) + (second value) + (let [value (second value)] + (if (coll? value) + (let [vals (for [item value] + (page-cp {} {:block/name item}))] + (interpose [:span ", "] vals)) + (if (not (string? value)) + value + (if-let [page (db/entity [:block/name (string/lower-case value)])] + (page-cp {} page) + (inline-text format value)))))))]))]))]]))) diff --git a/src/main/frontend/handler/editor.cljs b/src/main/frontend/handler/editor.cljs index e7711ad4805..45b5a35235a 100644 --- a/src/main/frontend/handler/editor.cljs +++ b/src/main/frontend/handler/editor.cljs @@ -923,6 +923,22 @@ (let [key (keyword key)] (block-property-aux! block-id key value))) +(defn set-block-query-properties! + [block-id all-properties key add?] + (when-let [block (db/entity [:block/uuid block-id])] + (let [query-properties (-> (get-in block [:block/properties :query-properties] "") + (common-handler/safe-read-string "Failed to parse query properties")) + query-properties (if (seq query-properties) + query-properties + all-properties) + query-properties (if add? + (distinct (conj query-properties key)) + (remove #{key} query-properties)) + query-properties (vec query-properties)] + (if (seq query-properties) + (set-block-property! block-id :query-properties (str query-properties)) + (remove-block-property! block-id :query-properties))))) + (defn set-block-timestamp! [block-id key value] (let [key (string/lower-case key) diff --git a/src/main/frontend/handler/events.cljs b/src/main/frontend/handler/events.cljs index dd8d94d2f09..64f8a7da0a5 100644 --- a/src/main/frontend/handler/events.cljs +++ b/src/main/frontend/handler/events.cljs @@ -7,6 +7,8 @@ [frontend.util :as util :refer [profile]] [frontend.config :as config] [frontend.handler.notification :as notification] + [frontend.handler.common :as common-handler] + [frontend.handler.editor :as editor-handler] [frontend.components.encryption :as encryption] [frontend.fs.nfs :as nfs] [frontend.db.conn :as conn] @@ -14,7 +16,9 @@ [frontend.db-schema :as db-schema] [frontend.db :as db] [datascript.core :as d] - ["semver" :as semver])) + ["semver" :as semver] + [clojure.set :as set] + [rum.core :as rum])) ;; TODO: should we move all events here? @@ -30,8 +34,8 @@ "Please make sure that you've installed the logseq app for the repo %s on GitHub. " repo-url) (ui/button - "Install Logseq on GitHub" - :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))]] + "Install Logseq on GitHub" + :href (str "https://github.com/apps/" config/github-app-name "/installations/new"))]] :error false)) @@ -86,17 +90,56 @@ "Grant native filesystem permission for directory: " [:b (config/get-local-dir repo)]] (ui/button - "Grant" - :class "ui__modal-enter" - :on-click (fn [] - (nfs/check-directory-permission! repo) - (close-fn)))]))) + "Grant" + :class "ui__modal-enter" + :on-click (fn [] + (nfs/check-directory-permission! repo) + (close-fn)))]))) (defmethod handle :modal/nfs-ask-permission [] (when-let [repo (get-local-repo)] (state/set-modal! (ask-permission repo)))) - +(defonce *query-properties (atom {})) +(rum/defc query-properties-settings-inner < rum/reactive + {:will-unmount (fn [state] + (reset! *query-properties {}) + state)} + [block shown-properties all-properties close-fn] + (let [query-properties (rum/react *query-properties)] + [:div.p-4 + [:div.font-bold "Properties settings for this query:"] + (for [property all-properties] + (let [property-value (get query-properties property) + shown? (if (nil? property-value) + (contains? shown-properties property) + property-value)] + [:div.flex.flex-row.m-2.justify-between.align-items + [:div (name property)] + [:div.mt-1 (ui/toggle shown? + (fn [] + (let [value (not shown?)] + (swap! *query-properties assoc property value) + (editor-handler/set-block-query-properties! + (:block/uuid block) + all-properties + property + value))) + true)]]))])) + +(defn query-properties-settings + [block shown-properties all-properties] + (fn [close-fn] + (query-properties-settings-inner block shown-properties all-properties close-fn))) + +(defmethod handle :modal/set-query-properties [[_ block all-properties]] + (let [block-properties (some-> (get-in block [:block/properties :query-properties]) + (common-handler/safe-read-string "Parsing query properties failed")) + shown-properties (if (seq block-properties) + (set block-properties) + (set all-properties)) + shown-properties (set/intersection (set all-properties) shown-properties)] + (state/set-modal! (query-properties-settings block shown-properties all-properties)))) (defmethod handle :after-db-restore [[_ repos]] (mapv (fn [{url :url} repo] diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 8f686622bfa..c0104bf2024 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -446,7 +446,7 @@ "exiting" "ease-in duration-200 opacity-100 translate-y-0 sm:scale-100" "exited" "ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95")} [:div.absolute.top-0.right-0.pt-2.pr-2 - [:button.ui__modal-close + [:a.ui__modal-close.opacity-60.hover:opacity-100 {:aria-label "Close" :type "button" :on-click close-fn} diff --git a/src/main/frontend/util/property.cljs b/src/main/frontend/util/property.cljs index ca632c8bf8b..8785bb0b9bf 100644 --- a/src/main/frontend/util/property.cljs +++ b/src/main/frontend/util/property.cljs @@ -14,7 +14,7 @@ (def built-in-properties (set/union - #{:id :custom-id :background-color :heading :collapsed :created-at :updated-at :last-modified-at :created_at :last_modified_at :query-table} + #{:id :custom-id :background-color :heading :collapsed :created-at :updated-at :last-modified-at :created_at :last_modified_at :query-table :query-properties} (set (map keyword config/markers)))) (defn properties-built-in?