From fbb9c2498b08a7504275f97d31982060d89c3d22 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Mon, 17 Feb 2025 16:06:35 +0800 Subject: [PATCH] refactor: all views support tabs --- src/main/frontend/components/all_pages.cljs | 31 ++-- src/main/frontend/components/objects.cljs | 119 ++------------- src/main/frontend/components/query/view.cljs | 39 ++--- src/main/frontend/components/reference.cljs | 16 +-- src/main/frontend/components/views.cljs | 143 ++++++++++++++----- src/main/frontend/db/async.cljs | 10 +- 6 files changed, 166 insertions(+), 192 deletions(-) diff --git a/src/main/frontend/components/all_pages.cljs b/src/main/frontend/components/all_pages.cljs index 2b08854c14..135d3da938 100644 --- a/src/main/frontend/components/all_pages.cljs +++ b/src/main/frontend/components/all_pages.cljs @@ -51,13 +51,13 @@ (rum/defc all-pages < rum/static [] - (let [db (db/get-db) - [data set-data!] (rum/use-state nil) + (let [[data set-data!] (rum/use-state nil) [loading? set-loading!] (rum/use-state true) columns' (views/build-columns {} (columns) {:with-object-name? false :with-id? false}) - view-entity (first (ldb/get-all-pages-views db))] + ;; view-entity (first (ldb/get-all-pages-views db)) + ] (hooks/use-effect! (fn [] (when-let [^js worker @state/*db-worker] @@ -71,15 +71,16 @@ [:div.ls-all-pages.w-full.mx-auto (if loading? (ui/skeleton) - (views/view view-entity {:data data - :set-data! set-data! - :title-key :all-pages/table-title - :columns columns' - :on-delete-rows (fn [table selected-rows] - (shui/dialog-open! - (component-page/batch-delete-dialog - selected-rows false - (fn [] - (when-let [f (get-in table [:data-fns :set-row-selection!])] - (f {})) - (set-data! (get-all-pages))))))}))])) + (views/view {:data data + :set-data! set-data! + :view-parent nil + :view-identity :all-pages + :columns columns' + :on-delete-rows (fn [table selected-rows] + (shui/dialog-open! + (component-page/batch-delete-dialog + selected-rows false + (fn [] + (when-let [f (get-in table [:data-fns :set-row-selection!])] + (f {})) + (set-data! (get-all-pages))))))}))])) diff --git a/src/main/frontend/components/objects.cljs b/src/main/frontend/components/objects.cljs index baca82352a..b207a3f20d 100644 --- a/src/main/frontend/components/objects.cljs +++ b/src/main/frontend/components/objects.cljs @@ -1,7 +1,6 @@ (ns frontend.components.objects "Provides table views for class objects and property related objects" (:require [frontend.components.filepicker :as filepicker] - [frontend.components.icon :as icon-component] [frontend.components.views :as views] [frontend.db :as db] [frontend.db-mixins :as db-mixins] @@ -15,8 +14,6 @@ [frontend.modules.outliner.ui :as ui-outliner-tx] [frontend.state :as state] [frontend.ui :as ui] - [frontend.util :as util] - [logseq.common.config :as common-config] [logseq.db :as ldb] [logseq.db.frontend.property :as db-property] [logseq.outliner.property :as outliner-property] @@ -39,77 +36,6 @@ (editor-handler/edit-block! (db/entity [:block/uuid (:block/uuid block)]) 0 {:container-id :unknown-container}) block)) -(defn- get-views - [ent] - (let [class (db/entity (:db/id ent))] - (->> (:logseq.property/_view-for class) - (remove (fn [view] - (contains? #{:linked-references :unlinked-references} - (:logseq.property.view/identity view)))) - (ldb/sort-by-order)))) - -(defn- create-view! - [class view-title views set-view-entity! set-views!] - (when-let [page (db/get-case-page common-config/views-page-name)] - (p/let [result (editor-handler/api-insert-new-block! view-title {:page (:block/uuid page) - :properties {:logseq.property/view-for (:db/id class)}}) - view (db/entity [:block/uuid (:block/uuid result)])] - (set-view-entity! view) - (set-views! (concat views [view]))))) - -(rum/defc class-views < rum/reactive db-mixins/query - [class views current-view {:keys [set-view-entity! set-views!]}] - [:div.views.flex.flex-row.items-center.flex-wrap.gap-1 - (for [view* views] - (let [view (db/sub-block (:db/id view*)) - current-view? (= (:db/id current-view) (:db/id view))] - (shui/button - {:variant :ghost - :size :sm - :class (str "text-sm px-2 py-0 h-6 " (when-not current-view? "text-muted-foreground")) - :on-click (fn [e] - (if (and current-view? (not= (:db/id view) (:db/id class))) - (shui/popup-show! - (.-target e) - (fn [] - [:<> - (shui/dropdown-menu-sub - (shui/dropdown-menu-sub-trigger - "Rename") - (shui/dropdown-menu-sub-content - (when-let [block-container (state/get-component :block/container)] - (block-container {} view)))) - (shui/dropdown-menu-item - {:key "Delete" - :on-click (fn [] - (p/do! - (editor-handler/delete-block-aux! view) - (let [views' (remove (fn [v] (= (:db/id v) (:db/id view))) views)] - (set-views! views') - (set-view-entity! (first views')) - (shui/popup-hide!))))} - "Delete")]) - {:as-dropdown? true - :align "start" - :content-props {:onClick shui/popup-hide!}}) - (set-view-entity! view)))} - (let [display-type (or (:db/ident (get view :logseq.property.view/type)) - :logseq.property.view/type.table)] - (when-let [icon (:logseq.property/icon (db/entity display-type))] - (icon-component/icon icon {:color? true}))) - (if (= (:db/id view) (:db/id class)) - "All" - (let [title (:block/title view)] - (if (= title "") - "New view" - title)))))) - (shui/button - {:variant :text - :size :sm - :class "!px-1 text-muted-foreground hover:text-foreground" - :on-click (fn [] (create-view! class "" views set-view-entity! set-views!))} - (ui/icon "plus" {}))]) - (defn- build-asset-file-column [config] {:id :file @@ -124,8 +50,6 @@ (rum/defc class-objects-inner < rum/static [config class objects properties] (let [[loading? set-loading?] (rum/use-state nil) - [view-entity set-view-entity!] (rum/use-state class) - [views set-views!] (rum/use-state [class]) [data set-data!] (rum/use-state objects) ;; Properties can be nil for published private graphs properties' (remove nil? properties) @@ -148,29 +72,20 @@ (fn [] (when (nil? loading?) (set-loading? true) - (p/let [_result (db-async/> (concat [class] views) - (util/distinct-by :db/id))] - (set-views! views) - (when-let [view (first views)] - (set-view-entity! view)) - (p/let [_result (db-async/> (mapcat second filtered-ref-blocks) (map (fn [b] (assoc (db/entity (:db/id b)) :id (:db/id b))))) - columns' (columns {} blocks) - views (filter (fn [v] (= (:logseq.property.view/identity v) :linked-references)) - (:logseq.property/_view-for page-entity))] + columns' (columns {} blocks)] (when (seq blocks) - (views/view (first views) - {:views-title "Linked references" - :view-identity :linked-references - :view-block-title "Linked references" - :view-parent page-entity - :data blocks - :columns columns'})))) + (views/view + {:view-parent page-entity + :view-identity :linked-references + :data blocks + :columns columns'})))) (defn- get-filtered-children [block parent->blocks] diff --git a/src/main/frontend/components/views.cljs b/src/main/frontend/components/views.cljs index ec2fd7dc9c..21475cb6b5 100644 --- a/src/main/frontend/components/views.cljs +++ b/src/main/frontend/components/views.cljs @@ -17,6 +17,7 @@ [frontend.date :as date] [frontend.db :as db] [frontend.db-mixins :as db-mixins] + [frontend.db.async :as db-async] [frontend.handler.db-based.property :as db-property-handler] [frontend.handler.editor :as editor-handler] [frontend.handler.property :as property-handler] @@ -1416,9 +1417,73 @@ (table-view table option row-selection *scroller-ref))) +(defn- create-view! + [view-parent view-identity] + (when-let [page (db/get-case-page common-config/views-page-name)] + (p/let [properties (cond-> + {:logseq.property/view-for (:db/id view-parent) + :logseq.property.view/identity view-identity} + (contains? #{:linked-references :unlinked-references} view-identity) + (assoc :logseq.property.view/type (:db/id (db/entity :logseq.property.view/type.list)))) + result (editor-handler/api-insert-new-block! "" {:page (:block/uuid page) + :properties properties})] + (db/entity [:block/uuid (:block/uuid result)])))) + +(rum/defc views-tab < rum/reactive db-mixins/query + [view-parent current-view {:keys [views set-view-entity! set-views! view-identity]}] + [:div.views.flex.flex-row.items-center.flex-wrap.gap-1 + (for [view* views] + (let [view (db/sub-block (:db/id view*)) + current-view? (= (:db/id current-view) (:db/id view))] + (shui/button + {:variant :ghost + :size :sm + :class (str "text-sm px-2 py-0 h-6 " (when-not current-view? "text-muted-foreground")) + :on-click (fn [e] + (if (and current-view? (not= (:db/id view) (:db/id view-parent))) + (shui/popup-show! + (.-target e) + (fn [] + [:<> + (shui/dropdown-menu-sub + (shui/dropdown-menu-sub-trigger + "Rename") + (shui/dropdown-menu-sub-content + (when-let [block-container (state/get-component :block/container)] + (block-container {} view)))) + (shui/dropdown-menu-item + {:key "Delete" + :on-click (fn [] + (p/do! + (editor-handler/delete-block-aux! view) + (let [views' (remove (fn [v] (= (:db/id v) (:db/id view))) views)] + (set-views! views') + (set-view-entity! (first views')) + (shui/popup-hide!))))} + "Delete")]) + {:as-dropdown? true + :align "start" + :content-props {:onClick shui/popup-hide!}}) + (set-view-entity! view)))} + (let [display-type (or (:db/ident (get view :logseq.property.view/type)) + :logseq.property.view/type.table)] + (when-let [icon (:logseq.property/icon (db/entity display-type))] + (icon-component/icon icon {:color? true}))) + (if (= (:db/id view) (:db/id view-parent)) + "All" + (let [title (:block/title view)] + (if (= title "") + "New view" + title)))))) + (shui/button + {:variant :text + :size :sm + :class "!px-1 text-muted-foreground hover:text-foreground" + :on-click (fn [] (create-view! view-parent view-identity))} + (ui/icon "plus" {}))]) + (rum/defc ^:large-vars/cleanup-todo view-inner < rum/static - [view-entity {:keys [data set-data! columns add-new-object! views-title title-key render-empty-title?] :as option - :or {render-empty-title? false}} + [view-entity {:keys [view-parent data set-data! columns add-new-object!] :as option} *scroller-ref] (let [[input set-input!] (rum/use-state "") sorting* (:logseq.property.table/sorting view-entity) @@ -1501,13 +1566,8 @@ {:ref *view-ref} (ui/foldable [:div.flex.flex-1.flex-wrap.items-center.justify-between.gap-1 - (when-not render-empty-title? - [:div.flex.flex-row.items-center.gap-2 - (or - views-title - [:div.font-medium.opacity-50.text-sm - (t (or title-key :views.table/default-title) - (count (:rows table)))])]) + [:div.flex.flex-row.items-center.gap-2 + (views-tab view-parent view-entity option)] [:div.view-actions.flex.items-center.gap-1 (when (seq sorting) @@ -1562,19 +1622,7 @@ (view-cp view-entity table option view-opts)))] {:title-trigger? false})])) -(defn- create-view! - [view-parent view-title view-identity] - (when-let [page (db/get-case-page common-config/views-page-name)] - (p/let [properties (cond-> - {:logseq.property/view-for (:db/id view-parent) - :logseq.property.view/identity view-identity} - (contains? #{:linked-references :unlinked-references} view-identity) - (assoc :logseq.property.view/type (:db/id (db/entity :logseq.property.view/type.list)))) - result (editor-handler/api-insert-new-block! view-title {:page (:block/uuid page) - :properties properties})] - (db/entity [:block/uuid (:block/uuid result)])))) - -(rum/defcs view +(rum/defcs view-container "Provides a view for data like query results and tagged objects, multiple layouts such as table and list are supported. Args: * view-entity: a db Entity @@ -1587,27 +1635,44 @@ * show-add-property?: whether to show `Add property` * add-property!: `fn` to add a new property (or column) * on-delete-rows: `fn` to trigger when deleting selected objects" - < rum/reactive - {:init (fn [state] - (let [[view-entity option] (:rum/args state) - *view-entity (atom view-entity)] - (when (and (nil? view-entity) - (:view-parent option) - (string? (:view-block-title option)) - (keyword? (:view-identity option))) - ;; view not exists yet, let's create one - (p/let [new-view (create-view! (:view-parent option) - (:view-block-title option) - (:view-identity option))] - (reset! *view-entity new-view))) - (assoc state ::view-entity *view-entity)))} + < rum/reactive db-mixins/query (rum/local nil ::scroller-ref) - [state _view-entity option] - (let [view-entity (rum/react (::view-entity state)) - view-entity' (or (db/sub-block (:db/id view-entity)) view-entity)] + [state view-entity option] + (let [view-entity' (or (db/sub-block (:db/id view-entity)) view-entity)] (rum/with-key (view-inner view-entity' (cond-> option config/publishing? (dissoc :add-new-object!)) (::scroller-ref state)) (str "view-" (:db/id view-entity'))))) + +(defn- get-views + [ent] + (let [class (db/entity (:db/id ent))] + (->> (:logseq.property/_view-for class) + (remove (fn [view] + (contains? #{:linked-references :unlinked-references} + (:logseq.property.view/identity view)))) + (ldb/sort-by-order)))) + +(rum/defc view < rum/static + [{:keys [view-parent view-identity view-entity] :as option}] + (let [[view-entity set-view-entity!] (rum/use-state view-entity) + [views set-views!] (rum/use-state nil)] + (hooks/use-effect! + (fn [] + (p/let [_result (db-async/